aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/9p-handle.c54
-rw-r--r--hw/9pfs/9p-local.c36
-rw-r--r--hw/9pfs/9p-proxy.c30
-rw-r--r--hw/9pfs/9p-synth.c2
-rw-r--r--hw/9pfs/9p-xattr.h5
-rw-r--r--hw/9pfs/9p.c22
-rw-r--r--hw/9pfs/9p.h14
-rw-r--r--hw/9pfs/virtio-9p-device.c62
-rw-r--r--hw/9pfs/xen-9p-backend.c2
-rw-r--r--hw/acpi/core.c1
-rw-r--r--hw/acpi/ipmi-stub.c1
-rw-r--r--hw/alpha/dp264.c4
-rw-r--r--hw/arm/fsl-imx6.c1
-rw-r--r--hw/arm/spitz.c1
-rw-r--r--hw/arm/virt-acpi-build.c18
-rw-r--r--hw/arm/xlnx-zcu102.c23
-rw-r--r--hw/arm/xlnx-zynqmp.c26
-rw-r--r--hw/audio/fmopl.c1
-rw-r--r--hw/audio/fmopl.h1
-rw-r--r--hw/audio/pcspk.c1
-rw-r--r--hw/block/block.c15
-rw-r--r--hw/block/dataplane/virtio-blk.c12
-rw-r--r--hw/block/dataplane/virtio-blk.h2
-rw-r--r--hw/block/fdc.c17
-rw-r--r--hw/block/m25p80.c80
-rw-r--r--hw/block/nvme.c372
-rw-r--r--hw/block/trace-events100
-rw-r--r--hw/block/virtio-blk.c30
-rw-r--r--hw/block/xen_disk.c53
-rw-r--r--hw/char/debugcon.c1
-rw-r--r--hw/char/xen_console.c1
-rw-r--r--hw/core/machine.c1
-rw-r--r--hw/core/qdev-properties-system.c1
-rw-r--r--hw/cpu/core.c1
-rw-r--r--hw/display/cirrus_vga.c1
-rw-r--r--hw/display/qxl.h1
-rw-r--r--hw/display/sm501.c30
-rw-r--r--hw/display/tc6393xb.c1
-rw-r--r--hw/display/vga-isa-mm.c4
-rw-r--r--hw/display/vga-isa.c3
-rw-r--r--hw/display/vga-pci.c1
-rw-r--r--hw/display/vga.c5
-rw-r--r--hw/display/vga_int.h3
-rw-r--r--hw/display/vga_regs.h (renamed from hw/display/vga.h)0
-rw-r--r--hw/display/virtio-vga.c1
-rw-r--r--hw/display/vmware_vga.c1
-rw-r--r--hw/display/xenfb.c294
-rw-r--r--hw/dma/Makefile.objs1
-rw-r--r--hw/dma/sparc32_dma.c2
-rw-r--r--hw/dma/trace-events10
-rw-r--r--hw/i2c/pm_smbus.c1
-rw-r--r--hw/i2c/ppc4xx_i2c.c198
-rw-r--r--hw/i2c/smbus_ich9.c1
-rw-r--r--hw/i386/Makefile.objs2
-rw-r--r--hw/i386/acpi-build.c35
-rw-r--r--hw/i386/amd_iommu.c5
-rw-r--r--hw/i386/amd_iommu.h5
-rw-r--r--hw/i386/kvm/i8259.c1
-rw-r--r--hw/i386/pc.c5
-rw-r--r--hw/i386/trace-events4
-rw-r--r--hw/i386/vmmouse.c (renamed from hw/input/vmmouse.c)1
-rw-r--r--hw/i386/vmport.c (renamed from hw/misc/vmport.c)24
-rw-r--r--hw/i386/xen/xen-mapcache.c2
-rw-r--r--hw/i386/xen/xen_platform.c1
-rw-r--r--hw/ide/Makefile.objs1
-rw-r--r--hw/ide/ahci.c1
-rw-r--r--hw/ide/cmd646.c1
-rw-r--r--hw/ide/core.c3
-rw-r--r--hw/ide/ich.c1
-rw-r--r--hw/ide/isa.c1
-rw-r--r--hw/ide/microdrive.c1
-rw-r--r--hw/ide/pci.c1
-rw-r--r--hw/ide/piix.c2
-rw-r--r--hw/ide/qdev.c12
-rw-r--r--hw/ide/sii3112.c368
-rw-r--r--hw/ide/trace-events5
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/input/Makefile.objs3
-rw-r--r--hw/input/adb-internal.h49
-rw-r--r--hw/input/adb-kbd.c400
-rw-r--r--hw/input/adb-mouse.c254
-rw-r--r--hw/input/adb.c622
-rw-r--r--hw/input/hid.c8
-rw-r--r--hw/input/trace-events8
-rw-r--r--hw/intc/apic.c12
-rw-r--r--hw/intc/arm_gic.c5
-rw-r--r--hw/intc/arm_gicv3_dist.c13
-rw-r--r--hw/intc/arm_gicv3_its_common.c10
-rw-r--r--hw/intc/arm_gicv3_its_kvm.c53
-rw-r--r--hw/intc/arm_gicv3_redist.c13
-rw-r--r--hw/intc/armv7m_nvic.c100
-rw-r--r--hw/intc/i8259.c86
-rw-r--r--hw/intc/i8259_common.c49
-rw-r--r--hw/intc/lm32_pic.c1
-rw-r--r--hw/intc/openpic.c102
-rw-r--r--hw/intc/slavio_intctl.c1
-rw-r--r--hw/intc/trace-events11
-rw-r--r--hw/intc/xics.c34
-rw-r--r--hw/intc/xics_spapr.c116
-rw-r--r--hw/ipmi/isa_ipmi_bt.c1
-rw-r--r--hw/ipmi/isa_ipmi_kcs.c1
-rw-r--r--hw/isa/i82378.c5
-rw-r--r--hw/isa/vt82c686.c1
-rw-r--r--hw/mem/pc-dimm.c2
-rw-r--r--hw/mips/boston.c14
-rw-r--r--hw/mips/mips_fulong2e.c4
-rw-r--r--hw/mips/mips_jazz.c5
-rw-r--r--hw/mips/mips_malta.c4
-rw-r--r--hw/mips/mips_r4k.c5
-rw-r--r--hw/misc/Makefile.objs2
-rw-r--r--hw/misc/imx6_ccm.c2
-rw-r--r--hw/misc/ivshmem.c1
-rw-r--r--hw/misc/pvpanic.c12
-rw-r--r--hw/misc/sga.c1
-rw-r--r--hw/moxie/moxiesim.c13
-rw-r--r--hw/net/e1000.c92
-rw-r--r--hw/net/e1000e.c4
-rw-r--r--hw/net/e1000e_core.c16
-rw-r--r--hw/net/e1000e_core.h2
-rw-r--r--hw/net/e1000x_common.h2
-rw-r--r--hw/net/eepro100.c32
-rw-r--r--hw/net/ftgmac100.c2
-rw-r--r--hw/net/imx_fec.c210
-rw-r--r--hw/net/lan9118.c3
-rw-r--r--hw/net/lance.c2
-rw-r--r--hw/net/ne2000-isa.c6
-rw-r--r--hw/net/ne2000.c4
-rw-r--r--hw/net/ne2000.h3
-rw-r--r--hw/net/opencores_eth.c3
-rw-r--r--hw/net/pcnet.c22
-rw-r--r--hw/net/rtl8139.c2
-rw-r--r--hw/net/sungem.c5
-rw-r--r--hw/net/sunhme.c25
-rw-r--r--hw/nios2/boot.c1
-rw-r--r--hw/nvram/Makefile.objs1
-rw-r--r--hw/nvram/eeprom_at24c.c205
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c1
-rw-r--r--hw/pci-host/apb.c544
-rw-r--r--hw/pci-host/ppce500.c5
-rw-r--r--hw/ppc/e500.c4
-rw-r--r--hw/ppc/pnv.c96
-rw-r--r--hw/ppc/pnv_bmc.c2
-rw-r--r--hw/ppc/pnv_core.c18
-rw-r--r--hw/ppc/pnv_lpc.c16
-rw-r--r--hw/ppc/pnv_psi.c4
-rw-r--r--hw/ppc/pnv_xscom.c10
-rw-r--r--hw/ppc/prep.c1
-rw-r--r--hw/ppc/spapr.c224
-rw-r--r--hw/ppc/spapr_cpu_core.c42
-rw-r--r--hw/ppc/spapr_events.c22
-rw-r--r--hw/ppc/spapr_hcall.c1
-rw-r--r--hw/ppc/spapr_pci.c19
-rw-r--r--hw/ppc/spapr_pci_vfio.c47
-rw-r--r--hw/ppc/spapr_rtas.c30
-rw-r--r--hw/ppc/spapr_vio.c5
-rw-r--r--hw/ppc/trace-events4
-rw-r--r--hw/s390x/3270-ccw.c2
-rw-r--r--hw/s390x/css-bridge.c13
-rw-r--r--hw/s390x/css.c35
-rw-r--r--hw/s390x/s390-ccw.c2
-rw-r--r--hw/s390x/s390-pci-bus.h1
-rw-r--r--hw/s390x/s390-pci-inst.c337
-rw-r--r--hw/s390x/s390-pci-inst.h22
-rw-r--r--hw/s390x/s390-virtio-ccw.c59
-rw-r--r--hw/s390x/virtio-ccw.c4
-rw-r--r--hw/scsi/scsi-bus.c16
-rw-r--r--hw/scsi/scsi-disk.c14
-rw-r--r--hw/scsi/vhost-user-scsi.c1
-rw-r--r--hw/sd/pxa2xx_mmci.c78
-rw-r--r--hw/sd/trace-events4
-rw-r--r--hw/smbios/smbios_type_38-stub.c1
-rw-r--r--hw/sparc/Makefile.objs2
-rw-r--r--hw/sparc/sun4m.c3
-rw-r--r--hw/sparc/sun4m_iommu.c (renamed from hw/dma/sun4m_iommu.c)13
-rw-r--r--hw/sparc/trace-events10
-rw-r--r--hw/sparc64/Makefile.objs1
-rw-r--r--hw/sparc64/sparc64.c2
-rw-r--r--hw/sparc64/sun4u.c193
-rw-r--r--hw/sparc64/sun4u_iommu.c342
-rw-r--r--hw/sparc64/trace-events9
-rw-r--r--hw/ssi/aspeed_smc.c3
-rw-r--r--hw/ssi/xilinx_spips.c928
-rw-r--r--hw/timer/i8254.c1
-rw-r--r--hw/timer/i8254_common.c1
-rw-r--r--hw/timer/mc146818rtc.c2
-rw-r--r--hw/timer/pxa2xx_timer.c17
-rw-r--r--hw/timer/slavio_timer.c1
-rw-r--r--hw/tpm/Makefile.objs5
-rw-r--r--hw/tpm/tpm_emulator.c116
-rw-r--r--hw/tpm/tpm_int.h31
-rw-r--r--hw/tpm/tpm_ioctl.h28
-rw-r--r--hw/tpm/tpm_passthrough.c91
-rw-r--r--hw/tpm/tpm_tis.c215
-rw-r--r--hw/tpm/tpm_util.c229
-rw-r--r--hw/tpm/tpm_util.h21
-rw-r--r--hw/unicore32/puv3.c15
-rw-r--r--hw/usb/bus.c22
-rw-r--r--hw/usb/dev-storage.c29
-rw-r--r--hw/vfio/ccw.c2
-rw-r--r--hw/vfio/common.c8
-rw-r--r--hw/vfio/pci.h2
-rw-r--r--hw/virtio/vhost-vsock.c2
-rw-r--r--hw/virtio/virtio-balloon.c2
-rw-r--r--hw/watchdog/wdt_ib700.c1
-rw-r--r--hw/xen/xen_pt.c1
205 files changed, 5696 insertions, 3033 deletions
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
index 9875f1894c..c1681d3c8a 100644
--- a/hw/9pfs/9p-handle.c
+++ b/hw/9pfs/9p-handle.c
@@ -41,10 +41,10 @@
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
-struct handle_data {
+typedef struct HandleData {
int mountfd;
int handle_bytes;
-};
+} HandleData;
static inline int name_to_handle(int dirfd, const char *name,
struct file_handle *fh, int *mnt_id, int flags)
@@ -79,7 +79,7 @@ static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
struct stat *stbuf)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
if (fd < 0) {
@@ -94,7 +94,7 @@ static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
char *buf, size_t bufsz)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
if (fd < 0) {
@@ -118,7 +118,7 @@ static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
static int handle_open(FsContext *ctx, V9fsPath *fs_path,
int flags, V9fsFidOpenState *fs)
{
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
return fs->fd;
@@ -207,7 +207,7 @@ static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -222,7 +222,7 @@ static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
const char *name, FsCred *credp)
{
int dirfd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
if (dirfd < 0) {
@@ -240,7 +240,7 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
const char *name, FsCred *credp)
{
int dirfd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
if (dirfd < 0) {
@@ -272,7 +272,7 @@ static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
{
int ret;
int dirfd, fd;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
if (dirfd < 0) {
@@ -297,7 +297,7 @@ static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
V9fsPath *dir_path, const char *name, FsCred *credp)
{
int fd, dirfd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
if (dirfd < 0) {
@@ -322,7 +322,7 @@ static int handle_link(FsContext *ctx, V9fsPath *oldpath,
V9fsPath *dirpath, const char *name)
{
int oldfd, newdirfd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
if (oldfd < 0) {
@@ -342,7 +342,7 @@ static int handle_link(FsContext *ctx, V9fsPath *oldpath,
static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
if (fd < 0) {
@@ -363,7 +363,7 @@ static int handle_rename(FsContext *ctx, const char *oldpath,
static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)fs_ctx->private;
+ HandleData *data = (HandleData *) fs_ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
if (fd < 0) {
@@ -379,7 +379,7 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
{
int ret;
int fd;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -418,7 +418,7 @@ static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
struct statfs *stbuf)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -433,7 +433,7 @@ static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
const char *name, void *value, size_t size)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -448,7 +448,7 @@ static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
void *value, size_t size)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -463,7 +463,7 @@ static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
void *value, size_t size, int flags)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -478,7 +478,7 @@ static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
const char *name)
{
int fd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
if (fd < 0) {
@@ -495,7 +495,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
char *buffer;
struct file_handle *fh;
int dirfd, ret, mnt_id;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
/* "." and ".." are not allowed */
if (!strcmp(name, ".") || !strcmp(name, "..")) {
@@ -536,7 +536,7 @@ static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
const char *new_name)
{
int olddirfd, newdirfd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
if (olddirfd < 0) {
@@ -557,7 +557,7 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
const char *name, int flags)
{
int dirfd, ret;
- struct handle_data *data = (struct handle_data *)ctx->private;
+ HandleData *data = (HandleData *) ctx->private;
int rflags;
dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
@@ -604,12 +604,12 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
#endif
}
-static int handle_init(FsContext *ctx)
+static int handle_init(FsContext *ctx, Error **errp)
{
int ret, mnt_id;
struct statfs stbuf;
struct file_handle fh;
- struct handle_data *data = g_malloc(sizeof(struct handle_data));
+ HandleData *data = g_malloc(sizeof(HandleData));
data->mountfd = open(ctx->fs_root, O_DIRECTORY);
if (data->mountfd < 0) {
@@ -646,17 +646,19 @@ out:
static void handle_cleanup(FsContext *ctx)
{
- struct handle_data *data = ctx->private;
+ HandleData *data = ctx->private;
close(data->mountfd);
g_free(data);
}
-static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
+static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
{
const char *sec_model = qemu_opt_get(opts, "security_model");
const char *path = qemu_opt_get(opts, "path");
+ warn_report("handle backend is deprecated");
+
if (sec_model) {
error_report("Invalid argument security_model specified with handle fsdriver");
return -1;
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index e51af87309..b25c185ff0 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1400,13 +1400,14 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
#endif
}
-static int local_init(FsContext *ctx)
+static int local_init(FsContext *ctx, Error **errp)
{
struct statfs stbuf;
LocalData *data = g_malloc(sizeof(*data));
data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY);
if (data->mountfd == -1) {
+ error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root);
goto err;
}
@@ -1459,16 +1460,21 @@ static void local_cleanup(FsContext *ctx)
g_free(data);
}
-static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
+static void error_append_security_model_hint(Error **errp)
+{
+ error_append_hint(errp, "Valid options are: security_model="
+ "[passthrough|mapped-xattr|mapped-file|none]\n");
+}
+
+static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
{
const char *sec_model = qemu_opt_get(opts, "security_model");
const char *path = qemu_opt_get(opts, "path");
- Error *err = NULL;
+ Error *local_err = NULL;
if (!sec_model) {
- error_report("Security model not specified, local fs needs security model");
- error_printf("valid options are:"
- "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
+ error_setg(errp, "security_model property not set");
+ error_append_security_model_hint(errp);
return -1;
}
@@ -1482,20 +1488,20 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
} else if (!strcmp(sec_model, "mapped-file")) {
fse->export_flags |= V9FS_SM_MAPPED_FILE;
} else {
- error_report("Invalid security model %s specified", sec_model);
- error_printf("valid options are:"
- "\t[passthrough|mapped-xattr|mapped-file|none]\n");
+ error_setg(errp, "invalid security_model property '%s'", sec_model);
+ error_append_security_model_hint(errp);
return -1;
}
if (!path) {
- error_report("fsdev: No path specified");
+ error_setg(errp, "path property not set");
return -1;
}
- fsdev_throttle_parse_opts(opts, &fse->fst, &err);
- if (err) {
- error_reportf_err(err, "Throttle configuration is not valid: ");
+ fsdev_throttle_parse_opts(opts, &fse->fst, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "invalid throttle configuration: ");
return -1;
}
@@ -1507,11 +1513,11 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
qemu_opt_get_number(opts, "dmode", SM_LOCAL_DIR_MODE_BITS) & 0777;
} else {
if (qemu_opt_find(opts, "fmode")) {
- error_report("fmode is only valid for mapped 9p modes");
+ error_setg(errp, "fmode is only valid for mapped security modes");
return -1;
}
if (qemu_opt_find(opts, "dmode")) {
- error_report("dmode is only valid for mapped 9p modes");
+ error_setg(errp, "dmode is only valid for mapped security modes");
return -1;
}
}
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index 28b20a7c3d..f030c6a428 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -1083,25 +1083,25 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
return err;
}
-static int connect_namedsocket(const char *path)
+static int connect_namedsocket(const char *path, Error **errp)
{
int sockfd, size;
struct sockaddr_un helper;
if (strlen(path) >= sizeof(helper.sun_path)) {
- error_report("Socket name too long");
+ error_setg(errp, "socket name too long");
return -1;
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
- error_report("Failed to create socket: %s", strerror(errno));
+ error_setg_errno(errp, errno, "failed to create client socket");
return -1;
}
strcpy(helper.sun_path, path);
helper.sun_family = AF_UNIX;
size = strlen(helper.sun_path) + sizeof(helper.sun_family);
if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
- error_report("Failed to connect to %s: %s", path, strerror(errno));
+ error_setg_errno(errp, errno, "failed to connect to '%s'", path);
close(sockfd);
return -1;
}
@@ -1111,17 +1111,27 @@ static int connect_namedsocket(const char *path)
return sockfd;
}
-static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
+static void error_append_socket_sockfd_hint(Error **errp)
+{
+ error_append_hint(errp, "Either specify socket=/some/path where /some/path"
+ " points to a listening AF_UNIX socket or sock_fd=fd"
+ " where fd is a file descriptor to a connected AF_UNIX"
+ " socket\n");
+}
+
+static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp)
{
const char *socket = qemu_opt_get(opts, "socket");
const char *sock_fd = qemu_opt_get(opts, "sock_fd");
if (!socket && !sock_fd) {
- error_report("Must specify either socket or sock_fd");
+ error_setg(errp, "both socket and sock_fd properties are missing");
+ error_append_socket_sockfd_hint(errp);
return -1;
}
if (socket && sock_fd) {
- error_report("Both socket and sock_fd options specified");
+ error_setg(errp, "both socket and sock_fd properties are set");
+ error_append_socket_sockfd_hint(errp);
return -1;
}
if (socket) {
@@ -1134,17 +1144,17 @@ static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
return 0;
}
-static int proxy_init(FsContext *ctx)
+static int proxy_init(FsContext *ctx, Error **errp)
{
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
int sock_id;
if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- sock_id = connect_namedsocket(ctx->fs_root);
+ sock_id = connect_namedsocket(ctx->fs_root, errp);
} else {
sock_id = atoi(ctx->fs_root);
if (sock_id < 0) {
- error_report("Socket descriptor not initialized");
+ error_setg(errp, "socket descriptor not initialized");
}
}
if (sock_id < 0) {
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index df0a8de08a..8f255e91c0 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -514,7 +514,7 @@ static int synth_unlinkat(FsContext *ctx, V9fsPath *dir,
return -1;
}
-static int synth_init(FsContext *ctx)
+static int synth_init(FsContext *ctx, Error **errp)
{
QLIST_INIT(&synth_root.child);
qemu_mutex_init(&synth_mutex);
diff --git a/hw/9pfs/9p-xattr.h b/hw/9pfs/9p-xattr.h
index 0d83996575..35bcd24f77 100644
--- a/hw/9pfs/9p-xattr.h
+++ b/hw/9pfs/9p-xattr.h
@@ -16,8 +16,7 @@
#include "qemu/xattr.h"
-typedef struct xattr_operations
-{
+struct XattrOperations {
const char *name;
ssize_t (*getxattr)(FsContext *ctx, const char *path,
const char *name, void *value, size_t size);
@@ -27,7 +26,7 @@ typedef struct xattr_operations
void *value, size_t size, int flags);
int (*removexattr)(FsContext *ctx,
const char *path, const char *name);
-} XattrOperations;
+};
ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
const char *name, void *value, size_t size);
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 52d46632fe..909a611394 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -41,7 +41,7 @@ enum {
Oappend = 0x80,
};
-ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
+static ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
{
ssize_t ret;
va_list ap;
@@ -53,7 +53,7 @@ ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
return ret;
}
-ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
+static ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
{
ssize_t ret;
va_list ap;
@@ -99,10 +99,10 @@ static int omode_to_uflags(int8_t mode)
return ret;
}
-struct dotl_openflag_map {
+typedef struct DotlOpenflagMap {
int dotl_flag;
int open_flag;
-};
+} DotlOpenflagMap;
static int dotl_to_open_flags(int flags)
{
@@ -113,7 +113,7 @@ static int dotl_to_open_flags(int flags)
*/
int oflags = flags & O_ACCMODE;
- struct dotl_openflag_map dotl_oflag_map[] = {
+ DotlOpenflagMap dotl_oflag_map[] = {
{ P9_DOTL_CREATE, O_CREAT },
{ P9_DOTL_EXCL, O_EXCL },
{ P9_DOTL_NOCTTY , O_NOCTTY },
@@ -3473,14 +3473,12 @@ void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr)
if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
(pdu_co_handlers[pdu->id] == NULL)) {
handler = v9fs_op_not_supp;
+ } else if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
+ handler = v9fs_fs_ro;
} else {
handler = pdu_co_handlers[pdu->id];
}
- if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
- handler = v9fs_fs_ro;
- }
-
qemu_co_queue_init(&pdu->complete);
co = qemu_coroutine_create(handler, pdu);
qemu_coroutine_enter(co);
@@ -3544,9 +3542,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
s->fid_list = NULL;
qemu_co_rwlock_init(&s->rename_lock);
- if (s->ops->init(&s->ctx) < 0) {
- error_setg(errp, "9pfs Failed to initialize fs-driver with id:%s"
- " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root);
+ if (s->ops->init(&s->ctx, errp) < 0) {
+ error_prepend(errp, "cannot initialize fsdev '%s': ",
+ s->fsconf.fsdev_id);
goto out;
}
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index cdfc4f4ce7..ffe658ab89 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -94,10 +94,10 @@ enum {
P9_QTFILE = 0x00,
};
-enum p9_proto_version {
+typedef enum P9ProtoVersion {
V9FS_PROTO_2000U = 0x01,
V9FS_PROTO_2000L = 0x02,
-};
+} P9ProtoVersion;
#define P9_NOTAG UINT16_MAX
#define P9_NOFID UINT32_MAX
@@ -118,6 +118,7 @@ static inline char *rpath(FsContext *ctx, const char *path)
typedef struct V9fsPDU V9fsPDU;
typedef struct V9fsState V9fsState;
+typedef struct V9fsTransport V9fsTransport;
typedef struct {
uint32_t size_le;
@@ -238,10 +239,10 @@ struct V9fsState
FileOperations *ops;
FsContext ctx;
char *tag;
- enum p9_proto_version proto_version;
+ P9ProtoVersion proto_version;
int32_t msize;
V9fsPDU pdus[MAX_REQ];
- const struct V9fsTransport *transport;
+ const V9fsTransport *transport;
/*
* lock ensuring atomic path update
* on rename.
@@ -348,8 +349,6 @@ int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
int v9fs_device_realize_common(V9fsState *s, Error **errp);
void v9fs_device_unrealize_common(V9fsState *s, Error **errp);
-ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
-ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
V9fsPDU *pdu_alloc(V9fsState *s);
void pdu_free(V9fsPDU *pdu);
void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr);
@@ -367,8 +366,7 @@ struct V9fsTransport {
void (*push_and_notify)(V9fsPDU *pdu);
};
-static inline int v9fs_register_transport(V9fsState *s,
- const struct V9fsTransport *t)
+static inline int v9fs_register_transport(V9fsState *s, const V9fsTransport *t)
{
assert(!s->transport);
s->transport = t;
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 62650b0a6b..43f4e53f33 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -20,8 +20,6 @@
#include "hw/virtio/virtio-access.h"
#include "qemu/iov.h"
-static const struct V9fsTransport virtio_9p_transport;
-
static void virtio_9p_push_and_notify(V9fsPDU *pdu)
{
V9fsState *s = pdu->s;
@@ -104,35 +102,6 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
g_free(cfg);
}
-static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- V9fsVirtioState *v = VIRTIO_9P(dev);
- V9fsState *s = &v->state;
-
- if (v9fs_device_realize_common(s, errp)) {
- goto out;
- }
-
- v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
- virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
- v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
- v9fs_register_transport(s, &virtio_9p_transport);
-
-out:
- return;
-}
-
-static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- V9fsVirtioState *v = VIRTIO_9P(dev);
- V9fsState *s = &v->state;
-
- virtio_cleanup(vdev);
- v9fs_device_unrealize_common(s, errp);
-}
-
static void virtio_9p_reset(VirtIODevice *vdev)
{
V9fsVirtioState *v = (V9fsVirtioState *)vdev;
@@ -215,7 +184,7 @@ static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
*pniov = elem->out_num;
}
-static const struct V9fsTransport virtio_9p_transport = {
+static const V9fsTransport virtio_9p_transport = {
.pdu_vmarshal = virtio_pdu_vmarshal,
.pdu_vunmarshal = virtio_pdu_vunmarshal,
.init_in_iov_from_pdu = virtio_init_in_iov_from_pdu,
@@ -223,6 +192,35 @@ static const struct V9fsTransport virtio_9p_transport = {
.push_and_notify = virtio_9p_push_and_notify,
};
+static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ V9fsVirtioState *v = VIRTIO_9P(dev);
+ V9fsState *s = &v->state;
+
+ if (v9fs_device_realize_common(s, errp)) {
+ goto out;
+ }
+
+ v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
+ virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
+ v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
+ v9fs_register_transport(s, &virtio_9p_transport);
+
+out:
+ return;
+}
+
+static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ V9fsVirtioState *v = VIRTIO_9P(dev);
+ V9fsState *s = &v->state;
+
+ virtio_cleanup(vdev);
+ v9fs_device_unrealize_common(s, errp);
+}
+
/* virtio-9p device */
static const VMStateDescription vmstate_virtio_9p = {
diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
index ee87f08926..df2a4100bf 100644
--- a/hw/9pfs/xen-9p-backend.c
+++ b/hw/9pfs/xen-9p-backend.c
@@ -233,7 +233,7 @@ static void xen_9pfs_push_and_notify(V9fsPDU *pdu)
qemu_bh_schedule(ring->bh);
}
-static const struct V9fsTransport xen_9p_transport = {
+static const V9fsTransport xen_9p_transport = {
.pdu_vmarshal = xen_9pfs_pdu_vmarshal,
.pdu_vunmarshal = xen_9pfs_pdu_vunmarshal,
.init_in_iov_from_pdu = xen_9pfs_init_in_iov_from_pdu,
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index cd0a1d357b..eb9b76f70b 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/acpi/acpi.h"
#include "hw/nvram/fw_cfg.h"
#include "qemu/config-file.h"
diff --git a/hw/acpi/ipmi-stub.c b/hw/acpi/ipmi-stub.c
index 98b6dcee0d..f525f71c2d 100644
--- a/hw/acpi/ipmi-stub.c
+++ b/hw/acpi/ipmi-stub.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "hw/acpi/ipmi.h"
void build_acpi_ipmi_devices(Aml *table, BusState *bus)
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index babd6ea514..766373eec7 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -78,9 +78,9 @@ static void clipper_init(MachineState *machine)
clipper_pci_map_irq);
/* Since we have an SRM-compatible PALcode, use the SRM epoch. */
- rtc_init(isa_bus, 1900, rtc_irq);
+ mc146818_rtc_init(isa_bus, 1900, rtc_irq);
- pit_init(isa_bus, 0x40, 0, NULL);
+ i8254_pit_init(isa_bus, 0x40, 0, NULL);
isa_create_simple(isa_bus, "i8042");
/* VGA setup. Don't bother loading the bios. */
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 59ef33efa9..b0d4088290 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -385,6 +385,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
spi_table[i].irq));
}
+ qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]);
object_property_set_bool(OBJECT(&s->eth), true, "realized", &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index feccdb00d3..ac1e15cbbc 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -29,7 +29,6 @@
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
#include "cpu.h"
#undef REG_FMT
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 3d78ff68e6..f7fa795278 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -453,6 +453,7 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiSerialPortConsoleRedirection *spcr;
const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART];
int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE;
+ int spcr_start = table_data->len;
spcr = acpi_data_push(table_data, sizeof(*spcr));
@@ -476,8 +477,8 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */
spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
- build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2,
- NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + spcr_start),
+ "SPCR", table_data->len - spcr_start, 2, NULL, NULL);
}
static void
@@ -512,8 +513,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
mem_base += numa_info[i].node_mem;
}
- build_header(linker, table_data, (void *)srat, "SRAT",
- table_data->len - srat_start, 3, NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + srat_start),
+ "SRAT", table_data->len - srat_start, 3, NULL, NULL);
}
static void
@@ -522,6 +523,7 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiTableMcfg *mcfg;
const MemMapEntry *memmap = vms->memmap;
int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
+ int mcfg_start = table_data->len;
mcfg = acpi_data_push(table_data, len);
mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base);
@@ -532,7 +534,8 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size
/ PCIE_MMCFG_SIZE_MIN) - 1;
- build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + mcfg_start),
+ "MCFG", table_data->len - mcfg_start, 1, NULL, NULL);
}
/* GTDT */
@@ -651,6 +654,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
static void build_fadt(GArray *table_data, BIOSLinker *linker,
VirtMachineState *vms, unsigned dsdt_tbl_offset)
{
+ int fadt_start = table_data->len;
AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data;
uint16_t bootflags;
@@ -681,8 +685,8 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker,
ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt),
ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
- build_header(linker, table_data,
- (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
+ build_header(linker, table_data, (void *)(table_data->data + fadt_start),
+ "FACP", table_data->len - fadt_start, 5, NULL, NULL);
}
/* DSDT */
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index bbe7d046e4..b126cf148b 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -151,6 +151,29 @@ static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
}
+ for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_FLASH; i++) {
+ SSIBus *spi_bus;
+ DeviceState *flash_dev;
+ qemu_irq cs_line;
+ DriveInfo *dinfo = drive_get_next(IF_MTD);
+ int bus = i / XLNX_ZYNQMP_NUM_QSPI_BUS_CS;
+ gchar *bus_name = g_strdup_printf("qspi%d", bus);
+
+ spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
+ g_free(bus_name);
+
+ flash_dev = ssi_create_slave_no_init(spi_bus, "n25q512a11");
+ if (dinfo) {
+ qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo),
+ &error_fatal);
+ }
+ qdev_init_nofail(flash_dev);
+
+ cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.qspi), i + 1, cs_line);
+ }
+
/* TODO create and connect IDE devices for ide_drive_get() */
xlnx_zcu102_binfo.ram_size = ram_size;
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index c707c66322..325642058b 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -40,6 +40,10 @@
#define SATA_ADDR 0xFD0C0000
#define SATA_NUM_PORTS 2
+#define QSPI_ADDR 0xff0f0000
+#define LQSPI_ADDR 0xc0000000
+#define QSPI_IRQ 15
+
#define DP_ADDR 0xfd4a0000
#define DP_IRQ 113
@@ -171,6 +175,9 @@ static void xlnx_zynqmp_init(Object *obj)
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
}
+ object_initialize(&s->qspi, sizeof(s->qspi), TYPE_XLNX_ZYNQMP_QSPIPS);
+ qdev_set_parent_bus(DEVICE(&s->qspi), sysbus_get_default());
+
object_initialize(&s->dp, sizeof(s->dp), TYPE_XLNX_DP);
qdev_set_parent_bus(DEVICE(&s->dp), sysbus_get_default());
@@ -411,6 +418,25 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
g_free(bus_name);
}
+ object_property_set_bool(OBJECT(&s->qspi), true, "realized", &err);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]);
+
+ for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_BUS; i++) {
+ gchar *bus_name;
+ gchar *target_bus;
+
+ /* Alias controller SPI bus to the SoC itself */
+ bus_name = g_strdup_printf("qspi%d", i);
+ target_bus = g_strdup_printf("spi%d", i);
+ object_property_add_alias(OBJECT(s), bus_name,
+ OBJECT(&s->qspi), target_bus,
+ &error_abort);
+ g_free(bus_name);
+ g_free(target_bus);
+ }
+
object_property_set_bool(OBJECT(&s->dp), true, "realized", &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
index 5cfb6a96dd..9f50a89b4a 100644
--- a/hw/audio/fmopl.c
+++ b/hw/audio/fmopl.c
@@ -34,7 +34,6 @@
#include <math.h>
//#include "driver.h" /* use M.A.M.E. */
#include "fmopl.h"
-#include "qemu/osdep.h"
#ifndef PI
#define PI 3.14159265358979323846
#endif
diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h
index f4065f425c..e7e578a48e 100644
--- a/hw/audio/fmopl.h
+++ b/hw/audio/fmopl.h
@@ -1,7 +1,6 @@
#ifndef FMOPL_H
#define FMOPL_H
-#include <stdint.h>
typedef void (*OPL_TIMERHANDLER)(void *param, int channel, double interval_Sec);
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index 0206f7399b..908696d483 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "hw/audio/soundhw.h"
#include "audio/audio.h"
diff --git a/hw/block/block.c b/hw/block/block.c
index 27878d0087..b0269c857f 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -51,7 +51,7 @@ void blkconf_blocksizes(BlockConf *conf)
}
}
-void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
+bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
bool resizable, Error **errp)
{
BlockBackend *blk = conf->blk;
@@ -76,7 +76,7 @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
ret = blk_set_perm(blk, perm, shared_perm, errp);
if (ret < 0) {
- return;
+ return false;
}
switch (conf->wce) {
@@ -99,9 +99,11 @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly,
blk_set_enable_write_cache(blk, wce);
blk_set_on_error(blk, rerror, werror);
+
+ return true;
}
-void blkconf_geometry(BlockConf *conf, int *ptrans,
+bool blkconf_geometry(BlockConf *conf, int *ptrans,
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
Error **errp)
{
@@ -129,15 +131,16 @@ void blkconf_geometry(BlockConf *conf, int *ptrans,
if (conf->cyls || conf->heads || conf->secs) {
if (conf->cyls < 1 || conf->cyls > cyls_max) {
error_setg(errp, "cyls must be between 1 and %u", cyls_max);
- return;
+ return false;
}
if (conf->heads < 1 || conf->heads > heads_max) {
error_setg(errp, "heads must be between 1 and %u", heads_max);
- return;
+ return false;
}
if (conf->secs < 1 || conf->secs > secs_max) {
error_setg(errp, "secs must be between 1 and %u", secs_max);
- return;
+ return false;
}
}
+ return true;
}
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 5556f0e64e..f6fc639e88 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -76,7 +76,7 @@ static void notify_guest_bh(void *opaque)
}
/* Context: QEMU global mutex held */
-void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
+bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
VirtIOBlockDataPlane **dataplane,
Error **errp)
{
@@ -91,11 +91,11 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
error_setg(errp,
"device is incompatible with iothread "
"(transport does not support notifiers)");
- return;
+ return false;
}
if (!virtio_device_ioeventfd_enabled(vdev)) {
error_setg(errp, "ioeventfd is required for iothread");
- return;
+ return false;
}
/* If dataplane is (re-)enabled while the guest is running there could
@@ -103,12 +103,12 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
*/
if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
error_prepend(errp, "cannot start virtio-blk dataplane: ");
- return;
+ return false;
}
}
/* Don't try if transport does not support notifiers. */
if (!virtio_device_ioeventfd_enabled(vdev)) {
- return;
+ return false;
}
s = g_new0(VirtIOBlockDataPlane, 1);
@@ -126,6 +126,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
s->batch_notify_vqs = bitmap_new(conf->num_queues);
*dataplane = s;
+
+ return true;
}
/* Context: QEMU global mutex held */
diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h
index db3f47b173..5e18bb99ae 100644
--- a/hw/block/dataplane/virtio-blk.h
+++ b/hw/block/dataplane/virtio-blk.h
@@ -19,7 +19,7 @@
typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
-void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
+bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
VirtIOBlockDataPlane **dataplane,
Error **errp);
void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 67f78ac702..7b7dd41296 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -473,16 +473,13 @@ static void fd_revalidate(FDrive *drv)
static void fd_change_cb(void *opaque, bool load, Error **errp)
{
FDrive *drive = opaque;
- Error *local_err = NULL;
if (!load) {
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
} else {
- blkconf_apply_backend_options(drive->conf,
- blk_is_read_only(drive->blk), false,
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!blkconf_apply_backend_options(drive->conf,
+ blk_is_read_only(drive->blk), false,
+ errp)) {
return;
}
}
@@ -522,7 +519,6 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
FDrive *drive;
- Error *local_err = NULL;
int ret;
if (dev->unit == -1) {
@@ -568,10 +564,9 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
- blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk),
- false, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!blkconf_apply_backend_options(&dev->conf,
+ blk_is_read_only(dev->conf.blk),
+ false, errp)) {
return;
}
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index a2438b9ed2..ea142160b3 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -240,6 +240,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) },
{ INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) },
{ INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
+ { INFO("n25q512a11", 0x20bb20, 0, 64 << 10, 1024, ER_4K) },
+ { INFO("n25q512a13", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
@@ -331,7 +333,10 @@ typedef enum {
WRDI = 0x4,
RDSR = 0x5,
WREN = 0x6,
+ BRRD = 0x16,
+ BRWR = 0x17,
JEDEC_READ = 0x9f,
+ BULK_ERASE_60 = 0x60,
BULK_ERASE = 0xc7,
READ_FSR = 0x70,
RDCR = 0x15,
@@ -355,6 +360,8 @@ typedef enum {
DPP = 0xa2,
QPP = 0x32,
QPP_4 = 0x34,
+ RDID_90 = 0x90,
+ RDID_AB = 0xab,
ERASE_4K = 0x20,
ERASE4_4K = 0x21,
@@ -405,6 +412,7 @@ typedef enum {
MAN_MACRONIX,
MAN_NUMONYX,
MAN_WINBOND,
+ MAN_SST,
MAN_GENERIC,
} Manufacturer;
@@ -423,6 +431,7 @@ typedef struct Flash {
uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ];
uint32_t len;
uint32_t pos;
+ bool data_read_loop;
uint8_t needed_bytes;
uint8_t cmd_in_progress;
uint32_t cur_addr;
@@ -475,6 +484,8 @@ static inline Manufacturer get_man(Flash *s)
return MAN_SPANSION;
case 0xC2:
return MAN_MACRONIX;
+ case 0xBF:
+ return MAN_SST;
default:
return MAN_GENERIC;
}
@@ -698,6 +709,7 @@ static void complete_collecting_data(Flash *s)
s->write_enable = false;
}
break;
+ case BRWR:
case EXTEND_ADDR_WRITE:
s->ear = s->data[0];
break;
@@ -710,6 +722,31 @@ static void complete_collecting_data(Flash *s)
case WEVCR:
s->enh_volatile_cfg = s->data[0];
break;
+ case RDID_90:
+ case RDID_AB:
+ if (get_man(s) == MAN_SST) {
+ if (s->cur_addr <= 1) {
+ if (s->cur_addr) {
+ s->data[0] = s->pi->id[2];
+ s->data[1] = s->pi->id[0];
+ } else {
+ s->data[0] = s->pi->id[0];
+ s->data[1] = s->pi->id[2];
+ }
+ s->pos = 0;
+ s->len = 2;
+ s->data_read_loop = true;
+ s->state = STATE_READING_DATA;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: Invalid read id address\n");
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: Read id (command 0x90/0xAB) is not supported"
+ " by device\n");
+ }
+ break;
default:
break;
}
@@ -925,6 +962,8 @@ static void decode_new_cmd(Flash *s, uint32_t value)
case PP4:
case PP4_4:
case DIE_ERASE:
+ case RDID_90:
+ case RDID_AB:
s->needed_bytes = get_addr_length(s);
s->pos = 0;
s->len = 0;
@@ -983,6 +1022,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
}
s->pos = 0;
s->len = 1;
+ s->data_read_loop = true;
s->state = STATE_READING_DATA;
break;
@@ -993,6 +1033,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
}
s->pos = 0;
s->len = 1;
+ s->data_read_loop = true;
s->state = STATE_READING_DATA;
break;
@@ -1015,6 +1056,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
s->state = STATE_READING_DATA;
break;
+ case BULK_ERASE_60:
case BULK_ERASE:
if (s->write_enable) {
DB_PRINT_L(0, "chip erase\n");
@@ -1032,12 +1074,14 @@ static void decode_new_cmd(Flash *s, uint32_t value)
case EX_4BYTE_ADDR:
s->four_bytes_address_mode = false;
break;
+ case BRRD:
case EXTEND_ADDR_READ:
s->data[0] = s->ear;
s->pos = 0;
s->len = 1;
s->state = STATE_READING_DATA;
break;
+ case BRWR:
case EXTEND_ADDR_WRITE:
if (s->write_enable) {
s->needed_bytes = 1;
@@ -1133,6 +1177,7 @@ static int m25p80_cs(SSISlave *ss, bool select)
s->pos = 0;
s->state = STATE_IDLE;
flash_sync_dirty(s, -1);
+ s->data_read_loop = false;
}
DB_PRINT_L(0, "%sselect\n", select ? "de" : "");
@@ -1198,7 +1243,9 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
s->pos++;
if (s->pos == s->len) {
s->pos = 0;
- s->state = STATE_IDLE;
+ if (!s->data_read_loop) {
+ s->state = STATE_IDLE;
+ }
}
break;
@@ -1269,11 +1316,38 @@ static Property m25p80_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static int m25p80_pre_load(void *opaque)
+{
+ Flash *s = (Flash *)opaque;
+
+ s->data_read_loop = false;
+ return 0;
+}
+
+static bool m25p80_data_read_loop_needed(void *opaque)
+{
+ Flash *s = (Flash *)opaque;
+
+ return s->data_read_loop;
+}
+
+static const VMStateDescription vmstate_m25p80_data_read_loop = {
+ .name = "m25p80/data_read_loop",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = m25p80_data_read_loop_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(data_read_loop, Flash),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_m25p80 = {
.name = "m25p80",
.version_id = 0,
.minimum_version_id = 0,
.pre_save = m25p80_pre_save,
+ .pre_load = m25p80_pre_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8(state, Flash),
VMSTATE_UINT8_ARRAY(data, Flash, M25P80_INTERNAL_DATA_BUFFER_SZ),
@@ -1295,6 +1369,10 @@ static const VMStateDescription vmstate_m25p80 = {
VMSTATE_UINT8(spansion_cr3nv, Flash),
VMSTATE_UINT8(spansion_cr4nv, Flash),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_m25p80_data_read_loop,
+ NULL
}
};
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 441e21ed1f..1ac356d3a5 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -34,8 +34,17 @@
#include "qapi/visitor.h"
#include "sysemu/block-backend.h"
+#include "qemu/log.h"
+#include "trace.h"
#include "nvme.h"
+#define NVME_GUEST_ERR(trace, fmt, ...) \
+ do { \
+ (trace_##trace)(__VA_ARGS__); \
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
+ } while (0)
+
static void nvme_process_sq(void *opaque);
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
@@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
{
if (cq->irq_enabled) {
if (msix_enabled(&(n->parent_obj))) {
+ trace_nvme_irq_msix(cq->vector);
msix_notify(&(n->parent_obj), cq->vector);
} else {
+ trace_nvme_irq_pin();
pci_irq_pulse(&n->parent_obj);
}
+ } else {
+ trace_nvme_irq_masked();
}
}
@@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
trans_len = MIN(len, trans_len);
int num_prps = (len >> n->page_bits) + 1;
- if (!prp1) {
+ if (unlikely(!prp1)) {
+ trace_nvme_err_invalid_prp();
return NVME_INVALID_FIELD | NVME_DNR;
} else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
@@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
}
len -= trans_len;
if (len) {
- if (!prp2) {
+ if (unlikely(!prp2)) {
+ trace_nvme_err_invalid_prp2_missing();
goto unmap;
}
if (len > n->page_size) {
@@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
if (i == n->max_prp_ents - 1 && len > n->page_size) {
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
goto unmap;
}
@@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
prp_ent = le64_to_cpu(prp_list[i]);
}
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
goto unmap;
}
@@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
i++;
}
} else {
- if (prp2 & (n->page_size - 1)) {
+ if (unlikely(prp2 & (n->page_size - 1))) {
+ trace_nvme_err_invalid_prp2_align(prp2);
goto unmap;
}
if (qsg->nsg) {
@@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
QEMUIOVector iov;
uint16_t status = NVME_SUCCESS;
+ trace_nvme_dma_read(prp1, prp2);
+
if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
if (qsg.nsg > 0) {
- if (dma_buf_read(ptr, len, &qsg)) {
+ if (unlikely(dma_buf_read(ptr, len, &qsg))) {
+ trace_nvme_err_invalid_dma();
status = NVME_INVALID_FIELD | NVME_DNR;
}
qemu_sglist_destroy(&qsg);
} else {
- if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+ if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
+ trace_nvme_err_invalid_dma();
status = NVME_INVALID_FIELD | NVME_DNR;
}
qemu_iovec_destroy(&iov);
@@ -273,7 +295,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
- if (slba + nlb > ns->id_ns.nsze) {
+ if (unlikely(slba + nlb > ns->id_ns.nsze)) {
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
return NVME_LBA_RANGE | NVME_DNR;
}
@@ -301,8 +324,11 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
- if ((slba + nlb) > ns->id_ns.nsze) {
+ trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba);
+
+ if (unlikely((slba + nlb) > ns->id_ns.nsze)) {
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
return NVME_LBA_RANGE | NVME_DNR;
}
@@ -336,7 +362,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
NvmeNamespace *ns;
uint32_t nsid = le32_to_cpu(cmd->nsid);
- if (nsid == 0 || nsid > n->num_namespaces) {
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
return NVME_INVALID_NSID | NVME_DNR;
}
@@ -350,6 +377,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
case NVME_CMD_READ:
return nvme_rw(n, ns, cmd, req);
default:
+ trace_nvme_err_invalid_opc(cmd->opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
}
@@ -373,10 +401,13 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
NvmeCQueue *cq;
uint16_t qid = le16_to_cpu(c->qid);
- if (!qid || nvme_check_sqid(n, qid)) {
+ if (unlikely(!qid || nvme_check_sqid(n, qid))) {
+ trace_nvme_err_invalid_del_sq(qid);
return NVME_INVALID_QID | NVME_DNR;
}
+ trace_nvme_del_sq(qid);
+
sq = n->sq[qid];
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
req = QTAILQ_FIRST(&sq->out_req_list);
@@ -439,19 +470,26 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
uint16_t qflags = le16_to_cpu(c->sq_flags);
uint64_t prp1 = le64_to_cpu(c->prp1);
- if (!cqid || nvme_check_cqid(n, cqid)) {
+ trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags);
+
+ if (unlikely(!cqid || nvme_check_cqid(n, cqid))) {
+ trace_nvme_err_invalid_create_sq_cqid(cqid);
return NVME_INVALID_CQID | NVME_DNR;
}
- if (!sqid || !nvme_check_sqid(n, sqid)) {
+ if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) {
+ trace_nvme_err_invalid_create_sq_sqid(sqid);
return NVME_INVALID_QID | NVME_DNR;
}
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
+ trace_nvme_err_invalid_create_sq_size(qsize);
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
}
- if (!prp1 || prp1 & (n->page_size - 1)) {
+ if (unlikely(!prp1 || prp1 & (n->page_size - 1))) {
+ trace_nvme_err_invalid_create_sq_addr(prp1);
return NVME_INVALID_FIELD | NVME_DNR;
}
- if (!(NVME_SQ_FLAGS_PC(qflags))) {
+ if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) {
+ trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags));
return NVME_INVALID_FIELD | NVME_DNR;
}
sq = g_malloc0(sizeof(*sq));
@@ -476,14 +514,17 @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
NvmeCQueue *cq;
uint16_t qid = le16_to_cpu(c->qid);
- if (!qid || nvme_check_cqid(n, qid)) {
+ if (unlikely(!qid || nvme_check_cqid(n, qid))) {
+ trace_nvme_err_invalid_del_cq_cqid(qid);
return NVME_INVALID_CQID | NVME_DNR;
}
cq = n->cq[qid];
- if (!QTAILQ_EMPTY(&cq->sq_list)) {
+ if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) {
+ trace_nvme_err_invalid_del_cq_notempty(qid);
return NVME_INVALID_QUEUE_DEL;
}
+ trace_nvme_del_cq(qid);
nvme_free_cq(cq, n);
return NVME_SUCCESS;
}
@@ -516,19 +557,27 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
uint16_t qflags = le16_to_cpu(c->cq_flags);
uint64_t prp1 = le64_to_cpu(c->prp1);
- if (!cqid || !nvme_check_cqid(n, cqid)) {
+ trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags,
+ NVME_CQ_FLAGS_IEN(qflags) != 0);
+
+ if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) {
+ trace_nvme_err_invalid_create_cq_cqid(cqid);
return NVME_INVALID_CQID | NVME_DNR;
}
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
+ trace_nvme_err_invalid_create_cq_size(qsize);
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
}
- if (!prp1) {
+ if (unlikely(!prp1)) {
+ trace_nvme_err_invalid_create_cq_addr(prp1);
return NVME_INVALID_FIELD | NVME_DNR;
}
- if (vector > n->num_queues) {
+ if (unlikely(vector > n->num_queues)) {
+ trace_nvme_err_invalid_create_cq_vector(vector);
return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
}
- if (!(NVME_CQ_FLAGS_PC(qflags))) {
+ if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) {
+ trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags));
return NVME_INVALID_FIELD | NVME_DNR;
}
@@ -543,6 +592,8 @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c)
uint64_t prp1 = le64_to_cpu(c->prp1);
uint64_t prp2 = le64_to_cpu(c->prp2);
+ trace_nvme_identify_ctrl();
+
return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
prp1, prp2);
}
@@ -554,11 +605,15 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c)
uint64_t prp1 = le64_to_cpu(c->prp1);
uint64_t prp2 = le64_to_cpu(c->prp2);
- if (nsid == 0 || nsid > n->num_namespaces) {
+ trace_nvme_identify_ns(nsid);
+
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
return NVME_INVALID_NSID | NVME_DNR;
}
ns = &n->namespaces[nsid - 1];
+
return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
prp1, prp2);
}
@@ -573,6 +628,8 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
uint16_t ret;
int i, j = 0;
+ trace_nvme_identify_nslist(min_nsid);
+
list = g_malloc0(data_len);
for (i = 0; i < n->num_namespaces; i++) {
if (i < min_nsid) {
@@ -601,6 +658,7 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
case 0x02:
return nvme_identify_nslist(n, c);
default:
+ trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
return NVME_INVALID_FIELD | NVME_DNR;
}
}
@@ -613,11 +671,14 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
switch (dw10) {
case NVME_VOLATILE_WRITE_CACHE:
result = blk_enable_write_cache(n->conf.blk);
+ trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
break;
case NVME_NUMBER_OF_QUEUES:
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
+ trace_nvme_getfeat_numq(result);
break;
default:
+ trace_nvme_err_invalid_getfeat(dw10);
return NVME_INVALID_FIELD | NVME_DNR;
}
@@ -635,10 +696,14 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
break;
case NVME_NUMBER_OF_QUEUES:
+ trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
+ ((dw11 >> 16) & 0xFFFF) + 1,
+ n->num_queues - 1, n->num_queues - 1);
req->cqe.result =
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
break;
default:
+ trace_nvme_err_invalid_setfeat(dw10);
return NVME_INVALID_FIELD | NVME_DNR;
}
return NVME_SUCCESS;
@@ -662,6 +727,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
case NVME_ADM_CMD_GET_FEATURES:
return nvme_get_feature(n, cmd, req);
default:
+ trace_nvme_err_invalid_admin_opc(cmd->opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
}
@@ -721,15 +787,78 @@ static int nvme_start_ctrl(NvmeCtrl *n)
uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
uint32_t page_size = 1 << page_bits;
- if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
- n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
- NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
- NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
- NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
- NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
- NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
- NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
- !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
+ if (unlikely(n->cq[0])) {
+ trace_nvme_err_startfail_cq();
+ return -1;
+ }
+ if (unlikely(n->sq[0])) {
+ trace_nvme_err_startfail_sq();
+ return -1;
+ }
+ if (unlikely(!n->bar.asq)) {
+ trace_nvme_err_startfail_nbarasq();
+ return -1;
+ }
+ if (unlikely(!n->bar.acq)) {
+ trace_nvme_err_startfail_nbaracq();
+ return -1;
+ }
+ if (unlikely(n->bar.asq & (page_size - 1))) {
+ trace_nvme_err_startfail_asq_misaligned(n->bar.asq);
+ return -1;
+ }
+ if (unlikely(n->bar.acq & (page_size - 1))) {
+ trace_nvme_err_startfail_acq_misaligned(n->bar.acq);
+ return -1;
+ }
+ if (unlikely(NVME_CC_MPS(n->bar.cc) <
+ NVME_CAP_MPSMIN(n->bar.cap))) {
+ trace_nvme_err_startfail_page_too_small(
+ NVME_CC_MPS(n->bar.cc),
+ NVME_CAP_MPSMIN(n->bar.cap));
+ return -1;
+ }
+ if (unlikely(NVME_CC_MPS(n->bar.cc) >
+ NVME_CAP_MPSMAX(n->bar.cap))) {
+ trace_nvme_err_startfail_page_too_large(
+ NVME_CC_MPS(n->bar.cc),
+ NVME_CAP_MPSMAX(n->bar.cap));
+ return -1;
+ }
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) <
+ NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) {
+ trace_nvme_err_startfail_cqent_too_small(
+ NVME_CC_IOCQES(n->bar.cc),
+ NVME_CTRL_CQES_MIN(n->bar.cap));
+ return -1;
+ }
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) >
+ NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) {
+ trace_nvme_err_startfail_cqent_too_large(
+ NVME_CC_IOCQES(n->bar.cc),
+ NVME_CTRL_CQES_MAX(n->bar.cap));
+ return -1;
+ }
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) <
+ NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) {
+ trace_nvme_err_startfail_sqent_too_small(
+ NVME_CC_IOSQES(n->bar.cc),
+ NVME_CTRL_SQES_MIN(n->bar.cap));
+ return -1;
+ }
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) >
+ NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) {
+ trace_nvme_err_startfail_sqent_too_large(
+ NVME_CC_IOSQES(n->bar.cc),
+ NVME_CTRL_SQES_MAX(n->bar.cap));
+ return -1;
+ }
+ if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) {
+ trace_nvme_err_startfail_asqent_sz_zero();
+ return -1;
+ }
+ if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) {
+ trace_nvme_err_startfail_acqent_sz_zero();
return -1;
}
@@ -749,16 +878,48 @@ static int nvme_start_ctrl(NvmeCtrl *n)
static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
unsigned size)
{
+ if (unlikely(offset & (sizeof(uint32_t) - 1))) {
+ NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32,
+ "MMIO write not 32-bit aligned,"
+ " offset=0x%"PRIx64"", offset);
+ /* should be ignored, fall through for now */
+ }
+
+ if (unlikely(size < sizeof(uint32_t))) {
+ NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall,
+ "MMIO write smaller than 32-bits,"
+ " offset=0x%"PRIx64", size=%u",
+ offset, size);
+ /* should be ignored, fall through for now */
+ }
+
switch (offset) {
- case 0xc:
+ case 0xc: /* INTMS */
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
+ "undefined access to interrupt mask set"
+ " when MSI-X is enabled");
+ /* should be ignored, fall through for now */
+ }
n->bar.intms |= data & 0xffffffff;
n->bar.intmc = n->bar.intms;
+ trace_nvme_mmio_intm_set(data & 0xffffffff,
+ n->bar.intmc);
break;
- case 0x10:
+ case 0x10: /* INTMC */
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
+ "undefined access to interrupt mask clr"
+ " when MSI-X is enabled");
+ /* should be ignored, fall through for now */
+ }
n->bar.intms &= ~(data & 0xffffffff);
n->bar.intmc = n->bar.intms;
+ trace_nvme_mmio_intm_clr(data & 0xffffffff,
+ n->bar.intmc);
break;
- case 0x14:
+ case 0x14: /* CC */
+ trace_nvme_mmio_cfg(data & 0xffffffff);
/* Windows first sends data, then sends enable bit */
if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
!NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
@@ -768,40 +929,82 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
n->bar.cc = data;
- if (nvme_start_ctrl(n)) {
+ if (unlikely(nvme_start_ctrl(n))) {
+ trace_nvme_err_startfail();
n->bar.csts = NVME_CSTS_FAILED;
} else {
+ trace_nvme_mmio_start_success();
n->bar.csts = NVME_CSTS_READY;
}
} else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
+ trace_nvme_mmio_stopped();
nvme_clear_ctrl(n);
n->bar.csts &= ~NVME_CSTS_READY;
}
if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
- nvme_clear_ctrl(n);
- n->bar.cc = data;
- n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
+ trace_nvme_mmio_shutdown_set();
+ nvme_clear_ctrl(n);
+ n->bar.cc = data;
+ n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
} else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
- n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
- n->bar.cc = data;
+ trace_nvme_mmio_shutdown_cleared();
+ n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
+ n->bar.cc = data;
+ }
+ break;
+ case 0x1C: /* CSTS */
+ if (data & (1 << 4)) {
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported,
+ "attempted to W1C CSTS.NSSRO"
+ " but CAP.NSSRS is zero (not supported)");
+ } else if (data != 0) {
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts,
+ "attempted to set a read only bit"
+ " of controller status");
+ }
+ break;
+ case 0x20: /* NSSR */
+ if (data == 0x4E564D65) {
+ trace_nvme_ub_mmiowr_ssreset_unsupported();
+ } else {
+ /* The spec says that writes of other values have no effect */
+ return;
}
break;
- case 0x24:
+ case 0x24: /* AQA */
n->bar.aqa = data & 0xffffffff;
+ trace_nvme_mmio_aqattr(data & 0xffffffff);
break;
- case 0x28:
+ case 0x28: /* ASQ */
n->bar.asq = data;
+ trace_nvme_mmio_asqaddr(data);
break;
- case 0x2c:
+ case 0x2c: /* ASQ hi */
n->bar.asq |= data << 32;
+ trace_nvme_mmio_asqaddr_hi(data, n->bar.asq);
break;
- case 0x30:
+ case 0x30: /* ACQ */
+ trace_nvme_mmio_acqaddr(data);
n->bar.acq = data;
break;
- case 0x34:
+ case 0x34: /* ACQ hi */
n->bar.acq |= data << 32;
+ trace_nvme_mmio_acqaddr_hi(data, n->bar.acq);
break;
+ case 0x38: /* CMBLOC */
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved,
+ "invalid write to reserved CMBLOC"
+ " when CMBSZ is zero, ignored");
+ return;
+ case 0x3C: /* CMBSZ */
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
+ "invalid write to read only CMBSZ, ignored");
+ return;
default:
+ NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
+ "invalid MMIO write,"
+ " offset=0x%"PRIx64", data=%"PRIx64"",
+ offset, data);
break;
}
}
@@ -812,9 +1015,26 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
uint8_t *ptr = (uint8_t *)&n->bar;
uint64_t val = 0;
+ if (unlikely(addr & (sizeof(uint32_t) - 1))) {
+ NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32,
+ "MMIO read not 32-bit aligned,"
+ " offset=0x%"PRIx64"", addr);
+ /* should RAZ, fall through for now */
+ } else if (unlikely(size < sizeof(uint32_t))) {
+ NVME_GUEST_ERR(nvme_ub_mmiord_toosmall,
+ "MMIO read smaller than 32-bits,"
+ " offset=0x%"PRIx64"", addr);
+ /* should RAZ, fall through for now */
+ }
+
if (addr < sizeof(n->bar)) {
memcpy(&val, ptr + addr, size);
+ } else {
+ NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
+ "MMIO read beyond last register,"
+ " offset=0x%"PRIx64", returning 0", addr);
}
+
return val;
}
@@ -822,22 +1042,36 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
{
uint32_t qid;
- if (addr & ((1 << 2) - 1)) {
+ if (unlikely(addr & ((1 << 2) - 1))) {
+ NVME_GUEST_ERR(nvme_ub_db_wr_misaligned,
+ "doorbell write not 32-bit aligned,"
+ " offset=0x%"PRIx64", ignoring", addr);
return;
}
if (((addr - 0x1000) >> 2) & 1) {
+ /* Completion queue doorbell write */
+
uint16_t new_head = val & 0xffff;
int start_sqs;
NvmeCQueue *cq;
qid = (addr - (0x1000 + (1 << 2))) >> 3;
- if (nvme_check_cqid(n, qid)) {
+ if (unlikely(nvme_check_cqid(n, qid))) {
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq,
+ "completion queue doorbell write"
+ " for nonexistent queue,"
+ " sqid=%"PRIu32", ignoring", qid);
return;
}
cq = n->cq[qid];
- if (new_head >= cq->size) {
+ if (unlikely(new_head >= cq->size)) {
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead,
+ "completion queue doorbell write value"
+ " beyond queue size, sqid=%"PRIu32","
+ " new_head=%"PRIu16", ignoring",
+ qid, new_head);
return;
}
@@ -855,16 +1089,27 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
nvme_isr_notify(n, cq);
}
} else {
+ /* Submission queue doorbell write */
+
uint16_t new_tail = val & 0xffff;
NvmeSQueue *sq;
qid = (addr - 0x1000) >> 3;
- if (nvme_check_sqid(n, qid)) {
+ if (unlikely(nvme_check_sqid(n, qid))) {
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq,
+ "submission queue doorbell write"
+ " for nonexistent queue,"
+ " sqid=%"PRIu32", ignoring", qid);
return;
}
sq = n->sq[qid];
- if (new_tail >= sq->size) {
+ if (unlikely(new_tail >= sq->size)) {
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail,
+ "submission queue doorbell write value"
+ " beyond queue size, sqid=%"PRIu32","
+ " new_tail=%"PRIu16", ignoring",
+ qid, new_tail);
return;
}
@@ -920,7 +1165,7 @@ static const MemoryRegionOps nvme_cmb_ops = {
},
};
-static int nvme_init(PCIDevice *pci_dev)
+static void nvme_realize(PCIDevice *pci_dev, Error **errp)
{
NvmeCtrl *n = NVME(pci_dev);
NvmeIdCtrl *id = &n->id_ctrl;
@@ -928,27 +1173,27 @@ static int nvme_init(PCIDevice *pci_dev)
int i;
int64_t bs_size;
uint8_t *pci_conf;
- Error *local_err = NULL;
if (!n->conf.blk) {
- return -1;
+ error_setg(errp, "drive property not set");
+ return;
}
bs_size = blk_getlength(n->conf.blk);
if (bs_size < 0) {
- return -1;
+ error_setg(errp, "could not get backing file size");
+ return;
}
blkconf_serial(&n->conf, &n->serial);
if (!n->serial) {
- return -1;
+ error_setg(errp, "serial property not set");
+ return;
}
blkconf_blocksizes(&n->conf);
- blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
- false, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return -1;
+ if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
+ false, errp)) {
+ return;
}
pci_conf = pci_dev->config;
@@ -1046,7 +1291,6 @@ static int nvme_init(PCIDevice *pci_dev)
cpu_to_le64(n->ns_size >>
id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds);
}
- return 0;
}
static void nvme_exit(PCIDevice *pci_dev)
@@ -1081,7 +1325,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
- pc->init = nvme_init;
+ pc->realize = nvme_realize;
pc->exit = nvme_exit;
pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
pc->vendor_id = PCI_VENDOR_ID_INTEL;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index cb6767b3ee..5acd495207 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -10,3 +10,103 @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
# hw/block/hd-geometry.c
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
+
+# hw/block/nvme.c
+# nvme traces for successful events
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
+nvme_irq_pin(void) "pulsing IRQ pin"
+nvme_irq_masked(void) "IRQ is masked"
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
+nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
+nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
+nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
+nvme_identify_ctrl(void) "identify controller"
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
+nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
+nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
+nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
+nvme_mmio_stopped(void) "cleared controller enable bit"
+nvme_mmio_shutdown_set(void) "shutdown bit set"
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
+
+# nvme traces for error conditions
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
+nvme_err_invalid_field(void) "invalid field"
+nvme_err_invalid_prp(void) "invalid PRP"
+nvme_err_invalid_sgl(void) "invalid SGL"
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
+nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
+nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
+nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
+nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
+nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
+nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
+nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
+nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
+nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
+nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
+nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
+nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
+nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
+nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
+nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
+nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
+nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
+nvme_err_startfail(void) "setting controller enable bit failed"
+
+# Traces for undefined behavior
+nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
+nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
+nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
+nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
+nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
+nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
+nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
+nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
+nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
+nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
+nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
+nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
+nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
+nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
+nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
+nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
+nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
+
+# hw/block/xen_disk.c
+xen_disk_alloc(char *name) "%s"
+xen_disk_init(char *name) "%s"
+xen_disk_connect(char *name) "%s"
+xen_disk_disconnect(char *name) "%s"
+xen_disk_free(char *name) "%s"
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 05d1440786..b1532e4e91 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -928,23 +928,34 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
error_setg(errp, "num-queues property must be larger than 0");
return;
}
+ if (!is_power_of_2(conf->queue_size) ||
+ conf->queue_size > VIRTQUEUE_MAX_SIZE) {
+ error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
+ "must be a power of 2 (max %d)",
+ conf->queue_size, VIRTQUEUE_MAX_SIZE);
+ return;
+ }
blkconf_serial(&conf->conf, &conf->serial);
- blkconf_apply_backend_options(&conf->conf,
- blk_is_read_only(conf->conf.blk), true,
- &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_apply_backend_options(&conf->conf,
+ blk_is_read_only(conf->conf.blk), true,
+ errp)) {
return;
}
s->original_wce = blk_enable_write_cache(conf->conf.blk);
- blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, errp)) {
return;
}
+
blkconf_blocksizes(&conf->conf);
+ if (conf->conf.logical_block_size >
+ conf->conf.physical_block_size) {
+ error_setg(errp,
+ "logical_block_size > physical_block_size not supported");
+ return;
+ }
+
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config));
@@ -953,7 +964,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
for (i = 0; i < conf->num_queues; i++) {
- virtio_add_queue(vdev, 128, virtio_blk_handle_output);
+ virtio_add_queue(vdev, conf->queue_size, virtio_blk_handle_output);
}
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
if (err != NULL) {
@@ -1012,6 +1023,7 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
+ DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
IOThread *),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index e431bd89e8..f74fcd42d1 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -27,10 +27,12 @@
#include "hw/xen/xen_backend.h"
#include "xen_blkif.h"
#include "sysemu/blockdev.h"
+#include "sysemu/iothread.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
+#include "trace.h"
/* ------------------------------------------------------------- */
@@ -125,6 +127,9 @@ struct XenBlkDev {
DriveInfo *dinfo;
BlockBackend *blk;
QEMUBH *bh;
+
+ IOThread *iothread;
+ AioContext *ctx;
};
/* ------------------------------------------------------------- */
@@ -596,9 +601,12 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
static void qemu_aio_complete(void *opaque, int ret)
{
struct ioreq *ioreq = opaque;
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+
+ aio_context_acquire(blkdev->ctx);
if (ret != 0) {
- xen_pv_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
+ xen_pv_printf(&blkdev->xendev, 0, "%s I/O error\n",
ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
ioreq->aio_errors++;
}
@@ -607,10 +615,10 @@ static void qemu_aio_complete(void *opaque, int ret)
if (ioreq->presync) {
ioreq->presync = 0;
ioreq_runio_qemu_aio(ioreq);
- return;
+ goto done;
}
if (ioreq->aio_inflight > 0) {
- return;
+ goto done;
}
if (xen_feature_grant_copy) {
@@ -647,16 +655,19 @@ static void qemu_aio_complete(void *opaque, int ret)
}
case BLKIF_OP_READ:
if (ioreq->status == BLKIF_RSP_OKAY) {
- block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
+ block_acct_done(blk_get_stats(blkdev->blk), &ioreq->acct);
} else {
- block_acct_failed(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
+ block_acct_failed(blk_get_stats(blkdev->blk), &ioreq->acct);
}
break;
case BLKIF_OP_DISCARD:
default:
break;
}
- qemu_bh_schedule(ioreq->blkdev->bh);
+ qemu_bh_schedule(blkdev->bh);
+
+done:
+ aio_context_release(blkdev->ctx);
}
static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number,
@@ -913,17 +924,29 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
static void blk_bh(void *opaque)
{
struct XenBlkDev *blkdev = opaque;
+
+ aio_context_acquire(blkdev->ctx);
blk_handle_requests(blkdev);
+ aio_context_release(blkdev->ctx);
}
static void blk_alloc(struct XenDevice *xendev)
{
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+ Error *err = NULL;
+
+ trace_xen_disk_alloc(xendev->name);
QLIST_INIT(&blkdev->inflight);
QLIST_INIT(&blkdev->finished);
QLIST_INIT(&blkdev->freelist);
- blkdev->bh = qemu_bh_new(blk_bh, blkdev);
+
+ blkdev->iothread = iothread_create(xendev->name, &err);
+ assert(!err);
+
+ blkdev->ctx = iothread_get_aio_context(blkdev->iothread);
+ blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev);
+
if (xen_mode != XEN_EMULATE) {
batch_maps = 1;
}
@@ -950,6 +973,8 @@ static int blk_init(struct XenDevice *xendev)
int info = 0;
char *directiosafe = NULL;
+ trace_xen_disk_init(xendev->name);
+
/* read xenstore entries */
if (blkdev->params == NULL) {
char *h = NULL;
@@ -1062,6 +1087,8 @@ static int blk_connect(struct XenDevice *xendev)
unsigned int i;
uint32_t *domids;
+ trace_xen_disk_connect(xendev->name);
+
/* read-only ? */
if (blkdev->directiosafe) {
qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO;
@@ -1287,6 +1314,8 @@ static int blk_connect(struct XenDevice *xendev)
blkdev->persistent_gnt_count = 0;
}
+ blk_set_aio_context(blkdev->blk, blkdev->ctx);
+
xen_be_bind_evtchn(&blkdev->xendev);
xen_pv_printf(&blkdev->xendev, 1, "ok: proto %s, nr-ring-ref %u, "
@@ -1300,13 +1329,20 @@ static void blk_disconnect(struct XenDevice *xendev)
{
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+ trace_xen_disk_disconnect(xendev->name);
+
+ aio_context_acquire(blkdev->ctx);
+
if (blkdev->blk) {
+ blk_set_aio_context(blkdev->blk, qemu_get_aio_context());
blk_detach_dev(blkdev->blk, blkdev);
blk_unref(blkdev->blk);
blkdev->blk = NULL;
}
xen_pv_unbind_evtchn(&blkdev->xendev);
+ aio_context_release(blkdev->ctx);
+
if (blkdev->sring) {
xengnttab_unmap(blkdev->xendev.gnttabdev, blkdev->sring,
blkdev->nr_ring_ref);
@@ -1345,6 +1381,8 @@ static int blk_free(struct XenDevice *xendev)
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
struct ioreq *ioreq;
+ trace_xen_disk_free(xendev->name);
+
blk_disconnect(xendev);
while (!QLIST_EMPTY(&blkdev->freelist)) {
@@ -1360,6 +1398,7 @@ static int blk_free(struct XenDevice *xendev)
g_free(blkdev->dev);
g_free(blkdev->devtype);
qemu_bh_delete(blkdev->bh);
+ iothread_destroy(blkdev->iothread);
return 0;
}
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index 95ccec6f8b..e2abc61b04 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -29,7 +29,6 @@
#include "hw/hw.h"
#include "chardev/char-fe.h"
#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon"
#define ISA_DEBUGCON_DEVICE(obj) \
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 3643dfe067..5e68326c19 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -27,7 +27,6 @@
#include "hw/hw.h"
#include "chardev/char-fe.h"
#include "hw/xen/xen_backend.h"
-#include "qapi/error.h"
#include <xen/io/console.h>
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 36c2fb069c..c857f3f934 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -20,7 +20,6 @@
#include "sysemu/numa.h"
#include "qemu/error-report.h"
#include "qemu/cutils.h"
-#include "sysemu/numa.h"
#include "sysemu/qtest.h"
static char *machine_get_accel(Object *obj, Error **errp)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index ec10da7424..1d3ba722fa 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -22,6 +22,7 @@
#include "qapi/visitor.h"
#include "chardev/char-fe.h"
#include "sysemu/iothread.h"
+#include "sysemu/tpm_backend.h"
static void get_pointer(Object *obj, Visitor *v, Property *prop,
char *(*print)(void *ptr),
diff --git a/hw/cpu/core.c b/hw/cpu/core.c
index bd578ab80c..7e42e2c87a 100644
--- a/hw/cpu/core.c
+++ b/hw/cpu/core.c
@@ -6,6 +6,7 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "hw/cpu/core.h"
#include "qapi/visitor.h"
#include "qapi/error.h"
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index bc32bf1e39..138ae961b9 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -31,7 +31,6 @@
#include "trace.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "ui/console.h"
#include "ui/pixel_ops.h"
#include "vga_int.h"
#include "hw/loader.h"
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index f6556adb73..8668a8e05a 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -3,7 +3,6 @@
#include "qemu-common.h"
-#include "ui/console.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "vga_int.h"
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 7f1822421a..4f7dc59b25 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -795,6 +795,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
case SM501_ARBTRTN_CONTROL:
ret = s->arbitration_control;
break;
+ case SM501_COMMAND_LIST_STATUS:
+ ret = 0x00180002; /* FIFOs are empty, everything idle */
case SM501_IRQ_MASK:
ret = s->irq_mask;
break;
@@ -812,6 +814,9 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
case SM501_POWER_MODE_CONTROL:
ret = s->power_mode_control;
break;
+ case SM501_ENDIAN_CONTROL:
+ ret = 0; /* Only default little endian mode is supported */
+ break;
default:
printf("sm501 system config : not implemented register read."
@@ -865,6 +870,12 @@ static void sm501_system_config_write(void *opaque, hwaddr addr,
case SM501_POWER_MODE_CONTROL:
s->power_mode_control = value & 0x00000003;
break;
+ case SM501_ENDIAN_CONTROL:
+ if (value & 0x00000001) {
+ printf("sm501 system config : big endian mode not implemented.\n");
+ abort();
+ }
+ break;
default:
printf("sm501 system config : not implemented register write."
@@ -924,6 +935,9 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
case SM501_DC_PANEL_PANNING_CONTROL:
ret = s->dc_panel_panning_control;
break;
+ case SM501_DC_PANEL_COLOR_KEY:
+ /* Not implemented yet */
+ break;
case SM501_DC_PANEL_FB_ADDR:
ret = s->dc_panel_fb_addr;
break;
@@ -956,6 +970,19 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
ret = s->dc_panel_v_sync;
break;
+ case SM501_DC_PANEL_HWC_ADDR:
+ ret = s->dc_panel_hwc_addr;
+ break;
+ case SM501_DC_PANEL_HWC_LOC:
+ ret = s->dc_panel_hwc_location;
+ break;
+ case SM501_DC_PANEL_HWC_COLOR_1_2:
+ ret = s->dc_panel_hwc_color_1_2;
+ break;
+ case SM501_DC_PANEL_HWC_COLOR_3:
+ ret = s->dc_panel_hwc_color_3;
+ break;
+
case SM501_DC_VIDEO_CONTROL:
ret = s->dc_video_control;
break;
@@ -1022,6 +1049,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
case SM501_DC_PANEL_PANNING_CONTROL:
s->dc_panel_panning_control = value & 0xFF3FFF3F;
break;
+ case SM501_DC_PANEL_COLOR_KEY:
+ /* Not implemented yet */
+ break;
case SM501_DC_PANEL_FB_ADDR:
s->dc_panel_fb_addr = value & 0x8FFFFFF0;
break;
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 74d10af3d4..0ae63605f0 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -172,6 +172,7 @@ static void tc6393xb_gpio_handler_update(TC6393xbState *s)
int bit;
level = s->gpio_level & s->gpio_dir;
+ level &= MAKE_64BIT_MASK(0, TC6393XB_GPIOS);
for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
bit = ctz32(diff);
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index 51ccbccc41..e887b45651 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -23,11 +23,9 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
+#include "hw/display/vga.h"
#include "vga_int.h"
#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
#define VGA_RAM_SIZE (8192 * 1024)
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index 1af95562f2..469834add5 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -25,8 +25,7 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
#include "vga_int.h"
#include "ui/pixel_ops.h"
#include "qemu/timer.h"
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 7adb89fcb4..1674bd3581 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -25,7 +25,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "ui/console.h"
#include "hw/pci/pci.h"
#include "vga_int.h"
#include "ui/pixel_ops.h"
diff --git a/hw/display/vga.c b/hw/display/vga.c
index a64a0942da..a0412000a5 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -24,11 +24,10 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/hw.h"
-#include "vga.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
+#include "hw/display/vga.h"
#include "hw/pci/pci.h"
#include "vga_int.h"
+#include "vga_regs.h"
#include "ui/pixel_ops.h"
#include "qemu/timer.h"
#include "hw/xen/xen.h"
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index ad34a1f048..fe23b81442 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -25,8 +25,9 @@
#ifndef HW_VGA_INT_H
#define HW_VGA_INT_H
-#include "hw/hw.h"
+#include "exec/ioport.h"
#include "exec/memory.h"
+#include "ui/console.h"
#define ST01_V_RETRACE 0x08
#define ST01_DISP_ENABLE 0x01
diff --git a/hw/display/vga.h b/hw/display/vga_regs.h
index 16886f5eed..16886f5eed 100644
--- a/hw/display/vga.h
+++ b/hw/display/vga_regs.h
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index f9b017d86b..baa74ba82c 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -1,7 +1,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "ui/console.h"
#include "vga_int.h"
#include "hw/virtio/virtio-pci.h"
#include "qapi/error.h"
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 0e6673a911..bd3e8b3586 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -26,7 +26,6 @@
#include "hw/hw.h"
#include "hw/loader.h"
#include "trace.h"
-#include "ui/console.h"
#include "ui/vnc.h"
#include "hw/pci/pci.h"
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 8e2547ac05..d4fc0fa5f2 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -27,6 +27,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
+#include "ui/input.h"
#include "ui/console.h"
#include "hw/xen/xen_backend.h"
@@ -51,9 +52,11 @@ struct common {
struct XenInput {
struct common c;
int abs_pointer_wanted; /* Whether guest supports absolute pointer */
- int button_state; /* Last seen pointer button state */
- int extended;
- QEMUPutMouseEntry *qmouse;
+ int raw_pointer_wanted; /* Whether guest supports raw (unscaled) pointer */
+ QemuInputHandlerState *qkbd;
+ QemuInputHandlerState *qmou;
+ int axis[INPUT_AXIS__MAX];
+ int wheel;
};
#define UP_QUEUE 8
@@ -119,79 +122,6 @@ static void common_unbind(struct common *c)
}
/* -------------------------------------------------------------------- */
-
-#if 0
-/*
- * These two tables are not needed any more, but left in here
- * intentionally as documentation, to show how scancode2linux[]
- * was generated.
- *
- * Tables to map from scancode to Linux input layer keycode.
- * Scancodes are hardware-specific. These maps assumes a
- * standard AT or PS/2 keyboard which is what QEMU feeds us.
- */
-const unsigned char atkbd_set2_keycode[512] = {
-
- 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
- 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
- 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
- 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
- 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
- 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
- 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
- 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
- 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
- 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
- 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
- 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
- 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
-
-};
-
-const unsigned char atkbd_unxlate_table[128] = {
-
- 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
- 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
- 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
- 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
- 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
- 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
- 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
- 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
-
-};
-#endif
-
-/*
- * for (i = 0; i < 128; i++) {
- * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
- * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
- * }
- */
-static const unsigned char scancode2linux[512] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
- 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
- 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
- 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
- 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
/* Send an event to the keyboard frontend driver */
static int xenfb_kbd_event(struct XenInput *xenfb,
union xenkbd_in_event *event)
@@ -262,36 +192,28 @@ static int xenfb_send_position(struct XenInput *xenfb,
/*
* Send a key event from the client to the guest OS
- * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
+ * QEMU gives us a QCode.
* We have to turn this into a Linux Input layer keycode.
*
- * Extra complexity from the fact that with extended scancodes
- * (like those produced by arrow keys) this method gets called
- * twice, but we only want to send a single event. So we have to
- * track the '0xe0' scancode state & collapse the extended keys
- * as needed.
- *
* Wish we could just send scancodes straight to the guest which
* already has code for dealing with this...
*/
-static void xenfb_key_event(void *opaque, int scancode)
+static void xenfb_key_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- struct XenInput *xenfb = opaque;
- int down = 1;
+ struct XenInput *xenfb = (struct XenInput *)dev;
+ InputKeyEvent *key = evt->u.key.data;
+ int qcode = qemu_input_key_value_to_qcode(key->key);
+ int lnx;
- if (scancode == 0xe0) {
- xenfb->extended = 1;
- return;
- } else if (scancode & 0x80) {
- scancode &= 0x7f;
- down = 0;
- }
- if (xenfb->extended) {
- scancode |= 0x80;
- xenfb->extended = 0;
+ if (qcode < qemu_input_map_qcode_to_linux_len) {
+ lnx = qemu_input_map_qcode_to_linux[qcode];
+
+ if (lnx) {
+ trace_xenfb_key_event(xenfb, lnx, key->down);
+ xenfb_send_key(xenfb, key->down, lnx);
+ }
}
- trace_xenfb_key_event(opaque, scancode2linux[scancode], down);
- xenfb_send_key(xenfb, down, scancode2linux[scancode]);
}
/*
@@ -303,48 +225,126 @@ static void xenfb_key_event(void *opaque, int scancode)
* given any button up/down events, so have to track changes in
* the button state.
*/
-static void xenfb_mouse_event(void *opaque,
- int dx, int dy, int dz, int button_state)
+static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- struct XenInput *xenfb = opaque;
- QemuConsole *con = qemu_console_lookup_by_index(0);
+ struct XenInput *xenfb = (struct XenInput *)dev;
+ InputBtnEvent *btn;
+ InputMoveEvent *move;
+ QemuConsole *con;
DisplaySurface *surface;
- int dw, dh, i;
+ int scale;
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ switch (btn->button) {
+ case INPUT_BUTTON_LEFT:
+ xenfb_send_key(xenfb, btn->down, BTN_LEFT);
+ break;
+ case INPUT_BUTTON_RIGHT:
+ xenfb_send_key(xenfb, btn->down, BTN_LEFT + 1);
+ break;
+ case INPUT_BUTTON_MIDDLE:
+ xenfb_send_key(xenfb, btn->down, BTN_LEFT + 2);
+ break;
+ case INPUT_BUTTON_WHEEL_UP:
+ if (btn->down) {
+ xenfb->wheel--;
+ }
+ break;
+ case INPUT_BUTTON_WHEEL_DOWN:
+ if (btn->down) {
+ xenfb->wheel++;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case INPUT_EVENT_KIND_ABS:
+ move = evt->u.abs.data;
+ if (xenfb->raw_pointer_wanted) {
+ xenfb->axis[move->axis] = move->value;
+ } else {
+ con = qemu_console_lookup_by_index(0);
+ if (!con) {
+ xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available");
+ return;
+ }
+ surface = qemu_console_surface(con);
+ switch (move->axis) {
+ case INPUT_AXIS_X:
+ scale = surface_width(surface) - 1;
+ break;
+ case INPUT_AXIS_Y:
+ scale = surface_height(surface) - 1;
+ break;
+ default:
+ scale = 0x8000;
+ break;
+ }
+ xenfb->axis[move->axis] = move->value * scale / 0x7fff;
+ }
+ break;
- if (!con) {
- xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available");
- return;
+ case INPUT_EVENT_KIND_REL:
+ move = evt->u.rel.data;
+ xenfb->axis[move->axis] += move->value;
+ break;
+
+ default:
+ break;
}
+}
- surface = qemu_console_surface(con);
- dw = surface_width(surface);
- dh = surface_height(surface);
+static void xenfb_mouse_sync(DeviceState *dev)
+{
+ struct XenInput *xenfb = (struct XenInput *)dev;
- trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
+ trace_xenfb_mouse_event(xenfb, xenfb->axis[INPUT_AXIS_X],
+ xenfb->axis[INPUT_AXIS_Y],
+ xenfb->wheel, 0,
xenfb->abs_pointer_wanted);
- if (xenfb->abs_pointer_wanted)
- xenfb_send_position(xenfb,
- dx * (dw - 1) / 0x7fff,
- dy * (dh - 1) / 0x7fff,
- dz);
- else
- xenfb_send_motion(xenfb, dx, dy, dz);
-
- for (i = 0 ; i < 8 ; i++) {
- int lastDown = xenfb->button_state & (1 << i);
- int down = button_state & (1 << i);
- if (down == lastDown)
- continue;
-
- if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
- return;
- }
- xenfb->button_state = button_state;
+ if (xenfb->abs_pointer_wanted) {
+ xenfb_send_position(xenfb, xenfb->axis[INPUT_AXIS_X],
+ xenfb->axis[INPUT_AXIS_Y],
+ xenfb->wheel);
+ } else {
+ xenfb_send_motion(xenfb, xenfb->axis[INPUT_AXIS_X],
+ xenfb->axis[INPUT_AXIS_Y],
+ xenfb->wheel);
+ xenfb->axis[INPUT_AXIS_X] = 0;
+ xenfb->axis[INPUT_AXIS_Y] = 0;
+ }
+ xenfb->wheel = 0;
}
+static QemuInputHandler xenfb_keyboard = {
+ .name = "Xen PV Keyboard",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = xenfb_key_event,
+};
+
+static QemuInputHandler xenfb_abs_mouse = {
+ .name = "Xen PV Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
+ .event = xenfb_mouse_event,
+ .sync = xenfb_mouse_sync,
+};
+
+static QemuInputHandler xenfb_rel_mouse = {
+ .name = "Xen PV Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = xenfb_mouse_event,
+ .sync = xenfb_mouse_sync,
+};
+
static int input_init(struct XenDevice *xendev)
{
xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
+ xenstore_write_be_int(xendev, "feature-raw-pointer", 1);
return 0;
}
@@ -357,7 +357,6 @@ static int input_initialise(struct XenDevice *xendev)
if (rc != 0)
return rc;
- qemu_add_kbd_event_handler(xenfb_key_event, in);
return 0;
}
@@ -369,25 +368,44 @@ static void input_connected(struct XenDevice *xendev)
&in->abs_pointer_wanted) == -1) {
in->abs_pointer_wanted = 0;
}
+ if (xenstore_read_fe_int(xendev, "request-raw-pointer",
+ &in->raw_pointer_wanted) == -1) {
+ in->raw_pointer_wanted = 0;
+ }
+ if (in->raw_pointer_wanted && in->abs_pointer_wanted == 0) {
+ xen_pv_printf(xendev, 0, "raw pointer set without abs pointer");
+ }
- if (in->qmouse) {
- qemu_remove_mouse_event_handler(in->qmouse);
+ if (in->qkbd) {
+ qemu_input_handler_unregister(in->qkbd);
+ }
+ if (in->qmou) {
+ qemu_input_handler_unregister(in->qmou);
}
trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
- in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
- in->abs_pointer_wanted,
- "Xen PVFB Mouse");
+
+ in->qkbd = qemu_input_handler_register((DeviceState *)in, &xenfb_keyboard);
+ in->qmou = qemu_input_handler_register((DeviceState *)in,
+ in->abs_pointer_wanted ? &xenfb_abs_mouse : &xenfb_rel_mouse);
+
+ if (in->raw_pointer_wanted) {
+ qemu_input_handler_activate(in->qkbd);
+ qemu_input_handler_activate(in->qmou);
+ }
}
static void input_disconnect(struct XenDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
- if (in->qmouse) {
- qemu_remove_mouse_event_handler(in->qmouse);
- in->qmouse = NULL;
+ if (in->qkbd) {
+ qemu_input_handler_unregister(in->qkbd);
+ in->qkbd = NULL;
+ }
+ if (in->qmou) {
+ qemu_input_handler_unregister(in->qmou);
+ in->qmou = NULL;
}
- qemu_add_kbd_event_handler(NULL, NULL);
common_unbind(&in->c);
}
diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs
index 087c8e6855..0b3a009b87 100644
--- a/hw/dma/Makefile.objs
+++ b/hw/dma/Makefile.objs
@@ -8,7 +8,6 @@ common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
common-obj-$(CONFIG_ZYNQ_DEVCFG) += xlnx-zynq-devcfg.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o
common-obj-$(CONFIG_STP2000) += sparc32_dma.o
-common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dpdma.o
obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index 01afb758b6..7b00a27de6 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -28,7 +28,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sparc/sparc32_dma.h"
-#include "hw/sparc/sun4m.h"
+#include "hw/sparc/sun4m_iommu.h"
#include "hw/sysbus.h"
#include "sysemu/dma.h"
#include "qapi/error.h"
diff --git a/hw/dma/trace-events b/hw/dma/trace-events
index 6b367f053b..22f53d0ff2 100644
--- a/hw/dma/trace-events
+++ b/hw/dma/trace-events
@@ -18,15 +18,5 @@ sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg
sparc32_dma_enable_raise(void) "Raise DMA enable"
sparc32_dma_enable_lower(void) "Lower DMA enable"
-# hw/dma/sun4m_iommu.c
-sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x"
-sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x"
-sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = 0x%"PRIx64
-sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush 0x%x"
-sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush 0x%x"
-sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr 0x%"PRIx64" => pte 0x%"PRIx64", *pte = 0x%x"
-sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva 0x%"PRIx64" => pa 0x%"PRIx64" iopte = 0x%x"
-sun4m_iommu_bad_addr(uint64_t addr) "bad addr 0x%"PRIx64
-
# hw/dma/i8257.c
i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index ec060d58cc..0d26e0f6b5 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -19,7 +19,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/i2c/pm_smbus.h"
#include "hw/i2c/smbus.h"
diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c
index 5a6bde951e..e873a445da 100644
--- a/hw/i2c/ppc4xx_i2c.c
+++ b/hw/i2c/ppc4xx_i2c.c
@@ -2,6 +2,8 @@
* PPC4xx I2C controller emulation
*
* Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016 BALATON Zoltan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,26 +27,118 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu-common.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/i2c/ppc4xx_i2c.h"
-/*#define DEBUG_I2C*/
+#define PPC4xx_I2C_MEM_SIZE 0x12
-#define PPC4xx_I2C_MEM_SIZE 0x11
+#define IIC_CNTL_PT (1 << 0)
+#define IIC_CNTL_READ (1 << 1)
+#define IIC_CNTL_CHT (1 << 2)
+#define IIC_CNTL_RPST (1 << 3)
+
+#define IIC_STS_PT (1 << 0)
+#define IIC_STS_ERR (1 << 2)
+#define IIC_STS_MDBS (1 << 5)
+
+#define IIC_EXTSTS_XFRA (1 << 0)
+
+#define IIC_XTCNTLSS_SRST (1 << 0)
+
+static void ppc4xx_i2c_reset(DeviceState *s)
+{
+ PPC4xxI2CState *i2c = PPC4xx_I2C(s);
+
+ /* FIXME: Should also reset bus?
+ *if (s->address != ADDR_RESET) {
+ * i2c_end_transfer(s->bus);
+ *}
+ */
+
+ i2c->mdata = 0;
+ i2c->lmadr = 0;
+ i2c->hmadr = 0;
+ i2c->cntl = 0;
+ i2c->mdcntl = 0;
+ i2c->sts = 0;
+ i2c->extsts = 0x8f;
+ i2c->sdata = 0;
+ i2c->lsadr = 0;
+ i2c->hsadr = 0;
+ i2c->clkdiv = 0;
+ i2c->intrmsk = 0;
+ i2c->xfrcnt = 0;
+ i2c->xtcntlss = 0;
+ i2c->directcntl = 0x0f;
+ i2c->intr = 0;
+}
+
+static inline bool ppc4xx_i2c_is_master(PPC4xxI2CState *i2c)
+{
+ return true;
+}
static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
{
PPC4xxI2CState *i2c = PPC4xx_I2C(opaque);
uint64_t ret;
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
-#endif
switch (addr) {
case 0x00:
- /*i2c_readbyte(&i2c->mdata);*/
ret = i2c->mdata;
+ if (ppc4xx_i2c_is_master(i2c)) {
+ ret = 0xff;
+
+ if (!(i2c->sts & IIC_STS_MDBS)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read "
+ "without starting transfer\n",
+ TYPE_PPC4xx_I2C, __func__);
+ } else {
+ int pending = (i2c->cntl >> 4) & 3;
+
+ /* get the next byte */
+ int byte = i2c_recv(i2c->bus);
+
+ if (byte < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed "
+ "for device 0x%02x\n", TYPE_PPC4xx_I2C,
+ __func__, i2c->lmadr);
+ ret = 0xff;
+ } else {
+ ret = byte;
+ /* Raise interrupt if enabled */
+ /*ppc4xx_i2c_raise_interrupt(i2c)*/;
+ }
+
+ if (!pending) {
+ i2c->sts &= ~IIC_STS_MDBS;
+ /*i2c_end_transfer(i2c->bus);*/
+ /*} else if (i2c->cntl & (IIC_CNTL_RPST | IIC_CNTL_CHT)) {*/
+ } else if (pending) {
+ /* current smbus implementation doesn't like
+ multibyte xfer repeated start */
+ i2c_end_transfer(i2c->bus);
+ if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) {
+ /* if non zero is returned, the adress is not valid */
+ i2c->sts &= ~IIC_STS_PT;
+ i2c->sts |= IIC_STS_ERR;
+ i2c->extsts |= IIC_EXTSTS_XFRA;
+ } else {
+ /*i2c->sts |= IIC_STS_PT;*/
+ i2c->sts |= IIC_STS_MDBS;
+ i2c->sts &= ~IIC_STS_ERR;
+ i2c->extsts = 0;
+ }
+ }
+ pending--;
+ i2c->cntl = (i2c->cntl & 0xcf) | (pending << 4);
+ }
+ } else {
+ qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n",
+ TYPE_PPC4xx_I2C, __func__);
+ }
break;
case 0x02:
ret = i2c->sdata;
@@ -88,13 +182,15 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
case 0x10:
ret = i2c->directcntl;
break;
+ case 0x11:
+ ret = i2c->intr;
+ break;
default:
- ret = 0x00;
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_PPC4xx_I2C, __func__, addr);
+ ret = 0;
break;
}
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " %02" PRIx64 "\n", __func__, addr, ret);
-#endif
return ret;
}
@@ -103,26 +199,70 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
unsigned int size)
{
PPC4xxI2CState *i2c = opaque;
-#ifdef DEBUG_I2C
- printf("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n",
- __func__, addr, value);
-#endif
+
switch (addr) {
case 0x00:
i2c->mdata = value;
- /*i2c_sendbyte(&i2c->mdata);*/
+ if (!i2c_bus_busy(i2c->bus)) {
+ /* assume we start a write transfer */
+ if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 0)) {
+ /* if non zero is returned, the adress is not valid */
+ i2c->sts &= ~IIC_STS_PT;
+ i2c->sts |= IIC_STS_ERR;
+ i2c->extsts |= IIC_EXTSTS_XFRA;
+ } else {
+ i2c->sts |= IIC_STS_PT;
+ i2c->sts &= ~IIC_STS_ERR;
+ i2c->extsts = 0;
+ }
+ }
+ if (i2c_bus_busy(i2c->bus)) {
+ if (i2c_send(i2c->bus, i2c->mdata)) {
+ /* if the target return non zero then end the transfer */
+ i2c->sts &= ~IIC_STS_PT;
+ i2c->sts |= IIC_STS_ERR;
+ i2c->extsts |= IIC_EXTSTS_XFRA;
+ i2c_end_transfer(i2c->bus);
+ }
+ }
break;
case 0x02:
i2c->sdata = value;
break;
case 0x04:
i2c->lmadr = value;
+ if (i2c_bus_busy(i2c->bus)) {
+ i2c_end_transfer(i2c->bus);
+ }
break;
case 0x05:
i2c->hmadr = value;
break;
case 0x06:
i2c->cntl = value;
+ if (i2c->cntl & IIC_CNTL_PT) {
+ if (i2c->cntl & IIC_CNTL_READ) {
+ if (i2c_bus_busy(i2c->bus)) {
+ /* end previous transfer */
+ i2c->sts &= ~IIC_STS_PT;
+ i2c_end_transfer(i2c->bus);
+ }
+ if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) {
+ /* if non zero is returned, the adress is not valid */
+ i2c->sts &= ~IIC_STS_PT;
+ i2c->sts |= IIC_STS_ERR;
+ i2c->extsts |= IIC_EXTSTS_XFRA;
+ } else {
+ /*i2c->sts |= IIC_STS_PT;*/
+ i2c->sts |= IIC_STS_MDBS;
+ i2c->sts &= ~IIC_STS_ERR;
+ i2c->extsts = 0;
+ }
+ } else {
+ /* we actually already did the write transfer... */
+ i2c->sts &= ~IIC_STS_PT;
+ }
+ }
break;
case 0x07:
i2c->mdcntl = value & 0xDF;
@@ -135,6 +275,7 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
break;
case 0x0A:
i2c->lsadr = value;
+ /*i2c_set_slave_address(i2c->bus, i2c->lsadr);*/
break;
case 0x0B:
i2c->hsadr = value;
@@ -149,11 +290,23 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
i2c->xfrcnt = value & 0x77;
break;
case 0x0F:
+ if (value & IIC_XTCNTLSS_SRST) {
+ /* Is it actually a full reset? U-Boot sets some regs before */
+ ppc4xx_i2c_reset(DEVICE(i2c));
+ break;
+ }
i2c->xtcntlss = value;
break;
case 0x10:
i2c->directcntl = value & 0x7;
break;
+ case 0x11:
+ i2c->intr = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_PPC4xx_I2C, __func__, addr);
+ break;
}
}
@@ -167,21 +320,6 @@ static const MemoryRegionOps ppc4xx_i2c_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void ppc4xx_i2c_reset(DeviceState *s)
-{
- PPC4xxI2CState *i2c = PPC4xx_I2C(s);
-
- i2c->mdata = 0x00;
- i2c->sdata = 0x00;
- i2c->cntl = 0x00;
- i2c->mdcntl = 0x00;
- i2c->sts = 0x00;
- i2c->extsts = 0x00;
- i2c->clkdiv = 0x00;
- i2c->xfrcnt = 0x00;
- i2c->directcntl = 0x0F;
-}
-
static void ppc4xx_i2c_init(Object *o)
{
PPC4xxI2CState *s = PPC4xx_I2C(o);
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index e47556c9d8..007cb6701d 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -26,7 +26,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/i2c/pm_smbus.h"
#include "hw/pci/pci.h"
#include "sysemu/sysemu.h"
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 2e5e1299ad..fd279e7584 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -5,6 +5,8 @@ obj-y += pc_sysfw.o
obj-y += x86-iommu.o intel_iommu.o
obj-y += amd_iommu.o
obj-$(CONFIG_XEN) += ../xenpv/ xen/
+obj-$(CONFIG_VMPORT) += vmport.o
+obj-$(CONFIG_VMMOUSE) += vmmouse.o
obj-y += kvmvapic.o
obj-y += acpi-build.o
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 73519ab3ac..18b939e469 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -28,8 +28,8 @@
#include "qemu/error-report.h"
#include "hw/pci/pci.h"
#include "qom/cpu.h"
-#include "hw/i386/pc.h"
#include "target/i386/cpu.h"
+#include "hw/misc/pvpanic.h"
#include "hw/timer/hpet.h"
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
@@ -208,7 +208,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info)
}
info->has_hpet = hpet_find();
- info->tpm_version = tpm_get_version();
+ info->tpm_version = tpm_get_version(tpm_find());
info->pvpanic_port = pvpanic_port();
info->applesmc_io_base = applesmc_port();
}
@@ -2038,7 +2038,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
}
- if (misc->tpm_version != TPM_VERSION_UNSPEC) {
+ if (TPM_IS_TIS(tpm_find())) {
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
}
@@ -2204,7 +2204,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
- if (misc->tpm_version != TPM_VERSION_UNSPEC) {
+ if (TPM_IS_TIS(tpm_find())) {
dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
@@ -2274,15 +2274,28 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
}
static void
-build_tpm2(GArray *table_data, BIOSLinker *linker)
+build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
{
- Acpi20TPM2 *tpm2_ptr;
-
- tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
+ Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
+ unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address);
+ unsigned log_addr_offset =
+ (char *)&tpm2_ptr->log_area_start_address - table_data->data;
tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
- tpm2_ptr->control_area_address = cpu_to_le64(0);
- tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
+ if (TPM_IS_TIS(tpm_find())) {
+ tpm2_ptr->control_area_address = cpu_to_le64(0);
+ tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
+
+ tpm2_ptr->log_area_minimum_length =
+ cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE);
+
+ /* log area start address to be filled by Guest linker */
+ bios_linker_loader_add_pointer(linker,
+ ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size,
+ ACPI_BUILD_TPMLOG_FILE, 0);
+ } else {
+ g_warn_if_reached();
+ }
build_header(linker, table_data,
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
@@ -2691,7 +2704,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
if (misc.tpm_version == TPM_VERSION_2_0) {
acpi_add_table(table_offsets, tables_blob);
- build_tpm2(tables_blob, tables->linker);
+ build_tpm2(tables_blob, tables->linker, tables->tcpalog);
}
}
if (pcms->numa_nodes) {
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index ad8155ca4c..eeaf0e0aa8 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -20,7 +20,10 @@
* Cache implementation inspired by hw/i386/intel_iommu.c
*/
#include "qemu/osdep.h"
-#include "hw/i386/amd_iommu.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pci_bus.h"
+#include "amd_iommu.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "trace.h"
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index d370ae3549..aeef802364 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -23,11 +23,6 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "hw/sysbus.h"
-#include "sysemu/dma.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci_bus.h"
#include "hw/i386/x86-iommu.h"
/* Capability registers */
diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c
index 11d1b726b6..b91e98074e 100644
--- a/hw/i386/kvm/i8259.c
+++ b/hw/i386/kvm/i8259.c
@@ -111,6 +111,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level)
{
int delivered;
+ pic_stat_update_irq(irq, level);
delivered = kvm_set_irq(kvm_state, irq, level);
apic_report_irq_delivered(delivered);
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 186545d2a4..3fcf318a95 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -69,6 +69,7 @@
#include "qom/cpu.h"
#include "hw/nmi.h"
#include "hw/i386/intel_iommu.h"
+#include "hw/net/ne2000-isa.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@@ -1565,7 +1566,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
}
}
- *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
+ *rtc_state = mc146818_rtc_init(isa_bus, 2000, rtc_irq);
qemu_register_boot_set(pc_boot_set, *rtc_state);
@@ -1573,7 +1574,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
if (kvm_pit_in_kernel()) {
pit = kvm_pit_init(isa_bus, 0x40);
} else {
- pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
+ pit = i8254_pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
}
if (hpet) {
/* connect PIT to output control line of the HPET */
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index d43b4b6cd3..22d44648af 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -113,3 +113,7 @@ amdvi_mode_invalid(uint8_t level, uint64_t addr)"error: translation level 0x%"PR
amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64
amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
+
+# hw/i386/vmport.c
+vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
+vmport_command(unsigned char command) "command: 0x%02x"
diff --git a/hw/input/vmmouse.c b/hw/i386/vmmouse.c
index b6d22086f4..65ef55329e 100644
--- a/hw/input/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "ui/console.h"
-#include "hw/input/ps2.h"
#include "hw/i386/pc.h"
#include "hw/qdev.h"
diff --git a/hw/misc/vmport.c b/hw/i386/vmport.c
index 165500223f..116aa09819 100644
--- a/hw/misc/vmport.c
+++ b/hw/i386/vmport.c
@@ -27,8 +27,8 @@
#include "hw/i386/pc.h"
#include "sysemu/hw_accel.h"
#include "hw/qdev.h"
-
-//#define VMPORT_DEBUG
+#include "qemu/log.h"
+#include "trace.h"
#define VMPORT_CMD_GETVERSION 0x0a
#define VMPORT_CMD_GETRAMSIZE 0x14
@@ -38,8 +38,7 @@
#define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT)
-typedef struct VMPortState
-{
+typedef struct VMPortState {
ISADevice parent_obj;
MemoryRegion io;
@@ -51,9 +50,11 @@ static VMPortState *port_state;
void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque)
{
- if (command >= VMPORT_ENTRIES)
+ if (command >= VMPORT_ENTRIES) {
return;
+ }
+ trace_vmport_register(command, func, opaque);
port_state->func[command] = func;
port_state->opaque[command] = opaque;
}
@@ -71,17 +72,14 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr,
cpu_synchronize_state(cs);
eax = env->regs[R_EAX];
- if (eax != VMPORT_MAGIC)
+ if (eax != VMPORT_MAGIC) {
return eax;
+ }
command = env->regs[R_ECX];
- if (command >= VMPORT_ENTRIES)
- return eax;
- if (!s->func[command])
- {
-#ifdef VMPORT_DEBUG
- fprintf(stderr, "vmport: unknown command %x\n", command);
-#endif
+ trace_vmport_command(command);
+ if (command >= VMPORT_ENTRIES || !s->func[command]) {
+ qemu_log_mask(LOG_UNIMP, "vmport: unknown command %x\n", command);
return eax;
}
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index baab93b614..efa35dc6e0 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -199,7 +199,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
*/
vaddr_base = mmap(vaddr, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
- if (vaddr_base == NULL) {
+ if (vaddr_base == MAP_FAILED) {
perror("mmap");
exit(-1);
}
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index 9ab54834d5..deb7a0c374 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -26,7 +26,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/ide.h"
#include "hw/pci/pci.h"
#include "hw/irq.h"
diff --git a/hw/ide/Makefile.objs b/hw/ide/Makefile.objs
index f0edca3300..fc328ffbe8 100644
--- a/hw/ide/Makefile.objs
+++ b/hw/ide/Makefile.objs
@@ -11,3 +11,4 @@ common-obj-$(CONFIG_MICRODRIVE) += microdrive.o
common-obj-$(CONFIG_AHCI) += ahci.o
common-obj-$(CONFIG_AHCI) += ich.o
common-obj-$(CONFIG_ALLWINNER_A10) += ahci-allwinner.o
+common-obj-$(CONFIG_IDE_SII3112) += sii3112.o
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 373311f91a..451b18b419 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/msi.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "qemu/error-report.h"
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 86b2a8f504..65aff518ec 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 471d0c928b..1ea5812b7e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -24,17 +24,16 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
#include "sysemu/dma.h"
#include "hw/block/block.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
-#include "qemu/error-report.h"
#include "hw/ide/internal.h"
#include "trace.h"
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 8dd0ced6b3..c01b24ecbe 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -63,7 +63,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/msi.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 40213d662c..9fb24fc92b 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
index 17917c0b30..fde4d4645e 100644
--- a/hw/ide/microdrive.c
+++ b/hw/ide/microdrive.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pcmcia.h"
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 25f1d36f3a..1ab0a892d0 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index dfb21f65fa..a3afe1fd29 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -25,11 +25,11 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
#include "sysemu/dma.h"
#include "hw/ide/pci.h"
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index a5181b4448..f395d24592 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -160,7 +160,6 @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
{
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
IDEState *s = bus->ifs + dev->unit;
- Error *err = NULL;
int ret;
if (!dev->conf.blk) {
@@ -191,16 +190,13 @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
blkconf_serial(&dev->conf, &dev->serial);
if (kind != IDE_CD) {
- blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
+ errp)) {
return;
}
}
- blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD,
- &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_apply_backend_options(&dev->conf, kind == IDE_CD,
+ kind != IDE_CD, errp)) {
return;
}
diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c
new file mode 100644
index 0000000000..e2f5562bb7
--- /dev/null
+++ b/hw/ide/sii3112.c
@@ -0,0 +1,368 @@
+/*
+ * QEMU SiI3112A PCI to Serial ATA Controller Emulation
+ *
+ * Copyright (C) 2017 BALATON Zoltan <balaton@eik.bme.hu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+/* For documentation on this and similar cards see:
+ * http://wiki.osdev.org/User:Quok/Silicon_Image_Datasheets
+ */
+
+#include <qemu/osdep.h>
+#include <hw/ide/pci.h>
+#include "trace.h"
+
+#define TYPE_SII3112_PCI "sii3112"
+#define SII3112_PCI(obj) OBJECT_CHECK(SiI3112PCIState, (obj), \
+ TYPE_SII3112_PCI)
+
+typedef struct SiI3112Regs {
+ uint32_t confstat;
+ uint32_t scontrol;
+ uint16_t sien;
+ uint8_t swdata;
+} SiI3112Regs;
+
+typedef struct SiI3112PCIState {
+ PCIIDEState i;
+ MemoryRegion mmio;
+ SiI3112Regs regs[2];
+} SiI3112PCIState;
+
+/* The sii3112_reg_read and sii3112_reg_write functions implement the
+ * Internal Register Space - BAR5 (section 6.7 of the data sheet).
+ */
+
+static uint64_t sii3112_reg_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ SiI3112PCIState *d = opaque;
+ uint64_t val = 0;
+
+ switch (addr) {
+ case 0x00:
+ val = d->i.bmdma[0].cmd;
+ break;
+ case 0x01:
+ val = d->regs[0].swdata;
+ break;
+ case 0x02:
+ val = d->i.bmdma[0].status;
+ break;
+ case 0x03:
+ val = 0;
+ break;
+ case 0x04 ... 0x07:
+ val = bmdma_addr_ioport_ops.read(&d->i.bmdma[0], addr - 4, size);
+ break;
+ case 0x08:
+ val = d->i.bmdma[1].cmd;
+ break;
+ case 0x09:
+ val = d->regs[1].swdata;
+ break;
+ case 0x0a:
+ val = d->i.bmdma[1].status;
+ break;
+ case 0x0b:
+ val = 0;
+ break;
+ case 0x0c ... 0x0f:
+ val = bmdma_addr_ioport_ops.read(&d->i.bmdma[1], addr - 12, size);
+ break;
+ case 0x10:
+ val = d->i.bmdma[0].cmd;
+ val |= (d->regs[0].confstat & (1UL << 11) ? (1 << 4) : 0); /*SATAINT0*/
+ val |= (d->regs[1].confstat & (1UL << 11) ? (1 << 6) : 0); /*SATAINT1*/
+ val |= (d->i.bmdma[1].status & BM_STATUS_INT ? (1 << 14) : 0);
+ val |= d->i.bmdma[0].status << 16;
+ val |= d->i.bmdma[1].status << 24;
+ break;
+ case 0x18:
+ val = d->i.bmdma[1].cmd;
+ val |= (d->regs[1].confstat & (1UL << 11) ? (1 << 4) : 0);
+ val |= d->i.bmdma[1].status << 16;
+ break;
+ case 0x80 ... 0x87:
+ if (size == 1) {
+ val = ide_ioport_read(&d->i.bus[0], addr - 0x80);
+ } else if (addr == 0x80) {
+ val = (size == 2) ? ide_data_readw(&d->i.bus[0], 0) :
+ ide_data_readl(&d->i.bus[0], 0);
+ } else {
+ val = (1ULL << (size * 8)) - 1;
+ }
+ break;
+ case 0x8a:
+ val = (size == 1) ? ide_status_read(&d->i.bus[0], 4) :
+ (1ULL << (size * 8)) - 1;
+ break;
+ case 0xa0:
+ val = d->regs[0].confstat;
+ break;
+ case 0xc0 ... 0xc7:
+ if (size == 1) {
+ val = ide_ioport_read(&d->i.bus[1], addr - 0xc0);
+ } else if (addr == 0xc0) {
+ val = (size == 2) ? ide_data_readw(&d->i.bus[1], 0) :
+ ide_data_readl(&d->i.bus[1], 0);
+ } else {
+ val = (1ULL << (size * 8)) - 1;
+ }
+ break;
+ case 0xca:
+ val = (size == 1) ? ide_status_read(&d->i.bus[0], 4) :
+ (1ULL << (size * 8)) - 1;
+ break;
+ case 0xe0:
+ val = d->regs[1].confstat;
+ break;
+ case 0x100:
+ val = d->regs[0].scontrol;
+ break;
+ case 0x104:
+ val = (d->i.bus[0].ifs[0].blk) ? 0x113 : 0;
+ break;
+ case 0x148:
+ val = d->regs[0].sien << 16;
+ break;
+ case 0x180:
+ val = d->regs[1].scontrol;
+ break;
+ case 0x184:
+ val = (d->i.bus[1].ifs[0].blk) ? 0x113 : 0;
+ break;
+ case 0x1c8:
+ val = d->regs[1].sien << 16;
+ break;
+ default:
+ val = 0;
+ }
+ trace_sii3112_read(size, addr, val);
+ return val;
+}
+
+static void sii3112_reg_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned int size)
+{
+ SiI3112PCIState *d = opaque;
+
+ trace_sii3112_write(size, addr, val);
+ switch (addr) {
+ case 0x00:
+ case 0x10:
+ bmdma_cmd_writeb(&d->i.bmdma[0], val);
+ break;
+ case 0x01:
+ case 0x11:
+ d->regs[0].swdata = val & 0x3f;
+ break;
+ case 0x02:
+ case 0x12:
+ d->i.bmdma[0].status = (val & 0x60) | (d->i.bmdma[0].status & 1) |
+ (d->i.bmdma[0].status & ~val & 6);
+ break;
+ case 0x04 ... 0x07:
+ bmdma_addr_ioport_ops.write(&d->i.bmdma[0], addr - 4, val, size);
+ break;
+ case 0x08:
+ case 0x18:
+ bmdma_cmd_writeb(&d->i.bmdma[1], val);
+ break;
+ case 0x09:
+ case 0x19:
+ d->regs[1].swdata = val & 0x3f;
+ break;
+ case 0x0a:
+ case 0x1a:
+ d->i.bmdma[1].status = (val & 0x60) | (d->i.bmdma[1].status & 1) |
+ (d->i.bmdma[1].status & ~val & 6);
+ break;
+ case 0x0c ... 0x0f:
+ bmdma_addr_ioport_ops.write(&d->i.bmdma[1], addr - 12, val, size);
+ break;
+ case 0x80 ... 0x87:
+ if (size == 1) {
+ ide_ioport_write(&d->i.bus[0], addr - 0x80, val);
+ } else if (addr == 0x80) {
+ if (size == 2) {
+ ide_data_writew(&d->i.bus[0], 0, val);
+ } else {
+ ide_data_writel(&d->i.bus[0], 0, val);
+ }
+ }
+ break;
+ case 0x8a:
+ if (size == 1) {
+ ide_cmd_write(&d->i.bus[0], 4, val);
+ }
+ break;
+ case 0xc0 ... 0xc7:
+ if (size == 1) {
+ ide_ioport_write(&d->i.bus[1], addr - 0xc0, val);
+ } else if (addr == 0xc0) {
+ if (size == 2) {
+ ide_data_writew(&d->i.bus[1], 0, val);
+ } else {
+ ide_data_writel(&d->i.bus[1], 0, val);
+ }
+ }
+ break;
+ case 0xca:
+ if (size == 1) {
+ ide_cmd_write(&d->i.bus[1], 4, val);
+ }
+ break;
+ case 0x100:
+ d->regs[0].scontrol = val & 0xfff;
+ if (val & 1) {
+ ide_bus_reset(&d->i.bus[0]);
+ }
+ break;
+ case 0x148:
+ d->regs[0].sien = (val >> 16) & 0x3eed;
+ break;
+ case 0x180:
+ d->regs[1].scontrol = val & 0xfff;
+ if (val & 1) {
+ ide_bus_reset(&d->i.bus[1]);
+ }
+ break;
+ case 0x1c8:
+ d->regs[1].sien = (val >> 16) & 0x3eed;
+ break;
+ default:
+ val = 0;
+ }
+}
+
+static const MemoryRegionOps sii3112_reg_ops = {
+ .read = sii3112_reg_read,
+ .write = sii3112_reg_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/* the PCI irq level is the logical OR of the two channels */
+static void sii3112_update_irq(SiI3112PCIState *s)
+{
+ int i, set = 0;
+
+ for (i = 0; i < 2; i++) {
+ set |= s->regs[i].confstat & (1UL << 11);
+ }
+ pci_set_irq(PCI_DEVICE(s), (set ? 1 : 0));
+}
+
+static void sii3112_set_irq(void *opaque, int channel, int level)
+{
+ SiI3112PCIState *s = opaque;
+
+ trace_sii3112_set_irq(channel, level);
+ if (level) {
+ s->regs[channel].confstat |= (1UL << 11);
+ } else {
+ s->regs[channel].confstat &= ~(1UL << 11);
+ }
+
+ sii3112_update_irq(s);
+}
+
+static void sii3112_reset(void *opaque)
+{
+ SiI3112PCIState *s = opaque;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ s->regs[i].confstat = 0x6515 << 16;
+ ide_bus_reset(&s->i.bus[i]);
+ }
+}
+
+static void sii3112_pci_realize(PCIDevice *dev, Error **errp)
+{
+ SiI3112PCIState *d = SII3112_PCI(dev);
+ PCIIDEState *s = PCI_IDE(dev);
+ MemoryRegion *mr;
+ qemu_irq *irq;
+ int i;
+
+ pci_config_set_interrupt_pin(dev->config, 1);
+ pci_set_byte(dev->config + PCI_CACHE_LINE_SIZE, 8);
+
+ /* BAR5 is in PCI memory space */
+ memory_region_init_io(&d->mmio, OBJECT(d), &sii3112_reg_ops, d,
+ "sii3112.bar5", 0x200);
+ pci_register_bar(dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+
+ /* BAR0-BAR4 are PCI I/O space aliases into BAR5 */
+ mr = g_new(MemoryRegion, 1);
+ memory_region_init_alias(mr, OBJECT(d), "sii3112.bar0", &d->mmio, 0x80, 8);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, mr);
+ mr = g_new(MemoryRegion, 1);
+ memory_region_init_alias(mr, OBJECT(d), "sii3112.bar1", &d->mmio, 0x88, 4);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, mr);
+ mr = g_new(MemoryRegion, 1);
+ memory_region_init_alias(mr, OBJECT(d), "sii3112.bar2", &d->mmio, 0xc0, 8);
+ pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, mr);
+ mr = g_new(MemoryRegion, 1);
+ memory_region_init_alias(mr, OBJECT(d), "sii3112.bar3", &d->mmio, 0xc8, 4);
+ pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, mr);
+ mr = g_new(MemoryRegion, 1);
+ memory_region_init_alias(mr, OBJECT(d), "sii3112.bar4", &d->mmio, 0, 16);
+ pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, mr);
+
+ irq = qemu_allocate_irqs(sii3112_set_irq, d, 2);
+ for (i = 0; i < 2; i++) {
+ ide_bus_new(&s->bus[i], sizeof(s->bus[i]), DEVICE(dev), i, 1);
+ ide_init2(&s->bus[i], irq[i]);
+
+ bmdma_init(&s->bus[i], &s->bmdma[i], s);
+ s->bmdma[i].bus = &s->bus[i];
+ ide_register_restart_cb(&s->bus[i]);
+ }
+ qemu_register_reset(sii3112_reset, s);
+}
+
+static void sii3112_pci_exitfn(PCIDevice *dev)
+{
+ PCIIDEState *d = PCI_IDE(dev);
+ int i;
+
+ for (i = 0; i < 2; ++i) {
+ memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+ memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+ }
+}
+
+static void sii3112_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pd = PCI_DEVICE_CLASS(klass);
+
+ pd->vendor_id = 0x1095;
+ pd->device_id = 0x3112;
+ pd->class_id = PCI_CLASS_STORAGE_RAID;
+ pd->revision = 1;
+ pd->realize = sii3112_pci_realize;
+ pd->exit = sii3112_pci_exitfn;
+ dc->desc = "SiI3112A SATA controller";
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo sii3112_pci_info = {
+ .name = TYPE_SII3112_PCI,
+ .parent = TYPE_PCI_IDE,
+ .instance_size = sizeof(SiI3112PCIState),
+ .class_init = sii3112_pci_class_init,
+};
+
+static void sii3112_register_types(void)
+{
+ type_register_static(&sii3112_pci_info);
+}
+
+type_init(sii3112_register_types)
diff --git a/hw/ide/trace-events b/hw/ide/trace-events
index 601bd97d81..0c39cabe72 100644
--- a/hw/ide/trace-events
+++ b/hw/ide/trace-events
@@ -37,6 +37,11 @@ bmdma_addr_write(uint64_t data) "data: 0x%016"PRIx64
bmdma_read(uint64_t addr, uint8_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x"
bmdma_write(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64
+# hw/ide/sii3112.c
+sii3112_read(int size, uint64_t addr, uint64_t val) "bmdma: read (size %d) 0x%"PRIx64" : 0x%02"PRIx64
+sii3112_write(int size, uint64_t addr, uint64_t val) "bmdma: write (size %d) 0x%"PRIx64" : 0x%02"PRIx64
+sii3112_set_irq(int channel, int level) "channel %d level %d"
+
# hw/ide/via.c
bmdma_read_via(uint64_t addr, uint32_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x"
bmdma_write_via(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 35c3059325..117ac4d95e 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -25,7 +25,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index 7715d7230d..77e53e6883 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-$(CONFIG_ADB) += adb.o
+common-obj-$(CONFIG_ADB) += adb.o adb-mouse.o adb-kbd.o
common-obj-y += hid.o
common-obj-$(CONFIG_LM832X) += lm832x.o
common-obj-$(CONFIG_PCKBD) += pckbd.o
@@ -6,7 +6,6 @@ common-obj-$(CONFIG_PL050) += pl050.o
common-obj-y += ps2.o
common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
common-obj-$(CONFIG_TSC2005) += tsc2005.o
-common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
common-obj-$(CONFIG_VIRTIO) += virtio-input.o
common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
diff --git a/hw/input/adb-internal.h b/hw/input/adb-internal.h
new file mode 100644
index 0000000000..2a779b8a0a
--- /dev/null
+++ b/hw/input/adb-internal.h
@@ -0,0 +1,49 @@
+/*
+ * QEMU ADB support
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* ADB commands */
+
+#define ADB_BUSRESET 0x00
+#define ADB_FLUSH 0x01
+#define ADB_WRITEREG 0x08
+#define ADB_READREG 0x0c
+
+/* ADB device commands */
+
+#define ADB_CMD_SELF_TEST 0xff
+#define ADB_CMD_CHANGE_ID 0xfe
+#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
+#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
+
+/* ADB default device IDs (upper 4 bits of ADB command byte) */
+
+#define ADB_DEVID_DONGLE 1
+#define ADB_DEVID_KEYBOARD 2
+#define ADB_DEVID_MOUSE 3
+#define ADB_DEVID_TABLET 4
+#define ADB_DEVID_MODEM 5
+#define ADB_DEVID_MISC 7
+
+extern const VMStateDescription vmstate_adb_device;
+
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
new file mode 100644
index 0000000000..354f56e41e
--- /dev/null
+++ b/hw/input/adb-kbd.c
@@ -0,0 +1,400 @@
+/*
+ * QEMU ADB keyboard support
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "hw/input/adb.h"
+#include "ui/input.h"
+#include "hw/input/adb-keys.h"
+#include "sysemu/sysemu.h"
+#include "adb-internal.h"
+#include "trace.h"
+
+#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD)
+
+typedef struct KBDState {
+ /*< private >*/
+ ADBDevice parent_obj;
+ /*< public >*/
+
+ uint8_t data[128];
+ int rptr, wptr, count;
+} KBDState;
+
+#define ADB_KEYBOARD_CLASS(class) \
+ OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD)
+#define ADB_KEYBOARD_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD)
+
+typedef struct ADBKeyboardClass {
+ /*< private >*/
+ ADBDeviceClass parent_class;
+ /*< public >*/
+
+ DeviceRealize parent_realize;
+} ADBKeyboardClass;
+
+/* The adb keyboard doesn't have every key imaginable */
+#define NO_KEY 0xff
+
+int qcode_to_adb_keycode[] = {
+ /* Make sure future additions are automatically set to NO_KEY */
+ [0 ... 0xff] = NO_KEY,
+
+ [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT,
+ [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT,
+ [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION,
+ [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION,
+ [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL,
+ [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL,
+ [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND,
+ [Q_KEY_CODE_META_R] = ADB_KEY_COMMAND,
+ [Q_KEY_CODE_SPC] = ADB_KEY_SPACEBAR,
+
+ [Q_KEY_CODE_ESC] = ADB_KEY_ESC,
+ [Q_KEY_CODE_1] = ADB_KEY_1,
+ [Q_KEY_CODE_2] = ADB_KEY_2,
+ [Q_KEY_CODE_3] = ADB_KEY_3,
+ [Q_KEY_CODE_4] = ADB_KEY_4,
+ [Q_KEY_CODE_5] = ADB_KEY_5,
+ [Q_KEY_CODE_6] = ADB_KEY_6,
+ [Q_KEY_CODE_7] = ADB_KEY_7,
+ [Q_KEY_CODE_8] = ADB_KEY_8,
+ [Q_KEY_CODE_9] = ADB_KEY_9,
+ [Q_KEY_CODE_0] = ADB_KEY_0,
+ [Q_KEY_CODE_MINUS] = ADB_KEY_MINUS,
+ [Q_KEY_CODE_EQUAL] = ADB_KEY_EQUAL,
+ [Q_KEY_CODE_BACKSPACE] = ADB_KEY_DELETE,
+ [Q_KEY_CODE_TAB] = ADB_KEY_TAB,
+ [Q_KEY_CODE_Q] = ADB_KEY_Q,
+ [Q_KEY_CODE_W] = ADB_KEY_W,
+ [Q_KEY_CODE_E] = ADB_KEY_E,
+ [Q_KEY_CODE_R] = ADB_KEY_R,
+ [Q_KEY_CODE_T] = ADB_KEY_T,
+ [Q_KEY_CODE_Y] = ADB_KEY_Y,
+ [Q_KEY_CODE_U] = ADB_KEY_U,
+ [Q_KEY_CODE_I] = ADB_KEY_I,
+ [Q_KEY_CODE_O] = ADB_KEY_O,
+ [Q_KEY_CODE_P] = ADB_KEY_P,
+ [Q_KEY_CODE_BRACKET_LEFT] = ADB_KEY_LEFT_BRACKET,
+ [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET,
+ [Q_KEY_CODE_RET] = ADB_KEY_RETURN,
+ [Q_KEY_CODE_A] = ADB_KEY_A,
+ [Q_KEY_CODE_S] = ADB_KEY_S,
+ [Q_KEY_CODE_D] = ADB_KEY_D,
+ [Q_KEY_CODE_F] = ADB_KEY_F,
+ [Q_KEY_CODE_G] = ADB_KEY_G,
+ [Q_KEY_CODE_H] = ADB_KEY_H,
+ [Q_KEY_CODE_J] = ADB_KEY_J,
+ [Q_KEY_CODE_K] = ADB_KEY_K,
+ [Q_KEY_CODE_L] = ADB_KEY_L,
+ [Q_KEY_CODE_SEMICOLON] = ADB_KEY_SEMICOLON,
+ [Q_KEY_CODE_APOSTROPHE] = ADB_KEY_APOSTROPHE,
+ [Q_KEY_CODE_GRAVE_ACCENT] = ADB_KEY_GRAVE_ACCENT,
+ [Q_KEY_CODE_BACKSLASH] = ADB_KEY_BACKSLASH,
+ [Q_KEY_CODE_Z] = ADB_KEY_Z,
+ [Q_KEY_CODE_X] = ADB_KEY_X,
+ [Q_KEY_CODE_C] = ADB_KEY_C,
+ [Q_KEY_CODE_V] = ADB_KEY_V,
+ [Q_KEY_CODE_B] = ADB_KEY_B,
+ [Q_KEY_CODE_N] = ADB_KEY_N,
+ [Q_KEY_CODE_M] = ADB_KEY_M,
+ [Q_KEY_CODE_COMMA] = ADB_KEY_COMMA,
+ [Q_KEY_CODE_DOT] = ADB_KEY_PERIOD,
+ [Q_KEY_CODE_SLASH] = ADB_KEY_FORWARD_SLASH,
+ [Q_KEY_CODE_ASTERISK] = ADB_KEY_KP_MULTIPLY,
+ [Q_KEY_CODE_CAPS_LOCK] = ADB_KEY_CAPS_LOCK,
+
+ [Q_KEY_CODE_F1] = ADB_KEY_F1,
+ [Q_KEY_CODE_F2] = ADB_KEY_F2,
+ [Q_KEY_CODE_F3] = ADB_KEY_F3,
+ [Q_KEY_CODE_F4] = ADB_KEY_F4,
+ [Q_KEY_CODE_F5] = ADB_KEY_F5,
+ [Q_KEY_CODE_F6] = ADB_KEY_F6,
+ [Q_KEY_CODE_F7] = ADB_KEY_F7,
+ [Q_KEY_CODE_F8] = ADB_KEY_F8,
+ [Q_KEY_CODE_F9] = ADB_KEY_F9,
+ [Q_KEY_CODE_F10] = ADB_KEY_F10,
+ [Q_KEY_CODE_F11] = ADB_KEY_F11,
+ [Q_KEY_CODE_F12] = ADB_KEY_F12,
+ [Q_KEY_CODE_PRINT] = ADB_KEY_F13,
+ [Q_KEY_CODE_SYSRQ] = ADB_KEY_F13,
+ [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14,
+ [Q_KEY_CODE_PAUSE] = ADB_KEY_F15,
+
+ [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR,
+ [Q_KEY_CODE_KP_EQUALS] = ADB_KEY_KP_EQUAL,
+ [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE,
+ [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY,
+ [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT,
+ [Q_KEY_CODE_KP_ADD] = ADB_KEY_KP_PLUS,
+ [Q_KEY_CODE_KP_ENTER] = ADB_KEY_KP_ENTER,
+ [Q_KEY_CODE_KP_DECIMAL] = ADB_KEY_KP_PERIOD,
+ [Q_KEY_CODE_KP_0] = ADB_KEY_KP_0,
+ [Q_KEY_CODE_KP_1] = ADB_KEY_KP_1,
+ [Q_KEY_CODE_KP_2] = ADB_KEY_KP_2,
+ [Q_KEY_CODE_KP_3] = ADB_KEY_KP_3,
+ [Q_KEY_CODE_KP_4] = ADB_KEY_KP_4,
+ [Q_KEY_CODE_KP_5] = ADB_KEY_KP_5,
+ [Q_KEY_CODE_KP_6] = ADB_KEY_KP_6,
+ [Q_KEY_CODE_KP_7] = ADB_KEY_KP_7,
+ [Q_KEY_CODE_KP_8] = ADB_KEY_KP_8,
+ [Q_KEY_CODE_KP_9] = ADB_KEY_KP_9,
+
+ [Q_KEY_CODE_UP] = ADB_KEY_UP,
+ [Q_KEY_CODE_DOWN] = ADB_KEY_DOWN,
+ [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT,
+ [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT,
+
+ [Q_KEY_CODE_HELP] = ADB_KEY_HELP,
+ [Q_KEY_CODE_INSERT] = ADB_KEY_HELP,
+ [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE,
+ [Q_KEY_CODE_HOME] = ADB_KEY_HOME,
+ [Q_KEY_CODE_END] = ADB_KEY_END,
+ [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP,
+ [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN,
+
+ [Q_KEY_CODE_POWER] = ADB_KEY_POWER
+};
+
+static void adb_kbd_put_keycode(void *opaque, int keycode)
+{
+ KBDState *s = opaque;
+
+ if (s->count < sizeof(s->data)) {
+ s->data[s->wptr] = keycode;
+ if (++s->wptr == sizeof(s->data)) {
+ s->wptr = 0;
+ }
+ s->count++;
+ }
+}
+
+static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
+{
+ KBDState *s = ADB_KEYBOARD(d);
+ int keycode;
+ int olen;
+
+ olen = 0;
+ if (s->count == 0) {
+ return 0;
+ }
+ keycode = s->data[s->rptr];
+ s->rptr++;
+ if (s->rptr == sizeof(s->data)) {
+ s->rptr = 0;
+ }
+ s->count--;
+ /*
+ * The power key is the only two byte value key, so it is a special case.
+ * Since 0x7f is not a used keycode for ADB we overload it to indicate the
+ * power button when we're storing keycodes in our internal buffer, and
+ * expand it out to two bytes when we send to the guest.
+ */
+ if (keycode == 0x7f) {
+ obuf[0] = 0x7f;
+ obuf[1] = 0x7f;
+ olen = 2;
+ } else {
+ obuf[0] = keycode;
+ /* NOTE: the power key key-up is the two byte sequence 0xff 0xff;
+ * otherwise we could in theory send a second keycode in the second
+ * byte, but choose not to bother.
+ */
+ obuf[1] = 0xff;
+ olen = 2;
+ }
+
+ return olen;
+}
+
+static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
+ const uint8_t *buf, int len)
+{
+ KBDState *s = ADB_KEYBOARD(d);
+ int cmd, reg, olen;
+
+ if ((buf[0] & 0x0f) == ADB_FLUSH) {
+ /* flush keyboard fifo */
+ s->wptr = s->rptr = s->count = 0;
+ return 0;
+ }
+
+ cmd = buf[0] & 0xc;
+ reg = buf[0] & 0x3;
+ olen = 0;
+ switch (cmd) {
+ case ADB_WRITEREG:
+ trace_adb_kbd_writereg(reg, buf[1]);
+ switch (reg) {
+ case 2:
+ /* LED status */
+ break;
+ case 3:
+ switch (buf[2]) {
+ case ADB_CMD_SELF_TEST:
+ break;
+ case ADB_CMD_CHANGE_ID:
+ case ADB_CMD_CHANGE_ID_AND_ACT:
+ case ADB_CMD_CHANGE_ID_AND_ENABLE:
+ d->devaddr = buf[1] & 0xf;
+ break;
+ default:
+ d->devaddr = buf[1] & 0xf;
+ /* we support handlers:
+ * 1: Apple Standard Keyboard
+ * 2: Apple Extended Keyboard (LShift = RShift)
+ * 3: Apple Extended Keyboard (LShift != RShift)
+ */
+ if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
+ d->handler = buf[2];
+ }
+ break;
+ }
+ }
+ break;
+ case ADB_READREG:
+ switch (reg) {
+ case 0:
+ olen = adb_kbd_poll(d, obuf);
+ break;
+ case 1:
+ break;
+ case 2:
+ obuf[0] = 0x00; /* XXX: check this */
+ obuf[1] = 0x07; /* led status */
+ olen = 2;
+ break;
+ case 3:
+ obuf[0] = d->handler;
+ obuf[1] = d->devaddr;
+ olen = 2;
+ break;
+ }
+ trace_adb_kbd_readreg(reg, obuf[0], obuf[1]);
+ break;
+ }
+ return olen;
+}
+
+/* This is where keyboard events enter this file */
+static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
+{
+ KBDState *s = (KBDState *)dev;
+ int qcode, keycode;
+
+ qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key);
+ if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) {
+ return;
+ }
+ /* FIXME: take handler into account when translating qcode */
+ keycode = qcode_to_adb_keycode[qcode];
+ if (keycode == NO_KEY) { /* We don't want to send this to the guest */
+ trace_adb_kbd_no_key();
+ return;
+ }
+ if (evt->u.key.data->down == false) { /* if key release event */
+ keycode = keycode | 0x80; /* create keyboard break code */
+ }
+
+ adb_kbd_put_keycode(s, keycode);
+}
+
+static const VMStateDescription vmstate_adb_kbd = {
+ .name = "adb_kbd",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice),
+ VMSTATE_BUFFER(data, KBDState),
+ VMSTATE_INT32(rptr, KBDState),
+ VMSTATE_INT32(wptr, KBDState),
+ VMSTATE_INT32(count, KBDState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void adb_kbd_reset(DeviceState *dev)
+{
+ ADBDevice *d = ADB_DEVICE(dev);
+ KBDState *s = ADB_KEYBOARD(dev);
+
+ d->handler = 1;
+ d->devaddr = ADB_DEVID_KEYBOARD;
+ memset(s->data, 0, sizeof(s->data));
+ s->rptr = 0;
+ s->wptr = 0;
+ s->count = 0;
+}
+
+static QemuInputHandler adb_keyboard_handler = {
+ .name = "QEMU ADB Keyboard",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = adb_keyboard_event,
+};
+
+static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
+{
+ ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev);
+ akc->parent_realize(dev, errp);
+ qemu_input_handler_register(dev, &adb_keyboard_handler);
+}
+
+static void adb_kbd_initfn(Object *obj)
+{
+ ADBDevice *d = ADB_DEVICE(obj);
+
+ d->devaddr = ADB_DEVID_KEYBOARD;
+}
+
+static void adb_kbd_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
+ ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc);
+
+ akc->parent_realize = dc->realize;
+ dc->realize = adb_kbd_realizefn;
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+
+ adc->devreq = adb_kbd_request;
+ dc->reset = adb_kbd_reset;
+ dc->vmsd = &vmstate_adb_kbd;
+}
+
+static const TypeInfo adb_kbd_type_info = {
+ .name = TYPE_ADB_KEYBOARD,
+ .parent = TYPE_ADB_DEVICE,
+ .instance_size = sizeof(KBDState),
+ .instance_init = adb_kbd_initfn,
+ .class_init = adb_kbd_class_init,
+ .class_size = sizeof(ADBKeyboardClass),
+};
+
+static void adb_kbd_register_types(void)
+{
+ type_register_static(&adb_kbd_type_info);
+}
+
+type_init(adb_kbd_register_types)
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
new file mode 100644
index 0000000000..c9004233b8
--- /dev/null
+++ b/hw/input/adb-mouse.c
@@ -0,0 +1,254 @@
+/*
+ * QEMU ADB mouse support
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "ui/console.h"
+#include "hw/input/adb.h"
+#include "adb-internal.h"
+#include "trace.h"
+
+#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
+
+typedef struct MouseState {
+ /*< public >*/
+ ADBDevice parent_obj;
+ /*< private >*/
+
+ int buttons_state, last_buttons_state;
+ int dx, dy, dz;
+} MouseState;
+
+#define ADB_MOUSE_CLASS(class) \
+ OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
+#define ADB_MOUSE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
+
+typedef struct ADBMouseClass {
+ /*< public >*/
+ ADBDeviceClass parent_class;
+ /*< private >*/
+
+ DeviceRealize parent_realize;
+} ADBMouseClass;
+
+static void adb_mouse_event(void *opaque,
+ int dx1, int dy1, int dz1, int buttons_state)
+{
+ MouseState *s = opaque;
+
+ s->dx += dx1;
+ s->dy += dy1;
+ s->dz += dz1;
+ s->buttons_state = buttons_state;
+}
+
+
+static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
+{
+ MouseState *s = ADB_MOUSE(d);
+ int dx, dy;
+
+ if (s->last_buttons_state == s->buttons_state &&
+ s->dx == 0 && s->dy == 0) {
+ return 0;
+ }
+
+ dx = s->dx;
+ if (dx < -63) {
+ dx = -63;
+ } else if (dx > 63) {
+ dx = 63;
+ }
+
+ dy = s->dy;
+ if (dy < -63) {
+ dy = -63;
+ } else if (dy > 63) {
+ dy = 63;
+ }
+
+ s->dx -= dx;
+ s->dy -= dy;
+ s->last_buttons_state = s->buttons_state;
+
+ dx &= 0x7f;
+ dy &= 0x7f;
+
+ if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) {
+ dy |= 0x80;
+ }
+ if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) {
+ dx |= 0x80;
+ }
+
+ obuf[0] = dy;
+ obuf[1] = dx;
+ return 2;
+}
+
+static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
+ const uint8_t *buf, int len)
+{
+ MouseState *s = ADB_MOUSE(d);
+ int cmd, reg, olen;
+
+ if ((buf[0] & 0x0f) == ADB_FLUSH) {
+ /* flush mouse fifo */
+ s->buttons_state = s->last_buttons_state;
+ s->dx = 0;
+ s->dy = 0;
+ s->dz = 0;
+ return 0;
+ }
+
+ cmd = buf[0] & 0xc;
+ reg = buf[0] & 0x3;
+ olen = 0;
+ switch (cmd) {
+ case ADB_WRITEREG:
+ trace_adb_mouse_writereg(reg, buf[1]);
+ switch (reg) {
+ case 2:
+ break;
+ case 3:
+ switch (buf[2]) {
+ case ADB_CMD_SELF_TEST:
+ break;
+ case ADB_CMD_CHANGE_ID:
+ case ADB_CMD_CHANGE_ID_AND_ACT:
+ case ADB_CMD_CHANGE_ID_AND_ENABLE:
+ d->devaddr = buf[1] & 0xf;
+ break;
+ default:
+ d->devaddr = buf[1] & 0xf;
+ /* we support handlers:
+ * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
+ * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
+ * we don't support handlers (at least):
+ * 0x03: Mouse systems A3 trackball
+ * 0x04: Extended Apple Mouse Protocol
+ * 0x2f: Microspeed mouse
+ * 0x42: Macally
+ * 0x5f: Microspeed mouse
+ * 0x66: Microspeed mouse
+ */
+ if (buf[2] == 1 || buf[2] == 2) {
+ d->handler = buf[2];
+ }
+ break;
+ }
+ }
+ break;
+ case ADB_READREG:
+ switch (reg) {
+ case 0:
+ olen = adb_mouse_poll(d, obuf);
+ break;
+ case 1:
+ break;
+ case 3:
+ obuf[0] = d->handler;
+ obuf[1] = d->devaddr;
+ olen = 2;
+ break;
+ }
+ trace_adb_mouse_readreg(reg, obuf[0], obuf[1]);
+ break;
+ }
+ return olen;
+}
+
+static void adb_mouse_reset(DeviceState *dev)
+{
+ ADBDevice *d = ADB_DEVICE(dev);
+ MouseState *s = ADB_MOUSE(dev);
+
+ d->handler = 2;
+ d->devaddr = ADB_DEVID_MOUSE;
+ s->last_buttons_state = s->buttons_state = 0;
+ s->dx = s->dy = s->dz = 0;
+}
+
+static const VMStateDescription vmstate_adb_mouse = {
+ .name = "adb_mouse",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
+ ADBDevice),
+ VMSTATE_INT32(buttons_state, MouseState),
+ VMSTATE_INT32(last_buttons_state, MouseState),
+ VMSTATE_INT32(dx, MouseState),
+ VMSTATE_INT32(dy, MouseState),
+ VMSTATE_INT32(dz, MouseState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
+{
+ MouseState *s = ADB_MOUSE(dev);
+ ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
+
+ amc->parent_realize(dev, errp);
+
+ qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
+}
+
+static void adb_mouse_initfn(Object *obj)
+{
+ ADBDevice *d = ADB_DEVICE(obj);
+
+ d->devaddr = ADB_DEVID_MOUSE;
+}
+
+static void adb_mouse_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
+ ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
+
+ amc->parent_realize = dc->realize;
+ dc->realize = adb_mouse_realizefn;
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+
+ adc->devreq = adb_mouse_request;
+ dc->reset = adb_mouse_reset;
+ dc->vmsd = &vmstate_adb_mouse;
+}
+
+static const TypeInfo adb_mouse_type_info = {
+ .name = TYPE_ADB_MOUSE,
+ .parent = TYPE_ADB_DEVICE,
+ .instance_size = sizeof(MouseState),
+ .instance_init = adb_mouse_initfn,
+ .class_init = adb_mouse_class_init,
+ .class_size = sizeof(ADBMouseClass),
+};
+
+static void adb_mouse_register_types(void)
+{
+ type_register_static(&adb_mouse_type_info);
+}
+
+type_init(adb_mouse_register_types)
diff --git a/hw/input/adb.c b/hw/input/adb.c
index fcca3a8eb9..23ae6f0d75 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -22,49 +22,12 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
#include "hw/input/adb.h"
-#include "ui/console.h"
-#include "include/hw/input/adb-keys.h"
-#include "ui/input.h"
-#include "sysemu/sysemu.h"
-
-/* debug ADB */
-//#define DEBUG_ADB
-
-#ifdef DEBUG_ADB
-#define ADB_DPRINTF(fmt, ...) \
-do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define ADB_DPRINTF(fmt, ...)
-#endif
-
-/* ADB commands */
-#define ADB_BUSRESET 0x00
-#define ADB_FLUSH 0x01
-#define ADB_WRITEREG 0x08
-#define ADB_READREG 0x0c
-
-/* ADB device commands */
-#define ADB_CMD_SELF_TEST 0xff
-#define ADB_CMD_CHANGE_ID 0xfe
-#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
-#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
-
-/* ADB default device IDs (upper 4 bits of ADB command byte) */
-#define ADB_DEVID_DONGLE 1
-#define ADB_DEVID_KEYBOARD 2
-#define ADB_DEVID_MOUSE 3
-#define ADB_DEVID_TABLET 4
-#define ADB_DEVID_MODEM 5
-#define ADB_DEVID_MISC 7
+#include "adb-internal.h"
/* error codes */
#define ADB_RET_NOTPRESENT (-2)
-/* The adb keyboard doesn't have every key imaginable */
-#define NO_KEY 0xff
-
static void adb_device_reset(ADBDevice *d)
{
qdev_reset_all(DEVICE(d));
@@ -127,7 +90,7 @@ static const TypeInfo adb_bus_type_info = {
.instance_size = sizeof(ADBBusState),
};
-static const VMStateDescription vmstate_adb_device = {
+const VMStateDescription vmstate_adb_device = {
.name = "adb_device",
.version_id = 0,
.minimum_version_id = 0,
@@ -166,591 +129,10 @@ static const TypeInfo adb_device_type_info = {
.class_init = adb_device_class_init,
};
-/***************************************************************/
-/* Keyboard ADB device */
-
-#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD)
-
-typedef struct KBDState {
- /*< private >*/
- ADBDevice parent_obj;
- /*< public >*/
-
- uint8_t data[128];
- int rptr, wptr, count;
-} KBDState;
-
-#define ADB_KEYBOARD_CLASS(class) \
- OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD)
-#define ADB_KEYBOARD_GET_CLASS(obj) \
- OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD)
-
-typedef struct ADBKeyboardClass {
- /*< private >*/
- ADBDeviceClass parent_class;
- /*< public >*/
-
- DeviceRealize parent_realize;
-} ADBKeyboardClass;
-
-int qcode_to_adb_keycode[] = {
- /* Make sure future additions are automatically set to NO_KEY */
- [0 ... 0xff] = NO_KEY,
-
- [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT,
- [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT,
- [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION,
- [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION,
- [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL,
- [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL,
- [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND,
- [Q_KEY_CODE_META_R] = ADB_KEY_COMMAND,
- [Q_KEY_CODE_SPC] = ADB_KEY_SPACEBAR,
-
- [Q_KEY_CODE_ESC] = ADB_KEY_ESC,
- [Q_KEY_CODE_1] = ADB_KEY_1,
- [Q_KEY_CODE_2] = ADB_KEY_2,
- [Q_KEY_CODE_3] = ADB_KEY_3,
- [Q_KEY_CODE_4] = ADB_KEY_4,
- [Q_KEY_CODE_5] = ADB_KEY_5,
- [Q_KEY_CODE_6] = ADB_KEY_6,
- [Q_KEY_CODE_7] = ADB_KEY_7,
- [Q_KEY_CODE_8] = ADB_KEY_8,
- [Q_KEY_CODE_9] = ADB_KEY_9,
- [Q_KEY_CODE_0] = ADB_KEY_0,
- [Q_KEY_CODE_MINUS] = ADB_KEY_MINUS,
- [Q_KEY_CODE_EQUAL] = ADB_KEY_EQUAL,
- [Q_KEY_CODE_BACKSPACE] = ADB_KEY_DELETE,
- [Q_KEY_CODE_TAB] = ADB_KEY_TAB,
- [Q_KEY_CODE_Q] = ADB_KEY_Q,
- [Q_KEY_CODE_W] = ADB_KEY_W,
- [Q_KEY_CODE_E] = ADB_KEY_E,
- [Q_KEY_CODE_R] = ADB_KEY_R,
- [Q_KEY_CODE_T] = ADB_KEY_T,
- [Q_KEY_CODE_Y] = ADB_KEY_Y,
- [Q_KEY_CODE_U] = ADB_KEY_U,
- [Q_KEY_CODE_I] = ADB_KEY_I,
- [Q_KEY_CODE_O] = ADB_KEY_O,
- [Q_KEY_CODE_P] = ADB_KEY_P,
- [Q_KEY_CODE_BRACKET_LEFT] = ADB_KEY_LEFT_BRACKET,
- [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET,
- [Q_KEY_CODE_RET] = ADB_KEY_RETURN,
- [Q_KEY_CODE_A] = ADB_KEY_A,
- [Q_KEY_CODE_S] = ADB_KEY_S,
- [Q_KEY_CODE_D] = ADB_KEY_D,
- [Q_KEY_CODE_F] = ADB_KEY_F,
- [Q_KEY_CODE_G] = ADB_KEY_G,
- [Q_KEY_CODE_H] = ADB_KEY_H,
- [Q_KEY_CODE_J] = ADB_KEY_J,
- [Q_KEY_CODE_K] = ADB_KEY_K,
- [Q_KEY_CODE_L] = ADB_KEY_L,
- [Q_KEY_CODE_SEMICOLON] = ADB_KEY_SEMICOLON,
- [Q_KEY_CODE_APOSTROPHE] = ADB_KEY_APOSTROPHE,
- [Q_KEY_CODE_GRAVE_ACCENT] = ADB_KEY_GRAVE_ACCENT,
- [Q_KEY_CODE_BACKSLASH] = ADB_KEY_BACKSLASH,
- [Q_KEY_CODE_Z] = ADB_KEY_Z,
- [Q_KEY_CODE_X] = ADB_KEY_X,
- [Q_KEY_CODE_C] = ADB_KEY_C,
- [Q_KEY_CODE_V] = ADB_KEY_V,
- [Q_KEY_CODE_B] = ADB_KEY_B,
- [Q_KEY_CODE_N] = ADB_KEY_N,
- [Q_KEY_CODE_M] = ADB_KEY_M,
- [Q_KEY_CODE_COMMA] = ADB_KEY_COMMA,
- [Q_KEY_CODE_DOT] = ADB_KEY_PERIOD,
- [Q_KEY_CODE_SLASH] = ADB_KEY_FORWARD_SLASH,
- [Q_KEY_CODE_ASTERISK] = ADB_KEY_KP_MULTIPLY,
- [Q_KEY_CODE_CAPS_LOCK] = ADB_KEY_CAPS_LOCK,
-
- [Q_KEY_CODE_F1] = ADB_KEY_F1,
- [Q_KEY_CODE_F2] = ADB_KEY_F2,
- [Q_KEY_CODE_F3] = ADB_KEY_F3,
- [Q_KEY_CODE_F4] = ADB_KEY_F4,
- [Q_KEY_CODE_F5] = ADB_KEY_F5,
- [Q_KEY_CODE_F6] = ADB_KEY_F6,
- [Q_KEY_CODE_F7] = ADB_KEY_F7,
- [Q_KEY_CODE_F8] = ADB_KEY_F8,
- [Q_KEY_CODE_F9] = ADB_KEY_F9,
- [Q_KEY_CODE_F10] = ADB_KEY_F10,
- [Q_KEY_CODE_F11] = ADB_KEY_F11,
- [Q_KEY_CODE_F12] = ADB_KEY_F12,
- [Q_KEY_CODE_PRINT] = ADB_KEY_F13,
- [Q_KEY_CODE_SYSRQ] = ADB_KEY_F13,
- [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14,
- [Q_KEY_CODE_PAUSE] = ADB_KEY_F15,
-
- [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR,
- [Q_KEY_CODE_KP_EQUALS] = ADB_KEY_KP_EQUAL,
- [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE,
- [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY,
- [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT,
- [Q_KEY_CODE_KP_ADD] = ADB_KEY_KP_PLUS,
- [Q_KEY_CODE_KP_ENTER] = ADB_KEY_KP_ENTER,
- [Q_KEY_CODE_KP_DECIMAL] = ADB_KEY_KP_PERIOD,
- [Q_KEY_CODE_KP_0] = ADB_KEY_KP_0,
- [Q_KEY_CODE_KP_1] = ADB_KEY_KP_1,
- [Q_KEY_CODE_KP_2] = ADB_KEY_KP_2,
- [Q_KEY_CODE_KP_3] = ADB_KEY_KP_3,
- [Q_KEY_CODE_KP_4] = ADB_KEY_KP_4,
- [Q_KEY_CODE_KP_5] = ADB_KEY_KP_5,
- [Q_KEY_CODE_KP_6] = ADB_KEY_KP_6,
- [Q_KEY_CODE_KP_7] = ADB_KEY_KP_7,
- [Q_KEY_CODE_KP_8] = ADB_KEY_KP_8,
- [Q_KEY_CODE_KP_9] = ADB_KEY_KP_9,
-
- [Q_KEY_CODE_UP] = ADB_KEY_UP,
- [Q_KEY_CODE_DOWN] = ADB_KEY_DOWN,
- [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT,
- [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT,
-
- [Q_KEY_CODE_HELP] = ADB_KEY_HELP,
- [Q_KEY_CODE_INSERT] = ADB_KEY_HELP,
- [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE,
- [Q_KEY_CODE_HOME] = ADB_KEY_HOME,
- [Q_KEY_CODE_END] = ADB_KEY_END,
- [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP,
- [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN,
-
- [Q_KEY_CODE_POWER] = ADB_KEY_POWER
-};
-
-static void adb_kbd_put_keycode(void *opaque, int keycode)
-{
- KBDState *s = opaque;
-
- if (s->count < sizeof(s->data)) {
- s->data[s->wptr] = keycode;
- if (++s->wptr == sizeof(s->data))
- s->wptr = 0;
- s->count++;
- }
-}
-
-static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
-{
- KBDState *s = ADB_KEYBOARD(d);
- int keycode;
- int olen;
-
- olen = 0;
- if (s->count == 0) {
- return 0;
- }
- keycode = s->data[s->rptr];
- s->rptr++;
- if (s->rptr == sizeof(s->data)) {
- s->rptr = 0;
- }
- s->count--;
- /*
- * The power key is the only two byte value key, so it is a special case.
- * Since 0x7f is not a used keycode for ADB we overload it to indicate the
- * power button when we're storing keycodes in our internal buffer, and
- * expand it out to two bytes when we send to the guest.
- */
- if (keycode == 0x7f) {
- obuf[0] = 0x7f;
- obuf[1] = 0x7f;
- olen = 2;
- } else {
- obuf[0] = keycode;
- /* NOTE: the power key key-up is the two byte sequence 0xff 0xff;
- * otherwise we could in theory send a second keycode in the second
- * byte, but choose not to bother.
- */
- obuf[1] = 0xff;
- olen = 2;
- }
-
- return olen;
-}
-
-static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
- const uint8_t *buf, int len)
-{
- KBDState *s = ADB_KEYBOARD(d);
- int cmd, reg, olen;
-
- if ((buf[0] & 0x0f) == ADB_FLUSH) {
- /* flush keyboard fifo */
- s->wptr = s->rptr = s->count = 0;
- return 0;
- }
-
- cmd = buf[0] & 0xc;
- reg = buf[0] & 0x3;
- olen = 0;
- switch(cmd) {
- case ADB_WRITEREG:
- switch(reg) {
- case 2:
- /* LED status */
- break;
- case 3:
- switch(buf[2]) {
- case ADB_CMD_SELF_TEST:
- break;
- case ADB_CMD_CHANGE_ID:
- case ADB_CMD_CHANGE_ID_AND_ACT:
- case ADB_CMD_CHANGE_ID_AND_ENABLE:
- d->devaddr = buf[1] & 0xf;
- break;
- default:
- d->devaddr = buf[1] & 0xf;
- /* we support handlers:
- * 1: Apple Standard Keyboard
- * 2: Apple Extended Keyboard (LShift = RShift)
- * 3: Apple Extended Keyboard (LShift != RShift)
- */
- if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
- d->handler = buf[2];
- }
- break;
- }
- }
- break;
- case ADB_READREG:
- switch(reg) {
- case 0:
- olen = adb_kbd_poll(d, obuf);
- break;
- case 1:
- break;
- case 2:
- obuf[0] = 0x00; /* XXX: check this */
- obuf[1] = 0x07; /* led status */
- olen = 2;
- break;
- case 3:
- obuf[0] = d->handler;
- obuf[1] = d->devaddr;
- olen = 2;
- break;
- }
- break;
- }
- return olen;
-}
-
-/* This is where keyboard events enter this file */
-static void adb_keyboard_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- KBDState *s = (KBDState *)dev;
- int qcode, keycode;
-
- qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key);
- if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) {
- return;
- }
- /* FIXME: take handler into account when translating qcode */
- keycode = qcode_to_adb_keycode[qcode];
- if (keycode == NO_KEY) { /* We don't want to send this to the guest */
- ADB_DPRINTF("Ignoring NO_KEY\n");
- return;
- }
- if (evt->u.key.data->down == false) { /* if key release event */
- keycode = keycode | 0x80; /* create keyboard break code */
- }
-
- adb_kbd_put_keycode(s, keycode);
-}
-
-static const VMStateDescription vmstate_adb_kbd = {
- .name = "adb_kbd",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice),
- VMSTATE_BUFFER(data, KBDState),
- VMSTATE_INT32(rptr, KBDState),
- VMSTATE_INT32(wptr, KBDState),
- VMSTATE_INT32(count, KBDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void adb_kbd_reset(DeviceState *dev)
-{
- ADBDevice *d = ADB_DEVICE(dev);
- KBDState *s = ADB_KEYBOARD(dev);
-
- d->handler = 1;
- d->devaddr = ADB_DEVID_KEYBOARD;
- memset(s->data, 0, sizeof(s->data));
- s->rptr = 0;
- s->wptr = 0;
- s->count = 0;
-}
-
-static QemuInputHandler adb_keyboard_handler = {
- .name = "QEMU ADB Keyboard",
- .mask = INPUT_EVENT_MASK_KEY,
- .event = adb_keyboard_event,
-};
-
-static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
-{
- ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev);
- akc->parent_realize(dev, errp);
- qemu_input_handler_register(dev, &adb_keyboard_handler);
-}
-
-static void adb_kbd_initfn(Object *obj)
-{
- ADBDevice *d = ADB_DEVICE(obj);
-
- d->devaddr = ADB_DEVID_KEYBOARD;
-}
-
-static void adb_kbd_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
- ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc);
-
- akc->parent_realize = dc->realize;
- dc->realize = adb_kbd_realizefn;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-
- adc->devreq = adb_kbd_request;
- dc->reset = adb_kbd_reset;
- dc->vmsd = &vmstate_adb_kbd;
-}
-
-static const TypeInfo adb_kbd_type_info = {
- .name = TYPE_ADB_KEYBOARD,
- .parent = TYPE_ADB_DEVICE,
- .instance_size = sizeof(KBDState),
- .instance_init = adb_kbd_initfn,
- .class_init = adb_kbd_class_init,
- .class_size = sizeof(ADBKeyboardClass),
-};
-
-/***************************************************************/
-/* Mouse ADB device */
-
-#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
-
-typedef struct MouseState {
- /*< public >*/
- ADBDevice parent_obj;
- /*< private >*/
-
- int buttons_state, last_buttons_state;
- int dx, dy, dz;
-} MouseState;
-
-#define ADB_MOUSE_CLASS(class) \
- OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
-#define ADB_MOUSE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
-
-typedef struct ADBMouseClass {
- /*< public >*/
- ADBDeviceClass parent_class;
- /*< private >*/
-
- DeviceRealize parent_realize;
-} ADBMouseClass;
-
-static void adb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
-{
- MouseState *s = opaque;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
-}
-
-
-static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
-{
- MouseState *s = ADB_MOUSE(d);
- int dx, dy;
-
- if (s->last_buttons_state == s->buttons_state &&
- s->dx == 0 && s->dy == 0)
- return 0;
-
- dx = s->dx;
- if (dx < -63)
- dx = -63;
- else if (dx > 63)
- dx = 63;
-
- dy = s->dy;
- if (dy < -63)
- dy = -63;
- else if (dy > 63)
- dy = 63;
-
- s->dx -= dx;
- s->dy -= dy;
- s->last_buttons_state = s->buttons_state;
-
- dx &= 0x7f;
- dy &= 0x7f;
-
- if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
- dy |= 0x80;
- if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
- dx |= 0x80;
-
- obuf[0] = dy;
- obuf[1] = dx;
- return 2;
-}
-
-static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
- const uint8_t *buf, int len)
-{
- MouseState *s = ADB_MOUSE(d);
- int cmd, reg, olen;
-
- if ((buf[0] & 0x0f) == ADB_FLUSH) {
- /* flush mouse fifo */
- s->buttons_state = s->last_buttons_state;
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- return 0;
- }
-
- cmd = buf[0] & 0xc;
- reg = buf[0] & 0x3;
- olen = 0;
- switch(cmd) {
- case ADB_WRITEREG:
- ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
- switch(reg) {
- case 2:
- break;
- case 3:
- switch(buf[2]) {
- case ADB_CMD_SELF_TEST:
- break;
- case ADB_CMD_CHANGE_ID:
- case ADB_CMD_CHANGE_ID_AND_ACT:
- case ADB_CMD_CHANGE_ID_AND_ENABLE:
- d->devaddr = buf[1] & 0xf;
- break;
- default:
- d->devaddr = buf[1] & 0xf;
- /* we support handlers:
- * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
- * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
- * we don't support handlers (at least):
- * 0x03: Mouse systems A3 trackball
- * 0x04: Extended Apple Mouse Protocol
- * 0x2f: Microspeed mouse
- * 0x42: Macally
- * 0x5f: Microspeed mouse
- * 0x66: Microspeed mouse
- */
- if (buf[2] == 1 || buf[2] == 2) {
- d->handler = buf[2];
- }
- break;
- }
- }
- break;
- case ADB_READREG:
- switch(reg) {
- case 0:
- olen = adb_mouse_poll(d, obuf);
- break;
- case 1:
- break;
- case 3:
- obuf[0] = d->handler;
- obuf[1] = d->devaddr;
- olen = 2;
- break;
- }
- ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
- obuf[0], obuf[1]);
- break;
- }
- return olen;
-}
-
-static void adb_mouse_reset(DeviceState *dev)
-{
- ADBDevice *d = ADB_DEVICE(dev);
- MouseState *s = ADB_MOUSE(dev);
-
- d->handler = 2;
- d->devaddr = ADB_DEVID_MOUSE;
- s->last_buttons_state = s->buttons_state = 0;
- s->dx = s->dy = s->dz = 0;
-}
-
-static const VMStateDescription vmstate_adb_mouse = {
- .name = "adb_mouse",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
- ADBDevice),
- VMSTATE_INT32(buttons_state, MouseState),
- VMSTATE_INT32(last_buttons_state, MouseState),
- VMSTATE_INT32(dx, MouseState),
- VMSTATE_INT32(dy, MouseState),
- VMSTATE_INT32(dz, MouseState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
-{
- MouseState *s = ADB_MOUSE(dev);
- ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
-
- amc->parent_realize(dev, errp);
-
- qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
-}
-
-static void adb_mouse_initfn(Object *obj)
-{
- ADBDevice *d = ADB_DEVICE(obj);
-
- d->devaddr = ADB_DEVID_MOUSE;
-}
-
-static void adb_mouse_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
- ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
-
- amc->parent_realize = dc->realize;
- dc->realize = adb_mouse_realizefn;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-
- adc->devreq = adb_mouse_request;
- dc->reset = adb_mouse_reset;
- dc->vmsd = &vmstate_adb_mouse;
-}
-
-static const TypeInfo adb_mouse_type_info = {
- .name = TYPE_ADB_MOUSE,
- .parent = TYPE_ADB_DEVICE,
- .instance_size = sizeof(MouseState),
- .instance_init = adb_mouse_initfn,
- .class_init = adb_mouse_class_init,
- .class_size = sizeof(ADBMouseClass),
-};
-
-
static void adb_register_types(void)
{
type_register_static(&adb_bus_type_info);
type_register_static(&adb_device_type_info);
- type_register_static(&adb_kbd_type_info);
- type_register_static(&adb_mouse_type_info);
}
type_init(adb_register_types)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 0d049ff61c..aa4fb826fd 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -57,14 +57,14 @@ static const uint8_t hid_usage_keys[0x100] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a,
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 88150ef7a6..a8d46cb766 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -1,5 +1,13 @@
# See docs/devel/tracing.txt for syntax documentation.
+# hw/input/adb-kbd.c
+adb_kbd_no_key(void) "Ignoring NO_KEY"
+adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
+adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+# hw/input/adb-mouse.c
+adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
+adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+
# hw/input/ps2.c
ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x"
ps2_keyboard_event(void *opaque, int qcode, int down, unsigned int modifier, unsigned int modifiers) "%p qcode %d down %d modifier 0x%x modifiers 0x%x"
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index fe15fb6024..6fda52b86c 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -305,6 +305,18 @@ static void apic_set_tpr(APICCommonState *s, uint8_t val)
}
}
+int apic_get_highest_priority_irr(DeviceState *dev)
+{
+ APICCommonState *s;
+
+ if (!dev) {
+ /* no interrupts */
+ return -1;
+ }
+ s = APIC_COMMON(dev);
+ return get_highest_priority_int(s->irr);
+}
+
static uint8_t apic_get_tpr(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_FROM_VAPIC);
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 5a0e2a3c1a..d701e49ff9 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -1261,7 +1261,8 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_read: Bad offset %x\n", (int)offset);
- return MEMTX_ERROR;
+ *data = 0;
+ break;
}
return MEMTX_OK;
}
@@ -1329,7 +1330,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_write: Bad offset %x\n", (int)offset);
- return MEMTX_ERROR;
+ return MEMTX_OK;
}
gic_update(s);
return MEMTX_OK;
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 3ea3dd0d40..93fe936862 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -817,6 +817,13 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data,
"%s: invalid guest read at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
trace_gicv3_dist_badread(offset, size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
+ *data = 0;
} else {
trace_gicv3_dist_read(offset, *data, size, attrs.secure);
}
@@ -852,6 +859,12 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data,
"%s: invalid guest write at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
trace_gicv3_dist_badwrite(offset, data, size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
} else {
trace_gicv3_dist_write(offset, data, size, attrs.secure);
}
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
index f2cce597a9..284c0a7584 100644
--- a/hw/intc/arm_gicv3_its_common.c
+++ b/hw/intc/arm_gicv3_its_common.c
@@ -67,7 +67,8 @@ static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
MemTxAttrs attrs)
{
qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset);
- return MEMTX_ERROR;
+ *data = 0;
+ return MEMTX_OK;
}
static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
@@ -82,15 +83,12 @@ static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
if (ret <= 0) {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS: Error sending MSI: %s\n", strerror(-ret));
- return MEMTX_DECODE_ERROR;
}
-
- return MEMTX_OK;
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS write at bad offset 0x%"PRIx64"\n", offset);
- return MEMTX_DECODE_ERROR;
}
+ return MEMTX_OK;
}
static const MemoryRegionOps gicv3_its_trans_ops = {
@@ -131,8 +129,6 @@ static void gicv3_its_common_reset(DeviceState *dev)
s->creadr = 0;
s->iidr = 0;
memset(&s->baser, 0, sizeof(s->baser));
-
- gicv3_its_post_load(s, 0);
}
static void gicv3_its_common_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
index 6fb45dffd7..bf290b8bff 100644
--- a/hw/intc/arm_gicv3_its_kvm.c
+++ b/hw/intc/arm_gicv3_its_kvm.c
@@ -28,6 +28,16 @@
#define TYPE_KVM_ARM_ITS "arm-its-kvm"
#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
+#define KVM_ARM_ITS_CLASS(klass) \
+ OBJECT_CLASS_CHECK(KVMARMITSClass, (klass), TYPE_KVM_ARM_ITS)
+#define KVM_ARM_ITS_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(KVMARMITSClass, (obj), TYPE_KVM_ARM_ITS)
+
+typedef struct KVMARMITSClass {
+ GICv3ITSCommonClass parent_class;
+ void (*parent_reset)(DeviceState *dev);
+} KVMARMITSClass;
+
static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
{
@@ -155,10 +165,6 @@ static void kvm_arm_its_post_load(GICv3ITSState *s)
{
int i;
- if (!s->iidr) {
- return;
- }
-
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_IIDR, &s->iidr, true, &error_abort);
@@ -190,6 +196,41 @@ static void kvm_arm_its_post_load(GICv3ITSState *s)
GITS_CTLR, &s->ctlr, true, &error_abort);
}
+static void kvm_arm_its_reset(DeviceState *dev)
+{
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
+ KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s);
+ int i;
+
+ c->parent_reset(dev);
+
+ if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+ KVM_DEV_ARM_ITS_CTRL_RESET)) {
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+ KVM_DEV_ARM_ITS_CTRL_RESET, NULL, true, &error_abort);
+ return;
+ }
+
+ error_report("ITS KVM: full reset is not supported by the host kernel");
+
+ if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
+ GITS_CTLR)) {
+ return;
+ }
+
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
+ GITS_CTLR, &s->ctlr, true, &error_abort);
+
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
+ GITS_CBASER, &s->cbaser, true, &error_abort);
+
+ for (i = 0; i < 8; i++) {
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
+ GITS_BASER + i * 8, &s->baser[i], true,
+ &error_abort);
+ }
+}
+
static Property kvm_arm_its_props[] = {
DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3",
GICv3State *),
@@ -200,12 +241,15 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
+ KVMARMITSClass *ic = KVM_ARM_ITS_CLASS(klass);
dc->realize = kvm_arm_its_realize;
dc->props = kvm_arm_its_props;
+ ic->parent_reset = dc->reset;
icc->send_msi = kvm_its_send_msi;
icc->pre_save = kvm_arm_its_pre_save;
icc->post_load = kvm_arm_its_post_load;
+ dc->reset = kvm_arm_its_reset;
}
static const TypeInfo kvm_arm_its_info = {
@@ -213,6 +257,7 @@ static const TypeInfo kvm_arm_its_info = {
.parent = TYPE_ARM_GICV3_ITS_COMMON,
.instance_size = sizeof(GICv3ITSState),
.class_init = kvm_arm_its_class_init,
+ .class_size = sizeof(KVMARMITSClass),
};
static void kvm_arm_its_register_types(void)
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 77e5cfa327..8a8684d76e 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -455,6 +455,13 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
"size %u\n", __func__, offset, size);
trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset,
size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
+ *data = 0;
} else {
trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data,
size, attrs.secure);
@@ -505,6 +512,12 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
"size %u\n", __func__, offset, size);
trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data,
size, attrs.secure);
+ /* The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+ r = MEMTX_OK;
} else {
trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data,
size, attrs.secure);
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 5d9c8834ad..dd49b6c335 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -1786,10 +1786,12 @@ static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size,
MemTxAttrs attrs)
{
+ MemoryRegion *mr = opaque;
+
if (attrs.secure) {
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
- return nvic_sysreg_write(opaque, addr, value, size, attrs);
+ return memory_region_dispatch_write(mr, addr, value, size, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
@@ -1803,10 +1805,12 @@ static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr,
uint64_t *data, unsigned size,
MemTxAttrs attrs)
{
+ MemoryRegion *mr = opaque;
+
if (attrs.secure) {
/* S accesses to the alias act like NS accesses to the real region */
attrs.secure = 0;
- return nvic_sysreg_read(opaque, addr, data, size, attrs);
+ return memory_region_dispatch_read(mr, addr, data, size, attrs);
} else {
/* NS attrs are RAZ/WI for privileged, and BusFault for user */
if (attrs.user) {
@@ -1823,6 +1827,36 @@ static const MemoryRegionOps nvic_sysreg_ns_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
+static MemTxResult nvic_systick_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ NVICState *s = opaque;
+ MemoryRegion *mr;
+
+ /* Direct the access to the correct systick */
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
+ return memory_region_dispatch_write(mr, addr, value, size, attrs);
+}
+
+static MemTxResult nvic_systick_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ NVICState *s = opaque;
+ MemoryRegion *mr;
+
+ /* Direct the access to the correct systick */
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
+ return memory_region_dispatch_read(mr, addr, data, size, attrs);
+}
+
+static const MemoryRegionOps nvic_systick_ops = {
+ .read_with_attrs = nvic_systick_read,
+ .write_with_attrs = nvic_systick_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
static int nvic_post_load(void *opaque, int version_id)
{
NVICState *s = opaque;
@@ -2001,17 +2035,16 @@ static void nvic_systick_trigger(void *opaque, int n, int level)
/* SysTick just asked us to pend its exception.
* (This is different from an external interrupt line's
* behaviour.)
- * TODO: when we implement the banked systicks we must make
- * this pend the correct banked exception.
+ * n == 0 : NonSecure systick
+ * n == 1 : Secure systick
*/
- armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK, false);
+ armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK, n);
}
}
static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
{
NVICState *s = NVIC(dev);
- SysBusDevice *systick_sbd;
Error *err = NULL;
int regionlen;
@@ -2028,14 +2061,35 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
/* include space for internal exception vectors */
s->num_irq += NVIC_FIRST_IRQ;
- object_property_set_bool(OBJECT(&s->systick), true, "realized", &err);
+ object_property_set_bool(OBJECT(&s->systick[M_REG_NS]), true,
+ "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
- systick_sbd = SYS_BUS_DEVICE(&s->systick);
- sysbus_connect_irq(systick_sbd, 0,
- qdev_get_gpio_in_named(dev, "systick-trigger", 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), 0,
+ qdev_get_gpio_in_named(dev, "systick-trigger",
+ M_REG_NS));
+
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
+ /* We couldn't init the secure systick device in instance_init
+ * as we didn't know then if the CPU had the security extensions;
+ * so we have to do it here.
+ */
+ object_initialize(&s->systick[M_REG_S], sizeof(s->systick[M_REG_S]),
+ TYPE_SYSTICK);
+ qdev_set_parent_bus(DEVICE(&s->systick[M_REG_S]), sysbus_get_default());
+
+ object_property_set_bool(OBJECT(&s->systick[M_REG_S]), true,
+ "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_S]), 0,
+ qdev_get_gpio_in_named(dev, "systick-trigger",
+ M_REG_S));
+ }
/* The NVIC and System Control Space (SCS) starts at 0xe000e000
* and looks like this:
@@ -2069,15 +2123,24 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s,
"nvic_sysregs", 0x1000);
memory_region_add_subregion(&s->container, 0, &s->sysregmem);
+
+ memory_region_init_io(&s->systickmem, OBJECT(s),
+ &nvic_systick_ops, s,
+ "nvic_systick", 0xe0);
+
memory_region_add_subregion_overlap(&s->container, 0x10,
- sysbus_mmio_get_region(systick_sbd, 0),
- 1);
+ &s->systickmem, 1);
if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s),
- &nvic_sysreg_ns_ops, s,
+ &nvic_sysreg_ns_ops, &s->sysregmem,
"nvic_sysregs_ns", 0x1000);
memory_region_add_subregion(&s->container, 0x20000, &s->sysreg_ns_mem);
+ memory_region_init_io(&s->systick_ns_mem, OBJECT(s),
+ &nvic_sysreg_ns_ops, &s->systickmem,
+ "nvic_systick_ns", 0xe0);
+ memory_region_add_subregion_overlap(&s->container, 0x20010,
+ &s->systick_ns_mem, 1);
}
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container);
@@ -2095,12 +2158,17 @@ static void armv7m_nvic_instance_init(Object *obj)
NVICState *nvic = NVIC(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- object_initialize(&nvic->systick, sizeof(nvic->systick), TYPE_SYSTICK);
- qdev_set_parent_bus(DEVICE(&nvic->systick), sysbus_get_default());
+ object_initialize(&nvic->systick[M_REG_NS],
+ sizeof(nvic->systick[M_REG_NS]), TYPE_SYSTICK);
+ qdev_set_parent_bus(DEVICE(&nvic->systick[M_REG_NS]), sysbus_get_default());
+ /* We can't initialize the secure systick here, as we don't know
+ * yet if we need it.
+ */
sysbus_init_irq(sbd, &nvic->excpout);
qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
- qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger", 1);
+ qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger",
+ M_REG_NUM_BANKS);
}
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index fe9ecd6bd4..1602255a87 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -25,24 +25,15 @@
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
-#include "monitor/monitor.h"
#include "qemu/timer.h"
#include "qemu/log.h"
#include "hw/isa/i8259_internal.h"
-#include "hw/intc/intc.h"
+#include "trace.h"
/* debug PIC */
//#define DEBUG_PIC
-#ifdef DEBUG_PIC
-#define DPRINTF(fmt, ...) \
- do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
//#define DEBUG_IRQ_LATENCY
-//#define DEBUG_IRQ_COUNT
#define TYPE_I8259 "isa-i8259"
#define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259)
@@ -58,12 +49,6 @@ typedef struct PICClass {
DeviceRealize parent_realize;
} PICClass;
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
-static int irq_level[16];
-#endif
-#ifdef DEBUG_IRQ_COUNT
-static uint64_t irq_count[16];
-#endif
#ifdef DEBUG_IRQ_LATENCY
static int64_t irq_time[16];
#endif
@@ -122,8 +107,7 @@ static void pic_update_irq(PICCommonState *s)
irq = pic_get_irq(s);
if (irq >= 0) {
- DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
- s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
+ trace_pic_update_irq(s->master, s->imr, s->irr, s->priority_add);
qemu_irq_raise(s->int_out[0]);
} else {
qemu_irq_lower(s->int_out[0]);
@@ -135,22 +119,11 @@ static void pic_set_irq(void *opaque, int irq, int level)
{
PICCommonState *s = opaque;
int mask = 1 << irq;
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
- defined(DEBUG_IRQ_LATENCY)
int irq_index = s->master ? irq : irq + 8;
-#endif
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
- if (level != irq_level[irq_index]) {
- DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
- irq_level[irq_index] = level;
-#ifdef DEBUG_IRQ_COUNT
- if (level == 1) {
- irq_count[irq_index]++;
- }
-#endif
- }
-#endif
+
+ trace_pic_set_irq(s->master, irq, level);
+ pic_stat_update_irq(irq_index, level);
+
#ifdef DEBUG_IRQ_LATENCY
if (level) {
irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -223,18 +196,18 @@ int pic_read_irq(DeviceState *d)
intno = s->irq_base + irq;
}
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
if (irq == 2) {
irq = irq2 + 8;
}
-#endif
+
#ifdef DEBUG_IRQ_LATENCY
printf("IRQ%d latency=%0.3fus\n",
irq,
(double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND);
#endif
- DPRINTF("pic_interrupt: irq=%d\n", irq);
+
+ trace_pic_interrupt(irq, intno);
return intno;
}
@@ -252,35 +225,6 @@ static void pic_reset(DeviceState *dev)
pic_init_reset(s);
}
-static bool pic_get_statistics(InterruptStatsProvider *obj,
- uint64_t **irq_counts, unsigned int *nb_irqs)
-{
- PICCommonState *s = PIC_COMMON(obj);
-
- if (s->master) {
-#ifdef DEBUG_IRQ_COUNT
- *irq_counts = irq_count;
- *nb_irqs = ARRAY_SIZE(irq_count);
-#else
- return false;
-#endif
- } else {
- *irq_counts = NULL;
- *nb_irqs = 0;
- }
- return true;
-}
-
-static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
-{
- PICCommonState *s = PIC_COMMON(obj);
- monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
- "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
- s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
- s->irq_base, s->read_reg_select, s->elcr,
- s->special_fully_nested_mode);
-}
-
static void pic_ioport_write(void *opaque, hwaddr addr64,
uint64_t val64, unsigned size)
{
@@ -289,7 +233,8 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
uint32_t val = val64;
int priority, cmd, irq;
- DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
+ trace_pic_ioport_write(s->master, addr, val);
+
if (addr == 0) {
if (val & 0x10) {
pic_init_reset(s);
@@ -402,7 +347,7 @@ static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
ret = s->imr;
}
}
- DPRINTF("read: addr=0x%02" HWADDR_PRIx " val=0x%02x\n", addr, ret);
+ trace_pic_ioport_read(s->master, addr, ret);
return ret;
}
@@ -497,13 +442,10 @@ static void i8259_class_init(ObjectClass *klass, void *data)
{
PICClass *k = PIC_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
k->parent_realize = dc->realize;
dc->realize = pic_realize;
dc->reset = pic_reset;
- ic->get_statistics = pic_get_statistics;
- ic->print_info = pic_print_info;
}
static const TypeInfo i8259_info = {
@@ -512,10 +454,6 @@ static const TypeInfo i8259_info = {
.parent = TYPE_PIC_COMMON,
.class_init = i8259_class_init,
.class_size = sizeof(PICClass),
- .interfaces = (InterfaceInfo[]) {
- { TYPE_INTERRUPT_STATS_PROVIDER },
- { }
- },
};
static void pic_register_types(void)
diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
index 18427b459a..c75c880157 100644
--- a/hw/intc/i8259_common.c
+++ b/hw/intc/i8259_common.c
@@ -25,6 +25,10 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "hw/isa/i8259_internal.h"
+#include "monitor/monitor.h"
+
+static int irq_level[16];
+static uint64_t irq_count[16];
void pic_reset_common(PICCommonState *s)
{
@@ -98,6 +102,44 @@ ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
return isadev;
}
+void pic_stat_update_irq(int irq, int level)
+{
+ if (level != irq_level[irq]) {
+ irq_level[irq] = level;
+ if (level == 1) {
+ irq_count[irq]++;
+ }
+ }
+}
+
+bool pic_get_statistics(InterruptStatsProvider *obj,
+ uint64_t **irq_counts, unsigned int *nb_irqs)
+{
+ PICCommonState *s = PIC_COMMON(obj);
+
+ if (s->master) {
+ *irq_counts = irq_count;
+ *nb_irqs = ARRAY_SIZE(irq_count);
+ } else {
+ *irq_counts = NULL;
+ *nb_irqs = 0;
+ }
+
+ return true;
+}
+
+void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
+{
+ PICCommonState *s = PIC_COMMON(obj);
+
+ pic_dispatch_pre_save(s);
+ monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
+ "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
+ s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
+ s->irq_base, s->read_reg_select, s->elcr,
+ s->special_fully_nested_mode);
+}
+
static const VMStateDescription vmstate_pic_common = {
.name = "i8259",
.version_id = 1,
@@ -136,6 +178,7 @@ static Property pic_properties_common[] = {
static void pic_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
dc->vmsd = &vmstate_pic_common;
dc->props = pic_properties_common;
@@ -147,6 +190,8 @@ static void pic_common_class_init(ObjectClass *klass, void *data)
* code.
*/
dc->user_creatable = false;
+ ic->get_statistics = pic_get_statistics;
+ ic->print_info = pic_print_info;
}
static const TypeInfo pic_common_type = {
@@ -156,6 +201,10 @@ static const TypeInfo pic_common_type = {
.class_size = sizeof(PICCommonClass),
.class_init = pic_common_class_init,
.abstract = true,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_INTERRUPT_STATS_PROVIDER },
+ { }
+ },
};
static void pic_common_register_types(void)
diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c
index 09e15115fb..db6c7afc2f 100644
--- a/hw/intc/lm32_pic.c
+++ b/hw/intc/lm32_pic.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "monitor/monitor.h"
#include "hw/sysbus.h"
#include "trace.h"
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 10d6e871fb..9159a06f07 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -46,6 +46,7 @@
#include "qapi/qmp/qerror.h"
#include "qemu/log.h"
#include "qemu/timer.h"
+#include "qemu/error-report.h"
//#define DEBUG_OPENPIC
@@ -58,8 +59,7 @@ static const int debug_openpic = 0;
static int get_current_cpu(void);
#define DPRINTF(fmt, ...) do { \
if (debug_openpic) { \
- printf("Core%d: ", get_current_cpu()); \
- printf(fmt , ## __VA_ARGS__); \
+ info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \
} \
} while (0)
@@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt)
}
}
- fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
+ error_report("%s: unsupported inttgt %d", __func__, inttgt);
return OPENPIC_OUTPUT_INT;
}
@@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q)
break;
}
- DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
+ DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d",
irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
@@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
dst = &opp->dst[n_CPU];
src = &opp->src[n_IRQ];
- DPRINTF("%s: IRQ %d active %d was %d\n",
+ DPRINTF("%s: IRQ %d active %d was %d",
__func__, n_IRQ, active, was_active);
if (src->output != OPENPIC_OUTPUT_INT) {
- DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
+ DPRINTF("%s: output %d irq %d active %d was %d count %d",
__func__, src->output, n_IRQ, active, was_active,
dst->outputs_active[src->output]);
@@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
*/
if (active) {
if (!was_active && dst->outputs_active[src->output]++ == 0) {
- DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
+ DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d",
__func__, src->output, n_CPU, n_IRQ);
qemu_irq_raise(dst->irqs[src->output]);
}
} else {
if (was_active && --dst->outputs_active[src->output] == 0) {
- DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
+ DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d",
__func__, src->output, n_CPU, n_IRQ);
qemu_irq_lower(dst->irqs[src->output]);
}
@@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
IRQ_check(opp, &dst->raised);
if (active && priority <= dst->ctpr) {
- DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
+ DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d",
__func__, n_IRQ, priority, dst->ctpr, n_CPU);
active = 0;
}
@@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
if (active) {
if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
priority <= dst->servicing.priority) {
- DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+ DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d",
__func__, n_IRQ, dst->servicing.next, n_CPU);
} else {
- DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
+ DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d",
__func__, n_CPU, n_IRQ, dst->raised.next);
qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
}
@@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
IRQ_get_next(opp, &dst->servicing);
if (dst->raised.priority > dst->ctpr &&
dst->raised.priority > dst->servicing.priority) {
- DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
+ DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d",
__func__, n_IRQ, dst->raised.next, dst->raised.priority,
dst->ctpr, dst->servicing.priority, n_CPU);
/* IRQ line stays asserted */
} else {
- DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
+ DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d",
__func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
}
@@ -489,7 +489,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
/* Interrupt source is disabled */
- DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
+ DPRINTF("%s: IRQ %d is disabled", __func__, n_IRQ);
active = false;
}
@@ -500,7 +500,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
* ctpr may have changed and we need to withdraw the interrupt.
*/
if (!active && !was_active) {
- DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
+ DPRINTF("%s: IRQ %d is already inactive", __func__, n_IRQ);
return;
}
@@ -512,7 +512,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
if (src->destmask == 0) {
/* No target */
- DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
+ DPRINTF("%s: IRQ %d has no target", __func__, n_IRQ);
return;
}
@@ -547,12 +547,12 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)
IRQSource *src;
if (n_IRQ >= OPENPIC_MAX_IRQ) {
- fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
+ error_report("%s: IRQ %d out of range", __func__, n_IRQ);
abort();
}
src = &opp->src[n_IRQ];
- DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
+ DPRINTF("openpic: set irq %d = %d ivpr=0x%08x",
n_IRQ, level, src->ivpr);
if (src->level) {
/* level-sensitive irq */
@@ -612,13 +612,13 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
}
src->idr = val & mask;
- DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
+ DPRINTF("Set IDR %d to 0x%08x", n_IRQ, src->idr);
if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
if (src->idr & crit_mask) {
if (src->idr & normal_mask) {
DPRINTF("%s: IRQ configured for multiple output types, using "
- "critical\n", __func__);
+ "critical", __func__);
}
src->output = OPENPIC_OUTPUT_CINT;
@@ -648,7 +648,7 @@ static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
IRQSource *src = &opp->src[n_IRQ];
src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
- DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
+ DPRINTF("Set ILR %d to 0x%08x, output %d", n_IRQ, src->idr,
src->output);
/* TODO: on MPIC v4.0 only, set nomask for non-INT */
@@ -688,7 +688,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
}
openpic_update_irq(opp, n_IRQ);
- DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
+ DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x", n_IRQ, val,
opp->src[n_IRQ].ivpr);
}
@@ -719,7 +719,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
IRQDest *dst;
int idx;
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+ DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
__func__, addr, val);
if (addr & 0xF) {
return;
@@ -747,11 +747,11 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
case 0x1090: /* PIR */
for (idx = 0; idx < opp->nb_cpus; idx++) {
if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
- DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+ DPRINTF("Raise OpenPIC RESET output for CPU %d", idx);
dst = &opp->dst[idx];
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
} else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
- DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+ DPRINTF("Lower OpenPIC RESET output for CPU %d", idx);
dst = &opp->dst[idx];
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
}
@@ -781,7 +781,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
OpenPICState *opp = opaque;
uint32_t retval;
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+ DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
retval = 0xFFFFFFFF;
if (addr & 0xF) {
return retval;
@@ -828,7 +828,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
default:
break;
}
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
+ DPRINTF("%s: => 0x%08x", __func__, retval);
return retval;
}
@@ -843,7 +843,7 @@ static void qemu_timer_cb(void *opaque)
uint32_t val = tmr->tbcr & ~TBCR_CI;
uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG); /* invert toggle. */
- DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ);
+ DPRINTF("%s n_IRQ=%d", __func__, n_IRQ);
/* Reload current count from base count and setup timer. */
tmr->tccr = val | tog;
openpic_tmr_set_tmr(tmr, val, /*enabled=*/true);
@@ -898,7 +898,7 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
OpenPICState *opp = opaque;
int idx;
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+ DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
__func__, (addr + 0x10f0), val);
if (addr & 0xF) {
return;
@@ -943,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
uint32_t retval = -1;
int idx;
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0);
+ DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr + 0x10f0);
if (addr & 0xF) {
goto out;
}
@@ -970,7 +970,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
}
out:
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
+ DPRINTF("%s: => 0x%08x", __func__, retval);
return retval;
}
@@ -981,7 +981,7 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
OpenPICState *opp = opaque;
int idx;
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+ DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
__func__, addr, val);
addr = addr & 0xffff;
@@ -1006,7 +1006,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
uint32_t retval;
int idx;
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+ DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
retval = 0xFFFFFFFF;
addr = addr & 0xffff;
@@ -1024,7 +1024,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
break;
}
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
+ DPRINTF("%s: => 0x%08x", __func__, retval);
return retval;
}
@@ -1035,7 +1035,7 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
int idx = opp->irq_msi;
int srs, ibs;
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+ DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
__func__, addr, val);
if (addr & 0xF) {
return;
@@ -1061,7 +1061,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
uint64_t r = 0;
int i, srs;
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+ DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
if (addr & 0xF) {
return -1;
}
@@ -1096,7 +1096,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
{
uint64_t r = 0;
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+ DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
/* TODO: EISR/EIMR */
@@ -1106,7 +1106,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
- DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+ DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
__func__, addr, val);
/* TODO: EISR/EIMR */
@@ -1120,7 +1120,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
IRQDest *dst;
int s_IRQ, n_IRQ;
- DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
+ DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x", __func__, idx,
addr, val);
if (idx < 0 || idx >= opp->nb_cpus) {
@@ -1146,16 +1146,16 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
case 0x80: /* CTPR */
dst->ctpr = val & 0x0000000F;
- DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
+ DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d",
__func__, idx, dst->ctpr, dst->raised.priority,
dst->servicing.priority);
if (dst->raised.priority <= dst->ctpr) {
- DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
+ DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr",
__func__, idx);
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
} else if (dst->raised.priority > dst->servicing.priority) {
- DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
+ DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d",
__func__, idx, dst->raised.next);
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
}
@@ -1168,11 +1168,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
/* Read-only register */
break;
case 0xB0: /* EOI */
- DPRINTF("EOI\n");
+ DPRINTF("EOI");
s_IRQ = IRQ_get_next(opp, &dst->servicing);
if (s_IRQ < 0) {
- DPRINTF("%s: EOI with no interrupt in service\n", __func__);
+ DPRINTF("%s: EOI with no interrupt in service", __func__);
break;
}
@@ -1185,7 +1185,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
if (n_IRQ != -1 &&
(s_IRQ == -1 ||
IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
- DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+ DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
idx, n_IRQ);
qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
}
@@ -1207,11 +1207,11 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
IRQSource *src;
int retval, irq;
- DPRINTF("Lower OpenPIC INT output\n");
+ DPRINTF("Lower OpenPIC INT output");
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
irq = IRQ_get_next(opp, &dst->raised);
- DPRINTF("IACK: irq=%d\n", irq);
+ DPRINTF("IACK: irq=%d", irq);
if (irq == -1) {
/* No more interrupt pending */
@@ -1221,7 +1221,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
src = &opp->src[irq];
if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
!(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
- fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
+ error_report("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x",
__func__, irq, dst->ctpr, src->ivpr);
openpic_update_irq(opp, irq);
retval = opp->spve;
@@ -1241,7 +1241,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
/* Timers and IPIs support multicast. */
if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) ||
((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) {
- DPRINTF("irq is IPI or TMR\n");
+ DPRINTF("irq is IPI or TMR");
src->destmask &= ~(1 << cpu);
if (src->destmask && !src->level) {
/* trigger on CPUs that didn't know about it yet */
@@ -1262,7 +1262,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
IRQDest *dst;
uint32_t retval;
- DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
+ DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr);
retval = 0xFFFFFFFF;
if (idx < 0 || idx >= opp->nb_cpus) {
@@ -1290,7 +1290,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
default:
break;
}
- DPRINTF("%s: => 0x%08x\n", __func__, retval);
+ DPRINTF("%s: => 0x%08x", __func__, retval);
return retval;
}
diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c
index 84e0bee4a9..817e02617e 100644
--- a/hw/intc/slavio_intctl.c
+++ b/hw/intc/slavio_intctl.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
-#include "hw/sparc/sun4m.h"
#include "monitor/monitor.h"
#include "hw/sysbus.h"
#include "hw/intc/intc.h"
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index b298fac7c6..be769186fc 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -1,5 +1,12 @@
# See docs/devel/tracing.txt for syntax documentation.
+# hw/intc/i8259.c
+pic_update_irq(bool master, uint8_t imr, uint8_t irr, uint8_t padd) "master %d imr %"PRIu8" irr %"PRIu8" padd %"PRIu8
+pic_set_irq(bool master, int irq, int level) "master %d irq %d level %d"
+pic_interrupt(int irq, int intno) "irq %d intno %d"
+pic_ioport_write(bool master, uint64_t addr, uint64_t val) "master %d addr 0x%"PRIx64" val 0x%"PRIx64
+pic_ioport_read(bool master, uint64_t addr, int val) "master %d addr 0x%"PRIx64" val 0x%x"
+
# hw/intc/apic_common.c
cpu_set_apic_base(uint64_t val) "0x%016"PRIx64
cpu_get_apic_base(uint64_t val) "0x%016"PRIx64
@@ -64,10 +71,6 @@ xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]
xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x"
xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]"
xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x"
-xics_alloc(int irq) "irq %d"
-xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
-xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
-xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free"
# hw/intc/s390_flic_kvm.c
flic_create_device(int err) "flic: create device failed %d"
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index a1cc0e420c..e73e623e3b 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -334,7 +334,6 @@ static void icp_realize(DeviceState *dev, Error **errp)
}
cpu = POWERPC_CPU(obj);
- cpu->intc = OBJECT(icp);
icp->cs = CPU(obj);
env = &cpu->env;
@@ -384,6 +383,27 @@ static const TypeInfo icp_info = {
.class_size = sizeof(ICPStateClass),
};
+Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp)
+{
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = object_new(type);
+ object_property_add_child(cpu, type, obj, &error_abort);
+ object_unref(obj);
+ object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(xi),
+ &error_abort);
+ object_property_add_const_link(obj, ICP_PROP_CPU, cpu, &error_abort);
+ object_property_set_bool(obj, true, "realized", &local_err);
+ if (local_err) {
+ object_unparent(obj);
+ error_propagate(errp, local_err);
+ obj = NULL;
+ }
+
+ return obj;
+}
+
/*
* ICS: Source layer
*/
@@ -693,18 +713,6 @@ static const TypeInfo xics_fabric_info = {
/*
* Exported functions
*/
-qemu_irq xics_get_qirq(XICSFabric *xi, int irq)
-{
- XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
- ICSState *ics = xic->ics_get(xi, irq);
-
- if (ics) {
- return ics->qirqs[irq - ics->offset];
- }
-
- return NULL;
-}
-
ICPState *xics_icp_get(XICSFabric *xi, int server)
{
XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index d98ea8b130..5a0967caf4 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -245,122 +245,6 @@ void xics_spapr_init(sPAPRMachineState *spapr)
spapr_register_hypercall(H_IPOLL, h_ipoll);
}
-#define ICS_IRQ_FREE(ics, srcno) \
- (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
-
-static int ics_find_free_block(ICSState *ics, int num, int alignnum)
-{
- int first, i;
-
- for (first = 0; first < ics->nr_irqs; first += alignnum) {
- if (num > (ics->nr_irqs - first)) {
- return -1;
- }
- for (i = first; i < first + num; ++i) {
- if (!ICS_IRQ_FREE(ics, i)) {
- break;
- }
- }
- if (i == (first + num)) {
- return first;
- }
- }
-
- return -1;
-}
-
-int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp)
-{
- int irq;
-
- if (!ics) {
- return -1;
- }
- if (irq_hint) {
- if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
- error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
- return -1;
- }
- irq = irq_hint;
- } else {
- irq = ics_find_free_block(ics, 1, 1);
- if (irq < 0) {
- error_setg(errp, "can't allocate IRQ: no IRQ left");
- return -1;
- }
- irq += ics->offset;
- }
-
- ics_set_irq_type(ics, irq - ics->offset, lsi);
- trace_xics_alloc(irq);
-
- return irq;
-}
-
-/*
- * Allocate block of consecutive IRQs, and return the number of the first IRQ in
- * the block. If align==true, aligns the first IRQ number to num.
- */
-int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi,
- bool align, Error **errp)
-{
- int i, first = -1;
-
- if (!ics) {
- return -1;
- }
-
- /*
- * MSIMesage::data is used for storing VIRQ so
- * it has to be aligned to num to support multiple
- * MSI vectors. MSI-X is not affected by this.
- * The hint is used for the first IRQ, the rest should
- * be allocated continuously.
- */
- if (align) {
- assert((num == 1) || (num == 2) || (num == 4) ||
- (num == 8) || (num == 16) || (num == 32));
- first = ics_find_free_block(ics, num, num);
- } else {
- first = ics_find_free_block(ics, num, 1);
- }
- if (first < 0) {
- error_setg(errp, "can't find a free %d-IRQ block", num);
- return -1;
- }
-
- if (first >= 0) {
- for (i = first; i < first + num; ++i) {
- ics_set_irq_type(ics, i, lsi);
- }
- }
- first += ics->offset;
-
- trace_xics_alloc_block(first, num, lsi, align);
-
- return first;
-}
-
-static void ics_free(ICSState *ics, int srcno, int num)
-{
- int i;
-
- for (i = srcno; i < srcno + num; ++i) {
- if (ICS_IRQ_FREE(ics, i)) {
- trace_xics_ics_free_warn(0, i + ics->offset);
- }
- memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
- }
-}
-
-void spapr_ics_free(ICSState *ics, int irq, int num)
-{
- if (ics_valid_irq(ics, irq)) {
- trace_xics_ics_free(0, irq, num);
- ics_free(ics, irq - ics->offset, num);
- }
-}
-
void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle)
{
uint32_t interrupt_server_ranges_prop[] = {
diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
index 2fcc3d2e7c..e098fd5206 100644
--- a/hw/ipmi/isa_ipmi_bt.c
+++ b/hw/ipmi/isa_ipmi_bt.c
@@ -26,7 +26,6 @@
#include "hw/hw.h"
#include "hw/ipmi/ipmi.h"
#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
/* Control register */
#define IPMI_BT_CLR_WR_BIT 0
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
index 80444977a0..689587b65d 100644
--- a/hw/ipmi/isa_ipmi_kcs.c
+++ b/hw/ipmi/isa_ipmi_kcs.c
@@ -26,7 +26,6 @@
#include "hw/hw.h"
#include "hw/ipmi/ipmi.h"
#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
#define IPMI_KCS_OBF_BIT 0
#define IPMI_KCS_IBF_BIT 1
diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c
index d20ea4c2ee..a5d67bc6d7 100644
--- a/hw/isa/i82378.c
+++ b/hw/isa/i82378.c
@@ -21,6 +21,7 @@
#include "hw/pci/pci.h"
#include "hw/i386/pc.h"
#include "hw/timer/i8254.h"
+#include "hw/timer/mc146818rtc.h"
#include "hw/audio/pcspk.h"
#define TYPE_I82378 "i82378"
@@ -97,7 +98,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp)
isa_bus_irqs(isabus, s->i8259);
/* 1 82C54 (pit) */
- isa = pit_init(isabus, 0x40, 0, NULL);
+ isa = i8254_pit_init(isabus, 0x40, 0, NULL);
/* speaker */
pcspk_init(isabus, isa);
@@ -106,7 +107,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp)
isa = isa_create_simple(isabus, "i82374");
/* timer */
- isa_create_simple(isabus, "mc146818rtc");
+ isa_create_simple(isabus, TYPE_MC146818_RTC);
}
static void i82378_init(Object *obj)
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index c129985e2a..4084b32be9 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/vt82c686.h"
#include "hw/i2c/i2c.h"
#include "hw/i2c/smbus.h"
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 66eace5a5c..6e74b61cb6 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -109,7 +109,6 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr);
vmstate_register_ram(vmstate_mr, dev);
- numa_set_mem_node_id(addr, memory_region_size(mr), dimm->node);
out:
error_propagate(errp, local_err);
@@ -122,7 +121,6 @@ void pc_dimm_memory_unplug(DeviceState *dev, MemoryHotplugState *hpms,
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm);
- numa_unset_mem_node_id(dimm->addr, memory_region_size(mr), dimm->node);
memory_region_del_subregion(&hpms->mr, mr);
vmstate_unregister_ram(vmstate_mr, dev);
}
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 1cb4b6aca2..fb23161b33 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -248,16 +248,6 @@ static const MemoryRegionOps boston_platreg_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void boston_flash_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static const MemoryRegionOps boston_flash_ops = {
- .write = boston_flash_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
static const TypeInfo boston_device = {
.name = TYPE_MIPS_BOSTON,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -481,8 +471,8 @@ static void boston_mach_init(MachineState *machine)
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1);
flash = g_new(MemoryRegion, 1);
- memory_region_init_rom_device_nomigrate(flash, NULL, &boston_flash_ops, s,
- "boston.flash", 128 * M_BYTE, &err);
+ memory_region_init_rom_nomigrate(flash, NULL,
+ "boston.flash", 128 * M_BYTE, &err);
memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0);
ddr = g_new(MemoryRegion, 1);
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 146cf0fccd..725e25a134 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -359,13 +359,13 @@ static void mips_fulong2e_init(MachineState *machine)
smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
/* init other devices */
- pit = pit_init(isa_bus, 0x40, 0, NULL);
+ pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
DMA_init(isa_bus, 0);
/* Super I/O */
isa_create_simple(isa_bus, "i8042");
- rtc_init(isa_bus, 2000, NULL);
+ mc146818_rtc_init(isa_bus, 2000, NULL);
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, 1);
diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c
index fe4f17389f..0d2c0683ba 100644
--- a/hw/mips/mips_jazz.c
+++ b/hw/mips/mips_jazz.c
@@ -39,6 +39,7 @@
#include "hw/loader.h"
#include "hw/timer/mc146818rtc.h"
#include "hw/timer/i8254.h"
+#include "hw/display/vga.h"
#include "hw/audio/pcspk.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
@@ -218,7 +219,7 @@ static void mips_jazz_init(MachineState *machine,
i8259 = i8259_init(isa_bus, env->irq[4]);
isa_bus_irqs(isa_bus, i8259);
DMA_init(isa_bus, 0);
- pit = pit_init(isa_bus, 0x40, 0, NULL);
+ pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
pcspk_init(isa_bus, pit);
/* Video card */
@@ -288,7 +289,7 @@ static void mips_jazz_init(MachineState *machine,
fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), -1, 0x80003000, fds);
/* Real time clock */
- rtc_init(isa_bus, 1980, NULL);
+ mc146818_rtc_init(isa_bus, 1980, NULL);
memory_region_init_io(rtc, NULL, &rtc_ops, NULL, "rtc", 0x1000);
memory_region_add_subregion(address_space, 0x80004000, rtc);
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index ec6af4a277..37f19428d6 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -1208,13 +1208,13 @@ void mips_malta_init(MachineState *machine)
isa_get_irq(NULL, 9), NULL, 0, NULL);
smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
g_free(smbus_eeprom_buf);
- pit = pit_init(isa_bus, 0x40, 0, NULL);
+ pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
DMA_init(isa_bus, 0);
/* Super I/O */
isa_create_simple(isa_bus, "i8042");
- rtc_init(isa_bus, 2000, NULL);
+ mc146818_rtc_init(isa_bus, 2000, NULL);
serial_hds_isa_init(isa_bus, 0, 2);
parallel_hds_isa_init(isa_bus, 1);
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index 3bbb1827e1..244bd41813 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -18,6 +18,7 @@
#include "hw/char/serial.h"
#include "hw/isa/isa.h"
#include "net/net.h"
+#include "hw/net/ne2000-isa.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
@@ -270,9 +271,9 @@ void mips_r4k_init(MachineState *machine)
i8259 = i8259_init(isa_bus, env->irq[2]);
isa_bus_irqs(isa_bus, i8259);
- rtc_init(isa_bus, 2000, NULL);
+ mc146818_rtc_init(isa_bus, 2000, NULL);
- pit = pit_init(isa_bus, 0x40, 0, NULL);
+ pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 10c88a84b4..d517f83e81 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -11,8 +11,6 @@ common-obj-$(CONFIG_EDU) += edu.o
common-obj-y += unimp.o
common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o
-obj-$(CONFIG_VMPORT) += vmport.o
-
# ARM devices
common-obj-$(CONFIG_PL310) += arm_l2x0.o
common-obj-$(CONFIG_INTEGRATOR_DEBUG) += arm_integrator_debug.o
diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c
index 1b421013a3..4fa94835fe 100644
--- a/hw/misc/imx6_ccm.c
+++ b/hw/misc/imx6_ccm.c
@@ -335,7 +335,7 @@ static uint64_t imx6_ccm_get_ipg_clk(IMX6CCMState *dev)
uint64_t freq = 0;
freq = imx6_ccm_get_ahb_clk(dev)
- / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));;
+ / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));
DPRINTF("freq = %d\n", (uint32_t)freq);
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index a5a46827fe..4919011f38 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -20,7 +20,6 @@
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c
index 2b1e9a6450..b26250dec9 100644
--- a/hw/misc/pvpanic.c
+++ b/hw/misc/pvpanic.c
@@ -13,14 +13,11 @@
*/
#include "qemu/osdep.h"
-#include "qapi/qmp/qobject.h"
-#include "qapi/qmp/qjson.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
#include "hw/nvram/fw_cfg.h"
-#include "hw/i386/pc.h"
-#include "qapi-event.h"
+#include "hw/misc/pvpanic.h"
/* The bit of supported pv event */
#define PVPANIC_F_PANICKED 0
@@ -28,9 +25,8 @@
/* The pv event value */
#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED)
-#define TYPE_ISA_PVPANIC_DEVICE "pvpanic"
#define ISA_PVPANIC_DEVICE(obj) \
- OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE)
+ OBJECT_CHECK(PVPanicState, (obj), TYPE_PVPANIC)
static void handle_event(int event)
{
@@ -107,7 +103,7 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
uint16_t pvpanic_port(void)
{
- Object *o = object_resolve_path_type("", TYPE_ISA_PVPANIC_DEVICE, NULL);
+ Object *o = object_resolve_path_type("", TYPE_PVPANIC, NULL);
if (!o) {
return 0;
}
@@ -129,7 +125,7 @@ static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
}
static TypeInfo pvpanic_isa_info = {
- .name = TYPE_ISA_PVPANIC_DEVICE,
+ .name = TYPE_PVPANIC,
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(PVPanicState),
.instance_init = pvpanic_isa_initfn,
diff --git a/hw/misc/sga.c b/hw/misc/sga.c
index 03b006d6f0..97fd63f176 100644
--- a/hw/misc/sga.c
+++ b/hw/misc/sga.c
@@ -26,7 +26,6 @@
*/
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
-#include "hw/i386/pc.h"
#include "hw/loader.h"
#include "sysemu/sysemu.h"
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index 3ba58481d0..6c200becab 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -25,12 +25,12 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/sysbus.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
@@ -41,6 +41,8 @@
#include "elf.h"
#define PHYS_MEM_BASE 0x80000000
+#define FIRMWARE_BASE 0x1000
+#define FIRMWARE_SIZE (128 * 0x1000)
typedef struct {
uint64_t ram_size;
@@ -123,8 +125,8 @@ static void moxiesim_init(MachineState *machine)
memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal);
memory_region_add_subregion(address_space_mem, ram_base, ram);
- memory_region_init_ram(rom, NULL, "moxie.rom", 128 * 0x1000, &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0x1000, rom);
+ memory_region_init_ram(rom, NULL, "moxie.rom", FIRMWARE_SIZE, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), FIRMWARE_BASE, rom);
if (kernel_filename) {
loader_params.ram_size = ram_size;
@@ -133,6 +135,11 @@ static void moxiesim_init(MachineState *machine)
loader_params.initrd_filename = initrd_filename;
load_kernel(cpu, &loader_params);
}
+ if (bios_name) {
+ if (load_image_targphys(bios_name, FIRMWARE_BASE, FIRMWARE_SIZE) < 0) {
+ error_report("Failed to load firmware '%s'", bios_name);
+ }
+ }
/* A single 16450 sits at offset 0x3f8. */
if (serial_hds[0]) {
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 05a00cba31..804ec08721 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -98,7 +98,10 @@ typedef struct E1000State_st {
unsigned char data[0x10000];
uint16_t size;
unsigned char vlan_needed;
+ unsigned char sum_needed;
+ bool cptse;
e1000x_txd_props props;
+ e1000x_txd_props tso_props;
uint16_t tso_frames;
} tx;
@@ -539,35 +542,37 @@ xmit_seg(E1000State *s)
uint16_t len;
unsigned int frames = s->tx.tso_frames, css, sofar;
struct e1000_tx *tp = &s->tx;
+ struct e1000x_txd_props *props = tp->cptse ? &tp->tso_props : &tp->props;
- if (tp->props.tse && tp->props.cptse) {
- css = tp->props.ipcss;
+ if (tp->cptse) {
+ css = props->ipcss;
DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
frames, tp->size, css);
- if (tp->props.ip) { /* IPv4 */
+ if (props->ip) { /* IPv4 */
stw_be_p(tp->data+css+2, tp->size - css);
stw_be_p(tp->data+css+4,
lduw_be_p(tp->data + css + 4) + frames);
} else { /* IPv6 */
stw_be_p(tp->data+css+4, tp->size - css);
}
- css = tp->props.tucss;
+ css = props->tucss;
len = tp->size - css;
- DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len);
- if (tp->props.tcp) {
- sofar = frames * tp->props.mss;
+ DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", props->tcp, css, len);
+ if (props->tcp) {
+ sofar = frames * props->mss;
stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
- if (tp->props.paylen - sofar > tp->props.mss) {
+ if (props->paylen - sofar > props->mss) {
tp->data[css + 13] &= ~9; /* PSH, FIN */
} else if (frames) {
e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC);
}
- } else /* UDP */
+ } else { /* UDP */
stw_be_p(tp->data+css+4, len);
- if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) {
+ }
+ if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
unsigned int phsum;
// add pseudo-header length before checksum calculation
- void *sp = tp->data + tp->props.tucso;
+ void *sp = tp->data + props->tucso;
phsum = lduw_be_p(sp) + len;
phsum = (phsum >> 16) + (phsum & 0xffff);
@@ -576,13 +581,11 @@ xmit_seg(E1000State *s)
tp->tso_frames++;
}
- if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) {
- putsum(tp->data, tp->size, tp->props.tucso,
- tp->props.tucss, tp->props.tucse);
+ if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
+ putsum(tp->data, tp->size, props->tucso, props->tucss, props->tucse);
}
- if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) {
- putsum(tp->data, tp->size, tp->props.ipcso,
- tp->props.ipcss, tp->props.ipcse);
+ if (tp->sum_needed & E1000_TXD_POPTS_IXSM) {
+ putsum(tp->data, tp->size, props->ipcso, props->ipcss, props->ipcse);
}
if (tp->vlan_needed) {
memmove(tp->vlan, tp->data, 4);
@@ -614,27 +617,27 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
- e1000x_read_tx_ctx_descr(xp, &tp->props);
- tp->tso_frames = 0;
- if (tp->props.tucso == 0) { /* this is probably wrong */
- DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
- tp->props.tucso = tp->props.tucss + (tp->props.tcp ? 16 : 6);
+ if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) {
+ e1000x_read_tx_ctx_descr(xp, &tp->tso_props);
+ tp->tso_frames = 0;
+ } else {
+ e1000x_read_tx_ctx_descr(xp, &tp->props);
}
return;
} else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
// data descriptor
if (tp->size == 0) {
- tp->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+ tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
}
- tp->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
+ tp->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
} else {
// legacy descriptor
- tp->props.cptse = 0;
+ tp->cptse = 0;
}
if (e1000x_vlan_enabled(s->mac_reg) &&
e1000x_is_vlan_txd(txd_lower) &&
- (tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) {
+ (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
tp->vlan_needed = 1;
stw_be_p(tp->vlan_header,
le16_to_cpu(s->mac_reg[VET]));
@@ -643,8 +646,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
}
addr = le64_to_cpu(dp->buffer_addr);
- if (tp->props.tse && tp->props.cptse) {
- msh = tp->props.hdr_len + tp->props.mss;
+ if (tp->cptse) {
+ msh = tp->tso_props.hdr_len + tp->tso_props.mss;
do {
bytes = split_size;
if (tp->size + bytes > msh)
@@ -653,21 +656,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
bytes = MIN(sizeof(tp->data) - tp->size, bytes);
pci_dma_read(d, addr, tp->data + tp->size, bytes);
sz = tp->size + bytes;
- if (sz >= tp->props.hdr_len && tp->size < tp->props.hdr_len) {
- memmove(tp->header, tp->data, tp->props.hdr_len);
+ if (sz >= tp->tso_props.hdr_len
+ && tp->size < tp->tso_props.hdr_len) {
+ memmove(tp->header, tp->data, tp->tso_props.hdr_len);
}
tp->size = sz;
addr += bytes;
if (sz == msh) {
xmit_seg(s);
- memmove(tp->data, tp->header, tp->props.hdr_len);
- tp->size = tp->props.hdr_len;
+ memmove(tp->data, tp->header, tp->tso_props.hdr_len);
+ tp->size = tp->tso_props.hdr_len;
}
split_size -= bytes;
} while (bytes && split_size);
- } else if (!tp->props.tse && tp->props.cptse) {
- // context descriptor TSE is not set, while data descriptor TSE is set
- DBGOUT(TXERR, "TCP segmentation error\n");
} else {
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
pci_dma_read(d, addr, tp->data + tp->size, split_size);
@@ -676,14 +677,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
if (!(txd_lower & E1000_TXD_CMD_EOP))
return;
- if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len)) {
+ if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) {
xmit_seg(s);
}
tp->tso_frames = 0;
- tp->props.sum_needed = 0;
+ tp->sum_needed = 0;
tp->vlan_needed = 0;
tp->size = 0;
- tp->props.cptse = 0;
+ tp->cptse = 0;
}
static uint32_t
@@ -1435,7 +1436,7 @@ static const VMStateDescription vmstate_e1000_full_mac_state = {
static const VMStateDescription vmstate_e1000 = {
.name = "e1000",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 1,
.pre_save = e1000_pre_save,
.post_load = e1000_post_load,
@@ -1461,7 +1462,7 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT16(tx.props.mss, E1000State),
VMSTATE_UINT16(tx.size, E1000State),
VMSTATE_UINT16(tx.tso_frames, E1000State),
- VMSTATE_UINT8(tx.props.sum_needed, E1000State),
+ VMSTATE_UINT8(tx.sum_needed, E1000State),
VMSTATE_INT8(tx.props.ip, E1000State),
VMSTATE_INT8(tx.props.tcp, E1000State),
VMSTATE_BUFFER(tx.header, E1000State),
@@ -1508,6 +1509,17 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
+ VMSTATE_UINT8_V(tx.tso_props.ipcss, E1000State, 3),
+ VMSTATE_UINT8_V(tx.tso_props.ipcso, E1000State, 3),
+ VMSTATE_UINT16_V(tx.tso_props.ipcse, E1000State, 3),
+ VMSTATE_UINT8_V(tx.tso_props.tucss, E1000State, 3),
+ VMSTATE_UINT8_V(tx.tso_props.tucso, E1000State, 3),
+ VMSTATE_UINT16_V(tx.tso_props.tucse, E1000State, 3),
+ VMSTATE_UINT32_V(tx.tso_props.paylen, E1000State, 3),
+ VMSTATE_UINT8_V(tx.tso_props.hdr_len, E1000State, 3),
+ VMSTATE_UINT16_V(tx.tso_props.mss, E1000State, 3),
+ VMSTATE_INT8_V(tx.tso_props.ip, E1000State, 3),
+ VMSTATE_INT8_V(tx.tso_props.tcp, E1000State, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index f1af279e8d..191398a3d5 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -556,7 +556,7 @@ static const VMStateDescription e1000e_vmstate_tx = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_UINT8(props.sum_needed, struct e1000e_tx),
+ VMSTATE_UINT8(sum_needed, struct e1000e_tx),
VMSTATE_UINT8(props.ipcss, struct e1000e_tx),
VMSTATE_UINT8(props.ipcso, struct e1000e_tx),
VMSTATE_UINT16(props.ipcse, struct e1000e_tx),
@@ -569,7 +569,7 @@ static const VMStateDescription e1000e_vmstate_tx = {
VMSTATE_INT8(props.ip, struct e1000e_tx),
VMSTATE_INT8(props.tcp, struct e1000e_tx),
VMSTATE_BOOL(props.tse, struct e1000e_tx),
- VMSTATE_BOOL(props.cptse, struct e1000e_tx),
+ VMSTATE_BOOL(cptse, struct e1000e_tx),
VMSTATE_BOOL(skip_cp, struct e1000e_tx),
VMSTATE_END_OF_LIST()
}
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index 43a8d89955..c93c4661ed 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -632,18 +632,18 @@ e1000e_rss_parse_packet(E1000ECore *core,
static void
e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
{
- if (tx->props.tse && tx->props.cptse) {
+ if (tx->props.tse && tx->cptse) {
net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss);
net_tx_pkt_update_ip_checksums(tx->tx_pkt);
e1000x_inc_reg_if_not_full(core->mac, TSCTC);
return;
}
- if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) {
+ if (tx->sum_needed & E1000_TXD_POPTS_TXSM) {
net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0);
}
- if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) {
+ if (tx->sum_needed & E1000_TXD_POPTS_IXSM) {
net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt);
}
}
@@ -715,13 +715,13 @@ e1000e_process_tx_desc(E1000ECore *core,
return;
} else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
/* data descriptor */
- tx->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8;
- tx->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
+ tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+ tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
e1000e_process_ts_option(core, dp);
} else {
/* legacy descriptor */
e1000e_process_ts_option(core, dp);
- tx->props.cptse = 0;
+ tx->cptse = 0;
}
addr = le64_to_cpu(dp->buffer_addr);
@@ -747,8 +747,8 @@ e1000e_process_tx_desc(E1000ECore *core,
tx->skip_cp = false;
net_tx_pkt_reset(tx->tx_pkt);
- tx->props.sum_needed = 0;
- tx->props.cptse = 0;
+ tx->sum_needed = 0;
+ tx->cptse = 0;
}
}
diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h
index 1ff6978ca1..7d8ff41890 100644
--- a/hw/net/e1000e_core.h
+++ b/hw/net/e1000e_core.h
@@ -71,6 +71,8 @@ struct E1000Core {
e1000x_txd_props props;
bool skip_cp;
+ unsigned char sum_needed;
+ bool cptse;
struct NetTxPkt *tx_pkt;
} tx[E1000E_NUM_QUEUES];
diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h
index 3072ce9d50..0268884e72 100644
--- a/hw/net/e1000x_common.h
+++ b/hw/net/e1000x_common.h
@@ -193,7 +193,6 @@ void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy);
void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size);
typedef struct e1000x_txd_props {
- unsigned char sum_needed;
uint8_t ipcss;
uint8_t ipcso;
uint16_t ipcse;
@@ -206,7 +205,6 @@ typedef struct e1000x_txd_props {
int8_t ip;
int8_t tcp;
bool tse;
- bool cptse;
} e1000x_txd_props;
void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index 1c0def555b..a07a63247e 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -44,6 +44,7 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
+#include "net/eth.h"
#include "hw/nvram/eeprom93xx.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
@@ -323,32 +324,8 @@ static const uint16_t eepro100_mdi_mask[] = {
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
-#define POLYNOMIAL 0x04c11db6
-
static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
-/* From FreeBSD (locally modified). */
-static unsigned e100_compute_mcast_idx(const uint8_t *ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry) {
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- }
- return (crc & BITS(7, 2)) >> 2;
-}
-
/* Read a 16 bit control/status (CSR) register. */
static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
{
@@ -845,7 +822,8 @@ static void set_multicast_list(EEPRO100State *s)
uint8_t multicast_addr[6];
pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
- unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr);
+ unsigned mcast_idx = (net_crc32(multicast_addr, ETH_ALEN) &
+ BITS(7, 2)) >> 2;
assert(mcast_idx < 64);
s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
}
@@ -1681,7 +1659,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
if (s->configuration[21] & BIT(3)) {
/* Multicast all bit is set, receive all multicast frames. */
} else {
- unsigned mcast_idx = e100_compute_mcast_idx(buf);
+ unsigned mcast_idx = (net_crc32(buf, ETH_ALEN) & BITS(7, 2)) >> 2;
assert(mcast_idx < 64);
if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
/* Multicast frame is allowed in hash table. */
@@ -1701,7 +1679,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
rfd_status |= 0x0004;
} else if (s->configuration[20] & BIT(6)) {
/* Multiple IA bit set. */
- unsigned mcast_idx = compute_mcast_idx(buf);
+ unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
assert(mcast_idx < 64);
if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 3c36ab9cec..704f452067 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -762,7 +762,7 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len)
}
/* TODO: this does not seem to work for ftgmac100 */
- mcast_idx = compute_mcast_idx(buf);
+ mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) {
return 0;
}
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 90e6ee35ba..4fb48f62ba 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -196,6 +196,31 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index)
}
}
+/*
+ * Versions of this device with more than one TX descriptor save the
+ * 2nd and 3rd descriptors in a subsection, to maintain migration
+ * compatibility with previous versions of the device that only
+ * supported a single descriptor.
+ */
+static bool imx_eth_is_multi_tx_ring(void *opaque)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ return s->tx_ring_num > 1;
+}
+
+static const VMStateDescription vmstate_imx_eth_txdescs = {
+ .name = "imx.fec/txdescs",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = imx_eth_is_multi_tx_ring,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tx_descriptor[1], IMXFECState),
+ VMSTATE_UINT32(tx_descriptor[2], IMXFECState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_imx_eth = {
.name = TYPE_IMX_FEC,
.version_id = 2,
@@ -203,15 +228,18 @@ static const VMStateDescription vmstate_imx_eth = {
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
VMSTATE_UINT32(rx_descriptor, IMXFECState),
- VMSTATE_UINT32(tx_descriptor, IMXFECState),
-
+ VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
VMSTATE_UINT32(phy_status, IMXFECState),
VMSTATE_UINT32(phy_control, IMXFECState),
VMSTATE_UINT32(phy_advertise, IMXFECState),
VMSTATE_UINT32(phy_int, IMXFECState),
VMSTATE_UINT32(phy_int_mask, IMXFECState),
VMSTATE_END_OF_LIST()
- }
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_imx_eth_txdescs,
+ NULL
+ },
};
#define PHY_INT_ENERGYON (1 << 7)
@@ -405,9 +433,8 @@ static void imx_eth_update(IMXFECState *s)
static void imx_fec_do_tx(IMXFECState *s)
{
int frame_size = 0, descnt = 0;
- uint8_t frame[ENET_MAX_FRAME_SIZE];
- uint8_t *ptr = frame;
- uint32_t addr = s->tx_descriptor;
+ uint8_t *ptr = s->frame;
+ uint32_t addr = s->tx_descriptor[0];
while (descnt++ < IMX_MAX_DESC) {
IMXFECBufDesc bd;
@@ -431,8 +458,8 @@ static void imx_fec_do_tx(IMXFECState *s)
frame_size += len;
if (bd.flags & ENET_BD_L) {
/* Last buffer in frame. */
- qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size);
- ptr = frame;
+ qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size);
+ ptr = s->frame;
frame_size = 0;
s->regs[ENET_EIR] |= ENET_INT_TXF;
}
@@ -448,17 +475,47 @@ static void imx_fec_do_tx(IMXFECState *s)
}
}
- s->tx_descriptor = addr;
+ s->tx_descriptor[0] = addr;
imx_eth_update(s);
}
-static void imx_enet_do_tx(IMXFECState *s)
+static void imx_enet_do_tx(IMXFECState *s, uint32_t index)
{
int frame_size = 0, descnt = 0;
- uint8_t frame[ENET_MAX_FRAME_SIZE];
- uint8_t *ptr = frame;
- uint32_t addr = s->tx_descriptor;
+
+ uint8_t *ptr = s->frame;
+ uint32_t addr, int_txb, int_txf, tdsr;
+ size_t ring;
+
+ switch (index) {
+ case ENET_TDAR:
+ ring = 0;
+ int_txb = ENET_INT_TXB;
+ int_txf = ENET_INT_TXF;
+ tdsr = ENET_TDSR;
+ break;
+ case ENET_TDAR1:
+ ring = 1;
+ int_txb = ENET_INT_TXB1;
+ int_txf = ENET_INT_TXF1;
+ tdsr = ENET_TDSR1;
+ break;
+ case ENET_TDAR2:
+ ring = 2;
+ int_txb = ENET_INT_TXB2;
+ int_txf = ENET_INT_TXF2;
+ tdsr = ENET_TDSR2;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bogus value for index %x\n",
+ __func__, index);
+ abort();
+ break;
+ }
+
+ addr = s->tx_descriptor[ring];
while (descnt++ < IMX_MAX_DESC) {
IMXENETBufDesc bd;
@@ -482,13 +539,13 @@ static void imx_enet_do_tx(IMXFECState *s)
frame_size += len;
if (bd.flags & ENET_BD_L) {
if (bd.option & ENET_BD_PINS) {
- struct ip_header *ip_hd = PKT_GET_IP_HDR(frame);
+ struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame);
if (IP_HEADER_VERSION(ip_hd) == 4) {
- net_checksum_calculate(frame, frame_size);
+ net_checksum_calculate(s->frame, frame_size);
}
}
if (bd.option & ENET_BD_IINS) {
- struct ip_header *ip_hd = PKT_GET_IP_HDR(frame);
+ struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame);
/* We compute checksum only for IPv4 frames */
if (IP_HEADER_VERSION(ip_hd) == 4) {
uint16_t csum;
@@ -498,57 +555,59 @@ static void imx_enet_do_tx(IMXFECState *s)
}
}
/* Last buffer in frame. */
- qemu_send_packet(qemu_get_queue(s->nic), frame, len);
- ptr = frame;
+
+ qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size);
+ ptr = s->frame;
+
frame_size = 0;
if (bd.option & ENET_BD_TX_INT) {
- s->regs[ENET_EIR] |= ENET_INT_TXF;
+ s->regs[ENET_EIR] |= int_txf;
}
}
if (bd.option & ENET_BD_TX_INT) {
- s->regs[ENET_EIR] |= ENET_INT_TXB;
+ s->regs[ENET_EIR] |= int_txb;
}
bd.flags &= ~ENET_BD_R;
/* Write back the modified descriptor. */
imx_enet_write_bd(&bd, addr);
/* Advance to the next descriptor. */
if ((bd.flags & ENET_BD_W) != 0) {
- addr = s->regs[ENET_TDSR];
+ addr = s->regs[tdsr];
} else {
addr += sizeof(bd);
}
}
- s->tx_descriptor = addr;
+ s->tx_descriptor[ring] = addr;
imx_eth_update(s);
}
-static void imx_eth_do_tx(IMXFECState *s)
+static void imx_eth_do_tx(IMXFECState *s, uint32_t index)
{
if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) {
- imx_enet_do_tx(s);
+ imx_enet_do_tx(s, index);
} else {
imx_fec_do_tx(s);
}
}
-static void imx_eth_enable_rx(IMXFECState *s)
+static void imx_eth_enable_rx(IMXFECState *s, bool flush)
{
IMXFECBufDesc bd;
- bool tmp;
+ bool rx_ring_full;
imx_fec_read_bd(&bd, s->rx_descriptor);
- tmp = ((bd.flags & ENET_BD_E) != 0);
+ rx_ring_full = !(bd.flags & ENET_BD_E);
- if (!tmp) {
+ if (rx_ring_full) {
FEC_PRINTF("RX buffer full\n");
- } else if (!s->regs[ENET_RDAR]) {
+ } else if (flush) {
qemu_flush_queued_packets(qemu_get_queue(s->nic));
}
- s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0;
+ s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR;
}
static void imx_eth_reset(DeviceState *d)
@@ -585,7 +644,7 @@ static void imx_eth_reset(DeviceState *d)
}
s->rx_descriptor = 0;
- s->tx_descriptor = 0;
+ memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
/* We also reset the PHY */
phy_reset(s);
@@ -791,6 +850,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
IMXFECState *s = IMX_FEC(opaque);
+ const bool single_tx_ring = !imx_eth_is_multi_tx_ring(s);
uint32_t index = offset >> 2;
FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index),
@@ -807,16 +867,24 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) {
if (!s->regs[index]) {
s->regs[index] = ENET_RDAR_RDAR;
- imx_eth_enable_rx(s);
+ imx_eth_enable_rx(s, true);
}
} else {
s->regs[index] = 0;
}
break;
- case ENET_TDAR:
+ case ENET_TDAR1: /* FALLTHROUGH */
+ case ENET_TDAR2: /* FALLTHROUGH */
+ if (unlikely(single_tx_ring)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: trying to access TDAR2 or TDAR1\n",
+ TYPE_IMX_FEC, __func__);
+ return;
+ }
+ case ENET_TDAR: /* FALLTHROUGH */
if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) {
s->regs[index] = ENET_TDAR_TDAR;
- imx_eth_do_tx(s);
+ imx_eth_do_tx(s, index);
}
s->regs[index] = 0;
break;
@@ -828,8 +896,12 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
if ((s->regs[index] & ENET_ECR_ETHEREN) == 0) {
s->regs[ENET_RDAR] = 0;
s->rx_descriptor = s->regs[ENET_RDSR];
- s->regs[ENET_TDAR] = 0;
- s->tx_descriptor = s->regs[ENET_TDSR];
+ s->regs[ENET_TDAR] = 0;
+ s->regs[ENET_TDAR1] = 0;
+ s->regs[ENET_TDAR2] = 0;
+ s->tx_descriptor[0] = s->regs[ENET_TDSR];
+ s->tx_descriptor[1] = s->regs[ENET_TDSR1];
+ s->tx_descriptor[2] = s->regs[ENET_TDSR2];
}
break;
case ENET_MMFR:
@@ -907,7 +979,29 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
} else {
s->regs[index] = value & ~7;
}
- s->tx_descriptor = s->regs[index];
+ s->tx_descriptor[0] = s->regs[index];
+ break;
+ case ENET_TDSR1:
+ if (unlikely(single_tx_ring)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: trying to access TDSR1\n",
+ TYPE_IMX_FEC, __func__);
+ return;
+ }
+
+ s->regs[index] = value & ~7;
+ s->tx_descriptor[1] = s->regs[index];
+ break;
+ case ENET_TDSR2:
+ if (unlikely(single_tx_ring)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: trying to access TDSR2\n",
+ TYPE_IMX_FEC, __func__);
+ return;
+ }
+
+ s->regs[index] = value & ~7;
+ s->tx_descriptor[2] = s->regs[index];
break;
case ENET_MRBR:
s->regs[index] = value & 0x00003ff0;
@@ -930,7 +1024,7 @@ static int imx_eth_can_receive(NetClientState *nc)
FEC_PRINTF("\n");
- return s->regs[ENET_RDAR] ? 1 : 0;
+ return !!s->regs[ENET_RDAR];
}
static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
@@ -1020,7 +1114,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
}
}
s->rx_descriptor = addr;
- imx_eth_enable_rx(s);
+ imx_eth_enable_rx(s, false);
imx_eth_update(s);
return len;
}
@@ -1037,6 +1131,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
uint8_t *crc_ptr;
unsigned int buf_len;
size_t size = len;
+ bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16;
FEC_PRINTF("len %d\n", (int)size);
@@ -1051,9 +1146,13 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
crc = cpu_to_be32(crc32(~0, buf, size));
crc_ptr = (uint8_t *) &crc;
- /* Huge frames are truncted. */
- if (size > ENET_MAX_FRAME_SIZE) {
- size = ENET_MAX_FRAME_SIZE;
+ if (shift16) {
+ size += 2;
+ }
+
+ /* Huge frames are truncated. */
+ if (size > s->regs[ENET_FTRL]) {
+ size = s->regs[ENET_FTRL];
flags |= ENET_BD_TR | ENET_BD_LG;
}
@@ -1076,7 +1175,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
TYPE_IMX_FEC, __func__);
break;
}
- buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR];
+ buf_len = MIN(size, s->regs[ENET_MRBR]);
bd.length = buf_len;
size -= buf_len;
@@ -1087,6 +1186,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
buf_len += size - 4;
}
buf_addr = bd.data;
+
+ if (shift16) {
+ /*
+ * If SHIFT16 bit of ENETx_RACC register is set we need to
+ * align the payload to 4-byte boundary.
+ */
+ const uint8_t zeros[2] = { 0 };
+
+ dma_memory_write(&address_space_memory, buf_addr,
+ zeros, sizeof(zeros));
+
+ buf_addr += sizeof(zeros);
+ buf_len -= sizeof(zeros);
+
+ /* We only do this once per Ethernet frame */
+ shift16 = false;
+ }
+
dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
buf += buf_len;
if (size < 4) {
@@ -1116,7 +1233,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
}
}
s->rx_descriptor = addr;
- imx_eth_enable_rx(s);
+ imx_eth_enable_rx(s, false);
imx_eth_update(s);
return len;
}
@@ -1164,15 +1281,13 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s,
- TYPE_IMX_FEC, 0x400);
+ TYPE_IMX_FEC, FSL_IMX25_FEC_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq[0]);
sysbus_init_irq(sbd, &s->irq[1]);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->conf.peers.ncs[0] = nd_table[0].netdev;
-
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
object_get_typename(OBJECT(dev)),
DEVICE(dev)->id, s);
@@ -1182,6 +1297,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
static Property imx_eth_properties[] = {
DEFINE_NIC_PROPERTIES(IMXFECState, conf),
+ DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 3db8937cac..b9032dac59 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
+#include "net/eth.h"
#include "hw/devices.h"
#include "sysemu/sysemu.h"
#include "hw/ptimer.h"
@@ -504,7 +505,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
}
} else {
/* Hash matching */
- hash = compute_mcast_idx(addr);
+ hash = net_crc32(addr, ETH_ALEN) >> 26;
if (hash & 0x20) {
return (s->mac_hashh >> (hash & 0x1f)) & 1;
} else {
diff --git a/hw/net/lance.c b/hw/net/lance.c
index 23929fd1e6..0028bc525d 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -40,7 +40,7 @@
#include "net/net.h"
#include "qemu/timer.h"
#include "qemu/sockets.h"
-#include "hw/sparc/sun4m.h"
+#include "hw/sparc/sparc32_dma.h"
#include "hw/net/lance.h"
#include "trace.h"
#include "sysemu/sysemu.h"
diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c
index f3455339ee..70e5c1d3d4 100644
--- a/hw/net/ne2000-isa.c
+++ b/hw/net/ne2000-isa.c
@@ -22,17 +22,15 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
+#include "hw/net/ne2000-isa.h"
#include "hw/qdev.h"
-#include "net/net.h"
#include "ne2000.h"
+#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#define TYPE_ISA_NE2000 "ne2k_isa"
#define ISA_NE2000(obj) OBJECT_CHECK(ISANE2000State, (obj), TYPE_ISA_NE2000)
typedef struct ISANE2000State {
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 3938e6ddd8..687ef84aac 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -22,9 +22,9 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
+#include "net/eth.h"
#include "ne2000.h"
#include "hw/loader.h"
#include "sysemu/sysemu.h"
@@ -201,7 +201,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
/* multicast */
if (!(s->rxcr & 0x08))
return size;
- mcast_idx = compute_mcast_idx(buf);
+ mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
return size;
} else if (s->mem[0] == buf[0] &&
diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h
index d213dccae3..adb8021bd1 100644
--- a/hw/net/ne2000.h
+++ b/hw/net/ne2000.h
@@ -1,6 +1,9 @@
#ifndef HW_NE2000_H
#define HW_NE2000_H
+#include "hw/hw.h"
+#include "net/net.h"
+
#define NE2000_PMEM_SIZE (32*1024)
#define NE2000_PMEM_START (16*1024)
#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START)
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index 268d6a7892..d42b79c08c 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -36,6 +36,7 @@
#include "hw/net/mii.h"
#include "hw/sysbus.h"
#include "net/net.h"
+#include "net/eth.h"
#include "sysemu/sysemu.h"
#include "trace.h"
@@ -373,7 +374,7 @@ static ssize_t open_eth_receive(NetClientState *nc,
if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) {
miss = GET_REGBIT(s, MODER, BRO);
} else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) {
- unsigned mcast_idx = compute_mcast_idx(buf);
+ unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
miss = !(s->regs[HASH0 + mcast_idx / 32] &
(1 << (mcast_idx % 32)));
trace_open_eth_receive_mcast(
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index 654455355f..39d5d93525 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -38,6 +38,7 @@
#include "qemu/osdep.h"
#include "hw/qdev.h"
#include "net/net.h"
+#include "net/eth.h"
#include "qemu/timer.h"
#include "qemu/sockets.h"
#include "sysemu/sysemu.h"
@@ -522,25 +523,6 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
be16_to_cpu(hdr->ether_type)); \
} while (0)
-#define MULTICAST_FILTER_LEN 8
-
-static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
-{
-#define LNC_POLYNOMIAL 0xEDB88320UL
- uint32_t crc = 0xFFFFFFFF;
- int idx, bit;
- uint8_t data;
-
- for (idx = 0; idx < 6; idx++) {
- for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
- crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
- data >>= 1;
- }
- }
- return crc;
-#undef LNC_POLYNOMIAL
-}
-
#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
/* generated using the AUTODIN II polynomial
@@ -656,7 +638,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
s->csr[10] & 0xff, s->csr[10] >> 8,
s->csr[11] & 0xff, s->csr[11] >> 8
};
- int index = lnc_mchash(hdr->ether_dhost) >> 26;
+ int index = net_crc32_le(hdr->ether_dhost, ETH_ALEN) >> 26;
return !!(ladr[index >> 3] & (1 << (index & 7)));
}
return 0;
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index a6b2a9f7a4..1cc95b8cba 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -882,7 +882,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
return size;
}
- int mcast_idx = compute_mcast_idx(buf);
+ int mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
{
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
index 6aa8d1117b..60f1e479f3 100644
--- a/hw/net/sungem.c
+++ b/hw/net/sungem.c
@@ -11,12 +11,11 @@
#include "hw/pci/pci.h"
#include "qemu/log.h"
#include "net/net.h"
+#include "net/eth.h"
#include "net/checksum.h"
#include "hw/net/mii.h"
#include "sysemu/sysemu.h"
#include "trace.h"
-/* For crc32 */
-#include <zlib.h>
#define TYPE_SUNGEM "sungem"
@@ -595,7 +594,7 @@ static ssize_t sungem_receive(NetClientState *nc, const uint8_t *buf,
}
/* Get MAC crc */
- mac_crc = crc32(~0, buf, 6);
+ mac_crc = net_crc32_le(buf, ETH_ALEN);
/* Packet isn't for me ? */
rx_cond = sungem_check_rx_mac(s, buf, mac_crc);
diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c
index b1efa1b88d..7558fca8f9 100644
--- a/hw/net/sunhme.c
+++ b/hw/net/sunhme.c
@@ -698,29 +698,6 @@ static inline void sunhme_set_rx_ring_nr(SunHMEState *s, int i)
s->erxregs[HME_ERXI_RING >> 2] = ring;
}
-#define POLYNOMIAL_LE 0xedb88320
-static uint32_t sunhme_crc32_le(const uint8_t *p, int len)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < len; i++) {
- b = *p++;
- for (j = 0; j < 8; j++) {
- carry = (crc & 0x1) ^ (b & 0x01);
- crc >>= 1;
- b >>= 1;
- if (carry) {
- crc = crc ^ POLYNOMIAL_LE;
- }
- }
- }
-
- return crc;
-}
-
#define MIN_BUF_SIZE 60
static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf,
@@ -761,7 +738,7 @@ static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf,
trace_sunhme_rx_filter_bcast_match();
} else if (s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_HENABLE) {
/* Didn't match local address, check hash filter */
- int mcast_idx = sunhme_crc32_le(buf, 6) >> 26;
+ int mcast_idx = net_crc32_le(buf, ETH_ALEN) >> 26;
if (!(s->macregs[(HME_MACI_HASHTAB0 >> 2) - (mcast_idx >> 4)] &
(1 << (mcast_idx & 0xf)))) {
/* Didn't match hash filter */
diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c
index 2b31f5b844..94f436e7fb 100644
--- a/hw/nios2/boot.c
+++ b/hw/nios2/boot.c
@@ -34,7 +34,6 @@
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
-#include "qemu-common.h"
#include "sysemu/device_tree.h"
#include "sysemu/sysemu.h"
#include "hw/loader.h"
diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
index c018f6b2ff..0f4ee71dcb 100644
--- a/hw/nvram/Makefile.objs
+++ b/hw/nvram/Makefile.objs
@@ -1,5 +1,6 @@
common-obj-$(CONFIG_DS1225Y) += ds1225y.o
common-obj-y += eeprom93xx.o
+common-obj-y += eeprom_at24c.o
common-obj-y += fw_cfg.o
common-obj-y += chrp_nvram.o
common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
new file mode 100644
index 0000000000..efa3621ac6
--- /dev/null
+++ b/hw/nvram/eeprom_at24c.c
@@ -0,0 +1,205 @@
+/*
+ * *AT24C* series I2C EEPROM
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the LICENSE file in the top-level directory.
+ */
+
+#include <string.h>
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "sysemu/block-backend.h"
+
+/* #define DEBUG_AT24C */
+
+#ifdef DEBUG_AT24C
+#define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
+ ## __VA_ARGS__)
+
+#define TYPE_AT24C_EE "at24c-eeprom"
+#define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE)
+
+typedef struct EEPROMState {
+ I2CSlave parent_obj;
+
+ /* address counter */
+ uint16_t cur;
+ /* total size in bytes */
+ uint32_t rsize;
+ bool writable;
+ /* cells changed since last START? */
+ bool changed;
+ /* during WRITE, # of address bytes transfered */
+ uint8_t haveaddr;
+
+ uint8_t *mem;
+
+ BlockBackend *blk;
+} EEPROMState;
+
+static
+int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
+{
+ EEPROMState *ee = container_of(s, EEPROMState, parent_obj);
+
+ switch (event) {
+ case I2C_START_SEND:
+ case I2C_START_RECV:
+ case I2C_FINISH:
+ ee->haveaddr = 0;
+ DPRINTK("clear\n");
+ if (ee->blk && ee->changed) {
+ int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0);
+ if (len != ee->rsize) {
+ ERR(TYPE_AT24C_EE
+ " : failed to write backing file\n");
+ }
+ DPRINTK("Wrote to backing file\n");
+ }
+ ee->changed = false;
+ break;
+ case I2C_NACK:
+ break;
+ }
+ return 0;
+}
+
+static
+int at24c_eeprom_recv(I2CSlave *s)
+{
+ EEPROMState *ee = AT24C_EE(s);
+ int ret;
+
+ ret = ee->mem[ee->cur];
+
+ ee->cur = (ee->cur + 1u) % ee->rsize;
+ DPRINTK("Recv %02x %c\n", ret, ret);
+
+ return ret;
+}
+
+static
+int at24c_eeprom_send(I2CSlave *s, uint8_t data)
+{
+ EEPROMState *ee = AT24C_EE(s);
+
+ if (ee->haveaddr < 2) {
+ ee->cur <<= 8;
+ ee->cur |= data;
+ ee->haveaddr++;
+ if (ee->haveaddr == 2) {
+ ee->cur %= ee->rsize;
+ DPRINTK("Set pointer %04x\n", ee->cur);
+ }
+
+ } else {
+ if (ee->writable) {
+ DPRINTK("Send %02x\n", data);
+ ee->mem[ee->cur] = data;
+ ee->changed = true;
+ } else {
+ DPRINTK("Send error %02x read-only\n", data);
+ }
+ ee->cur = (ee->cur + 1u) % ee->rsize;
+
+ }
+
+ return 0;
+}
+
+static
+int at24c_eeprom_init(I2CSlave *i2c)
+{
+ EEPROMState *ee = AT24C_EE(i2c);
+
+ ee->mem = g_malloc0(ee->rsize);
+
+ if (ee->blk) {
+ int64_t len = blk_getlength(ee->blk);
+
+ if (len != ee->rsize) {
+ ERR(TYPE_AT24C_EE " : Backing file size %lu != %u\n",
+ (unsigned long)len, (unsigned)ee->rsize);
+ exit(1);
+ }
+
+ if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, &error_fatal) < 0)
+ {
+ ERR(TYPE_AT24C_EE
+ " : Backing file incorrect permission\n");
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+static
+void at24c_eeprom_reset(DeviceState *state)
+{
+ EEPROMState *ee = AT24C_EE(state);
+
+ ee->changed = false;
+ ee->cur = 0;
+ ee->haveaddr = 0;
+
+ memset(ee->mem, 0, ee->rsize);
+
+ if (ee->blk) {
+ int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize);
+
+ if (len != ee->rsize) {
+ ERR(TYPE_AT24C_EE
+ " : Failed initial sync with backing file\n");
+ }
+ DPRINTK("Reset read backing file\n");
+ }
+}
+
+static Property at24c_eeprom_props[] = {
+ DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0),
+ DEFINE_PROP_BOOL("writable", EEPROMState, writable, true),
+ DEFINE_PROP_DRIVE("drive", EEPROMState, blk),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static
+void at24c_eeprom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = &at24c_eeprom_init;
+ k->event = &at24c_eeprom_event;
+ k->recv = &at24c_eeprom_recv;
+ k->send = &at24c_eeprom_send;
+
+ dc->props = at24c_eeprom_props;
+ dc->reset = at24c_eeprom_reset;
+}
+
+static
+const TypeInfo at24c_eeprom_type = {
+ .name = TYPE_AT24C_EE,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(EEPROMState),
+ .class_size = sizeof(I2CSlaveClass),
+ .class_init = at24c_eeprom_class_init,
+};
+
+static void at24c_eeprom_register(void)
+{
+ type_register_static(&at24c_eeprom_type);
+}
+
+type_init(at24c_eeprom_register)
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 2a81eec943..e62de4218f 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -16,7 +16,6 @@
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pci_bridge.h"
-#include "hw/i386/pc.h"
#include "qemu/range.h"
#include "qemu/error-report.h"
#include "sysemu/numa.h"
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index 1df998443d..ec676f94b6 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -36,6 +36,7 @@
#include "hw/pci-host/apb.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
+#include "qapi/error.h"
#include "qemu/log.h"
/* debug APB */
@@ -48,16 +49,6 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
#define APB_DPRINTF(fmt, ...)
#endif
-/* debug IOMMU */
-//#define DEBUG_IOMMU
-
-#ifdef DEBUG_IOMMU
-#define IOMMU_DPRINTF(fmt, ...) \
-do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define IOMMU_DPRINTF(fmt, ...)
-#endif
-
/*
* Chipset docs:
* PBM: "UltraSPARC IIi User's Manual",
@@ -79,94 +70,8 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
#define RESET_WCMASK 0x98000000
#define RESET_WMASK 0x60000000
-#define MAX_IVEC 0x40
#define NO_IRQ_REQUEST (MAX_IVEC + 1)
-#define IOMMU_PAGE_SIZE_8K (1ULL << 13)
-#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
-#define IOMMU_PAGE_SIZE_64K (1ULL << 16)
-#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
-
-#define IOMMU_NREGS 3
-
-#define IOMMU_CTRL 0x0
-#define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
-#define IOMMU_CTRL_MMU_EN (1ULL)
-
-#define IOMMU_CTRL_TSB_SHIFT 16
-
-#define IOMMU_BASE 0x8
-#define IOMMU_FLUSH 0x10
-
-#define IOMMU_TTE_DATA_V (1ULL << 63)
-#define IOMMU_TTE_DATA_SIZE (1ULL << 61)
-#define IOMMU_TTE_DATA_W (1ULL << 1)
-
-#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
-#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
-
-#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
-#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
-
-#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
-#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
-
-typedef struct IOMMUState {
- AddressSpace iommu_as;
- IOMMUMemoryRegion iommu;
-
- uint64_t regs[IOMMU_NREGS];
-} IOMMUState;
-
-#define TYPE_APB "pbm"
-
-#define APB_DEVICE(obj) \
- OBJECT_CHECK(APBState, (obj), TYPE_APB)
-
-#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region"
-
-typedef struct APBState {
- PCIHostState parent_obj;
-
- MemoryRegion apb_config;
- MemoryRegion pci_config;
- MemoryRegion pci_mmio;
- MemoryRegion pci_ioport;
- uint64_t pci_irq_in;
- IOMMUState iommu;
- uint32_t pci_control[16];
- uint32_t pci_irq_map[8];
- uint32_t pci_err_irq_map[4];
- uint32_t obio_irq_map[32];
- qemu_irq *pbm_irqs;
- qemu_irq *ivec_irqs;
- unsigned int irq_request;
- uint32_t reset_control;
- unsigned int nr_resets;
-} APBState;
-
-#define TYPE_PBM_PCI_BRIDGE "pbm-bridge"
-#define PBM_PCI_BRIDGE(obj) \
- OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE)
-
-typedef struct PBMPCIBridge {
- /*< private >*/
- PCIBridge parent_obj;
-
- /* Is this busA with in-built devices (ebus)? */
- bool busA;
-} PBMPCIBridge;
-
static inline void pbm_set_request(APBState *s, unsigned int irq_num)
{
APB_DPRINTF("%s: request irq %d\n", __func__, irq_num);
@@ -221,216 +126,10 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &is->iommu_as;
}
-/* Called from RCU critical section */
-static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr,
- IOMMUAccessFlags flag)
-{
- IOMMUState *is = container_of(iommu, IOMMUState, iommu);
- hwaddr baseaddr, offset;
- uint64_t tte;
- uint32_t tsbsize;
- IOMMUTLBEntry ret = {
- .target_as = &address_space_memory,
- .iova = 0,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_NONE,
- };
-
- if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) {
- /* IOMMU disabled, passthrough using standard 8K page */
- ret.iova = addr & IOMMU_PAGE_MASK_8K;
- ret.translated_addr = addr;
- ret.addr_mask = IOMMU_PAGE_MASK_8K;
- ret.perm = IOMMU_RW;
-
- return ret;
- }
-
- baseaddr = is->regs[IOMMU_BASE >> 3];
- tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7;
-
- if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) {
- /* 64K */
- switch (tsbsize) {
- case 0:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13;
- break;
- case 1:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13;
- break;
- case 2:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13;
- break;
- case 3:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13;
- break;
- case 4:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13;
- break;
- case 5:
- offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13;
- break;
- default:
- /* Not implemented, error */
- return ret;
- }
- } else {
- /* 8K */
- switch (tsbsize) {
- case 0:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10;
- break;
- case 1:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10;
- break;
- case 2:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10;
- break;
- case 3:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10;
- break;
- case 4:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10;
- break;
- case 5:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10;
- break;
- case 6:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10;
- break;
- case 7:
- offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10;
- break;
- }
- }
-
- tte = address_space_ldq_be(&address_space_memory, baseaddr + offset,
- MEMTXATTRS_UNSPECIFIED, NULL);
-
- if (!(tte & IOMMU_TTE_DATA_V)) {
- /* Invalid mapping */
- return ret;
- }
-
- if (tte & IOMMU_TTE_DATA_W) {
- /* Writeable */
- ret.perm = IOMMU_RW;
- } else {
- ret.perm = IOMMU_RO;
- }
-
- /* Extract phys */
- if (tte & IOMMU_TTE_DATA_SIZE) {
- /* 64K */
- ret.iova = addr & IOMMU_PAGE_MASK_64K;
- ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K;
- ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1);
- } else {
- /* 8K */
- ret.iova = addr & IOMMU_PAGE_MASK_8K;
- ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K;
- ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1);
- }
-
- return ret;
-}
-
-static void iommu_config_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- IOMMUState *is = opaque;
-
- IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64
- " size: %d\n", addr, val, size);
-
- switch (addr) {
- case IOMMU_CTRL:
- if (size == 4) {
- is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL;
- is->regs[IOMMU_CTRL >> 3] |= val << 32;
- } else {
- is->regs[IOMMU_CTRL >> 3] = val;
- }
- break;
- case IOMMU_CTRL + 0x4:
- is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL;
- is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL;
- break;
- case IOMMU_BASE:
- if (size == 4) {
- is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL;
- is->regs[IOMMU_BASE >> 3] |= val << 32;
- } else {
- is->regs[IOMMU_BASE >> 3] = val;
- }
- break;
- case IOMMU_BASE + 0x4:
- is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
- is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
- break;
- case IOMMU_FLUSH:
- case IOMMU_FLUSH + 0x4:
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "apb iommu: Unimplemented register write "
- "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
- addr, size, val);
- break;
- }
-}
-
-static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size)
-{
- IOMMUState *is = opaque;
- uint64_t val;
-
- switch (addr) {
- case IOMMU_CTRL:
- if (size == 4) {
- val = is->regs[IOMMU_CTRL >> 3] >> 32;
- } else {
- val = is->regs[IOMMU_CTRL >> 3];
- }
- break;
- case IOMMU_CTRL + 0x4:
- val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL;
- break;
- case IOMMU_BASE:
- if (size == 4) {
- val = is->regs[IOMMU_BASE >> 3] >> 32;
- } else {
- val = is->regs[IOMMU_BASE >> 3];
- }
- break;
- case IOMMU_BASE + 0x4:
- val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
- break;
- case IOMMU_FLUSH:
- case IOMMU_FLUSH + 0x4:
- val = 0;
- break;
- default:
- qemu_log_mask(LOG_UNIMP,
- "apb iommu: Unimplemented register read "
- "reg 0x%" HWADDR_PRIx " size 0x%x\n",
- addr, size);
- val = 0;
- break;
- }
-
- IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64
- " size: %d\n", addr, val, size);
-
- return val;
-}
-
static void apb_config_writel (void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
APBState *s = opaque;
- IOMMUState *is = &s->iommu;
APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
@@ -438,9 +137,6 @@ static void apb_config_writel (void *opaque, hwaddr addr,
case 0x30 ... 0x4f: /* DMA error registers */
/* XXX: not implemented yet */
break;
- case 0x200 ... 0x217: /* IOMMU */
- iommu_config_write(is, (addr & 0x1f), val, size);
- break;
case 0xc00 ... 0xc3f: /* PCI interrupt control */
if (addr & 4) {
unsigned int ino = (addr & 0x3f) >> 3;
@@ -512,7 +208,6 @@ static uint64_t apb_config_readl (void *opaque,
hwaddr addr, unsigned size)
{
APBState *s = opaque;
- IOMMUState *is = &s->iommu;
uint32_t val;
switch (addr & 0xffff) {
@@ -520,9 +215,6 @@ static uint64_t apb_config_readl (void *opaque,
val = 0;
/* XXX: not implemented yet */
break;
- case 0x200 ... 0x217: /* IOMMU */
- val = iommu_config_read(is, (addr & 0x1f), size);
- break;
case 0xc00 ... 0xc3f: /* PCI interrupt control */
if (addr & 4) {
val = s->pci_irq_map[(addr & 0x3f) >> 3];
@@ -603,32 +295,27 @@ static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
return irq_num;
}
-static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
+static int pci_pbmA_map_irq(PCIDevice *pci_dev, int irq_num)
{
- PBMPCIBridge *br = PBM_PCI_BRIDGE(pci_bridge_get_device(
- PCI_BUS(qdev_get_parent_bus(DEVICE(pci_dev)))));
-
- int bus_offset;
- if (br->busA) {
- bus_offset = 0x0;
-
- /* The on-board devices have fixed (legacy) OBIO intnos */
- switch (PCI_SLOT(pci_dev->devfn)) {
- case 1:
- /* Onboard NIC */
- return 0x21;
- case 3:
- /* Onboard IDE */
- return 0x20;
-
- default:
- /* Normal intno, fall through */
- break;
- }
- } else {
- bus_offset = 0x10;
+ /* The on-board devices have fixed (legacy) OBIO intnos */
+ switch (PCI_SLOT(pci_dev->devfn)) {
+ case 1:
+ /* Onboard NIC */
+ return OBIO_NIC_IRQ;
+ case 3:
+ /* Onboard IDE */
+ return OBIO_HDD_IRQ;
+ default:
+ /* Normal intno, fall through */
+ break;
}
- return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
+
+ return ((PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
+}
+
+static int pci_pbmB_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+ return (0x10 + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f;
}
static void pci_apb_set_irq(void *opaque, int irq_num, int level)
@@ -672,18 +359,11 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp)
* the reset value should be zero unless the boot pin is tied high
* (which is true) and thus it should be PCI_COMMAND_MEMORY.
*/
- uint16_t cmd = PCI_COMMAND_MEMORY;
PBMPCIBridge *br = PBM_PCI_BRIDGE(dev);
pci_bridge_initfn(dev, TYPE_PCI_BUS);
- /* If initialising busA, ensure that we allow IO transactions so that
- we get the early serial console until OpenBIOS configures the bridge */
- if (br->busA) {
- cmd |= PCI_COMMAND_IO;
- }
-
- pci_set_word(dev->config + PCI_COMMAND, cmd);
+ pci_set_word(dev->config + PCI_COMMAND, PCI_COMMAND_MEMORY);
pci_set_word(dev->config + PCI_STATUS,
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM);
@@ -697,78 +377,12 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp)
pci_bridge_update_mappings(PCI_BRIDGE(br));
}
-PCIBus *pci_apb_init(hwaddr special_base,
- hwaddr mem_base,
- qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB,
- qemu_irq **pbm_irqs)
-{
- DeviceState *dev;
- SysBusDevice *s;
- PCIHostState *phb;
- APBState *d;
- IOMMUState *is;
- PCIDevice *pci_dev;
- PCIBridge *br;
-
- /* Ultrasparc PBM main bus */
- dev = qdev_create(NULL, TYPE_APB);
- d = APB_DEVICE(dev);
- phb = PCI_HOST_BRIDGE(dev);
- phb->bus = pci_register_root_bus(DEVICE(phb), "pci",
- pci_apb_set_irq, pci_apb_map_irq, d,
- &d->pci_mmio,
- &d->pci_ioport,
- 0, 32, TYPE_PCI_BUS);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- /* apb_config */
- sysbus_mmio_map(s, 0, special_base);
- /* PCI configuration space */
- sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
- /* pci_ioport */
- sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
-
- memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
- memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
-
- *pbm_irqs = d->pbm_irqs;
- d->ivec_irqs = ivec_irqs;
-
- pci_create_simple(phb->bus, 0, "pbm-pci");
-
- /* APB IOMMU */
- is = &d->iommu;
- memset(is, 0, sizeof(IOMMUState));
-
- memory_region_init_iommu(&is->iommu, sizeof(is->iommu),
- TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev),
- "iommu-apb", UINT64_MAX);
- address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as");
- pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
-
- /* APB secondary busses */
- pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
- TYPE_PBM_PCI_BRIDGE);
- br = PCI_BRIDGE(pci_dev);
- pci_bridge_map_irq(br, "pciB", pci_pbm_map_irq);
- qdev_init_nofail(&pci_dev->qdev);
- *busB = pci_bridge_get_sec_bus(br);
-
- pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true,
- TYPE_PBM_PCI_BRIDGE);
- br = PCI_BRIDGE(pci_dev);
- pci_bridge_map_irq(br, "pciA", pci_pbm_map_irq);
- qdev_prop_set_bit(DEVICE(pci_dev), "busA", true);
- qdev_init_nofail(&pci_dev->qdev);
- *busA = pci_bridge_get_sec_bus(br);
-
- return phb->bus;
-}
-
static void pci_pbm_reset(DeviceState *d)
{
- unsigned int i;
APBState *s = APB_DEVICE(d);
+ PCIDevice *pci_dev;
+ unsigned int i;
+ uint16_t cmd;
for (i = 0; i < 8; i++) {
s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
@@ -784,6 +398,15 @@ static void pci_pbm_reset(DeviceState *d)
/* Power on reset */
s->reset_control = POR;
}
+
+ /* As this is the busA PCI bridge which contains the on-board devices
+ * attached to the ebus, ensure that we initially allow IO transactions
+ * so that we get the early serial console until OpenBIOS can properly
+ * configure the PCI bridge itself */
+ pci_dev = PCI_DEVICE(s->bridgeA);
+ cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
+ pci_set_word(pci_dev->config + PCI_COMMAND, cmd | PCI_COMMAND_IO);
+ pci_bridge_update_mappings(PCI_BRIDGE(pci_dev));
}
static const MemoryRegionOps pci_config_ops = {
@@ -792,12 +415,57 @@ static const MemoryRegionOps pci_config_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static int pci_pbm_init_device(SysBusDevice *dev)
+static void pci_pbm_realize(DeviceState *dev, Error **errp)
{
- APBState *s;
+ APBState *s = APB_DEVICE(dev);
+ PCIHostState *phb = PCI_HOST_BRIDGE(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(s);
+ PCIDevice *pci_dev;
+
+ /* apb_config */
+ sysbus_mmio_map(sbd, 0, s->special_base);
+ /* PCI configuration space */
+ sysbus_mmio_map(sbd, 1, s->special_base + 0x1000000ULL);
+ /* pci_ioport */
+ sysbus_mmio_map(sbd, 2, s->special_base + 0x2000000ULL);
+
+ memory_region_init(&s->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL);
+ memory_region_add_subregion(get_system_memory(), s->mem_base,
+ &s->pci_mmio);
+
+ phb->bus = pci_register_root_bus(dev, "pci",
+ pci_apb_set_irq, pci_apb_map_irq, s,
+ &s->pci_mmio,
+ &s->pci_ioport,
+ 0, 32, TYPE_PCI_BUS);
+
+ pci_create_simple(phb->bus, 0, "pbm-pci");
+
+ /* APB IOMMU */
+ memory_region_add_subregion_overlap(&s->apb_config, 0x200,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(s->iommu), 0), 1);
+ pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, s->iommu);
+
+ /* APB secondary busses */
+ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true,
+ TYPE_PBM_PCI_BRIDGE);
+ s->bridgeB = PCI_BRIDGE(pci_dev);
+ pci_bridge_map_irq(s->bridgeB, "pciB", pci_pbmB_map_irq);
+ qdev_init_nofail(&pci_dev->qdev);
+
+ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true,
+ TYPE_PBM_PCI_BRIDGE);
+ s->bridgeA = PCI_BRIDGE(pci_dev);
+ pci_bridge_map_irq(s->bridgeA, "pciA", pci_pbmA_map_irq);
+ qdev_init_nofail(&pci_dev->qdev);
+}
+
+static void pci_pbm_init(Object *obj)
+{
+ APBState *s = APB_DEVICE(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
unsigned int i;
- s = APB_DEVICE(dev);
for (i = 0; i < 8; i++) {
s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
}
@@ -807,28 +475,33 @@ static int pci_pbm_init_device(SysBusDevice *dev)
for (i = 0; i < 32; i++) {
s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
}
- s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
+ qdev_init_gpio_in_named(DEVICE(s), pci_apb_set_irq, "pbm-irq", MAX_IVEC);
+ qdev_init_gpio_out_named(DEVICE(s), s->ivec_irqs, "ivec-irq", MAX_IVEC);
s->irq_request = NO_IRQ_REQUEST;
s->pci_irq_in = 0ULL;
+ /* IOMMU */
+ object_property_add_link(obj, "iommu", TYPE_SUN4U_IOMMU,
+ (Object **) &s->iommu,
+ qdev_prop_allow_set_link_before_realize,
+ 0, NULL);
+
/* apb_config */
memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s,
"apb-config", 0x10000);
/* at region 0 */
- sysbus_init_mmio(dev, &s->apb_config);
+ sysbus_init_mmio(sbd, &s->apb_config);
memory_region_init_io(&s->pci_config, OBJECT(s), &pci_config_ops, s,
"apb-pci-config", 0x1000000);
/* at region 1 */
- sysbus_init_mmio(dev, &s->pci_config);
+ sysbus_init_mmio(sbd, &s->pci_config);
/* pci_ioport */
memory_region_init(&s->pci_ioport, OBJECT(s), "apb-pci-ioport", 0x1000000);
/* at region 2 */
- sysbus_init_mmio(dev, &s->pci_ioport);
-
- return 0;
+ sysbus_init_mmio(sbd, &s->pci_ioport);
}
static void pbm_pci_host_realize(PCIDevice *d, Error **errp)
@@ -867,28 +540,30 @@ static const TypeInfo pbm_pci_host_info = {
},
};
+static Property pbm_pci_host_properties[] = {
+ DEFINE_PROP_UINT64("special-base", APBState, special_base, 0),
+ DEFINE_PROP_UINT64("mem-base", APBState, mem_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void pbm_host_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = pci_pbm_init_device;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->realize = pci_pbm_realize;
dc->reset = pci_pbm_reset;
+ dc->props = pbm_pci_host_properties;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
static const TypeInfo pbm_host_info = {
.name = TYPE_APB,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(APBState),
+ .instance_init = pci_pbm_init,
.class_init = pbm_host_class_init,
};
-static Property pbm_pci_properties[] = {
- DEFINE_PROP_BOOL("busA", PBMPCIBridge, busA, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -904,7 +579,6 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->reset = pci_bridge_reset;
dc->vmsd = &vmstate_pci_device;
- dc->props = pbm_pci_properties;
}
static const TypeInfo pbm_pci_bridge_info = {
@@ -918,25 +592,11 @@ static const TypeInfo pbm_pci_bridge_info = {
},
};
-static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data)
-{
- IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
-
- imrc->translate = pbm_translate_iommu;
-}
-
-static const TypeInfo pbm_iommu_memory_region_info = {
- .parent = TYPE_IOMMU_MEMORY_REGION,
- .name = TYPE_APB_IOMMU_MEMORY_REGION,
- .class_init = pbm_iommu_memory_region_class_init,
-};
-
static void pbm_register_types(void)
{
type_register_static(&pbm_host_info);
type_register_static(&pbm_pci_host_info);
type_register_static(&pbm_pci_bridge_info);
- type_register_static(&pbm_iommu_memory_region_info);
}
type_init(pbm_register_types)
diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index 67edbf744c..eb75e080fc 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp)
PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
"/e500-ccsr"));
- pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
- d->config[PCI_HEADER_TYPE] =
- (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
- PCI_HEADER_TYPE_BRIDGE;
-
memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0", &ccsr->ccsr_space,
0, int128_get64(ccsr->ccsr_space.size));
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 5cf0dabef3..c4fe06ea2a 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -685,6 +685,8 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
int i, j, k;
dev = qdev_create(NULL, TYPE_OPENPIC);
+ object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev),
+ &error_fatal);
qdev_prop_set_uint32(dev, "model", params->mpic_version);
qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
@@ -884,6 +886,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* PCI */
dev = qdev_create(NULL, "e500-pcihost");
+ object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
+ &error_abort);
qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
qdev_init_nofail(dev);
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index c35c439d81..9475e8479c 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -77,8 +77,7 @@ static const char *pnv_chip_core_typename(const PnvChip *o)
* that has a different "affinity". In practice, it means one range
* per chip.
*/
-static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start,
- hwaddr size)
+static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size)
{
char *mem_name;
uint64_t mem_reg_property[2];
@@ -119,7 +118,7 @@ static int get_cpus_node(void *fdt)
* device tree, used in XSCOM to address cores and in interrupt
* servers.
*/
-static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
+static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
{
CPUState *cs = CPU(DEVICE(pc->threads));
DeviceClass *dc = DEVICE_GET_CLASS(cs);
@@ -228,8 +227,8 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
servers_prop, sizeof(servers_prop))));
}
-static void powernv_populate_icp(PnvChip *chip, void *fdt, uint32_t pir,
- uint32_t nr_threads)
+static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir,
+ uint32_t nr_threads)
{
uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
char *name;
@@ -277,13 +276,13 @@ static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt)
return offset;
}
-static void powernv_populate_chip(PnvChip *chip, void *fdt)
+static void pnv_dt_chip(PnvChip *chip, void *fdt)
{
const char *typename = pnv_chip_core_typename(chip);
size_t typesize = object_type_get_instance_size(typename);
int i;
- pnv_xscom_populate(chip, fdt, 0);
+ pnv_dt_xscom(chip, fdt, 0);
/* The default LPC bus of a multichip system is on chip 0. It's
* recognized by the firmware (skiboot) using a "primary"
@@ -298,20 +297,18 @@ static void powernv_populate_chip(PnvChip *chip, void *fdt)
for (i = 0; i < chip->nr_cores; i++) {
PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize);
- powernv_create_core_node(chip, pnv_core, fdt);
+ pnv_dt_core(chip, pnv_core, fdt);
/* Interrupt Control Presenters (ICP). One per core. */
- powernv_populate_icp(chip, fdt, pnv_core->pir,
- CPU_CORE(pnv_core)->nr_threads);
+ pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads);
}
if (chip->ram_size) {
- powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start,
- chip->ram_size);
+ pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size);
}
}
-static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off)
+static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off)
{
uint32_t io_base = d->ioport_id;
uint32_t io_regs[] = {
@@ -331,7 +328,7 @@ static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off)
_FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00")));
}
-static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off)
+static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off)
{
const char compatible[] = "ns16550\0pnpPNP,501";
uint32_t io_base = d->ioport_id;
@@ -362,7 +359,7 @@ static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off)
_FDT((fdt_setprop_string(fdt, node, "device_type", "serial")));
}
-static void powernv_populate_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
+static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off)
{
const char compatible[] = "bt\0ipmi-bt";
uint32_t io_base;
@@ -401,17 +398,17 @@ typedef struct ForeachPopulateArgs {
int offset;
} ForeachPopulateArgs;
-static int powernv_populate_isa_device(DeviceState *dev, void *opaque)
+static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
{
ForeachPopulateArgs *args = opaque;
ISADevice *d = ISA_DEVICE(dev);
if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
- powernv_populate_rtc(d, args->fdt, args->offset);
+ pnv_dt_rtc(d, args->fdt, args->offset);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) {
- powernv_populate_serial(d, args->fdt, args->offset);
+ pnv_dt_serial(d, args->fdt, args->offset);
} else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) {
- powernv_populate_ipmi_bt(d, args->fdt, args->offset);
+ pnv_dt_ipmi_bt(d, args->fdt, args->offset);
} else {
error_report("unknown isa device %s@i%x", qdev_fw_name(dev),
d->ioport_id);
@@ -420,7 +417,7 @@ static int powernv_populate_isa_device(DeviceState *dev, void *opaque)
return 0;
}
-static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset)
+static void pnv_dt_isa(ISABus *bus, void *fdt, int lpc_offset)
{
ForeachPopulateArgs args = {
.fdt = fdt,
@@ -429,14 +426,13 @@ static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset)
/* ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach() */
- qbus_walk_children(BUS(bus), powernv_populate_isa_device,
- NULL, NULL, NULL, &args);
+ qbus_walk_children(BUS(bus), pnv_dt_isa_device, NULL, NULL, NULL, &args);
}
-static void *powernv_create_fdt(MachineState *machine)
+static void *pnv_dt_create(MachineState *machine)
{
const char plat_compat[] = "qemu,powernv\0ibm,powernv";
- PnvMachineState *pnv = POWERNV_MACHINE(machine);
+ PnvMachineState *pnv = PNV_MACHINE(machine);
void *fdt;
char *buf;
int off;
@@ -479,15 +475,15 @@ static void *powernv_create_fdt(MachineState *machine)
/* Populate device tree for each chip */
for (i = 0; i < pnv->num_chips; i++) {
- powernv_populate_chip(pnv->chips[i], fdt);
+ pnv_dt_chip(pnv->chips[i], fdt);
}
/* Populate ISA devices on chip 0 */
lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt);
- powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset);
+ pnv_dt_isa(pnv->isa_bus, fdt, lpc_offset);
if (pnv->bmc) {
- pnv_bmc_populate_sensors(pnv->bmc, fdt);
+ pnv_dt_bmc_sensors(pnv->bmc, fdt);
}
return fdt;
@@ -495,17 +491,17 @@ static void *powernv_create_fdt(MachineState *machine)
static void pnv_powerdown_notify(Notifier *n, void *opaque)
{
- PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine());
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
if (pnv->bmc) {
pnv_bmc_powerdown(pnv->bmc);
}
}
-static void ppc_powernv_reset(void)
+static void pnv_reset(void)
{
MachineState *machine = MACHINE(qdev_get_machine());
- PnvMachineState *pnv = POWERNV_MACHINE(machine);
+ PnvMachineState *pnv = PNV_MACHINE(machine);
void *fdt;
Object *obj;
@@ -524,7 +520,7 @@ static void ppc_powernv_reset(void)
pnv->bmc = IPMI_BMC(obj);
}
- fdt = powernv_create_fdt(machine);
+ fdt = pnv_dt_create(machine);
/* Pack resulting tree */
_FDT((fdt_pack(fdt)));
@@ -552,9 +548,9 @@ static ISABus *pnv_isa_create(PnvChip *chip)
return isa_bus;
}
-static void ppc_powernv_init(MachineState *machine)
+static void pnv_init(MachineState *machine)
{
- PnvMachineState *pnv = POWERNV_MACHINE(machine);
+ PnvMachineState *pnv = PNV_MACHINE(machine);
MemoryRegion *ram;
char *fw_filename;
long fw_size;
@@ -567,7 +563,7 @@ static void ppc_powernv_init(MachineState *machine)
}
ram = g_new(MemoryRegion, 1);
- memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram",
+ memory_region_allocate_system_memory(ram, NULL, "pnv.ram",
machine->ram_size);
memory_region_add_subregion(get_system_memory(), 0, ram);
@@ -655,7 +651,7 @@ static void ppc_powernv_init(MachineState *machine)
serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS);
/* Create an RTC ISA device too */
- rtc_init(pnv->isa_bus, 2000, NULL);
+ mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
/* OpenPOWER systems use a IPMI SEL Event message to notify the
* host to powerdown */
@@ -974,7 +970,7 @@ static void pnv_chip_class_init(ObjectClass *klass, void *data)
static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
{
- PnvMachineState *pnv = POWERNV_MACHINE(xi);
+ PnvMachineState *pnv = PNV_MACHINE(xi);
int i;
for (i = 0; i < pnv->num_chips; i++) {
@@ -987,7 +983,7 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
static void pnv_ics_resend(XICSFabric *xi)
{
- PnvMachineState *pnv = POWERNV_MACHINE(xi);
+ PnvMachineState *pnv = PNV_MACHINE(xi);
int i;
for (i = 0; i < pnv->num_chips; i++) {
@@ -1021,7 +1017,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
static void pnv_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon)
{
- PnvMachineState *pnv = POWERNV_MACHINE(obj);
+ PnvMachineState *pnv = PNV_MACHINE(obj);
int i;
CPUState *cs;
@@ -1039,13 +1035,13 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp);
+ visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp);
}
static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- PnvMachineState *pnv = POWERNV_MACHINE(obj);
+ PnvMachineState *pnv = PNV_MACHINE(obj);
uint32_t num_chips;
Error *local_err = NULL;
@@ -1067,13 +1063,13 @@ static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name,
pnv->num_chips = num_chips;
}
-static void powernv_machine_initfn(Object *obj)
+static void pnv_machine_initfn(Object *obj)
{
- PnvMachineState *pnv = POWERNV_MACHINE(obj);
+ PnvMachineState *pnv = PNV_MACHINE(obj);
pnv->num_chips = 1;
}
-static void powernv_machine_class_props_init(ObjectClass *oc)
+static void pnv_machine_class_props_init(ObjectClass *oc)
{
object_class_property_add(oc, "num-chips", "uint32",
pnv_get_num_chips, pnv_set_num_chips,
@@ -1083,15 +1079,15 @@ static void powernv_machine_class_props_init(ObjectClass *oc)
NULL);
}
-static void powernv_machine_class_init(ObjectClass *oc, void *data)
+static void pnv_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
mc->desc = "IBM PowerNV (Non-Virtualized)";
- mc->init = ppc_powernv_init;
- mc->reset = ppc_powernv_reset;
+ mc->init = pnv_init;
+ mc->reset = pnv_reset;
mc->max_cpus = MAX_CPUS;
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
@@ -1104,7 +1100,7 @@ static void powernv_machine_class_init(ObjectClass *oc, void *data)
xic->ics_resend = pnv_ics_resend;
ispc->print_info = pnv_pic_print_info;
- powernv_machine_class_props_init(oc);
+ pnv_machine_class_props_init(oc);
}
#define DEFINE_PNV_CHIP_TYPE(type, class_initfn) \
@@ -1116,11 +1112,11 @@ static void powernv_machine_class_init(ObjectClass *oc, void *data)
static const TypeInfo types[] = {
{
- .name = TYPE_POWERNV_MACHINE,
+ .name = TYPE_PNV_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(PnvMachineState),
- .instance_init = powernv_machine_initfn,
- .class_init = powernv_machine_class_init,
+ .instance_init = pnv_machine_initfn,
+ .class_init = pnv_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ TYPE_INTERRUPT_STATS_PROVIDER },
diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c
index 7b60b4c360..b2cf441ee7 100644
--- a/hw/ppc/pnv_bmc.c
+++ b/hw/ppc/pnv_bmc.c
@@ -73,7 +73,7 @@ void pnv_bmc_powerdown(IPMIBmc *bmc)
pnv_gen_oem_sel(bmc, SOFT_OFF);
}
-void pnv_bmc_populate_sensors(IPMIBmc *bmc, void *fdt)
+void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt)
{
int offset;
int i;
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 82ff440b33..7e8a76df44 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -37,7 +37,7 @@ static const char *pnv_core_cpu_typename(PnvCore *pc)
return cpu_type;
}
-static void powernv_cpu_reset(void *opaque)
+static void pnv_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
@@ -54,7 +54,7 @@ static void powernv_cpu_reset(void *opaque)
env->msr |= MSR_HVB; /* Hypervisor mode */
}
-static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
+static void pnv_cpu_init(PowerPCCPU *cpu, Error **errp)
{
CPUPPCState *env = &cpu->env;
int core_pir;
@@ -73,7 +73,7 @@ static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
- qemu_register_reset(powernv_cpu_reset, cpu);
+ qemu_register_reset(pnv_cpu_reset, cpu);
}
/*
@@ -126,7 +126,6 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp)
Error *local_err = NULL;
CPUState *cs = CPU(child);
PowerPCCPU *cpu = POWERPC_CPU(cs);
- Object *obj;
object_property_set_bool(child, true, "realized", &local_err);
if (local_err) {
@@ -134,21 +133,14 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp)
return;
}
- obj = object_new(TYPE_PNV_ICP);
- object_property_add_child(child, "icp", obj, NULL);
- object_unref(obj);
- object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(xi),
- &error_abort);
- object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort);
- object_property_set_bool(obj, true, "realized", &local_err);
+ cpu->intc = icp_create(child, TYPE_PNV_ICP, xi, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
- powernv_cpu_init(cpu, &local_err);
+ pnv_cpu_init(cpu, &local_err);
if (local_err) {
- object_unparent(obj);
error_propagate(errp, local_err);
return;
}
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index f03a80a29b..c42b4a8f6c 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -92,7 +92,7 @@ enum {
#define LPC_HC_REGS_OPB_SIZE 0x00001000
-static int pnv_lpc_populate(PnvXScomInterface *dev, void *fdt, int xscom_offset)
+static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
{
const char compat[] = "ibm,power8-lpc\0ibm,lpc";
char *name;
@@ -146,13 +146,13 @@ static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data,
return success;
}
-#define ECCB_CTL_READ (1ull << (63 - 15))
+#define ECCB_CTL_READ PPC_BIT(15)
#define ECCB_CTL_SZ_LSH (63 - 7)
-#define ECCB_CTL_SZ_MASK (0xfull << ECCB_CTL_SZ_LSH)
-#define ECCB_CTL_ADDR_MASK 0xffffffffu;
+#define ECCB_CTL_SZ_MASK PPC_BITMASK(4, 7)
+#define ECCB_CTL_ADDR_MASK PPC_BITMASK(32, 63)
-#define ECCB_STAT_OP_DONE (1ull << (63 - 52))
-#define ECCB_STAT_OP_ERR (1ull << (63 - 52))
+#define ECCB_STAT_OP_DONE PPC_BIT(52)
+#define ECCB_STAT_OP_ERR PPC_BIT(52)
#define ECCB_STAT_RD_DATA_LSH (63 - 37)
#define ECCB_STAT_RD_DATA_MASK (0xffffffff << ECCB_STAT_RD_DATA_LSH)
@@ -482,7 +482,7 @@ static void pnv_lpc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
- xdc->populate = pnv_lpc_populate;
+ xdc->dt_xscom = pnv_lpc_dt_xscom;
dc->realize = pnv_lpc_realize;
}
@@ -515,7 +515,7 @@ type_init(pnv_lpc_register_types)
*/
static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level)
{
- PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine());
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
uint32_t old_state = pnv->cpld_irqstate;
PnvLpcController *lpc = PNV_LPC(opaque);
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 9876c26622..5b969127c3 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -510,7 +510,7 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
}
}
-static int pnv_psi_populate(PnvXScomInterface *dev, void *fdt, int xscom_offset)
+static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset)
{
const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x";
char *name;
@@ -546,7 +546,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
- xdc->populate = pnv_psi_populate;
+ xdc->dt_xscom = pnv_psi_dt_xscom;
dc->realize = pnv_psi_realize;
dc->props = pnv_psi_properties;
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index 38bc85f117..e51d634f40 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -207,15 +207,15 @@ typedef struct ForeachPopulateArgs {
int xscom_offset;
} ForeachPopulateArgs;
-static int xscom_populate_child(Object *child, void *opaque)
+static int xscom_dt_child(Object *child, void *opaque)
{
if (object_dynamic_cast(child, TYPE_PNV_XSCOM_INTERFACE)) {
ForeachPopulateArgs *args = opaque;
PnvXScomInterface *xd = PNV_XSCOM_INTERFACE(child);
PnvXScomInterfaceClass *xc = PNV_XSCOM_INTERFACE_GET_CLASS(xd);
- if (xc->populate) {
- _FDT((xc->populate(xd, args->fdt, args->xscom_offset)));
+ if (xc->dt_xscom) {
+ _FDT((xc->dt_xscom(xd, args->fdt, args->xscom_offset)));
}
}
return 0;
@@ -224,7 +224,7 @@ static int xscom_populate_child(Object *child, void *opaque)
static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom";
static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom";
-int pnv_xscom_populate(PnvChip *chip, void *fdt, int root_offset)
+int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset)
{
uint64_t reg[] = { cpu_to_be64(PNV_XSCOM_BASE(chip)),
cpu_to_be64(PNV_XSCOM_SIZE) };
@@ -255,7 +255,7 @@ int pnv_xscom_populate(PnvChip *chip, void *fdt, int root_offset)
args.fdt = fdt;
args.xscom_offset = xscom_offset;
- object_child_foreach(OBJECT(chip), xscom_populate_child, &args);
+ object_child_foreach(OBJECT(chip), xscom_dt_child, &args);
return 0;
}
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 6f8accc397..af08ac319a 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -42,6 +42,7 @@
#include "hw/loader.h"
#include "hw/timer/mc146818rtc.h"
#include "hw/isa/pc87312.h"
+#include "hw/net/ne2000-isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/arch_init.h"
#include "sysemu/kvm.h"
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 1ac7eb0f8c..dfd352c473 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -641,6 +641,26 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
}
+static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
+{
+ MemoryDeviceInfoList *info;
+
+ for (info = list; info; info = info->next) {
+ MemoryDeviceInfo *value = info->value;
+
+ if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) {
+ PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data;
+
+ if (pcdimm_info->addr >= addr &&
+ addr < (pcdimm_info->addr + pcdimm_info->size)) {
+ return pcdimm_info->node;
+ }
+ }
+ }
+
+ return -1;
+}
+
/*
* Adds ibm,dynamic-reconfiguration-memory node.
* Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
@@ -658,6 +678,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
lmb_size;
uint32_t *int_buf, *cur_index, buf_len;
int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
+ MemoryDeviceInfoList *dimms = NULL;
/*
* Don't create the node if there is no hotpluggable memory
@@ -692,6 +713,11 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
goto out;
}
+ if (hotplug_lmb_start) {
+ MemoryDeviceInfoList **prev = &dimms;
+ qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
+ }
+
/* ibm,dynamic-memory */
int_buf[0] = cpu_to_be32(nr_lmbs);
cur_index++;
@@ -709,7 +735,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc));
dynamic_memory[3] = cpu_to_be32(0); /* reserved */
- dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL));
+ dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr));
if (memory_region_present(get_system_memory(), addr)) {
dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
} else {
@@ -732,6 +758,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
}
+ qapi_free_MemoryDeviceInfoList(dimms);
ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
if (ret < 0) {
goto out;
@@ -916,9 +943,8 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
_FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
RTAS_EVENT_SCAN_RATE));
- if (msi_nonbroken) {
- _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
- }
+ g_assert(msi_nonbroken);
+ _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0));
/*
* According to PAPR, rtas ibm,os-term does not guarantee a return
@@ -1427,7 +1453,7 @@ static int spapr_reset_drcs(Object *child, void *opaque)
return 0;
}
-static void ppc_spapr_reset(void)
+static void spapr_machine_reset(void)
{
MachineState *machine = MACHINE(qdev_get_machine());
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
@@ -1440,7 +1466,10 @@ static void ppc_spapr_reset(void)
/* Check for unknown sysbus devices */
foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
- if (kvm_enabled() && kvmppc_has_cap_mmu_radix()) {
+ first_ppc_cpu = POWERPC_CPU(first_cpu);
+ if (kvm_enabled() && kvmppc_has_cap_mmu_radix() &&
+ ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
+ spapr->max_compat_pvr)) {
/* If using KVM with radix mode available, VCPUs can be started
* without a HPT because KVM will start them in radix mode.
* Set the GR bit in PATB so that we know there is no HPT. */
@@ -1475,7 +1504,7 @@ static void ppc_spapr_reset(void)
spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new();
- ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
+ ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
}
fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size);
@@ -1499,7 +1528,6 @@ static void ppc_spapr_reset(void)
g_free(fdt);
/* Set up the entry state */
- first_ppc_cpu = POWERPC_CPU(first_cpu);
first_ppc_cpu->env.gpr[3] = fdt_addr;
first_ppc_cpu->env.gpr[5] = 0;
first_cpu->halted = 0;
@@ -2265,7 +2293,7 @@ out:
}
/* pSeries LPAR / sPAPR hardware init */
-static void ppc_spapr_init(MachineState *machine)
+static void spapr_machine_init(MachineState *machine)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
@@ -2793,7 +2821,7 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
}
-static void spapr_machine_initfn(Object *obj)
+static void spapr_instance_init(Object *obj)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
@@ -3180,12 +3208,10 @@ void spapr_core_release(DeviceState *dev)
if (smc->pre_2_10_has_unused_icps) {
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc));
- size_t size = object_type_get_instance_size(scc->cpu_type);
int i;
for (i = 0; i < cc->nr_threads; i++) {
- CPUState *cs = CPU(sc->threads + i * size);
+ CPUState *cs = CPU(sc->threads[i]);
pre_2_10_vmstate_register_dummy_icp(cs->cpu_index);
}
@@ -3231,7 +3257,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
- CPUState *cs = CPU(core->threads);
+ CPUState *cs = CPU(core->threads[0]);
sPAPRDRConnector *drc;
Error *local_err = NULL;
int smt = kvmppc_smt_threads();
@@ -3276,15 +3302,12 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
core_slot->cpu = OBJECT(dev);
if (smc->pre_2_10_has_unused_icps) {
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc));
- size_t size = object_type_get_instance_size(scc->cpu_type);
int i;
for (i = 0; i < cc->nr_threads; i++) {
sPAPRCPUCore *sc = SPAPR_CPU_CORE(dev);
- void *obj = sc->threads + i * size;
- cs = CPU(obj);
+ cs = CPU(sc->threads[i]);
pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
}
}
@@ -3563,6 +3586,139 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
return cpu ? ICP(cpu->intc) : NULL;
}
+#define ICS_IRQ_FREE(ics, srcno) \
+ (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
+
+static int ics_find_free_block(ICSState *ics, int num, int alignnum)
+{
+ int first, i;
+
+ for (first = 0; first < ics->nr_irqs; first += alignnum) {
+ if (num > (ics->nr_irqs - first)) {
+ return -1;
+ }
+ for (i = first; i < first + num; ++i) {
+ if (!ICS_IRQ_FREE(ics, i)) {
+ break;
+ }
+ }
+ if (i == (first + num)) {
+ return first;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Allocate the IRQ number and set the IRQ type, LSI or MSI
+ */
+static void spapr_irq_set_lsi(sPAPRMachineState *spapr, int irq, bool lsi)
+{
+ ics_set_irq_type(spapr->ics, irq - spapr->ics->offset, lsi);
+}
+
+int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi,
+ Error **errp)
+{
+ ICSState *ics = spapr->ics;
+ int irq;
+
+ if (!ics) {
+ return -1;
+ }
+ if (irq_hint) {
+ if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
+ error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
+ return -1;
+ }
+ irq = irq_hint;
+ } else {
+ irq = ics_find_free_block(ics, 1, 1);
+ if (irq < 0) {
+ error_setg(errp, "can't allocate IRQ: no IRQ left");
+ return -1;
+ }
+ irq += ics->offset;
+ }
+
+ spapr_irq_set_lsi(spapr, irq, lsi);
+ trace_spapr_irq_alloc(irq);
+
+ return irq;
+}
+
+/*
+ * Allocate block of consecutive IRQs, and return the number of the first IRQ in
+ * the block. If align==true, aligns the first IRQ number to num.
+ */
+int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi,
+ bool align, Error **errp)
+{
+ ICSState *ics = spapr->ics;
+ int i, first = -1;
+
+ if (!ics) {
+ return -1;
+ }
+
+ /*
+ * MSIMesage::data is used for storing VIRQ so
+ * it has to be aligned to num to support multiple
+ * MSI vectors. MSI-X is not affected by this.
+ * The hint is used for the first IRQ, the rest should
+ * be allocated continuously.
+ */
+ if (align) {
+ assert((num == 1) || (num == 2) || (num == 4) ||
+ (num == 8) || (num == 16) || (num == 32));
+ first = ics_find_free_block(ics, num, num);
+ } else {
+ first = ics_find_free_block(ics, num, 1);
+ }
+ if (first < 0) {
+ error_setg(errp, "can't find a free %d-IRQ block", num);
+ return -1;
+ }
+
+ first += ics->offset;
+ for (i = first; i < first + num; ++i) {
+ spapr_irq_set_lsi(spapr, i, lsi);
+ }
+
+ trace_spapr_irq_alloc_block(first, num, lsi, align);
+
+ return first;
+}
+
+void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
+{
+ ICSState *ics = spapr->ics;
+ int srcno = irq - ics->offset;
+ int i;
+
+ if (ics_valid_irq(ics, irq)) {
+ trace_spapr_irq_free(0, irq, num);
+ for (i = srcno; i < srcno + num; ++i) {
+ if (ICS_IRQ_FREE(ics, i)) {
+ trace_spapr_irq_free_warn(0, i + ics->offset);
+ }
+ memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
+ }
+ }
+}
+
+qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
+{
+ ICSState *ics = spapr->ics;
+
+ if (ics_valid_irq(ics, irq)) {
+ return ics->qirqs[irq - ics->offset];
+ }
+
+ return NULL;
+}
+
static void spapr_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon)
{
@@ -3622,8 +3778,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
* functions for the specific versioned machine types can override
* these details for backwards compatibility
*/
- mc->init = ppc_spapr_init;
- mc->reset = ppc_spapr_reset;
+ mc->init = spapr_machine_init;
+ mc->reset = spapr_machine_reset;
mc->block_default_type = IF_SCSI;
mc->max_cpus = 1024;
mc->no_parallel = 1;
@@ -3670,7 +3826,7 @@ static const TypeInfo spapr_machine_info = {
.parent = TYPE_MACHINE,
.abstract = true,
.instance_size = sizeof(sPAPRMachineState),
- .instance_init = spapr_machine_initfn,
+ .instance_init = spapr_instance_init,
.instance_finalize = spapr_machine_finalizefn,
.class_size = sizeof(sPAPRMachineClass),
.class_init = spapr_machine_class_init,
@@ -3714,27 +3870,47 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix)
/*
+ * pseries-2.12
+ */
+static void spapr_machine_2_12_instance_options(MachineState *machine)
+{
+}
+
+static void spapr_machine_2_12_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE(2_12, "2.12", true);
+
+/*
* pseries-2.11
*/
+#define SPAPR_COMPAT_2_11 \
+ HW_COMPAT_2_11
+
static void spapr_machine_2_11_instance_options(MachineState *machine)
{
+ spapr_machine_2_12_instance_options(machine);
}
static void spapr_machine_2_11_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ spapr_machine_2_12_class_options(mc);
+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11);
}
-DEFINE_SPAPR_MACHINE(2_11, "2.11", true);
+DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
/*
* pseries-2.10
*/
#define SPAPR_COMPAT_2_10 \
- HW_COMPAT_2_10 \
+ HW_COMPAT_2_10
static void spapr_machine_2_10_instance_options(MachineState *machine)
{
+ spapr_machine_2_11_instance_options(machine);
}
static void spapr_machine_2_10_class_options(MachineClass *mc)
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 3a4c174012..ac19b2e0b7 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -6,6 +6,7 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "hw/cpu/core.h"
#include "hw/ppc/spapr_cpu_core.h"
#include "target/ppc/cpu.h"
@@ -26,6 +27,7 @@ static void spapr_cpu_reset(void *opaque)
PowerPCCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
cpu_reset(cs);
@@ -35,6 +37,13 @@ static void spapr_cpu_reset(void *opaque)
cs->halted = 1;
env->spr[SPR_HIOR] = 0;
+
+ /* Disable Power-saving mode Exit Cause exceptions for the CPU.
+ * This can cause issues when rebooting the guest if a secondary
+ * is awaken */
+ if (cs != first_cpu) {
+ env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
+ }
}
static void spapr_cpu_destroy(PowerPCCPU *cpu)
@@ -79,13 +88,11 @@ const char *spapr_get_cpu_core_type(const char *cpu_type)
static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp)
{
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
- size_t size = object_type_get_instance_size(scc->cpu_type);
CPUCore *cc = CPU_CORE(dev);
int i;
for (i = 0; i < cc->nr_threads; i++) {
- void *obj = sc->threads + i * size;
+ Object *obj = OBJECT(sc->threads[i]);
DeviceState *dev = DEVICE(obj);
CPUState *cs = CPU(dev);
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -104,7 +111,6 @@ static void spapr_cpu_core_realize_child(Object *child,
Error *local_err = NULL;
CPUState *cs = CPU(child);
PowerPCCPU *cpu = POWERPC_CPU(cs);
- Object *obj;
object_property_set_bool(child, true, "realized", &local_err);
if (local_err) {
@@ -116,21 +122,14 @@ static void spapr_cpu_core_realize_child(Object *child,
goto error;
}
- obj = object_new(spapr->icp_type);
- object_property_add_child(child, "icp", obj, &error_abort);
- object_unref(obj);
- object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(spapr),
- &error_abort);
- object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort);
- object_property_set_bool(obj, true, "realized", &local_err);
+ cpu->intc = icp_create(child, spapr->icp_type, XICS_FABRIC(spapr),
+ &local_err);
if (local_err) {
- goto free_icp;
+ goto error;
}
return;
-free_icp:
- object_unparent(obj);
error:
error_propagate(errp, local_err);
}
@@ -146,9 +145,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
CPUCore *cc = CPU_CORE(OBJECT(dev));
- size_t size;
Error *local_err = NULL;
- void *obj;
+ Object *obj;
int i, j;
if (!spapr) {
@@ -156,18 +154,16 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
return;
}
- size = object_type_get_instance_size(scc->cpu_type);
- sc->threads = g_malloc0(size * cc->nr_threads);
+ sc->threads = g_new(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
char id[32];
CPUState *cs;
PowerPCCPU *cpu;
- obj = sc->threads + i * size;
+ obj = object_new(scc->cpu_type);
- object_initialize(obj, size, scc->cpu_type);
cs = CPU(obj);
- cpu = POWERPC_CPU(cs);
+ cpu = sc->threads[i] = POWERPC_CPU(obj);
cs->cpu_index = cc->core_id + i;
cpu->vcpu_id = (cc->core_id * spapr->vsmt / smp_threads) + i;
if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->vcpu_id)) {
@@ -192,7 +188,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
}
for (j = 0; j < cc->nr_threads; j++) {
- obj = sc->threads + j * size;
+ obj = OBJECT(sc->threads[j]);
spapr_cpu_core_realize_child(obj, spapr, &local_err);
if (local_err) {
@@ -203,7 +199,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
err:
while (--i >= 0) {
- obj = sc->threads + i * size;
+ obj = OBJECT(sc->threads[i]);
object_unparent(obj);
}
g_free(sc->threads);
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index e377fc7dde..86836f0626 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -282,8 +282,7 @@ void spapr_dt_events(sPAPRMachineState *spapr, void *fdt)
continue;
}
- interrupts[0] = cpu_to_be32(source->irq);
- interrupts[1] = 0;
+ spapr_dt_xics_irq(interrupts, source->irq, false);
_FDT(node_offset = fdt_add_subnode(fdt, event_sources, source_name));
_FDT(fdt_setprop(fdt, node_offset, "interrupts", interrupts,
@@ -293,9 +292,6 @@ void spapr_dt_events(sPAPRMachineState *spapr, void *fdt)
irq_ranges[count++] = cpu_to_be32(1);
}
- irq_ranges[count] = cpu_to_be32(count);
- count++;
-
_FDT((fdt_setprop(fdt, event_sources, "interrupt-controller", NULL, 0)));
_FDT((fdt_setprop_cell(fdt, event_sources, "#interrupt-cells", 2)));
_FDT((fdt_setprop(fdt, event_sources, "interrupt-ranges",
@@ -472,9 +468,8 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
rtas_event_log_queue(spapr, entry);
- qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr),
- rtas_event_log_to_irq(spapr,
- RTAS_LOG_TYPE_EPOW)));
+ qemu_irq_pulse(spapr_qirq(spapr,
+ rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_EPOW)));
}
static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
@@ -556,9 +551,8 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
rtas_event_log_queue(spapr, entry);
- qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr),
- rtas_event_log_to_irq(spapr,
- RTAS_LOG_TYPE_HOTPLUG)));
+ qemu_irq_pulse(spapr_qirq(spapr,
+ rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_HOTPLUG)));
}
void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc)
@@ -678,7 +672,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,
spapr_event_sources_get_source(spapr->event_sources, i);
g_assert(source->enabled);
- qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), source->irq));
+ qemu_irq_pulse(spapr_qirq(spapr, source->irq));
}
}
@@ -718,7 +712,7 @@ void spapr_events_init(sPAPRMachineState *spapr)
spapr->event_sources = spapr_event_sources_new();
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW,
- spapr_ics_alloc(spapr->ics, 0, false,
+ spapr_irq_alloc(spapr, 0, false,
&error_fatal));
/* NOTE: if machine supports modern/dedicated hotplug event source,
@@ -731,7 +725,7 @@ void spapr_events_init(sPAPRMachineState *spapr)
*/
if (spapr->use_hotplug_event_source) {
spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG,
- spapr_ics_alloc(spapr->ics, 0, false,
+ spapr_irq_alloc(spapr, 0, false,
&error_fatal));
}
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index be22a6b289..51eba52e86 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -13,7 +13,6 @@
#include "trace.h"
#include "kvm_ppc.h"
#include "hw/ppc/spapr_ovec.h"
-#include "qemu/error-report.h"
#include "mmu-book3s-v3.h"
struct SPRSyncState {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index f38be2f0b4..37f18b3d32 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -314,7 +314,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return;
}
- spapr_ics_free(spapr->ics, msi->first_irq, msi->num);
+ spapr_irq_free(spapr, msi->first_irq, msi->num);
if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0);
}
@@ -352,7 +352,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
/* Allocate MSIs */
- irq = spapr_ics_alloc_block(spapr->ics, req_num, false,
+ irq = spapr_irq_alloc_block(spapr, req_num, false,
ret_intr_type == RTAS_TYPE_MSI, &err);
if (err) {
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
@@ -363,7 +363,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
/* Release previous MSIs */
if (msi) {
- spapr_ics_free(spapr->ics, msi->first_irq, msi->num);
+ spapr_irq_free(spapr, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr);
}
@@ -723,7 +723,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr,
trace_spapr_pci_msi_write(addr, data, irq);
- qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), irq));
+ qemu_irq_pulse(spapr_qirq(spapr, irq));
}
static const MemoryRegionOps spapr_msi_ops = {
@@ -1675,7 +1675,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
uint32_t irq;
Error *local_err = NULL;
- irq = spapr_ics_alloc_block(spapr->ics, 1, true, false, &local_err);
+ irq = spapr_irq_alloc_block(spapr, 1, true, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: ");
@@ -1696,9 +1696,9 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
/* DMA setup */
if (((sphb->page_size_mask & qemu_getrampagesize()) == 0)
&& kvm_enabled()) {
- error_report("System page size 0x%lx is not enabled in page_size_mask "
- "(0x%"PRIx64"). Performance may be slow",
- qemu_getrampagesize(), sphb->page_size_mask);
+ warn_report("System page size 0x%lx is not enabled in page_size_mask "
+ "(0x%"PRIx64"). Performance may be slow",
+ qemu_getrampagesize(), sphb->page_size_mask);
}
for (i = 0; i < windows_supported; ++i) {
@@ -2121,8 +2121,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
irqmap[2] = 0;
irqmap[3] = cpu_to_be32(j+1);
irqmap[4] = cpu_to_be32(xics_phandle);
- irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
- irqmap[6] = cpu_to_be32(0x8);
+ spapr_dt_xics_irq(&irqmap[5], phb->lsi_table[lsi_num].irq, true);
}
}
/* Write interrupt map */
diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c
index 8448e0b024..053efb03bd 100644
--- a/hw/ppc/spapr_pci_vfio.c
+++ b/hw/ppc/spapr_pci_vfio.c
@@ -29,31 +29,6 @@
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
-#define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge"
-
-#define SPAPR_PCI_VFIO_HOST_BRIDGE(obj) \
- OBJECT_CHECK(sPAPRPHBVFIOState, (obj), TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE)
-
-typedef struct sPAPRPHBVFIOState sPAPRPHBVFIOState;
-
-struct sPAPRPHBVFIOState {
- sPAPRPHBState phb;
-
- int32_t iommugroupid;
-};
-
-static Property spapr_phb_vfio_properties[] = {
- DEFINE_PROP_INT32("iommu", sPAPRPHBVFIOState, iommugroupid, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_phb_vfio_instance_init(Object *obj)
-{
- if (!qtest_enabled()) {
- error_report("spapr-pci-vfio-host-bridge is deprecated");
- }
-}
-
bool spapr_phb_eeh_available(sPAPRPHBState *sphb)
{
return vfio_eeh_as_ok(&sphb->iommu_as);
@@ -218,25 +193,3 @@ int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb)
return RTAS_OUT_SUCCESS;
}
-
-static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->props = spapr_phb_vfio_properties;
-}
-
-static const TypeInfo spapr_phb_vfio_info = {
- .name = TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE,
- .parent = TYPE_SPAPR_PCI_HOST_BRIDGE,
- .instance_size = sizeof(sPAPRPHBVFIOState),
- .instance_init = spapr_phb_vfio_instance_init,
- .class_init = spapr_phb_vfio_class_init,
-};
-
-static void spapr_pci_vfio_register_types(void)
-{
- type_register_static(&spapr_phb_vfio_info);
-}
-
-type_init(spapr_pci_vfio_register_types)
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index cdf0b607a0..2b89e1d448 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -162,6 +162,8 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
if (cpu != NULL) {
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ Error *local_err = NULL;
if (!cs->halted) {
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
@@ -173,7 +175,19 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
* new cpu enters */
kvm_cpu_synchronize_state(cs);
+ /* Set compatibility mode to match existing cpus */
+ ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
+ return;
+ }
+
env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
+
+ /* Enable Power-saving mode Exit Cause exceptions for the new CPU */
+ env->spr[SPR_LPCR] |= pcc->lpcr_pm;
+
env->nip = start;
env->gpr[3] = r3;
cs->halted = 0;
@@ -197,19 +211,15 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
cs->halted = 1;
qemu_cpu_kick(cs);
- /*
- * While stopping a CPU, the guest calls H_CPPR which
- * effectively disables interrupts on XICS level.
- * However decrementer interrupts in TCG can still
- * wake the CPU up so here we disable interrupts in MSR
- * as well.
- * As rtas_start_cpu() resets the whole MSR anyway, there is
- * no need to bother with specific bits, we just clear it.
- */
- env->msr = 0;
+
+ /* Disable Power-saving mode Exit Cause exceptions for the CPU.
+ * This could deliver an interrupt on a dying CPU and crash the
+ * guest */
+ env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
}
static inline int sysparm_st(target_ulong addr, target_ulong len,
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index ea3bc8bd9e..472dd6f33a 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -126,8 +126,9 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
if (dev->irq) {
- uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
+ uint32_t ints_prop[2];
+ spapr_dt_xics_irq(ints_prop, dev->irq, false);
ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
sizeof(ints_prop));
if (ret < 0) {
@@ -454,7 +455,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
dev->qdev.id = id;
}
- dev->irq = spapr_ics_alloc(spapr->ics, dev->irq, false, &local_err);
+ dev->irq = spapr_irq_alloc(spapr, dev->irq, false, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 4a6a6490fa..b7c3e64b5e 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -12,6 +12,10 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "
# hw/ppc/spapr.c
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"
spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
+spapr_irq_alloc(int irq) "irq %d"
+spapr_irq_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d"
+spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
+spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free"
# hw/ppc/spapr_hcall.c
spapr_cas_pvr_try(uint32_t pvr) "0x%x"
diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c
index 081e3ef6f4..3af13ea027 100644
--- a/hw/s390x/3270-ccw.c
+++ b/hw/s390x/3270-ccw.c
@@ -104,7 +104,7 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
SubchDev *sch;
Error *err = NULL;
- sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp);
+ sch = css_create_sch(cdev->devno, cbus->squash_mcss, errp);
if (!sch) {
return;
}
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index c4a9735d71..a02d708239 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -99,6 +99,8 @@ VirtualCssBus *virtual_css_bus_init(void)
/* Create bridge device */
dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE);
+ object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE,
+ OBJECT(dev), NULL);
qdev_init_nofail(dev);
/* Create bus on bridge device */
@@ -123,6 +125,11 @@ static Property virtual_css_bridge_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static bool prop_get_true(Object *obj, Error **errp)
+{
+ return true;
+}
+
static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
{
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
@@ -131,6 +138,12 @@ static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
hc->unplug = ccw_device_unplug;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->props = virtual_css_bridge_properties;
+ object_class_property_add_bool(klass, "cssid-unrestricted",
+ prop_get_true, NULL, NULL);
+ object_class_property_set_description(klass, "cssid-unrestricted",
+ "A css device can use any cssid, regardless whether virtual"
+ " or not (read only, always true)",
+ NULL);
}
static const TypeInfo virtual_css_bridge_info = {
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index f6b5c807cd..1c526fd7e2 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -13,7 +13,6 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "hw/qdev.h"
-#include "qemu/error-report.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "exec/address-spaces.h"
@@ -1723,12 +1722,6 @@ void css_undo_stcrw(CRW *crw)
QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling);
}
-int css_do_tpi(IOIntCode *int_code, int lowcore)
-{
- /* No pending interrupts for !KVM. */
- return 0;
- }
-
int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid,
int rfmt, void *buf)
{
@@ -2370,22 +2363,12 @@ const PropertyInfo css_devid_ro_propinfo = {
.get = get_css_devid,
};
-SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
- Error **errp)
+SubchDev *css_create_sch(CssDevId bus_id, bool squash_mcss, Error **errp)
{
uint16_t schid = 0;
SubchDev *sch;
if (bus_id.valid) {
- if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) {
- error_setg(errp, "cssid %hhx not valid for %s devices",
- bus_id.cssid,
- (is_virtual ? "virtual" : "non-virtual"));
- return NULL;
- }
- }
-
- if (bus_id.valid) {
if (squash_mcss) {
bus_id.cssid = channel_subsys.default_cssid;
} else if (!channel_subsys.css[bus_id.cssid]) {
@@ -2396,19 +2379,8 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
bus_id.devid, &schid, errp)) {
return NULL;
}
- } else if (squash_mcss || is_virtual) {
- bus_id.cssid = channel_subsys.default_cssid;
-
- if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid,
- &bus_id.devid, &schid, errp)) {
- return NULL;
- }
} else {
- for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) {
- if (bus_id.cssid == VIRTUAL_CSSID) {
- continue;
- }
-
+ for (bus_id.cssid = channel_subsys.default_cssid;;) {
if (!channel_subsys.css[bus_id.cssid]) {
css_create_css_image(bus_id.cssid, false);
}
@@ -2418,7 +2390,8 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
NULL)) {
break;
}
- if (bus_id.cssid == MAX_CSSID) {
+ bus_id.cssid = (bus_id.cssid + 1) % MAX_CSSID;
+ if (bus_id.cssid == channel_subsys.default_cssid) {
error_setg(errp, "Virtual channel subsystem is full!");
return NULL;
}
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 0ef232ec27..4a9d4d2534 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -77,7 +77,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
goto out_err_propagate;
}
- sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err);
+ sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, &err);
if (!sch) {
goto out_mdevid_free;
}
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 560bd82a0f..2993f0ddef 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -284,6 +284,7 @@ struct S390PCIBusDevice {
uint64_t fmb_addr;
uint8_t isc;
uint16_t noi;
+ uint16_t maxstbl;
uint8_t sum;
S390MsixInfo msix;
AdapterRoutes routes;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 8e088f3dc9..be449210d9 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -142,7 +142,7 @@ out:
return rc;
}
-int clp_service_call(S390CPU *cpu, uint8_t r2)
+int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
{
ClpReqHdr *reqh;
ClpRspHdr *resh;
@@ -158,37 +158,40 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
}
if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
reqh = (ClpReqHdr *)buffer;
req_len = lduw_p(&reqh->len);
if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) {
- program_interrupt(env, PGM_OPERAND, 4);
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
req_len + sizeof(*resh))) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
resh = (ClpRspHdr *)(buffer + req_len);
res_len = lduw_p(&resh->len);
if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) {
- program_interrupt(env, PGM_OPERAND, 4);
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
if ((req_len + res_len) > 8192) {
- program_interrupt(env, PGM_OPERAND, 4);
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
req_len + res_len)) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
@@ -294,6 +297,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
stw_p(&resgrp->mui, 0);
stw_p(&resgrp->i, 128);
+ stw_p(&resgrp->maxstbl, 128);
resgrp->version = 0;
stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
@@ -308,19 +312,78 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
out:
if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer,
req_len + res_len)) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
setcc(cpu, cc);
return 0;
}
-int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
+/**
+ * Swap data contained in s390x big endian registers to little endian
+ * PCI bars.
+ *
+ * @ptr: a pointer to a uint64_t data field
+ * @len: the length of the valid data, must be 1,2,4 or 8
+ */
+static int zpci_endian_swap(uint64_t *ptr, uint8_t len)
+{
+ uint64_t data = *ptr;
+
+ switch (len) {
+ case 1:
+ break;
+ case 2:
+ data = bswap16(data);
+ break;
+ case 4:
+ data = bswap32(data);
+ break;
+ case 8:
+ data = bswap64(data);
+ break;
+ default:
+ return -EINVAL;
+ }
+ *ptr = data;
+ return 0;
+}
+
+static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset,
+ uint8_t len)
+{
+ MemoryRegion *subregion;
+ uint64_t subregion_size;
+
+ QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
+ subregion_size = int128_get64(subregion->size);
+ if ((offset >= subregion->addr) &&
+ (offset + len) <= (subregion->addr + subregion_size)) {
+ mr = subregion;
+ break;
+ }
+ }
+ return mr;
+}
+
+static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
+ uint64_t offset, uint64_t *data, uint8_t len)
+{
+ MemoryRegion *mr;
+
+ mr = pbdev->pdev->io_regions[pcias].memory;
+ mr = s390_get_subregion(mr, offset, len);
+ offset -= mr->addr;
+ return memory_region_dispatch_read(mr, offset, data, len,
+ MEMTXATTRS_UNSPECIFIED);
+}
+
+int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
S390PCIBusDevice *pbdev;
uint64_t offset;
uint64_t data;
- MemoryRegion *mr;
MemTxResult result;
uint8_t len;
uint32_t fh;
@@ -329,12 +392,12 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
}
if (r2 & 0x1) {
- program_interrupt(env, PGM_SPECIFICATION, 4);
+ s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
return 0;
}
@@ -343,6 +406,11 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
len = env->regs[r2] & 0xf;
offset = env->regs[r2 + 1];
+ if (!(fh & FH_MASK_ENABLE)) {
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ }
+
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
DPRINTF("pcilg no pci dev\n");
@@ -351,12 +419,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
}
switch (pbdev->state) {
- case ZPCI_FS_RESERVED:
- case ZPCI_FS_STANDBY:
- case ZPCI_FS_DISABLED:
case ZPCI_FS_PERMANENT_ERROR:
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
@@ -365,44 +428,33 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
break;
}
- if (pcias < 6) {
- if ((8 - (offset & 0x7)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
+ switch (pcias) {
+ case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX:
+ if (!len || (len > (8 - (offset & 0x7)))) {
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
- mr = pbdev->pdev->io_regions[pcias].memory;
- result = memory_region_dispatch_read(mr, offset, &data, len,
- MEMTXATTRS_UNSPECIFIED);
+ result = zpci_read_bar(pbdev, pcias, offset, &data, len);
if (result != MEMTX_OK) {
- program_interrupt(env, PGM_OPERAND, 4);
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
- } else if (pcias == 15) {
- if ((4 - (offset & 0x3)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
+ break;
+ case ZPCI_CONFIG_BAR:
+ if (!len || (len > (4 - (offset & 0x3))) || len == 3) {
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
data = pci_host_config_read_common(
pbdev->pdev, offset, pci_config_size(pbdev->pdev), len);
- switch (len) {
- case 1:
- break;
- case 2:
- data = bswap16(data);
- break;
- case 4:
- data = bswap32(data);
- break;
- case 8:
- data = bswap64(data);
- break;
- default:
- program_interrupt(env, PGM_OPERAND, 4);
+ if (zpci_endian_swap(&data, len)) {
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
- } else {
- DPRINTF("invalid space\n");
+ break;
+ default:
+ DPRINTF("pcilg invalid space\n");
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
return 0;
@@ -413,24 +465,23 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
return 0;
}
-static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias)
+static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
+ uint64_t offset, uint64_t data, uint8_t len)
{
- if (pbdev->msix.available && pbdev->msix.table_bar == pcias &&
- offset >= pbdev->msix.table_offset &&
- offset < (pbdev->msix.table_offset +
- pbdev->msix.entries * PCI_MSIX_ENTRY_SIZE)) {
- return 1;
- } else {
- return 0;
- }
+ MemoryRegion *mr;
+
+ mr = pbdev->pdev->io_regions[pcias].memory;
+ mr = s390_get_subregion(mr, offset, len);
+ offset -= mr->addr;
+ return memory_region_dispatch_write(mr, offset, data, len,
+ MEMTXATTRS_UNSPECIFIED);
}
-int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
+int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
uint64_t offset, data;
S390PCIBusDevice *pbdev;
- MemoryRegion *mr;
MemTxResult result;
uint8_t len;
uint32_t fh;
@@ -439,12 +490,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
}
if (r2 & 0x1) {
- program_interrupt(env, PGM_SPECIFICATION, 4);
+ s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
return 0;
}
@@ -452,6 +503,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
pcias = (env->regs[r2] >> 16) & 0xf;
len = env->regs[r2] & 0xf;
offset = env->regs[r2 + 1];
+ data = env->regs[r1];
+
+ if (!(fh & FH_MASK_ENABLE)) {
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
+ return 0;
+ }
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
@@ -461,12 +518,10 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
}
switch (pbdev->state) {
- case ZPCI_FS_RESERVED:
- case ZPCI_FS_STANDBY:
- case ZPCI_FS_DISABLED:
+ /* ZPCI_FS_RESERVED, ZPCI_FS_STANDBY and ZPCI_FS_DISABLED
+ * are already covered by the FH_MASK_ENABLE check above
+ */
case ZPCI_FS_PERMANENT_ERROR:
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
@@ -475,52 +530,37 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
break;
}
- data = env->regs[r1];
- if (pcias < 6) {
- if ((8 - (offset & 0x7)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
+ switch (pcias) {
+ /* A ZPCI PCI card may use any BAR from BAR 0 to BAR 5 */
+ case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX:
+ /* Check length:
+ * A length of 0 is invalid and length should not cross a double word
+ */
+ if (!len || (len > (8 - (offset & 0x7)))) {
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
- if (trap_msix(pbdev, offset, pcias)) {
- offset = offset - pbdev->msix.table_offset;
- mr = &pbdev->pdev->msix_table_mmio;
- } else {
- mr = pbdev->pdev->io_regions[pcias].memory;
- }
-
- result = memory_region_dispatch_write(mr, offset, data, len,
- MEMTXATTRS_UNSPECIFIED);
+ result = zpci_write_bar(pbdev, pcias, offset, data, len);
if (result != MEMTX_OK) {
- program_interrupt(env, PGM_OPERAND, 4);
- return 0;
- }
- } else if (pcias == 15) {
- if ((4 - (offset & 0x3)) < len) {
- program_interrupt(env, PGM_OPERAND, 4);
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
- switch (len) {
- case 1:
- break;
- case 2:
- data = bswap16(data);
- break;
- case 4:
- data = bswap32(data);
- break;
- case 8:
- data = bswap64(data);
- break;
- default:
- program_interrupt(env, PGM_OPERAND, 4);
+ break;
+ case ZPCI_CONFIG_BAR:
+ /* ZPCI uses the pseudo BAR number 15 as configuration space */
+ /* possible access lengths are 1,2,4 and must not cross a word */
+ if (!len || (len > (4 - (offset & 0x3))) || len == 3) {
+ s390_program_interrupt(env, PGM_OPERAND, 4, ra);
return 0;
}
-
+ /* len = 1,2,4 so we do not need to test */
+ zpci_endian_swap(&data, len);
pci_host_config_write_common(pbdev->pdev, offset,
pci_config_size(pbdev->pdev),
data, len);
- } else {
+ break;
+ default:
DPRINTF("pcistg invalid space\n");
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
@@ -531,7 +571,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
return 0;
}
-int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
+int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
uint32_t fh;
@@ -545,12 +585,12 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
cpu_synchronize_state(CPU(cpu));
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 4);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
goto out;
}
if (r2 & 0x1) {
- program_interrupt(env, PGM_SPECIFICATION, 4);
+ s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
goto out;
}
@@ -624,12 +664,13 @@ out:
}
int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
- uint8_t ar)
+ uint8_t ar, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
S390PCIBusDevice *pbdev;
MemoryRegion *mr;
MemTxResult result;
+ uint64_t offset;
int i;
uint32_t fh;
uint8_t pcias;
@@ -637,29 +678,17 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
uint8_t buffer[128];
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 6);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
return 0;
}
fh = env->regs[r1] >> 32;
pcias = (env->regs[r1] >> 16) & 0xf;
len = env->regs[r1] & 0xff;
+ offset = env->regs[r3];
- if (pcias > 5) {
- DPRINTF("pcistb invalid space\n");
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
- return 0;
- }
-
- switch (len) {
- case 16:
- case 32:
- case 64:
- case 128:
- break;
- default:
- program_interrupt(env, PGM_SPECIFICATION, 6);
+ if (!(fh & FH_MASK_ENABLE)) {
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -671,12 +700,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
}
switch (pbdev->state) {
- case ZPCI_FS_RESERVED:
- case ZPCI_FS_STANDBY:
- case ZPCI_FS_DISABLED:
case ZPCI_FS_PERMANENT_ERROR:
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
@@ -685,28 +709,62 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
break;
}
+ if (pcias > ZPCI_IO_BAR_MAX) {
+ DPRINTF("pcistb invalid space\n");
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
+ return 0;
+ }
+
+ /* Verify the address, offset and length */
+ /* offset must be a multiple of 8 */
+ if (offset % 8) {
+ goto specification_error;
+ }
+ /* Length must be greater than 8, a multiple of 8 */
+ /* and not greater than maxstbl */
+ if ((len <= 8) || (len % 8) || (len > pbdev->maxstbl)) {
+ goto specification_error;
+ }
+ /* Do not cross a 4K-byte boundary */
+ if (((offset & 0xfff) + len) > 0x1000) {
+ goto specification_error;
+ }
+ /* Guest address must be double word aligned */
+ if (gaddr & 0x07UL) {
+ goto specification_error;
+ }
+
mr = pbdev->pdev->io_regions[pcias].memory;
- if (!memory_region_access_valid(mr, env->regs[r3], len, true)) {
- program_interrupt(env, PGM_OPERAND, 6);
+ mr = s390_get_subregion(mr, offset, len);
+ offset -= mr->addr;
+
+ if (!memory_region_access_valid(mr, offset, len, true)) {
+ s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
}
if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
for (i = 0; i < len / 8; i++) {
- result = memory_region_dispatch_write(mr, env->regs[r3] + i * 8,
- ldq_p(buffer + i * 8), 8,
- MEMTXATTRS_UNSPECIFIED);
+ result = memory_region_dispatch_write(mr, offset + i * 8,
+ ldq_p(buffer + i * 8), 8,
+ MEMTXATTRS_UNSPECIFIED);
if (result != MEMTX_OK) {
- program_interrupt(env, PGM_OPERAND, 6);
+ s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
}
}
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
+
+specification_error:
+ s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ return 0;
}
static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
@@ -767,7 +825,8 @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev)
return 0;
}
-static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib)
+static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib,
+ uintptr_t ra)
{
uint64_t pba = ldq_p(&fib.pba);
uint64_t pal = ldq_p(&fib.pal);
@@ -776,14 +835,14 @@ static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib)
uint8_t t = (g_iota >> 11) & 0x1;
if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) {
- program_interrupt(env, PGM_OPERAND, 6);
+ s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return -EINVAL;
}
/* currently we only support designation type 1 with translation */
if (!(dt == ZPCI_IOTA_RTTO && t)) {
error_report("unsupported ioat dt %d t %d", dt, t);
- program_interrupt(env, PGM_OPERAND, 6);
+ s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return -EINVAL;
}
@@ -804,7 +863,8 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu)
iommu->g_iota = 0;
}
-int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
+int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
+ uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
uint8_t oc, dmaas;
@@ -814,7 +874,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
uint64_t cc = ZPCI_PCI_LS_OK;
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 6);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
return 0;
}
@@ -823,7 +883,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
fh = env->regs[r1] >> 32;
if (fiba & 0x7) {
- program_interrupt(env, PGM_SPECIFICATION, 6);
+ s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
return 0;
}
@@ -846,11 +906,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
}
if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
if (fib.fmt != 0) {
- program_interrupt(env, PGM_OPERAND, 6);
+ s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
}
@@ -879,7 +940,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
} else if (pbdev->iommu->enabled) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
- } else if (reg_ioat(env, pbdev->iommu, fib)) {
+ } else if (reg_ioat(env, pbdev->iommu, fib, ra)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
@@ -904,7 +965,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
pci_dereg_ioat(pbdev->iommu);
- if (reg_ioat(env, pbdev->iommu, fib)) {
+ if (reg_ioat(env, pbdev->iommu, fib, ra)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
@@ -935,7 +996,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
break;
default:
- program_interrupt(&cpu->env, PGM_OPERAND, 6);
+ s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra);
cc = ZPCI_PCI_LS_ERR;
}
@@ -943,7 +1004,8 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
return 0;
}
-int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
+int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
+ uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
uint8_t dmaas;
@@ -954,7 +1016,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
uint64_t cc = ZPCI_PCI_LS_OK;
if (env->psw.mask & PSW_MASK_PSTATE) {
- program_interrupt(env, PGM_PRIVILEGED, 6);
+ s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
return 0;
}
@@ -968,7 +1030,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
}
if (fiba & 0x7) {
- program_interrupt(env, PGM_SPECIFICATION, 6);
+ s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
return 0;
}
@@ -1026,6 +1088,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
out:
if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
+ s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h
index 94a959f91c..91c3d61f2a 100644
--- a/hw/s390x/s390-pci-inst.h
+++ b/hw/s390x/s390-pci-inst.h
@@ -162,7 +162,7 @@ typedef struct ClpRspQueryPciGrp {
#define CLP_RSP_QPCIG_MASK_FRAME 0x2
#define CLP_RSP_QPCIG_MASK_REFRESH 0x1
uint8_t fr;
- uint16_t reserved2;
+ uint16_t maxstbl;
uint16_t mui;
uint64_t reserved3;
uint64_t dasm; /* dma address space mask */
@@ -293,13 +293,19 @@ typedef struct ZpciFib {
int pci_dereg_irqs(S390PCIBusDevice *pbdev);
void pci_dereg_ioat(S390PCIIOMMU *iommu);
-int clp_service_call(S390CPU *cpu, uint8_t r2);
-int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
-int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
-int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
+int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra);
+int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra);
+int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra);
+int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra);
int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
- uint8_t ar);
-int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar);
-int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar);
+ uint8_t ar, uintptr_t ra);
+int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
+ uintptr_t ra);
+int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
+ uintptr_t ra);
+
+#define ZPCI_IO_BAR_MIN 0
+#define ZPCI_IO_BAR_MAX 5
+#define ZPCI_CONFIG_BAR 15
#endif
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 6a57f94197..35df7e19c5 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -152,14 +152,38 @@ static void virtio_ccw_register_hcalls(void)
virtio_ccw_hcall_early_printk);
}
+/*
+ * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages
+ * as the dirty bitmap must be managed by bitops that take an int as
+ * position indicator. If we have a guest beyond that we will split off
+ * new subregions. The split must happen on a segment boundary (1MB).
+ */
+#define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1)
+#define SEG_MSK (~0xfffffULL)
+#define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & SEG_MSK)
static void s390_memory_init(ram_addr_t mem_size)
{
MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
+ ram_addr_t chunk, offset = 0;
+ unsigned int number = 0;
+ gchar *name;
/* allocate RAM for core */
- memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size);
- memory_region_add_subregion(sysmem, 0, ram);
+ name = g_strdup_printf("s390.ram");
+ while (mem_size) {
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
+ uint64_t size = mem_size;
+
+ /* KVM does not allow memslots >= 8 TB */
+ chunk = MIN(size, KVM_SLOT_MAX_BYTES);
+ memory_region_allocate_system_memory(ram, NULL, name, chunk);
+ memory_region_add_subregion(sysmem, offset, ram);
+ mem_size -= chunk;
+ offset += chunk;
+ g_free(name);
+ name = g_strdup_printf("s390.ram.%u", ++number);
+ }
+ g_free(name);
/* Initialize storage key device */
s390_skeys_init();
@@ -302,13 +326,17 @@ static void ccw_init(MachineState *machine)
/*
* Non mcss-e enabled guests only see the devices from the default
* css, which is determined by the value of the squash_mcss property.
- * Note: we must not squash non virtual devices to css 0xFE.
*/
if (css_bus->squash_mcss) {
ret = css_create_css_image(0, true);
} else {
ret = css_create_css_image(VIRTUAL_CSSID, true);
}
+ if (qemu_opt_get(qemu_get_machine_opts(), "s390-squash-mcss")) {
+ warn_report("The machine property 's390-squash-mcss' is deprecated"
+ " (obsoleted by lifting the cssid restrictions).");
+ }
+
assert(ret == 0);
if (css_migration_enabled()) {
css_register_vmstate();
@@ -583,7 +611,7 @@ static inline void s390_machine_initfn(Object *obj)
object_property_add_bool(obj, "s390-squash-mcss",
machine_get_squash_mcss,
machine_set_squash_mcss, NULL);
- object_property_set_description(obj, "s390-squash-mcss",
+ object_property_set_description(obj, "s390-squash-mcss", "(deprecated) "
"enable/disable squashing subchannels into the default css",
NULL);
object_property_set_bool(obj, false, "s390-squash-mcss", NULL);
@@ -639,6 +667,9 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
+#define CCW_COMPAT_2_11 \
+ HW_COMPAT_2_11
+
#define CCW_COMPAT_2_10 \
HW_COMPAT_2_10
@@ -716,14 +747,30 @@ bool css_migration_enabled(void)
.value = "0",\
},
+static void ccw_machine_2_12_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_2_12_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(2_12, "2.12", true);
+
static void ccw_machine_2_11_instance_options(MachineState *machine)
{
+ static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V2_11 };
+ ccw_machine_2_12_instance_options(machine);
+
+ /* before 2.12 we emulated the very first z900 */
+ s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat);
}
static void ccw_machine_2_11_class_options(MachineClass *mc)
{
+ ccw_machine_2_12_class_options(mc);
+ SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_11);
}
-DEFINE_CCW_MACHINE(2_11, "2.11", true);
+DEFINE_CCW_MACHINE(2_11, "2.11", false);
static void ccw_machine_2_10_instance_options(MachineState *machine)
{
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 184515ce94..38f6a8afc9 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -486,7 +486,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
} else {
address_space_stb(&address_space_memory, ccw.cda, vdev->status,
MEMTXATTRS_UNSPECIFIED, NULL);
- sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);;
+ sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);
ret = 0;
}
break;
@@ -701,7 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
SubchDev *sch;
Error *err = NULL;
- sch = css_create_sch(ccw_dev->devno, true, cbus->squash_mcss, errp);
+ sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, errp);
if (!sch) {
return;
}
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 977f7bce1f..965becf31f 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -540,20 +540,8 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
if (req->lun != 0) {
const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED);
- if (fixed_sense) {
- r->buf[0] = 0x70;
- r->buf[2] = sense.key;
- r->buf[10] = 10;
- r->buf[12] = sense.asc;
- r->buf[13] = sense.ascq;
- r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN);
- } else {
- r->buf[0] = 0x72;
- r->buf[1] = sense.key;
- r->buf[2] = sense.asc;
- r->buf[3] = sense.ascq;
- r->len = 8;
- }
+ r->len = scsi_build_sense_buf(r->buf, req->cmd.xfer,
+ sense, fixed_sense);
} else {
r->len = scsi_device_get_sense(r->req.dev, r->buf,
MIN(req->cmd.xfer, r->buf_len),
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 12431177a7..e58833a087 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2332,7 +2332,6 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
static void scsi_realize(SCSIDevice *dev, Error **errp)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- Error *err = NULL;
if (!s->qdev.conf.blk) {
error_setg(errp, "drive property not set");
@@ -2356,17 +2355,13 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
}
if (dev->type == TYPE_DISK) {
- blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, errp)) {
return;
}
}
- blkconf_apply_backend_options(&dev->conf,
- blk_is_read_only(s->qdev.conf.blk),
- dev->type == TYPE_DISK, &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_apply_backend_options(&dev->conf,
+ blk_is_read_only(s->qdev.conf.blk),
+ dev->type == TYPE_DISK, errp)) {
return;
}
@@ -3009,6 +3004,7 @@ static const TypeInfo scsi_cd_info = {
static Property scsi_block_properties[] = {
DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
+ DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false),
DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index f7561e23fa..9389ed48e0 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -18,7 +18,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "qemu/typedefs.h"
#include "qom/object.h"
#include "hw/fw-path-provider.h"
#include "hw/qdev-core.h"
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
index 3deccf02c9..82f8ec0d50 100644
--- a/hw/sd/pxa2xx_mmci.c
+++ b/hw/sd/pxa2xx_mmci.c
@@ -19,6 +19,8 @@
#include "hw/qdev.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "trace.h"
#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI)
@@ -278,45 +280,56 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- uint32_t ret;
+ uint32_t ret = 0;
switch (offset) {
case MMC_STRPCL:
- return 0;
+ break;
case MMC_STAT:
- return s->status;
+ ret = s->status;
+ break;
case MMC_CLKRT:
- return s->clkrt;
+ ret = s->clkrt;
+ break;
case MMC_SPI:
- return s->spi;
+ ret = s->spi;
+ break;
case MMC_CMDAT:
- return s->cmdat;
+ ret = s->cmdat;
+ break;
case MMC_RESTO:
- return s->resp_tout;
+ ret = s->resp_tout;
+ break;
case MMC_RDTO:
- return s->read_tout;
+ ret = s->read_tout;
+ break;
case MMC_BLKLEN:
- return s->blklen;
+ ret = s->blklen;
+ break;
case MMC_NUMBLK:
- return s->numblk;
+ ret = s->numblk;
+ break;
case MMC_PRTBUF:
- return 0;
+ break;
case MMC_I_MASK:
- return s->intmask;
+ ret = s->intmask;
+ break;
case MMC_I_REG:
- return s->intreq;
+ ret = s->intreq;
+ break;
case MMC_CMD:
- return s->cmd | 0x40;
+ ret = s->cmd | 0x40;
+ break;
case MMC_ARGH:
- return s->arg >> 16;
+ ret = s->arg >> 16;
+ break;
case MMC_ARGL:
- return s->arg & 0xffff;
+ ret = s->arg & 0xffff;
+ break;
case MMC_RES:
- if (s->resp_len < 9)
- return s->resp_fifo[s->resp_len ++];
- return 0;
+ ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0;
+ break;
case MMC_RXFIFO:
- ret = 0;
while (size-- && s->rx_len) {
ret |= s->rx_fifo[s->rx_start++] << (size << 3);
s->rx_start &= 0x1f;
@@ -324,16 +337,20 @@ static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
}
s->intreq &= ~INT_RXFIFO_REQ;
pxa2xx_mmci_fifo_update(s);
- return ret;
+ break;
case MMC_RDWAIT:
- return 0;
+ break;
case MMC_BLKS_REM:
- return s->numblk;
+ ret = s->numblk;
+ break;
default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
+ __func__, offset);
}
+ trace_pxa2xx_mmci_read(size, offset, ret);
- return 0;
+ return ret;
}
static void pxa2xx_mmci_write(void *opaque,
@@ -341,6 +358,7 @@ static void pxa2xx_mmci_write(void *opaque,
{
PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+ trace_pxa2xx_mmci_write(size, offset, value);
switch (offset) {
case MMC_STRPCL:
if (value & STRPCL_STRT_CLK) {
@@ -368,8 +386,10 @@ static void pxa2xx_mmci_write(void *opaque,
case MMC_SPI:
s->spi = value & 0xf;
- if (value & SPI_SPI_MODE)
- printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
+ if (value & SPI_SPI_MODE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: attempted to use card in SPI mode\n", __func__);
+ }
break;
case MMC_CMDAT:
@@ -442,7 +462,9 @@ static void pxa2xx_mmci_write(void *opaque,
break;
default:
- hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect reg 0x%02" HWADDR_PRIx " "
+ "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
}
}
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index 1fc0bcf44b..6eca3470e2 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -3,3 +3,7 @@
# hw/sd/milkymist-memcard.c
milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
+
+# hw/sd/pxa2xx_mmci.c
+pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
+pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
diff --git a/hw/smbios/smbios_type_38-stub.c b/hw/smbios/smbios_type_38-stub.c
index 9528c2c28e..5b83c9b1f1 100644
--- a/hw/smbios/smbios_type_38-stub.c
+++ b/hw/smbios/smbios_type_38-stub.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "hw/smbios/ipmi.h"
void smbios_build_type_38_table(void)
diff --git a/hw/sparc/Makefile.objs b/hw/sparc/Makefile.objs
index c987b5b5df..e2d0828c39 100644
--- a/hw/sparc/Makefile.objs
+++ b/hw/sparc/Makefile.objs
@@ -1 +1 @@
-obj-y += sun4m.o leon3.o
+obj-y += sun4m_iommu.o sun4m.o leon3.o
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 24c2b8a555..dd0038095b 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -28,7 +28,7 @@
#include "hw/sysbus.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
-#include "hw/sparc/sun4m.h"
+#include "hw/sparc/sun4m_iommu.h"
#include "hw/timer/m48t59.h"
#include "hw/sparc/sparc32_dma.h"
#include "hw/block/fdc.h"
@@ -36,7 +36,6 @@
#include "net/net.h"
#include "hw/boards.h"
#include "hw/scsi/esp.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "hw/nvram/sun_nvram.h"
#include "hw/nvram/chrp_nvram.h"
diff --git a/hw/dma/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c
index 30a05e8823..b677601fc6 100644
--- a/hw/dma/sun4m_iommu.c
+++ b/hw/sparc/sun4m_iommu.c
@@ -23,7 +23,7 @@
*/
#include "qemu/osdep.h"
-#include "hw/sparc/sun4m.h"
+#include "hw/sparc/sun4m_iommu.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
#include "trace.h"
@@ -125,7 +125,7 @@
#define IOMMU_PAGE_SHIFT 12
#define IOMMU_PAGE_SIZE (1 << IOMMU_PAGE_SHIFT)
-#define IOMMU_PAGE_MASK ~(IOMMU_PAGE_SIZE - 1)
+#define IOMMU_PAGE_MASK (~(IOMMU_PAGE_SIZE - 1))
static uint64_t iommu_mem_read(void *opaque, hwaddr addr,
unsigned size)
@@ -218,8 +218,8 @@ static void iommu_mem_write(void *opaque, hwaddr addr,
s->regs[saddr] = val & IOMMU_SBCFG_MASK;
break;
case IOMMU_ARBEN:
- // XXX implement SBus probing: fault when reading unmapped
- // addresses, fault cause and address stored to MMU/IOMMU
+ /* XXX implement SBus probing: fault when reading unmapped
+ addresses, fault cause and address stored to MMU/IOMMU */
s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
break;
case IOMMU_MASK_ID:
@@ -272,8 +272,9 @@ static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
trace_sun4m_iommu_bad_addr(addr);
s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV |
IOMMU_AFSR_FAV;
- if (!is_write)
+ if (!is_write) {
s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
+ }
s->regs[IOMMU_AFAR] = addr;
qemu_irq_raise(s->irq);
}
@@ -322,7 +323,7 @@ static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu,
}
static const VMStateDescription vmstate_iommu = {
- .name ="iommu",
+ .name = "iommu",
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
diff --git a/hw/sparc/trace-events b/hw/sparc/trace-events
index efd765cbe6..6e7259f8f8 100644
--- a/hw/sparc/trace-events
+++ b/hw/sparc/trace-events
@@ -6,6 +6,16 @@ sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d"
sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d"
sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
+# hw/sparc/sun4m_iommu.c
+sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x"
+sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x"
+sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = 0x%"PRIx64
+sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush 0x%x"
+sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush 0x%x"
+sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr 0x%"PRIx64" => pte 0x%"PRIx64", *pte = 0x%x"
+sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva 0x%"PRIx64" => pa 0x%"PRIx64" iopte = 0x%x"
+sun4m_iommu_bad_addr(uint64_t addr) "bad addr 0x%"PRIx64
+
# hw/sparc/leon3.c
leon3_set_irq(int intno) "Set CPU IRQ %d"
leon3_reset_irq(int intno) "Reset CPU IRQ %d"
diff --git a/hw/sparc64/Makefile.objs b/hw/sparc64/Makefile.objs
index cf9de21133..117e0ff27d 100644
--- a/hw/sparc64/Makefile.objs
+++ b/hw/sparc64/Makefile.objs
@@ -1,3 +1,4 @@
obj-y += sparc64.o
+obj-y += sun4u_iommu.o
obj-y += sun4u.o
obj-y += niagara.o \ No newline at end of file
diff --git a/hw/sparc64/sparc64.c b/hw/sparc64/sparc64.c
index 9453e2c390..95a06f00b2 100644
--- a/hw/sparc64/sparc64.c
+++ b/hw/sparc64/sparc64.c
@@ -350,6 +350,8 @@ SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr)
uint32_t hstick_frequency = 100 * 1000000;
cpu = SPARC_CPU(cpu_create(cpu_type));
+ qdev_init_gpio_in_named(DEVICE(cpu), sparc64_cpu_set_ivec_irq,
+ "ivec-irq", IVEC_MAX);
env = &cpu->env;
env->tick = cpu_timer_create("tick", cpu, tick_irq,
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 1672f256e7..ec45ec2801 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -27,7 +27,9 @@
#include "cpu.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
+#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_host.h"
#include "hw/pci-host/apb.h"
#include "hw/i386/pc.h"
#include "hw/char/serial.h"
@@ -46,17 +48,9 @@
#include "hw/ide/pci.h"
#include "hw/loader.h"
#include "elf.h"
+#include "trace.h"
#include "qemu/cutils.h"
-//#define DEBUG_EBUS
-
-#ifdef DEBUG_EBUS
-#define EBUS_DPRINTF(fmt, ...) \
- do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define EBUS_DPRINTF(fmt, ...)
-#endif
-
#define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000
#define PROM_SIZE_MAX (4 * 1024 * 1024)
@@ -81,11 +75,19 @@ struct hwdef {
};
typedef struct EbusState {
- PCIDevice pci_dev;
+ /*< private >*/
+ PCIDevice parent_obj;
+
+ ISABus *isa_bus;
+ qemu_irq isa_bus_irqs[ISA_NUM_IRQS];
+ uint64_t console_serial_base;
MemoryRegion bar0;
MemoryRegion bar1;
} EbusState;
+#define TYPE_EBUS "ebus"
+#define EBUS(obj) OBJECT_CHECK(EbusState, (obj), TYPE_EBUS)
+
void DMA_init(ISABus *bus, int high_page_enable)
{
}
@@ -203,48 +205,72 @@ typedef struct ResetData {
uint64_t prom_addr;
} ResetData;
-static void isa_irq_handler(void *opaque, int n, int level)
+static void ebus_isa_irq_handler(void *opaque, int n, int level)
{
- static const int isa_irq_to_ivec[16] = {
- [1] = 0x29, /* keyboard */
- [4] = 0x2b, /* serial */
- [6] = 0x27, /* floppy */
- [7] = 0x22, /* parallel */
- [12] = 0x2a, /* mouse */
- };
- qemu_irq *irqs = opaque;
- int ivec;
-
- assert(n < ARRAY_SIZE(isa_irq_to_ivec));
- ivec = isa_irq_to_ivec[n];
- EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
- if (ivec) {
- qemu_set_irq(irqs[ivec], level);
+ EbusState *s = EBUS(opaque);
+ qemu_irq irq = s->isa_bus_irqs[n];
+
+ /* Pass ISA bus IRQs onto their gpio equivalent */
+ trace_ebus_isa_irq_handler(n, level);
+ if (irq) {
+ qemu_set_irq(irq, level);
}
}
/* EBUS (Eight bit bus) bridge */
-static ISABus *
-pci_ebus_init(PCIDevice *pci_dev, qemu_irq *irqs)
+static void ebus_realize(PCIDevice *pci_dev, Error **errp)
{
+ EbusState *s = EBUS(pci_dev);
+ DeviceState *dev;
qemu_irq *isa_irq;
- ISABus *isa_bus;
+ DriveInfo *fd[MAX_FD];
+ int i;
- isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0"));
- isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
- isa_bus_irqs(isa_bus, isa_irq);
- return isa_bus;
-}
+ s->isa_bus = isa_bus_new(DEVICE(pci_dev), get_system_memory(),
+ pci_address_space_io(pci_dev), errp);
+ if (!s->isa_bus) {
+ error_setg(errp, "unable to instantiate EBUS ISA bus");
+ return;
+ }
-static void pci_ebus_realize(PCIDevice *pci_dev, Error **errp)
-{
- EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
+ /* ISA bus */
+ isa_irq = qemu_allocate_irqs(ebus_isa_irq_handler, s, ISA_NUM_IRQS);
+ isa_bus_irqs(s->isa_bus, isa_irq);
+ qdev_init_gpio_out_named(DEVICE(s), s->isa_bus_irqs, "isa-irq",
+ ISA_NUM_IRQS);
- if (!isa_bus_new(DEVICE(pci_dev), get_system_memory(),
- pci_address_space_io(pci_dev), errp)) {
- return;
+ /* Serial ports */
+ i = 0;
+ if (s->console_serial_base) {
+ serial_mm_init(pci_address_space(pci_dev), s->console_serial_base,
+ 0, NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
+ i++;
}
+ serial_hds_isa_init(s->isa_bus, i, MAX_SERIAL_PORTS);
+
+ /* Parallel ports */
+ parallel_hds_isa_init(s->isa_bus, MAX_PARALLEL_PORTS);
+ /* Keyboard */
+ isa_create_simple(s->isa_bus, "i8042");
+
+ /* Floppy */
+ for (i = 0; i < MAX_FD; i++) {
+ fd[i] = drive_get(IF_FLOPPY, 0, i);
+ }
+ dev = DEVICE(isa_create(s->isa_bus, TYPE_ISA_FDC));
+ if (fd[0]) {
+ qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]),
+ &error_abort);
+ }
+ if (fd[1]) {
+ qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]),
+ &error_abort);
+ }
+ qdev_prop_set_uint32(dev, "dma", -1);
+ qdev_init_nofail(dev);
+
+ /* PCI */
pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
pci_dev->config[0x05] = 0x00;
pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
@@ -260,22 +286,30 @@ static void pci_ebus_realize(PCIDevice *pci_dev, Error **errp)
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
}
+static Property ebus_properties[] = {
+ DEFINE_PROP_UINT64("console-serial-base", EbusState,
+ console_serial_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void ebus_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- k->realize = pci_ebus_realize;
+ k->realize = ebus_realize;
k->vendor_id = PCI_VENDOR_ID_SUN;
k->device_id = PCI_DEVICE_ID_SUN_EBUS;
k->revision = 0x01;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ dc->props = ebus_properties;
}
static const TypeInfo ebus_info = {
- .name = "ebus",
+ .name = TYPE_EBUS,
.parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EbusState),
.class_init = ebus_class_init,
+ .instance_size = sizeof(EbusState),
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
@@ -431,14 +465,12 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
Nvram *nvram;
unsigned int i;
uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
+ APBState *apb;
PCIBus *pci_bus, *pci_busA, *pci_busB;
PCIDevice *ebus, *pci_dev;
- ISABus *isa_bus;
SysBusDevice *s;
- qemu_irq *ivec_irqs, *pbm_irqs;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- DriveInfo *fd[MAX_FD];
- DeviceState *dev;
+ DeviceState *iommu, *dev;
FWCfgState *fw_cfg;
NICInfo *nd;
MACAddr macaddr;
@@ -447,14 +479,31 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
/* init CPUs */
cpu = sparc64_cpu_devinit(machine->cpu_type, hwdef->prom_addr);
+ /* IOMMU */
+ iommu = qdev_create(NULL, TYPE_SUN4U_IOMMU);
+ qdev_init_nofail(iommu);
+
/* set up devices */
ram_init(0, machine->ram_size);
prom_init(hwdef->prom_addr, bios_name);
- ivec_irqs = qemu_allocate_irqs(sparc64_cpu_set_ivec_irq, cpu, IVEC_MAX);
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_busA,
- &pci_busB, &pbm_irqs);
+ /* Init APB (PCI host bridge) */
+ apb = APB_DEVICE(qdev_create(NULL, TYPE_APB));
+ qdev_prop_set_uint64(DEVICE(apb), "special-base", APB_SPECIAL_BASE);
+ qdev_prop_set_uint64(DEVICE(apb), "mem-base", APB_MEM_BASE);
+ object_property_set_link(OBJECT(apb), OBJECT(iommu), "iommu", &error_abort);
+ qdev_init_nofail(DEVICE(apb));
+
+ /* Wire up PCI interrupts to CPU */
+ for (i = 0; i < IVEC_MAX; i++) {
+ qdev_connect_gpio_out_named(DEVICE(apb), "ivec-irq", i,
+ qdev_get_gpio_in_named(DEVICE(cpu), "ivec-irq", i));
+ }
+
+ pci_bus = PCI_HOST_BRIDGE(apb)->bus;
+ pci_busA = pci_bridge_get_sec_bus(apb->bridgeA);
+ pci_busB = pci_bridge_get_sec_bus(apb->bridgeB);
/* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is
reserved (leaving no slots free after on-board devices) however slots
@@ -463,20 +512,22 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
pci_busA->slot_reserved_mask = 0xfffffff1;
pci_busB->slot_reserved_mask = 0xfffffff0;
- ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, "ebus");
+ ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, TYPE_EBUS);
+ qdev_prop_set_uint64(DEVICE(ebus), "console-serial-base",
+ hwdef->console_serial_base);
qdev_init_nofail(DEVICE(ebus));
- isa_bus = pci_ebus_init(ebus, pbm_irqs);
-
- i = 0;
- if (hwdef->console_serial_base) {
- serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
- NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
- i++;
- }
-
- serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
- parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
+ /* Wire up "well-known" ISA IRQs to APB legacy obio IRQs */
+ qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 7,
+ qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_LPT_IRQ));
+ qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 6,
+ qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_FDD_IRQ));
+ qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 1,
+ qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_KBD_IRQ));
+ qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 12,
+ qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_MSE_IRQ));
+ qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 4,
+ qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_SER_IRQ));
pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA");
@@ -516,24 +567,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
qdev_init_nofail(&pci_dev->qdev);
pci_ide_create_devs(pci_dev, hd);
- isa_create_simple(isa_bus, "i8042");
-
- /* Floppy */
- for(i = 0; i < MAX_FD; i++) {
- fd[i] = drive_get(IF_FLOPPY, 0, i);
- }
- dev = DEVICE(isa_create(isa_bus, TYPE_ISA_FDC));
- if (fd[0]) {
- qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]),
- &error_abort);
- }
- if (fd[1]) {
- qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]),
- &error_abort);
- }
- qdev_prop_set_uint32(dev, "dma", -1);
- qdev_init_nofail(dev);
-
/* Map NVRAM into I/O (ebus) space */
nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59);
s = SYS_BUS_DEVICE(nvram);
diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c
new file mode 100644
index 0000000000..4cf8e69be9
--- /dev/null
+++ b/hw/sparc64/sun4u_iommu.c
@@ -0,0 +1,342 @@
+/*
+ * QEMU sun4u IOMMU emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2012,2013 Artyom Tarasenko
+ * Copyright (c) 2017 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/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/sparc/sun4u_iommu.h"
+#include "exec/address-spaces.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+
+#define IOMMU_PAGE_SIZE_8K (1ULL << 13)
+#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
+#define IOMMU_PAGE_SIZE_64K (1ULL << 16)
+#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
+
+#define IOMMU_CTRL 0x0
+#define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
+#define IOMMU_CTRL_MMU_EN (1ULL)
+
+#define IOMMU_CTRL_TSB_SHIFT 16
+
+#define IOMMU_BASE 0x8
+#define IOMMU_FLUSH 0x10
+
+#define IOMMU_TTE_DATA_V (1ULL << 63)
+#define IOMMU_TTE_DATA_SIZE (1ULL << 61)
+#define IOMMU_TTE_DATA_W (1ULL << 1)
+
+#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
+#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
+
+#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
+#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
+
+#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
+#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
+
+
+/* Called from RCU critical section */
+static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
+ hwaddr addr,
+ IOMMUAccessFlags flag)
+{
+ IOMMUState *is = container_of(iommu, IOMMUState, iommu);
+ hwaddr baseaddr, offset;
+ uint64_t tte;
+ uint32_t tsbsize;
+ IOMMUTLBEntry ret = {
+ .target_as = &address_space_memory,
+ .iova = 0,
+ .translated_addr = 0,
+ .addr_mask = ~(hwaddr)0,
+ .perm = IOMMU_NONE,
+ };
+
+ if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) {
+ /* IOMMU disabled, passthrough using standard 8K page */
+ ret.iova = addr & IOMMU_PAGE_MASK_8K;
+ ret.translated_addr = addr;
+ ret.addr_mask = IOMMU_PAGE_MASK_8K;
+ ret.perm = IOMMU_RW;
+
+ return ret;
+ }
+
+ baseaddr = is->regs[IOMMU_BASE >> 3];
+ tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7;
+
+ if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) {
+ /* 64K */
+ switch (tsbsize) {
+ case 0:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13;
+ break;
+ case 1:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13;
+ break;
+ case 2:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13;
+ break;
+ case 3:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13;
+ break;
+ case 4:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13;
+ break;
+ case 5:
+ offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13;
+ break;
+ default:
+ /* Not implemented, error */
+ return ret;
+ }
+ } else {
+ /* 8K */
+ switch (tsbsize) {
+ case 0:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10;
+ break;
+ case 1:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10;
+ break;
+ case 2:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10;
+ break;
+ case 3:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10;
+ break;
+ case 4:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10;
+ break;
+ case 5:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10;
+ break;
+ case 6:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10;
+ break;
+ case 7:
+ offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10;
+ break;
+ }
+ }
+
+ tte = address_space_ldq_be(&address_space_memory, baseaddr + offset,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+
+ if (!(tte & IOMMU_TTE_DATA_V)) {
+ /* Invalid mapping */
+ return ret;
+ }
+
+ if (tte & IOMMU_TTE_DATA_W) {
+ /* Writeable */
+ ret.perm = IOMMU_RW;
+ } else {
+ ret.perm = IOMMU_RO;
+ }
+
+ /* Extract phys */
+ if (tte & IOMMU_TTE_DATA_SIZE) {
+ /* 64K */
+ ret.iova = addr & IOMMU_PAGE_MASK_64K;
+ ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K;
+ ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1);
+ } else {
+ /* 8K */
+ ret.iova = addr & IOMMU_PAGE_MASK_8K;
+ ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K;
+ ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1);
+ }
+
+ trace_sun4u_iommu_translate(ret.iova, ret.translated_addr, tte);
+
+ return ret;
+}
+
+static void iommu_mem_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ IOMMUState *is = opaque;
+
+ trace_sun4u_iommu_mem_write(addr, val, size);
+
+ switch (addr) {
+ case IOMMU_CTRL:
+ if (size == 4) {
+ is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL;
+ is->regs[IOMMU_CTRL >> 3] |= val << 32;
+ } else {
+ is->regs[IOMMU_CTRL >> 3] = val;
+ }
+ break;
+ case IOMMU_CTRL + 0x4:
+ is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL;
+ is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL;
+ break;
+ case IOMMU_BASE:
+ if (size == 4) {
+ is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL;
+ is->regs[IOMMU_BASE >> 3] |= val << 32;
+ } else {
+ is->regs[IOMMU_BASE >> 3] = val;
+ }
+ break;
+ case IOMMU_BASE + 0x4:
+ is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
+ is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
+ break;
+ case IOMMU_FLUSH:
+ case IOMMU_FLUSH + 0x4:
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "sun4u-iommu: Unimplemented register write "
+ "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
+ addr, size, val);
+ break;
+ }
+}
+
+static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IOMMUState *is = opaque;
+ uint64_t val;
+
+ switch (addr) {
+ case IOMMU_CTRL:
+ if (size == 4) {
+ val = is->regs[IOMMU_CTRL >> 3] >> 32;
+ } else {
+ val = is->regs[IOMMU_CTRL >> 3];
+ }
+ break;
+ case IOMMU_CTRL + 0x4:
+ val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL;
+ break;
+ case IOMMU_BASE:
+ if (size == 4) {
+ val = is->regs[IOMMU_BASE >> 3] >> 32;
+ } else {
+ val = is->regs[IOMMU_BASE >> 3];
+ }
+ break;
+ case IOMMU_BASE + 0x4:
+ val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
+ break;
+ case IOMMU_FLUSH:
+ case IOMMU_FLUSH + 0x4:
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "sun4u-iommu: Unimplemented register read "
+ "reg 0x%" HWADDR_PRIx " size 0x%x\n",
+ addr, size);
+ val = 0;
+ break;
+ }
+
+ trace_sun4u_iommu_mem_read(addr, val, size);
+
+ return val;
+}
+
+static const MemoryRegionOps iommu_mem_ops = {
+ .read = iommu_mem_read,
+ .write = iommu_mem_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void iommu_reset(DeviceState *d)
+{
+ IOMMUState *s = SUN4U_IOMMU(d);
+
+ memset(s->regs, 0, IOMMU_NREGS * sizeof(uint64_t));
+}
+
+static void iommu_init(Object *obj)
+{
+ IOMMUState *s = SUN4U_IOMMU(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_iommu(&s->iommu, sizeof(s->iommu),
+ TYPE_SUN4U_IOMMU_MEMORY_REGION, OBJECT(s),
+ "iommu-sun4u", UINT64_MAX);
+ address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "iommu-as");
+
+ memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu",
+ IOMMU_NREGS * sizeof(uint64_t));
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void iommu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = iommu_reset;
+}
+
+static const TypeInfo iommu_info = {
+ .name = TYPE_SUN4U_IOMMU,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IOMMUState),
+ .instance_init = iommu_init,
+ .class_init = iommu_class_init,
+};
+
+static void sun4u_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+ imrc->translate = sun4u_translate_iommu;
+}
+
+static const TypeInfo sun4u_iommu_memory_region_info = {
+ .parent = TYPE_IOMMU_MEMORY_REGION,
+ .name = TYPE_SUN4U_IOMMU_MEMORY_REGION,
+ .class_init = sun4u_iommu_memory_region_class_init,
+};
+
+static void iommu_register_types(void)
+{
+ type_register_static(&iommu_info);
+ type_register_static(&sun4u_iommu_memory_region_info);
+}
+
+type_init(iommu_register_types)
diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events
new file mode 100644
index 0000000000..2ee2d75f70
--- /dev/null
+++ b/hw/sparc64/trace-events
@@ -0,0 +1,9 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/sparc64/sun4u.c
+ebus_isa_irq_handler(int n, int level) "Set ISA IRQ %d level %d"
+
+# hw/sparc64/sun4u_iommu.c
+sun4u_iommu_mem_read(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d"
+sun4u_iommu_mem_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d"
+sun4u_iommu_translate(uint64_t addr, uint64_t trans_addr, uint64_t tte) "xlate 0x%"PRIx64" => pa 0x%"PRIx64" tte: 0x%"PRIx64
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index cb515730c5..5059396bc6 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -26,8 +26,7 @@
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
-#include "include/qemu/error-report.h"
-#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
#include "hw/ssi/aspeed_smc.h"
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index ef56d35f2c..d8187fadd1 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -27,11 +27,11 @@
#include "sysemu/sysemu.h"
#include "hw/ptimer.h"
#include "qemu/log.h"
-#include "qemu/fifo8.h"
-#include "hw/ssi/ssi.h"
#include "qemu/bitops.h"
#include "hw/ssi/xilinx_spips.h"
#include "qapi/error.h"
+#include "hw/register.h"
+#include "sysemu/dma.h"
#include "migration/blocker.h"
#ifndef XILINX_SPIPS_ERR_DEBUG
@@ -48,7 +48,7 @@
/* config register */
#define R_CONFIG (0x00 / 4)
#define IFMODE (1U << 31)
-#define ENDIAN (1 << 26)
+#define R_CONFIG_ENDIAN (1 << 26)
#define MODEFAIL_GEN_EN (1 << 17)
#define MAN_START_COM (1 << 16)
#define MAN_START_EN (1 << 15)
@@ -66,17 +66,35 @@
/* interrupt mechanism */
#define R_INTR_STATUS (0x04 / 4)
+#define R_INTR_STATUS_RESET (0x104)
#define R_INTR_EN (0x08 / 4)
#define R_INTR_DIS (0x0C / 4)
#define R_INTR_MASK (0x10 / 4)
#define IXR_TX_FIFO_UNDERFLOW (1 << 6)
+/* Poll timeout not implemented */
+#define IXR_RX_FIFO_EMPTY (1 << 11)
+#define IXR_GENERIC_FIFO_FULL (1 << 10)
+#define IXR_GENERIC_FIFO_NOT_FULL (1 << 9)
+#define IXR_TX_FIFO_EMPTY (1 << 8)
+#define IXR_GENERIC_FIFO_EMPTY (1 << 7)
#define IXR_RX_FIFO_FULL (1 << 5)
#define IXR_RX_FIFO_NOT_EMPTY (1 << 4)
#define IXR_TX_FIFO_FULL (1 << 3)
#define IXR_TX_FIFO_NOT_FULL (1 << 2)
#define IXR_TX_FIFO_MODE_FAIL (1 << 1)
#define IXR_RX_FIFO_OVERFLOW (1 << 0)
-#define IXR_ALL ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
+#define IXR_ALL ((1 << 13) - 1)
+#define GQSPI_IXR_MASK 0xFBE
+#define IXR_SELF_CLEAR \
+(IXR_GENERIC_FIFO_EMPTY \
+| IXR_GENERIC_FIFO_FULL \
+| IXR_GENERIC_FIFO_NOT_FULL \
+| IXR_TX_FIFO_EMPTY \
+| IXR_TX_FIFO_FULL \
+| IXR_TX_FIFO_NOT_FULL \
+| IXR_RX_FIFO_EMPTY \
+| IXR_RX_FIFO_FULL \
+| IXR_RX_FIFO_NOT_EMPTY)
#define R_EN (0x14 / 4)
#define R_DELAY (0x18 / 4)
@@ -85,6 +103,9 @@
#define R_SLAVE_IDLE_COUNT (0x24 / 4)
#define R_TX_THRES (0x28 / 4)
#define R_RX_THRES (0x2C / 4)
+#define R_GPIO (0x30 / 4)
+#define R_LPBK_DLY_ADJ (0x38 / 4)
+#define R_LPBK_DLY_ADJ_RESET (0x33)
#define R_TXD1 (0x80 / 4)
#define R_TXD2 (0x84 / 4)
#define R_TXD3 (0x88 / 4)
@@ -93,8 +114,9 @@
#define R_LQSPI_CFG_RESET 0x03A002EB
#define LQSPI_CFG_LQ_MODE (1U << 31)
#define LQSPI_CFG_TWO_MEM (1 << 30)
-#define LQSPI_CFG_SEP_BUS (1 << 30)
+#define LQSPI_CFG_SEP_BUS (1 << 29)
#define LQSPI_CFG_U_PAGE (1 << 28)
+#define LQSPI_CFG_ADDR4 (1 << 27)
#define LQSPI_CFG_MODE_EN (1 << 25)
#define LQSPI_CFG_MODE_WIDTH 8
#define LQSPI_CFG_MODE_SHIFT 16
@@ -102,115 +124,168 @@
#define LQSPI_CFG_DUMMY_SHIFT 8
#define LQSPI_CFG_INST_CODE 0xFF
+#define R_CMND (0xc0 / 4)
+ #define R_CMND_RXFIFO_DRAIN (1 << 19)
+ FIELD(CMND, PARTIAL_BYTE_LEN, 16, 3)
+#define R_CMND_EXT_ADD (1 << 15)
+ FIELD(CMND, RX_DISCARD, 8, 7)
+ FIELD(CMND, DUMMY_CYCLES, 2, 6)
+#define R_CMND_DMA_EN (1 << 1)
+#define R_CMND_PUSH_WAIT (1 << 0)
+#define R_TRANSFER_SIZE (0xc4 / 4)
#define R_LQSPI_STS (0xA4 / 4)
#define LQSPI_STS_WR_RECVD (1 << 1)
#define R_MOD_ID (0xFC / 4)
+#define R_GQSPI_SELECT (0x144 / 4)
+ FIELD(GQSPI_SELECT, GENERIC_QSPI_EN, 0, 1)
+#define R_GQSPI_ISR (0x104 / 4)
+#define R_GQSPI_IER (0x108 / 4)
+#define R_GQSPI_IDR (0x10c / 4)
+#define R_GQSPI_IMR (0x110 / 4)
+#define R_GQSPI_IMR_RESET (0xfbe)
+#define R_GQSPI_TX_THRESH (0x128 / 4)
+#define R_GQSPI_RX_THRESH (0x12c / 4)
+#define R_GQSPI_GPIO (0x130 / 4)
+#define R_GQSPI_LPBK_DLY_ADJ (0x138 / 4)
+#define R_GQSPI_LPBK_DLY_ADJ_RESET (0x33)
+#define R_GQSPI_CNFG (0x100 / 4)
+ FIELD(GQSPI_CNFG, MODE_EN, 30, 2)
+ FIELD(GQSPI_CNFG, GEN_FIFO_START_MODE, 29, 1)
+ FIELD(GQSPI_CNFG, GEN_FIFO_START, 28, 1)
+ FIELD(GQSPI_CNFG, ENDIAN, 26, 1)
+ /* Poll timeout not implemented */
+ FIELD(GQSPI_CNFG, EN_POLL_TIMEOUT, 20, 1)
+ /* QEMU doesnt care about any of these last three */
+ FIELD(GQSPI_CNFG, BR, 3, 3)
+ FIELD(GQSPI_CNFG, CPH, 2, 1)
+ FIELD(GQSPI_CNFG, CPL, 1, 1)
+#define R_GQSPI_GEN_FIFO (0x140 / 4)
+#define R_GQSPI_TXD (0x11c / 4)
+#define R_GQSPI_RXD (0x120 / 4)
+#define R_GQSPI_FIFO_CTRL (0x14c / 4)
+ FIELD(GQSPI_FIFO_CTRL, RX_FIFO_RESET, 2, 1)
+ FIELD(GQSPI_FIFO_CTRL, TX_FIFO_RESET, 1, 1)
+ FIELD(GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET, 0, 1)
+#define R_GQSPI_GFIFO_THRESH (0x150 / 4)
+#define R_GQSPI_DATA_STS (0x15c / 4)
+/* We use the snapshot register to hold the core state for the currently
+ * or most recently executed command. So the generic fifo format is defined
+ * for the snapshot register
+ */
+#define R_GQSPI_GF_SNAPSHOT (0x160 / 4)
+ FIELD(GQSPI_GF_SNAPSHOT, POLL, 19, 1)
+ FIELD(GQSPI_GF_SNAPSHOT, STRIPE, 18, 1)
+ FIELD(GQSPI_GF_SNAPSHOT, RECIEVE, 17, 1)
+ FIELD(GQSPI_GF_SNAPSHOT, TRANSMIT, 16, 1)
+ FIELD(GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT, 14, 2)
+ FIELD(GQSPI_GF_SNAPSHOT, CHIP_SELECT, 12, 2)
+ FIELD(GQSPI_GF_SNAPSHOT, SPI_MODE, 10, 2)
+ FIELD(GQSPI_GF_SNAPSHOT, EXPONENT, 9, 1)
+ FIELD(GQSPI_GF_SNAPSHOT, DATA_XFER, 8, 1)
+ FIELD(GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA, 0, 8)
+#define R_GQSPI_MOD_ID (0x1fc / 4)
+#define R_GQSPI_MOD_ID_RESET (0x10a0000)
+
+#define R_QSPIDMA_DST_CTRL (0x80c / 4)
+#define R_QSPIDMA_DST_CTRL_RESET (0x803ffa00)
+#define R_QSPIDMA_DST_I_MASK (0x820 / 4)
+#define R_QSPIDMA_DST_I_MASK_RESET (0xfe)
+#define R_QSPIDMA_DST_CTRL2 (0x824 / 4)
+#define R_QSPIDMA_DST_CTRL2_RESET (0x081bfff8)
+
/* size of TXRX FIFOs */
-#define RXFF_A 32
-#define TXFF_A 32
+#define RXFF_A (128)
+#define TXFF_A (128)
#define RXFF_A_Q (64 * 4)
#define TXFF_A_Q (64 * 4)
/* 16MB per linear region */
#define LQSPI_ADDRESS_BITS 24
-/* Bite off 4k chunks at a time */
-#define LQSPI_CACHE_SIZE 1024
#define SNOOP_CHECKING 0xFF
-#define SNOOP_NONE 0xFE
+#define SNOOP_ADDR 0xF0
+#define SNOOP_NONE 0xEE
#define SNOOP_STRIPING 0
-typedef enum {
- READ = 0x3,
- FAST_READ = 0xb,
- DOR = 0x3b,
- QOR = 0x6b,
- DIOR = 0xbb,
- QIOR = 0xeb,
-
- PP = 0x2,
- DPP = 0xa2,
- QPP = 0x32,
-} FlashCMD;
-
-typedef struct {
- XilinxSPIPS parent_obj;
-
- uint8_t lqspi_buf[LQSPI_CACHE_SIZE];
- hwaddr lqspi_cached_addr;
- Error *migration_blocker;
- bool mmio_execution_enabled;
-} XilinxQSPIPS;
-
-typedef struct XilinxSPIPSClass {
- SysBusDeviceClass parent_class;
-
- const MemoryRegionOps *reg_ops;
-
- uint32_t rx_fifo_size;
- uint32_t tx_fifo_size;
-} XilinxSPIPSClass;
-
static inline int num_effective_busses(XilinxSPIPS *s)
{
return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
}
-static inline bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field)
-{
- return ~field & (1 << i) && (s->regs[R_CONFIG] & MANUAL_CS
- || !fifo8_is_empty(&s->tx_fifo));
-}
-
-static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
+static void xilinx_spips_update_cs(XilinxSPIPS *s, int field)
{
- int i, j;
- bool found = false;
- int field = s->regs[R_CONFIG] >> CS_SHIFT;
+ int i;
for (i = 0; i < s->num_cs; i++) {
- for (j = 0; j < num_effective_busses(s); j++) {
- int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
- int cs_to_set = (j * s->num_cs + i + upage) %
- (s->num_cs * s->num_busses);
-
- if (xilinx_spips_cs_is_set(s, i, field) && !found) {
- DB_PRINT_L(0, "selecting slave %d\n", i);
- qemu_set_irq(s->cs_lines[cs_to_set], 0);
- } else {
- DB_PRINT_L(0, "deselecting slave %d\n", i);
- qemu_set_irq(s->cs_lines[cs_to_set], 1);
- }
- }
- if (xilinx_spips_cs_is_set(s, i, field)) {
- found = true;
+ bool old_state = s->cs_lines_state[i];
+ bool new_state = field & (1 << i);
+
+ if (old_state != new_state) {
+ s->cs_lines_state[i] = new_state;
+ s->rx_discard = ARRAY_FIELD_EX32(s->regs, CMND, RX_DISCARD);
+ DB_PRINT_L(1, "%sselecting slave %d\n", new_state ? "" : "de", i);
}
+ qemu_set_irq(s->cs_lines[i], !new_state);
}
- if (!found) {
+ if (!(field & ((1 << s->num_cs) - 1))) {
s->snoop_state = SNOOP_CHECKING;
+ s->cmd_dummies = 0;
+ s->link_state = 1;
+ s->link_state_next = 1;
+ s->link_state_next_when = 0;
DB_PRINT_L(1, "moving to snoop check state\n");
}
}
+static void xlnx_zynqmp_qspips_update_cs_lines(XlnxZynqMPQSPIPS *s)
+{
+ if (s->regs[R_GQSPI_GF_SNAPSHOT]) {
+ int field = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, CHIP_SELECT);
+ xilinx_spips_update_cs(XILINX_SPIPS(s), field);
+ }
+}
+
+static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
+{
+ int field = ~((s->regs[R_CONFIG] & CS) >> CS_SHIFT);
+
+ /* In dual parallel, mirror low CS to both */
+ if (num_effective_busses(s) == 2) {
+ /* Single bit chip-select for qspi */
+ field &= 0x1;
+ field |= field << 1;
+ /* Dual stack U-Page */
+ } else if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM &&
+ s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE) {
+ /* Single bit chip-select for qspi */
+ field &= 0x1;
+ /* change from CS0 to CS1 */
+ field <<= 1;
+ }
+ /* Auto CS */
+ if (!(s->regs[R_CONFIG] & MANUAL_CS) &&
+ fifo8_is_empty(&s->tx_fifo)) {
+ field = 0;
+ }
+ xilinx_spips_update_cs(s, field);
+}
+
static void xilinx_spips_update_ixr(XilinxSPIPS *s)
{
- if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE) {
- return;
+ if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
+ s->regs[R_INTR_STATUS] &= ~IXR_SELF_CLEAR;
+ s->regs[R_INTR_STATUS] |=
+ (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
+ (s->rx_fifo.num >= s->regs[R_RX_THRES] ?
+ IXR_RX_FIFO_NOT_EMPTY : 0) |
+ (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
+ (fifo8_is_empty(&s->tx_fifo) ? IXR_TX_FIFO_EMPTY : 0) |
+ (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
}
- /* These are set/cleared as they occur */
- s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
- IXR_TX_FIFO_MODE_FAIL);
- /* these are pure functions of fifo state, set them here */
- s->regs[R_INTR_STATUS] |=
- (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
- (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
- (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
- (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
- /* drive external interrupt pin */
int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
IXR_ALL);
if (new_irqline != s->irqline) {
@@ -219,14 +294,42 @@ static void xilinx_spips_update_ixr(XilinxSPIPS *s)
}
}
+static void xlnx_zynqmp_qspips_update_ixr(XlnxZynqMPQSPIPS *s)
+{
+ uint32_t gqspi_int;
+ int new_irqline;
+
+ s->regs[R_GQSPI_ISR] &= ~IXR_SELF_CLEAR;
+ s->regs[R_GQSPI_ISR] |=
+ (fifo32_is_empty(&s->fifo_g) ? IXR_GENERIC_FIFO_EMPTY : 0) |
+ (fifo32_is_full(&s->fifo_g) ? IXR_GENERIC_FIFO_FULL : 0) |
+ (s->fifo_g.fifo.num < s->regs[R_GQSPI_GFIFO_THRESH] ?
+ IXR_GENERIC_FIFO_NOT_FULL : 0) |
+ (fifo8_is_empty(&s->rx_fifo_g) ? IXR_RX_FIFO_EMPTY : 0) |
+ (fifo8_is_full(&s->rx_fifo_g) ? IXR_RX_FIFO_FULL : 0) |
+ (s->rx_fifo_g.num >= s->regs[R_GQSPI_RX_THRESH] ?
+ IXR_RX_FIFO_NOT_EMPTY : 0) |
+ (fifo8_is_empty(&s->tx_fifo_g) ? IXR_TX_FIFO_EMPTY : 0) |
+ (fifo8_is_full(&s->tx_fifo_g) ? IXR_TX_FIFO_FULL : 0) |
+ (s->tx_fifo_g.num < s->regs[R_GQSPI_TX_THRESH] ?
+ IXR_TX_FIFO_NOT_FULL : 0);
+
+ /* GQSPI Interrupt Trigger Status */
+ gqspi_int = (~s->regs[R_GQSPI_IMR]) & s->regs[R_GQSPI_ISR] & GQSPI_IXR_MASK;
+ new_irqline = !!(gqspi_int & IXR_ALL);
+
+ /* drive external interrupt pin */
+ if (new_irqline != s->gqspi_irqline) {
+ s->gqspi_irqline = new_irqline;
+ qemu_set_irq(XILINX_SPIPS(s)->irq, s->gqspi_irqline);
+ }
+}
+
static void xilinx_spips_reset(DeviceState *d)
{
XilinxSPIPS *s = XILINX_SPIPS(d);
- int i;
- for (i = 0; i < XLNX_SPIPS_R_MAX; i++) {
- s->regs[i] = 0;
- }
+ memset(s->regs, 0, sizeof(s->regs));
fifo8_reset(&s->rx_fifo);
fifo8_reset(&s->rx_fifo);
@@ -238,19 +341,54 @@ static void xilinx_spips_reset(DeviceState *d)
/* FIXME: move magic number definition somewhere sensible */
s->regs[R_MOD_ID] = 0x01090106;
s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
+ s->link_state = 1;
+ s->link_state_next = 1;
+ s->link_state_next_when = 0;
s->snoop_state = SNOOP_CHECKING;
+ s->cmd_dummies = 0;
+ s->man_start_com = false;
xilinx_spips_update_ixr(s);
xilinx_spips_update_cs_lines(s);
}
-/* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB)
+static void xlnx_zynqmp_qspips_reset(DeviceState *d)
+{
+ XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(d);
+
+ xilinx_spips_reset(d);
+
+ memset(s->regs, 0, sizeof(s->regs));
+
+ fifo8_reset(&s->rx_fifo_g);
+ fifo8_reset(&s->rx_fifo_g);
+ fifo32_reset(&s->fifo_g);
+ s->regs[R_INTR_STATUS] = R_INTR_STATUS_RESET;
+ s->regs[R_GPIO] = 1;
+ s->regs[R_LPBK_DLY_ADJ] = R_LPBK_DLY_ADJ_RESET;
+ s->regs[R_GQSPI_GFIFO_THRESH] = 0x10;
+ s->regs[R_MOD_ID] = 0x01090101;
+ s->regs[R_GQSPI_IMR] = R_GQSPI_IMR_RESET;
+ s->regs[R_GQSPI_TX_THRESH] = 1;
+ s->regs[R_GQSPI_RX_THRESH] = 1;
+ s->regs[R_GQSPI_GPIO] = 1;
+ s->regs[R_GQSPI_LPBK_DLY_ADJ] = R_GQSPI_LPBK_DLY_ADJ_RESET;
+ s->regs[R_GQSPI_MOD_ID] = R_GQSPI_MOD_ID_RESET;
+ s->regs[R_QSPIDMA_DST_CTRL] = R_QSPIDMA_DST_CTRL_RESET;
+ s->regs[R_QSPIDMA_DST_I_MASK] = R_QSPIDMA_DST_I_MASK_RESET;
+ s->regs[R_QSPIDMA_DST_CTRL2] = R_QSPIDMA_DST_CTRL2_RESET;
+ s->man_start_com_g = false;
+ s->gqspi_irqline = 0;
+ xlnx_zynqmp_qspips_update_ixr(s);
+}
+
+/* N way (num) in place bit striper. Lay out row wise bits (MSB to LSB)
* column wise (from element 0 to N-1). num is the length of x, and dir
* reverses the direction of the transform. Best illustrated by example:
* Each digit in the below array is a single bit (num == 3):
*
- * {{ 76543210, } ----- stripe (dir == false) -----> {{ FCheb630, }
- * { hgfedcba, } { GDAfc741, }
- * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { HEBgda52, }}
+ * {{ 76543210, } ----- stripe (dir == false) -----> {{ 741gdaFC, }
+ * { hgfedcba, } { 630fcHEB, }
+ * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { 52hebGDA, }}
*/
static inline void stripe8(uint8_t *x, int num, bool dir)
@@ -258,34 +396,188 @@ static inline void stripe8(uint8_t *x, int num, bool dir)
uint8_t r[num];
memset(r, 0, sizeof(uint8_t) * num);
int idx[2] = {0, 0};
- int bit[2] = {0, 0};
+ int bit[2] = {0, 7};
int d = dir;
for (idx[0] = 0; idx[0] < num; ++idx[0]) {
- for (bit[0] = 0; bit[0] < 8; ++bit[0]) {
- r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0;
+ for (bit[0] = 7; bit[0] >= 0; bit[0]--) {
+ r[idx[!d]] |= x[idx[d]] & 1 << bit[d] ? 1 << bit[!d] : 0;
idx[1] = (idx[1] + 1) % num;
if (!idx[1]) {
- bit[1]++;
+ bit[1]--;
}
}
}
memcpy(x, r, sizeof(uint8_t) * num);
}
+static void xlnx_zynqmp_qspips_flush_fifo_g(XlnxZynqMPQSPIPS *s)
+{
+ while (s->regs[R_GQSPI_DATA_STS] || !fifo32_is_empty(&s->fifo_g)) {
+ uint8_t tx_rx[2] = { 0 };
+ int num_stripes = 1;
+ uint8_t busses;
+ int i;
+
+ if (!s->regs[R_GQSPI_DATA_STS]) {
+ uint8_t imm;
+
+ s->regs[R_GQSPI_GF_SNAPSHOT] = fifo32_pop(&s->fifo_g);
+ DB_PRINT_L(0, "GQSPI command: %x\n", s->regs[R_GQSPI_GF_SNAPSHOT]);
+ if (!s->regs[R_GQSPI_GF_SNAPSHOT]) {
+ DB_PRINT_L(0, "Dummy GQSPI Delay Command Entry, Do nothing");
+ continue;
+ }
+ xlnx_zynqmp_qspips_update_cs_lines(s);
+
+ imm = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA);
+ if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) {
+ /* immedate transfer */
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) ||
+ ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
+ s->regs[R_GQSPI_DATA_STS] = 1;
+ /* CS setup/hold - do nothing */
+ } else {
+ s->regs[R_GQSPI_DATA_STS] = 0;
+ }
+ } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, EXPONENT)) {
+ if (imm > 31) {
+ qemu_log_mask(LOG_UNIMP, "QSPI exponential transfer too"
+ " long - 2 ^ %" PRId8 " requested\n", imm);
+ }
+ s->regs[R_GQSPI_DATA_STS] = 1ul << imm;
+ } else {
+ s->regs[R_GQSPI_DATA_STS] = imm;
+ }
+ }
+ /* Zero length transfer check */
+ if (!s->regs[R_GQSPI_DATA_STS]) {
+ continue;
+ }
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE) &&
+ fifo8_is_full(&s->rx_fifo_g)) {
+ /* No space in RX fifo for transfer - try again later */
+ return;
+ }
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, STRIPE) &&
+ (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) ||
+ ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE))) {
+ num_stripes = 2;
+ }
+ if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) {
+ tx_rx[0] = ARRAY_FIELD_EX32(s->regs,
+ GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA);
+ } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT)) {
+ for (i = 0; i < num_stripes; ++i) {
+ if (!fifo8_is_empty(&s->tx_fifo_g)) {
+ tx_rx[i] = fifo8_pop(&s->tx_fifo_g);
+ s->tx_fifo_g_align++;
+ } else {
+ return;
+ }
+ }
+ }
+ if (num_stripes == 1) {
+ /* mirror */
+ tx_rx[1] = tx_rx[0];
+ }
+ busses = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT);
+ for (i = 0; i < 2; ++i) {
+ DB_PRINT_L(1, "bus %d tx = %02x\n", i, tx_rx[i]);
+ tx_rx[i] = ssi_transfer(XILINX_SPIPS(s)->spi[i], tx_rx[i]);
+ DB_PRINT_L(1, "bus %d rx = %02x\n", i, tx_rx[i]);
+ }
+ if (s->regs[R_GQSPI_DATA_STS] > 1 &&
+ busses == 0x3 && num_stripes == 2) {
+ s->regs[R_GQSPI_DATA_STS] -= 2;
+ } else if (s->regs[R_GQSPI_DATA_STS] > 0) {
+ s->regs[R_GQSPI_DATA_STS]--;
+ }
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) {
+ for (i = 0; i < 2; ++i) {
+ if (busses & (1 << i)) {
+ DB_PRINT_L(1, "bus %d push_byte = %02x\n", i, tx_rx[i]);
+ fifo8_push(&s->rx_fifo_g, tx_rx[i]);
+ s->rx_fifo_g_align++;
+ }
+ }
+ }
+ if (!s->regs[R_GQSPI_DATA_STS]) {
+ for (; s->tx_fifo_g_align % 4; s->tx_fifo_g_align++) {
+ fifo8_pop(&s->tx_fifo_g);
+ }
+ for (; s->rx_fifo_g_align % 4; s->rx_fifo_g_align++) {
+ fifo8_push(&s->rx_fifo_g, 0);
+ }
+ }
+ }
+}
+
+static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command)
+{
+ if (!qs) {
+ /* The SPI device is not a QSPI device */
+ return -1;
+ }
+
+ switch (command) { /* check for dummies */
+ case READ: /* no dummy bytes/cycles */
+ case PP:
+ case DPP:
+ case QPP:
+ case READ_4:
+ case PP_4:
+ case QPP_4:
+ return 0;
+ case FAST_READ:
+ case DOR:
+ case QOR:
+ case DOR_4:
+ case QOR_4:
+ return 1;
+ case DIOR:
+ case FAST_READ_4:
+ case DIOR_4:
+ return 2;
+ case QIOR:
+ case QIOR_4:
+ return 5;
+ default:
+ return -1;
+ }
+}
+
+static inline uint8_t get_addr_length(XilinxSPIPS *s, uint8_t cmd)
+{
+ switch (cmd) {
+ case PP_4:
+ case QPP_4:
+ case READ_4:
+ case QIOR_4:
+ case FAST_READ_4:
+ case DOR_4:
+ case QOR_4:
+ case DIOR_4:
+ return 4;
+ default:
+ return (s->regs[R_CMND] & R_CMND_EXT_ADD) ? 4 : 3;
+ }
+}
+
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
int debug_level = 0;
+ XilinxQSPIPS *q = (XilinxQSPIPS *) object_dynamic_cast(OBJECT(s),
+ TYPE_XILINX_QSPIPS);
for (;;) {
int i;
uint8_t tx = 0;
uint8_t tx_rx[num_effective_busses(s)];
+ uint8_t dummy_cycles = 0;
+ uint8_t addr_length;
if (fifo8_is_empty(&s->tx_fifo)) {
- if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
- s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
- }
xilinx_spips_update_ixr(s);
return;
} else if (s->snoop_state == SNOOP_STRIPING) {
@@ -293,53 +585,102 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
tx_rx[i] = fifo8_pop(&s->tx_fifo);
}
stripe8(tx_rx, num_effective_busses(s), false);
- } else {
+ } else if (s->snoop_state >= SNOOP_ADDR) {
tx = fifo8_pop(&s->tx_fifo);
for (i = 0; i < num_effective_busses(s); ++i) {
tx_rx[i] = tx;
}
+ } else {
+ /* Extract a dummy byte and generate dummy cycles according to the
+ * link state */
+ tx = fifo8_pop(&s->tx_fifo);
+ dummy_cycles = 8 / s->link_state;
}
for (i = 0; i < num_effective_busses(s); ++i) {
- DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
- tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]);
- DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
+ int bus = num_effective_busses(s) - 1 - i;
+ if (dummy_cycles) {
+ int d;
+ for (d = 0; d < dummy_cycles; ++d) {
+ tx_rx[0] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[0]);
+ }
+ } else {
+ DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
+ tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]);
+ DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
+ }
}
- if (fifo8_is_full(&s->rx_fifo)) {
+ if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) {
+ DB_PRINT_L(debug_level, "dircarding drained rx byte\n");
+ /* Do nothing */
+ } else if (s->rx_discard) {
+ DB_PRINT_L(debug_level, "dircarding discarded rx byte\n");
+ s->rx_discard -= 8 / s->link_state;
+ } else if (fifo8_is_full(&s->rx_fifo)) {
s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
DB_PRINT_L(0, "rx FIFO overflow");
} else if (s->snoop_state == SNOOP_STRIPING) {
stripe8(tx_rx, num_effective_busses(s), true);
for (i = 0; i < num_effective_busses(s); ++i) {
fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]);
+ DB_PRINT_L(debug_level, "pushing striped rx byte\n");
}
} else {
+ DB_PRINT_L(debug_level, "pushing unstriped rx byte\n");
fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
}
+ if (s->link_state_next_when) {
+ s->link_state_next_when--;
+ if (!s->link_state_next_when) {
+ s->link_state = s->link_state_next;
+ }
+ }
+
DB_PRINT_L(debug_level, "initial snoop state: %x\n",
(unsigned)s->snoop_state);
switch (s->snoop_state) {
case (SNOOP_CHECKING):
- switch (tx) { /* new instruction code */
- case READ: /* 3 address bytes, no dummy bytes/cycles */
- case PP:
+ /* Store the count of dummy bytes in the txfifo */
+ s->cmd_dummies = xilinx_spips_num_dummies(q, tx);
+ addr_length = get_addr_length(s, tx);
+ if (s->cmd_dummies < 0) {
+ s->snoop_state = SNOOP_NONE;
+ } else {
+ s->snoop_state = SNOOP_ADDR + addr_length - 1;
+ }
+ switch (tx) {
case DPP:
- case QPP:
- s->snoop_state = 3;
- break;
- case FAST_READ: /* 3 address bytes, 1 dummy byte */
case DOR:
+ case DOR_4:
+ s->link_state_next = 2;
+ s->link_state_next_when = addr_length + s->cmd_dummies;
+ break;
+ case QPP:
+ case QPP_4:
case QOR:
- case DIOR: /* FIXME: these vary between vendor - set to spansion */
- s->snoop_state = 4;
+ case QOR_4:
+ s->link_state_next = 4;
+ s->link_state_next_when = addr_length + s->cmd_dummies;
+ break;
+ case DIOR:
+ case DIOR_4:
+ s->link_state = 2;
break;
- case QIOR: /* 3 address bytes, 2 dummy bytes */
- s->snoop_state = 6;
+ case QIOR:
+ case QIOR_4:
+ s->link_state = 4;
break;
- default:
+ }
+ break;
+ case (SNOOP_ADDR):
+ /* Address has been transmitted, transmit dummy cycles now if
+ * needed */
+ if (s->cmd_dummies < 0) {
s->snoop_state = SNOOP_NONE;
+ } else {
+ s->snoop_state = s->cmd_dummies;
}
break;
case (SNOOP_STRIPING):
@@ -358,12 +699,128 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
}
}
-static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max)
+static inline void tx_data_bytes(Fifo8 *fifo, uint32_t value, int num, bool be)
+{
+ int i;
+ for (i = 0; i < num && !fifo8_is_full(fifo); ++i) {
+ if (be) {
+ fifo8_push(fifo, (uint8_t)(value >> 24));
+ value <<= 8;
+ } else {
+ fifo8_push(fifo, (uint8_t)value);
+ value >>= 8;
+ }
+ }
+}
+
+static void xilinx_spips_check_zero_pump(XilinxSPIPS *s)
+{
+ if (!s->regs[R_TRANSFER_SIZE]) {
+ return;
+ }
+ if (!fifo8_is_empty(&s->tx_fifo) && s->regs[R_CMND] & R_CMND_PUSH_WAIT) {
+ return;
+ }
+ /*
+ * The zero pump must never fill tx fifo such that rx overflow is
+ * possible
+ */
+ while (s->regs[R_TRANSFER_SIZE] &&
+ s->rx_fifo.num + s->tx_fifo.num < RXFF_A_Q - 3) {
+ /* endianess just doesn't matter when zero pumping */
+ tx_data_bytes(&s->tx_fifo, 0, 4, false);
+ s->regs[R_TRANSFER_SIZE] &= ~0x03ull;
+ s->regs[R_TRANSFER_SIZE] -= 4;
+ }
+}
+
+static void xilinx_spips_check_flush(XilinxSPIPS *s)
+{
+ if (s->man_start_com ||
+ (!fifo8_is_empty(&s->tx_fifo) &&
+ !(s->regs[R_CONFIG] & MAN_START_EN))) {
+ xilinx_spips_check_zero_pump(s);
+ xilinx_spips_flush_txfifo(s);
+ }
+ if (fifo8_is_empty(&s->tx_fifo) && !s->regs[R_TRANSFER_SIZE]) {
+ s->man_start_com = false;
+ }
+ xilinx_spips_update_ixr(s);
+}
+
+static void xlnx_zynqmp_qspips_check_flush(XlnxZynqMPQSPIPS *s)
+{
+ bool gqspi_has_work = s->regs[R_GQSPI_DATA_STS] ||
+ !fifo32_is_empty(&s->fifo_g);
+
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) {
+ if (s->man_start_com_g || (gqspi_has_work &&
+ !ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, GEN_FIFO_START_MODE))) {
+ xlnx_zynqmp_qspips_flush_fifo_g(s);
+ }
+ } else {
+ xilinx_spips_check_flush(XILINX_SPIPS(s));
+ }
+ if (!gqspi_has_work) {
+ s->man_start_com_g = false;
+ }
+ xlnx_zynqmp_qspips_update_ixr(s);
+}
+
+static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max)
{
int i;
- for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
- value[i] = fifo8_pop(&s->rx_fifo);
+ for (i = 0; i < max && !fifo8_is_empty(fifo); ++i) {
+ value[i] = fifo8_pop(fifo);
+ }
+ return max - i;
+}
+
+static const void *pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num)
+{
+ void *ret;
+
+ if (max == 0 || max > fifo->num) {
+ abort();
+ }
+ *num = MIN(fifo->capacity - fifo->head, max);
+ ret = &fifo->data[fifo->head];
+ fifo->head += *num;
+ fifo->head %= fifo->capacity;
+ fifo->num -= *num;
+ return ret;
+}
+
+static void xlnx_zynqmp_qspips_notify(void *opaque)
+{
+ XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(opaque);
+ XilinxSPIPS *s = XILINX_SPIPS(rq);
+ Fifo8 *recv_fifo;
+
+ if (ARRAY_FIELD_EX32(rq->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) {
+ if (!(ARRAY_FIELD_EX32(rq->regs, GQSPI_CNFG, MODE_EN) == 2)) {
+ return;
+ }
+ recv_fifo = &rq->rx_fifo_g;
+ } else {
+ if (!(s->regs[R_CMND] & R_CMND_DMA_EN)) {
+ return;
+ }
+ recv_fifo = &s->rx_fifo;
+ }
+ while (recv_fifo->num >= 4
+ && stream_can_push(rq->dma, xlnx_zynqmp_qspips_notify, rq))
+ {
+ size_t ret;
+ uint32_t num;
+ const void *rxd = pop_buf(recv_fifo, 4, &num);
+
+ memcpy(rq->dma_buf, rxd, num);
+
+ ret = stream_push(rq->dma, rq->dma_buf, 4);
+ assert(ret == 4);
+ xlnx_zynqmp_qspips_check_flush(rq);
}
}
@@ -374,6 +831,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
uint32_t mask = ~0;
uint32_t ret;
uint8_t rx_buf[4];
+ int shortfall;
addr >>= 2;
switch (addr) {
@@ -384,6 +842,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
ret = s->regs[addr] & IXR_ALL;
s->regs[addr] = 0;
DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+ xilinx_spips_update_ixr(s);
return ret;
case R_INTR_MASK:
mask = IXR_ALL;
@@ -404,10 +863,15 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
break;
case R_RX_DATA:
memset(rx_buf, 0, sizeof(rx_buf));
- rx_data_bytes(s, rx_buf, s->num_txrx_bytes);
- ret = s->regs[R_CONFIG] & ENDIAN ? cpu_to_be32(*(uint32_t *)rx_buf)
- : cpu_to_le32(*(uint32_t *)rx_buf);
+ shortfall = rx_data_bytes(&s->rx_fifo, rx_buf, s->num_txrx_bytes);
+ ret = s->regs[R_CONFIG] & R_CONFIG_ENDIAN ?
+ cpu_to_be32(*(uint32_t *)rx_buf) :
+ cpu_to_le32(*(uint32_t *)rx_buf);
+ if (!(s->regs[R_CONFIG] & R_CONFIG_ENDIAN)) {
+ ret <<= 8 * shortfall;
+ }
DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+ xilinx_spips_check_flush(s);
xilinx_spips_update_ixr(s);
return ret;
}
@@ -417,16 +881,39 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
}
-static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
+static uint64_t xlnx_zynqmp_qspips_read(void *opaque,
+ hwaddr addr, unsigned size)
{
- int i;
- for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
- if (s->regs[R_CONFIG] & ENDIAN) {
- fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
- value <<= 8;
- } else {
- fifo8_push(&s->tx_fifo, (uint8_t)value);
- value >>= 8;
+ XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(opaque);
+ uint32_t reg = addr / 4;
+ uint32_t ret;
+ uint8_t rx_buf[4];
+ int shortfall;
+
+ if (reg <= R_MOD_ID) {
+ return xilinx_spips_read(opaque, addr, size);
+ } else {
+ switch (reg) {
+ case R_GQSPI_RXD:
+ if (fifo8_is_empty(&s->rx_fifo_g)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Read from empty GQSPI RX FIFO\n");
+ return 0;
+ }
+ memset(rx_buf, 0, sizeof(rx_buf));
+ shortfall = rx_data_bytes(&s->rx_fifo_g, rx_buf,
+ XILINX_SPIPS(s)->num_txrx_bytes);
+ ret = ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN) ?
+ cpu_to_be32(*(uint32_t *)rx_buf) :
+ cpu_to_le32(*(uint32_t *)rx_buf);
+ if (!ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN)) {
+ ret <<= 8 * shortfall;
+ }
+ xlnx_zynqmp_qspips_check_flush(s);
+ xlnx_zynqmp_qspips_update_ixr(s);
+ return ret;
+ default:
+ return s->regs[reg];
}
}
}
@@ -435,7 +922,6 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
int mask = ~0;
- int man_start_com = 0;
XilinxSPIPS *s = opaque;
DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
@@ -443,8 +929,8 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
switch (addr) {
case R_CONFIG:
mask = ~(R_CONFIG_RSVD | MAN_START_COM);
- if (value & MAN_START_COM) {
- man_start_com = 1;
+ if ((value & MAN_START_COM) && (s->regs[R_CONFIG] & MAN_START_EN)) {
+ s->man_start_com = true;
}
break;
case R_INTR_STATUS:
@@ -471,25 +957,26 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
mask = 0;
break;
case R_TX_DATA:
- tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
+ tx_data_bytes(&s->tx_fifo, (uint32_t)value, s->num_txrx_bytes,
+ s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
goto no_reg_update;
case R_TXD1:
- tx_data_bytes(s, (uint32_t)value, 1);
+ tx_data_bytes(&s->tx_fifo, (uint32_t)value, 1,
+ s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
goto no_reg_update;
case R_TXD2:
- tx_data_bytes(s, (uint32_t)value, 2);
+ tx_data_bytes(&s->tx_fifo, (uint32_t)value, 2,
+ s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
goto no_reg_update;
case R_TXD3:
- tx_data_bytes(s, (uint32_t)value, 3);
+ tx_data_bytes(&s->tx_fifo, (uint32_t)value, 3,
+ s->regs[R_CONFIG] & R_CONFIG_ENDIAN);
goto no_reg_update;
}
s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
no_reg_update:
xilinx_spips_update_cs_lines(s);
- if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) ||
- (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) {
- xilinx_spips_flush_txfifo(s);
- }
+ xilinx_spips_check_flush(s);
xilinx_spips_update_cs_lines(s);
xilinx_spips_update_ixr(s);
}
@@ -517,6 +1004,7 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
XilinxQSPIPS *q = XILINX_QSPIPS(opaque);
+ XilinxSPIPS *s = XILINX_SPIPS(opaque);
xilinx_spips_write(opaque, addr, value, size);
addr >>= 2;
@@ -524,6 +1012,72 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr,
if (addr == R_LQSPI_CFG) {
xilinx_qspips_invalidate_mmio_ptr(q);
}
+ if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) {
+ fifo8_reset(&s->rx_fifo);
+ }
+}
+
+static void xlnx_zynqmp_qspips_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(opaque);
+ uint32_t reg = addr / 4;
+
+ if (reg <= R_MOD_ID) {
+ xilinx_qspips_write(opaque, addr, value, size);
+ } else {
+ switch (reg) {
+ case R_GQSPI_CNFG:
+ if (FIELD_EX32(value, GQSPI_CNFG, GEN_FIFO_START) &&
+ ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, GEN_FIFO_START_MODE)) {
+ s->man_start_com_g = true;
+ }
+ s->regs[reg] = value & ~(R_GQSPI_CNFG_GEN_FIFO_START_MASK);
+ break;
+ case R_GQSPI_GEN_FIFO:
+ if (!fifo32_is_full(&s->fifo_g)) {
+ fifo32_push(&s->fifo_g, value);
+ }
+ break;
+ case R_GQSPI_TXD:
+ tx_data_bytes(&s->tx_fifo_g, (uint32_t)value, 4,
+ ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN));
+ break;
+ case R_GQSPI_FIFO_CTRL:
+ if (FIELD_EX32(value, GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET)) {
+ fifo32_reset(&s->fifo_g);
+ }
+ if (FIELD_EX32(value, GQSPI_FIFO_CTRL, TX_FIFO_RESET)) {
+ fifo8_reset(&s->tx_fifo_g);
+ }
+ if (FIELD_EX32(value, GQSPI_FIFO_CTRL, RX_FIFO_RESET)) {
+ fifo8_reset(&s->rx_fifo_g);
+ }
+ break;
+ case R_GQSPI_IDR:
+ s->regs[R_GQSPI_IMR] |= value;
+ break;
+ case R_GQSPI_IER:
+ s->regs[R_GQSPI_IMR] &= ~value;
+ break;
+ case R_GQSPI_ISR:
+ s->regs[R_GQSPI_ISR] &= ~value;
+ break;
+ case R_GQSPI_IMR:
+ case R_GQSPI_RXD:
+ case R_GQSPI_GF_SNAPSHOT:
+ case R_GQSPI_MOD_ID:
+ break;
+ default:
+ s->regs[reg] = value;
+ break;
+ }
+ xlnx_zynqmp_qspips_update_cs_lines(s);
+ xlnx_zynqmp_qspips_check_flush(s);
+ xlnx_zynqmp_qspips_update_cs_lines(s);
+ xlnx_zynqmp_qspips_update_ixr(s);
+ }
+ xlnx_zynqmp_qspips_notify(s);
}
static const MemoryRegionOps qspips_ops = {
@@ -532,6 +1086,12 @@ static const MemoryRegionOps qspips_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static const MemoryRegionOps xlnx_zynqmp_qspips_ops = {
+ .read = xlnx_zynqmp_qspips_read,
+ .write = xlnx_zynqmp_qspips_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
#define LQSPI_CACHE_SIZE 1024
static void lqspi_load_cache(void *opaque, hwaddr addr)
@@ -563,6 +1123,9 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
/* read address */
DB_PRINT_L(0, "pushing read address %06x\n", flash_addr);
+ if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_ADDR4) {
+ fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 24));
+ }
fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
@@ -586,11 +1149,11 @@ static void lqspi_load_cache(void *opaque, hwaddr addr)
while (cache_entry < LQSPI_CACHE_SIZE) {
for (i = 0; i < 64; ++i) {
- tx_data_bytes(s, 0, 1);
+ tx_data_bytes(&s->tx_fifo, 0, 1, false);
}
xilinx_spips_flush_txfifo(s);
for (i = 0; i < 64; ++i) {
- rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1);
+ rx_data_bytes(&s->rx_fifo, &q->lqspi_buf[cache_entry++], 1);
}
}
@@ -666,6 +1229,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
}
s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
+ s->cs_lines_state = g_new0(bool, s->num_cs * s->num_busses);
for (i = 0, cs = s->cs_lines; i < s->num_busses; ++i, cs += s->num_cs) {
ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]);
}
@@ -676,7 +1240,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
}
memory_region_init_io(&s->iomem, OBJECT(s), xsc->reg_ops, s,
- "spi", XLNX_SPIPS_R_MAX * 4);
+ "spi", XLNX_ZYNQMP_SPIPS_R_MAX * 4);
sysbus_init_mmio(sbd, &s->iomem);
s->irqline = -1;
@@ -714,6 +1278,28 @@ static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
}
}
+static void xlnx_zynqmp_qspips_realize(DeviceState *dev, Error **errp)
+{
+ XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(dev);
+ XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s);
+
+ xilinx_qspips_realize(dev, errp);
+ fifo8_create(&s->rx_fifo_g, xsc->rx_fifo_size);
+ fifo8_create(&s->tx_fifo_g, xsc->tx_fifo_size);
+ fifo32_create(&s->fifo_g, 32);
+}
+
+static void xlnx_zynqmp_qspips_init(Object *obj)
+{
+ XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(obj);
+
+ object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE,
+ (Object **)&rq->dma,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ NULL);
+}
+
static int xilinx_spips_post_load(void *opaque, int version_id)
{
xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
@@ -735,6 +1321,46 @@ static const VMStateDescription vmstate_xilinx_spips = {
}
};
+static int xlnx_zynqmp_qspips_post_load(void *opaque, int version_id)
+{
+ XlnxZynqMPQSPIPS *s = (XlnxZynqMPQSPIPS *)opaque;
+ XilinxSPIPS *qs = XILINX_SPIPS(s);
+
+ if (ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN) &&
+ fifo8_is_empty(&qs->rx_fifo) && fifo8_is_empty(&qs->tx_fifo)) {
+ xlnx_zynqmp_qspips_update_ixr(s);
+ xlnx_zynqmp_qspips_update_cs_lines(s);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_xilinx_qspips = {
+ .name = "xilinx_qspips",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(parent_obj, XilinxQSPIPS, 0,
+ vmstate_xilinx_spips, XilinxSPIPS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_xlnx_zynqmp_qspips = {
+ .name = "xlnx_zynqmp_qspips",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = xlnx_zynqmp_qspips_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(parent_obj, XlnxZynqMPQSPIPS, 0,
+ vmstate_xilinx_qspips, XilinxQSPIPS),
+ VMSTATE_FIFO8(tx_fifo_g, XlnxZynqMPQSPIPS),
+ VMSTATE_FIFO8(rx_fifo_g, XlnxZynqMPQSPIPS),
+ VMSTATE_FIFO32(fifo_g, XlnxZynqMPQSPIPS),
+ VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPQSPIPS, XLNX_ZYNQMP_SPIPS_R_MAX),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static Property xilinx_qspips_properties[] = {
/* We had to turn this off for 2.10 as it is not compatible with migration.
* It can be enabled but will prevent the device to be migrated.
@@ -779,6 +1405,19 @@ static void xilinx_spips_class_init(ObjectClass *klass, void *data)
xsc->tx_fifo_size = TXFF_A;
}
+static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, void * data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
+
+ dc->realize = xlnx_zynqmp_qspips_realize;
+ dc->reset = xlnx_zynqmp_qspips_reset;
+ dc->vmsd = &vmstate_xlnx_zynqmp_qspips;
+ xsc->reg_ops = &xlnx_zynqmp_qspips_ops;
+ xsc->rx_fifo_size = RXFF_A_Q;
+ xsc->tx_fifo_size = TXFF_A_Q;
+}
+
static const TypeInfo xilinx_spips_info = {
.name = TYPE_XILINX_SPIPS,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -794,10 +1433,19 @@ static const TypeInfo xilinx_qspips_info = {
.class_init = xilinx_qspips_class_init,
};
+static const TypeInfo xlnx_zynqmp_qspips_info = {
+ .name = TYPE_XLNX_ZYNQMP_QSPIPS,
+ .parent = TYPE_XILINX_QSPIPS,
+ .instance_size = sizeof(XlnxZynqMPQSPIPS),
+ .instance_init = xlnx_zynqmp_qspips_init,
+ .class_init = xlnx_zynqmp_qspips_class_init,
+};
+
static void xilinx_spips_register_types(void)
{
type_register_static(&xilinx_spips_info);
type_register_static(&xilinx_qspips_info);
+ type_register_static(&xlnx_zynqmp_qspips_info);
}
type_init(xilinx_spips_register_types)
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
index 5e61ad50a8..dbc4a0baec 100644
--- a/hw/timer/i8254.c
+++ b/hw/timer/i8254.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "qemu/timer.h"
#include "hw/timer/i8254.h"
diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c
index b623c96198..6190b6fc5d 100644
--- a/hw/timer/i8254_common.c
+++ b/hw/timer/i8254_common.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
#include "qemu/timer.h"
#include "hw/timer/i8254.h"
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 7764be25ec..35a05a64cc 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -999,7 +999,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
qdev_init_gpio_out(dev, &s->irq, 1);
}
-ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
+ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
{
DeviceState *dev;
ISADevice *isadev;
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
index 68ba5a70b3..a489bf5159 100644
--- a/hw/timer/pxa2xx_timer.c
+++ b/hw/timer/pxa2xx_timer.c
@@ -13,6 +13,7 @@
#include "sysemu/sysemu.h"
#include "hw/arm/pxa.h"
#include "hw/sysbus.h"
+#include "qemu/log.h"
#define OSMR0 0x00
#define OSMR1 0x04
@@ -252,8 +253,14 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
case OSNR:
return s->snapshot;
default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unknown register 0x%02" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
badreg:
- hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
+ __func__, offset);
}
return 0;
@@ -377,8 +384,14 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset,
}
break;
default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unknown register 0x%02" HWADDR_PRIx " "
+ "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
+ break;
badreg:
- hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: incorrect register 0x%02" HWADDR_PRIx " "
+ "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
}
}
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index a8cc9c0148..4694b653a7 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
-#include "hw/sparc/sun4m.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "hw/sysbus.h"
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 41f0b7a590..7a93b24636 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,3 +1,4 @@
+common-obj-y += tpm_util.o
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
-common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
-common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o
+common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
index e1a68104d6..35c78de5a9 100644
--- a/hw/tpm/tpm_emulator.c
+++ b/hw/tpm/tpm_emulator.c
@@ -33,7 +33,6 @@
#include "sysemu/tpm_backend.h"
#include "tpm_int.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "tpm_util.h"
#include "tpm_ioctl.h"
#include "migration/blocker.h"
@@ -73,6 +72,9 @@ typedef struct TPMEmulator {
Error *migration_blocker;
QemuMutex mutex;
+
+ unsigned int established_flag:1;
+ unsigned int established_flag_cached:1;
} TPMEmulator;
@@ -186,7 +188,6 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
- TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state);
Error *err = NULL;
DPRINTF("processing TPM command");
@@ -201,7 +202,6 @@ static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
goto error;
}
- tic->request_completed(TPM_IF(tb->tpm_state));
return;
error:
@@ -234,13 +234,14 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
switch (tpm_emu->tpm_version) {
case TPM_VERSION_1_2:
caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
- PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD;
+ PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
+ PTM_CAP_SET_BUFFERSIZE;
tpm = "1.2";
break;
case TPM_VERSION_2_0:
caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
- PTM_CAP_SET_DATAFD;
+ PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
tpm = "2";
break;
case TPM_VERSION_UNSPEC:
@@ -257,12 +258,76 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
return 0;
}
-static int tpm_emulator_startup_tpm(TPMBackend *tb)
+static int tpm_emulator_stop_tpm(TPMBackend *tb)
+{
+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+ ptm_res res;
+
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
+ error_report("tpm-emulator: Could not stop TPM: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = be32_to_cpu(res);
+ if (res) {
+ error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x", res);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_set_buffer_size(TPMBackend *tb,
+ size_t wanted_size,
+ size_t *actual_size)
+{
+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+ ptm_setbuffersize psbs;
+
+ if (tpm_emulator_stop_tpm(tb) < 0) {
+ return -1;
+ }
+
+ psbs.u.req.buffersize = cpu_to_be32(wanted_size);
+
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
+ sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
+ error_report("tpm-emulator: Could not set buffer size: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
+ if (psbs.u.resp.tpm_result != 0) {
+ error_report("tpm-emulator: TPM result for set buffer size : 0x%x",
+ psbs.u.resp.tpm_result);
+ return -1;
+ }
+
+ if (actual_size) {
+ *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
+ }
+
+ DPRINTF("buffer size: %u, min: %u, max: %u\n",
+ be32_to_cpu(psbs.u.resp.buffersize),
+ be32_to_cpu(psbs.u.resp.minsize),
+ be32_to_cpu(psbs.u.resp.maxsize));
+
+ return 0;
+}
+
+static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
ptm_init init;
ptm_res res;
+ if (buffersize != 0 &&
+ tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
+ goto err_exit;
+ }
+
DPRINTF("%s", __func__);
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
sizeof(init)) < 0) {
@@ -287,16 +352,22 @@ static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
ptm_est est;
- DPRINTF("%s", __func__);
+ if (tpm_emu->established_flag_cached) {
+ return tpm_emu->established_flag;
+ }
+
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
0, sizeof(est)) < 0) {
error_report("tpm-emulator: Could not get the TPM established flag: %s",
strerror(errno));
return false;
}
- DPRINTF("established flag: %0x", est.u.resp.bit);
+ DPRINTF("got established flag: %0x", est.u.resp.bit);
- return (est.u.resp.bit != 0);
+ tpm_emu->established_flag_cached = 1;
+ tpm_emu->established_flag = (est.u.resp.bit != 0);
+
+ return tpm_emu->established_flag;
}
static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
@@ -327,6 +398,8 @@ static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
return -1;
}
+ tpm_emu->established_flag_cached = 0;
+
return 0;
}
@@ -340,6 +413,7 @@ static void tpm_emulator_cancel_cmd(TPMBackend *tb)
return;
}
+ /* FIXME: make the function non-blocking, or it may block a VCPU */
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
sizeof(res)) < 0) {
error_report("tpm-emulator: Could not cancel command: %s",
@@ -357,6 +431,17 @@ static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
return tpm_emu->tpm_version;
}
+static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
+{
+ size_t actual_size;
+
+ if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
+ return 4096;
+ }
+
+ return actual_size;
+}
+
static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
{
Error *err = NULL;
@@ -465,22 +550,16 @@ err:
return -1;
}
-static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
+static TPMBackend *tpm_emulator_create(QemuOpts *opts)
{
TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
- tb->id = g_strdup(id);
-
if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
- goto err_exit;
+ object_unref(OBJECT(tb));
+ return NULL;
}
return tb;
-
-err_exit:
- object_unref(OBJECT(tb));
-
- return NULL;
}
static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
@@ -563,6 +642,7 @@ static void tpm_emulator_class_init(ObjectClass *klass, void *data)
tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
tbc->get_tpm_version = tpm_emulator_get_tpm_version;
+ tbc->get_buffer_size = tpm_emulator_get_buffer_size;
tbc->get_tpm_options = tpm_emulator_get_tpm_options;
tbc->handle_request = tpm_emulator_handle_request;
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 9c045b6691..abbca5191a 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -13,28 +13,8 @@
#define TPM_TPM_INT_H
#include "qemu/osdep.h"
-#include "qom/object.h"
-#define TYPE_TPM_IF "tpm-if"
-#define TPM_IF_CLASS(klass) \
- OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF)
-#define TPM_IF_GET_CLASS(obj) \
- OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF)
-#define TPM_IF(obj) \
- INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF)
-
-typedef struct TPMIf {
- Object parent_obj;
-} TPMIf;
-
-typedef struct TPMIfClass {
- InterfaceClass parent_class;
-
- /* run in thread pool by backend */
- void (*request_completed)(TPMIf *obj);
-} TPMIfClass;
-
-#define TPM_STANDARD_CMDLINE_OPTS \
+#define TPM_STANDARD_CMDLINE_OPTS \
{ \
.name = "type", \
.type = QEMU_OPT_STRING, \
@@ -65,11 +45,20 @@ struct tpm_resp_hdr {
#define TPM_ORD_ContinueSelfTest 0x53
#define TPM_ORD_GetTicks 0xf1
+#define TPM_ORD_GetCapability 0x65
+#define TPM_CAP_PROPERTY 0x05
+
+#define TPM_CAP_PROP_INPUT_BUFFER 0x124
/* TPM2 defines */
#define TPM2_ST_NO_SESSIONS 0x8001
#define TPM2_CC_ReadClock 0x00000181
+#define TPM2_CC_GetCapability 0x0000017a
+
+#define TPM2_CAP_TPM_PROPERTIES 0x6
+
+#define TPM2_PT_MAX_COMMAND_SIZE 0x11e
#endif /* TPM_TPM_INT_H */
diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
index 33564b11de..54c8d345ad 100644
--- a/hw/tpm/tpm_ioctl.h
+++ b/hw/tpm/tpm_ioctl.h
@@ -169,6 +169,28 @@ struct ptm_getconfig {
#define PTM_CONFIG_FLAG_FILE_KEY 0x1
#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2
+/*
+ * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM.
+ * A 0 on input queries for the current buffer size. Any other
+ * number will try to set the buffer size. The returned number is
+ * the buffer size that will be used, which can be larger than the
+ * requested one, if it was below the minimum, or smaller than the
+ * requested one, if it was above the maximum.
+ */
+struct ptm_setbuffersize {
+ union {
+ struct {
+ uint32_t buffersize; /* 0 to query for current buffer size */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ uint32_t buffersize; /* buffer size in use */
+ uint32_t minsize; /* min. supported buffer size */
+ uint32_t maxsize; /* max. supported buffer size */
+ } resp; /* response */
+ } u;
+};
+
typedef uint64_t ptm_cap;
typedef struct ptm_est ptm_est;
@@ -179,6 +201,7 @@ typedef struct ptm_init ptm_init;
typedef struct ptm_getstate ptm_getstate;
typedef struct ptm_setstate ptm_setstate;
typedef struct ptm_getconfig ptm_getconfig;
+typedef struct ptm_setbuffersize ptm_setbuffersize;
/* capability flags returned by PTM_GET_CAPABILITY */
#define PTM_CAP_INIT (1)
@@ -194,6 +217,7 @@ typedef struct ptm_getconfig ptm_getconfig;
#define PTM_CAP_STOP (1 << 10)
#define PTM_CAP_GET_CONFIG (1 << 11)
#define PTM_CAP_SET_DATAFD (1 << 12)
+#define PTM_CAP_SET_BUFFERSIZE (1 << 13)
enum {
PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap),
@@ -212,6 +236,7 @@ enum {
PTM_STOP = _IOR('P', 13, ptm_res),
PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig),
PTM_SET_DATAFD = _IOR('P', 15, ptm_res),
+ PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize),
};
/*
@@ -240,7 +265,8 @@ enum {
CMD_SET_STATEBLOB,
CMD_STOP,
CMD_GET_CONFIG,
- CMD_SET_DATAFD
+ CMD_SET_DATAFD,
+ CMD_SET_BUFFERSIZE,
};
#endif /* _TPM_IOCTL_H */
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index c440aff4b2..149fae63e6 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -29,7 +29,6 @@
#include "sysemu/tpm_backend.h"
#include "tpm_int.h"
#include "hw/hw.h"
-#include "hw/i386/pc.h"
#include "qapi/clone-visitor.h"
#include "tpm_util.h"
@@ -57,6 +56,7 @@ struct TPMPassthruState {
int cancel_fd;
TPMVersion tpm_version;
+ size_t tpm_buffersize;
};
typedef struct TPMPassthruState TPMPassthruState;
@@ -89,6 +89,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
bool is_selftest;
const struct tpm_resp_hdr *hdr;
+ /* FIXME: protect shared variables or use other sync mechanism */
tpm_pt->tpm_op_canceled = false;
tpm_pt->tpm_executing = true;
*selftest_done = false;
@@ -139,14 +140,11 @@ err_exit:
static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state);
DPRINTF("tpm_passthrough: processing command %p\n", cmd);
tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len,
cmd->out, cmd->out_len, &cmd->selftest_done);
-
- tic->request_completed(TPM_IF(tb->tpm_state));
}
static void tpm_passthrough_reset(TPMBackend *tb)
@@ -181,12 +179,11 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
*/
if (tpm_pt->tpm_executing) {
if (tpm_pt->cancel_fd >= 0) {
+ tpm_pt->tpm_op_canceled = true;
n = write(tpm_pt->cancel_fd, "-", 1);
if (n != 1) {
error_report("Canceling TPM command failed: %s",
strerror(errno));
- } else {
- tpm_pt->tpm_op_canceled = true;
}
} else {
error_report("Cannot cancel TPM command due to missing "
@@ -202,6 +199,19 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
return tpm_pt->tpm_version;
}
+static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
+{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+ int ret;
+
+ ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version,
+ &tpm_pt->tpm_buffersize);
+ if (ret < 0) {
+ tpm_pt->tpm_buffersize = 4096;
+ }
+ return tpm_pt->tpm_buffersize;
+}
+
/*
* Unless path or file descriptor set has been provided by user,
* determine the sysfs cancel file following kernel documentation
@@ -229,9 +239,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
dev) < sizeof(path)) {
fd = qemu_open(path, O_WRONLY);
- if (fd >= 0) {
- tpm_pt->options->cancel_path = g_strdup(path);
- } else {
+ if (fd < 0) {
error_report("tpm_passthrough: Could not open TPM cancel "
"path %s : %s", path, strerror(errno));
}
@@ -244,9 +252,9 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
return fd;
}
-static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
+static int
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
const char *value;
value = qemu_opt_get(opts, "cancel-path");
@@ -266,52 +274,47 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
if (tpm_pt->tpm_fd < 0) {
error_report("Cannot access TPM device using '%s': %s",
tpm_pt->tpm_dev, strerror(errno));
- goto err_free_parameters;
+ return -1;
}
if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
error_report("'%s' is not a TPM device.",
tpm_pt->tpm_dev);
- goto err_close_tpmdev;
+ return -1;
}
- return 0;
-
- err_close_tpmdev:
- qemu_close(tpm_pt->tpm_fd);
- tpm_pt->tpm_fd = -1;
-
- err_free_parameters:
- qapi_free_TPMPassthroughOptions(tpm_pt->options);
- tpm_pt->options = NULL;
- tpm_pt->tpm_dev = NULL;
+ tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
+ if (tpm_pt->cancel_fd < 0) {
+ return -1;
+ }
- return 1;
+ return 0;
}
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
+static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
{
Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
- TPMBackend *tb = TPM_BACKEND(obj);
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- tb->id = g_strdup(id);
-
- if (tpm_passthrough_handle_device_opts(opts, tb)) {
- goto err_exit;
+ if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+ object_unref(obj);
+ return NULL;
}
- tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
- if (tpm_pt->cancel_fd < 0) {
- goto err_exit;
- }
+ return TPM_BACKEND(obj);
+}
- return tb;
+static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize)
+{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-err_exit:
- object_unref(obj);
+ if (buffersize && buffersize < tpm_pt->tpm_buffersize) {
+ error_report("Requested buffer size of %zu is smaller than host TPM's "
+ "fixed buffer size of %zu",
+ buffersize, tpm_pt->tpm_buffersize);
+ return -1;
+ }
- return NULL;
+ return 0;
}
static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
@@ -355,8 +358,12 @@ static void tpm_passthrough_inst_finalize(Object *obj)
tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
- qemu_close(tpm_pt->tpm_fd);
- qemu_close(tpm_pt->cancel_fd);
+ if (tpm_pt->tpm_fd >= 0) {
+ qemu_close(tpm_pt->tpm_fd);
+ }
+ if (tpm_pt->cancel_fd >= 0) {
+ qemu_close(tpm_pt->cancel_fd);
+ }
qapi_free_TPMPassthroughOptions(tpm_pt->options);
}
@@ -368,12 +375,14 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
tbc->opts = tpm_passthrough_cmdline_opts;
tbc->desc = "Passthrough TPM backend driver";
tbc->create = tpm_passthrough_create;
+ tbc->startup_tpm = tpm_passthrough_startup_tpm;
tbc->reset = tpm_passthrough_reset;
tbc->cancel_cmd = tpm_passthrough_cancel_cmd;
tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag;
tbc->reset_tpm_established_flag =
tpm_passthrough_reset_tpm_established_flag;
tbc->get_tpm_version = tpm_passthrough_get_tpm_version;
+ tbc->get_buffer_size = tpm_passthrough_get_buffer_size;
tbc->get_tpm_options = tpm_passthrough_get_tpm_options;
tbc->handle_request = tpm_passthrough_handle_request;
}
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index 42d647d363..561384cd86 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -24,17 +24,13 @@
#include "qemu/osdep.h"
#include "hw/isa/isa.h"
-#include "sysemu/tpm_backend.h"
-#include "tpm_int.h"
-#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci_ids.h"
#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/main-loop.h"
+
#include "hw/acpi/tpm.h"
+#include "hw/pci/pci_ids.h"
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "tpm_util.h"
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
#define TPM_TIS_LOCALITY_SHIFT 12
@@ -52,11 +48,6 @@ typedef enum {
TPM_TIS_STATE_RECEPTION,
} TPMTISState;
-typedef struct TPMSizedBuffer {
- uint32_t size;
- uint8_t *buffer;
-} TPMSizedBuffer;
-
/* locality data -- all fields are persisted */
typedef struct TPMLocality {
TPMTISState state;
@@ -65,20 +56,14 @@ typedef struct TPMLocality {
uint32_t iface_id;
uint32_t inte;
uint32_t ints;
-
- uint16_t w_offset;
- uint16_t r_offset;
- TPMSizedBuffer w_buffer;
- TPMSizedBuffer r_buffer;
} TPMLocality;
-struct TPMState {
+typedef struct TPMState {
ISADevice busdev;
MemoryRegion mmio;
- QEMUBH *bh;
- uint32_t offset;
- uint8_t buf[TPM_TIS_BUFFER_MAX];
+ unsigned char buffer[TPM_TIS_BUFFER_MAX];
+ uint16_t rw_offset;
uint8_t active_locty;
uint8_t aborting_locty;
@@ -89,13 +74,13 @@ struct TPMState {
qemu_irq irq;
uint32_t irq_num;
- uint8_t locty_number;
TPMBackendCmd cmd;
- char *backend;
TPMBackend *be_driver;
TPMVersion be_tpm_version;
-};
+
+ size_t be_buffer_size;
+} TPMState;
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
@@ -220,23 +205,19 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
}
-static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
-{
- return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
-}
-
-static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
+static void tpm_tis_show_buffer(const unsigned char *buffer,
+ size_t buffer_size, const char *string)
{
#ifdef DEBUG_TIS
uint32_t len, i;
- len = tpm_tis_get_size_from_buffer(sb);
+ len = MIN(tpm_cmd_get_size(buffer), buffer_size);
DPRINTF("tpm_tis: %s length = %d\n", string, len);
for (i = 0; i < len; i++) {
if (i && !(i % 16)) {
DPRINTF("\n");
}
- DPRINTF("%.2X ", sb->buffer[i]);
+ DPRINTF("%.2X ", buffer[i]);
}
DPRINTF("\n");
#endif
@@ -266,22 +247,21 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
*/
static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
{
- TPMLocality *locty_data = &s->loc[locty];
-
- tpm_tis_show_buffer(&s->loc[locty].w_buffer, "tpm_tis: To TPM");
+ tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
+ "tpm_tis: To TPM");
/*
- * w_offset serves as length indicator for length of data;
+ * rw_offset serves as length indicator for length of data;
* it's reset when the response comes back
*/
s->loc[locty].state = TPM_TIS_STATE_EXECUTION;
s->cmd = (TPMBackendCmd) {
.locty = locty,
- .in = locty_data->w_buffer.buffer,
- .in_len = locty_data->w_offset,
- .out = locty_data->r_buffer.buffer,
- .out_len = locty_data->r_buffer.size
+ .in = s->buffer,
+ .in_len = s->rw_offset,
+ .out = s->buffer,
+ .out_len = s->be_buffer_size,
};
tpm_backend_deliver_request(s->be_driver, &s->cmd);
@@ -361,8 +341,7 @@ static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
/* abort -- this function switches the locality */
static void tpm_tis_abort(TPMState *s, uint8_t locty)
{
- s->loc[locty].r_offset = 0;
- s->loc[locty].w_offset = 0;
+ s->rw_offset = 0;
DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", s->next_locty);
@@ -411,18 +390,28 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
tpm_tis_abort(s, locty);
}
-static void tpm_tis_receive_bh(void *opaque)
+/*
+ * Callback from the TPM to indicate that the response was received.
+ */
+static void tpm_tis_request_completed(TPMIf *ti)
{
- TPMState *s = opaque;
+ TPMState *s = TPM(ti);
uint8_t locty = s->cmd.locty;
+ uint8_t l;
+
+ if (s->cmd.selftest_done) {
+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
+ s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
+ }
+ }
tpm_tis_sts_set(&s->loc[locty],
TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
s->loc[locty].state = TPM_TIS_STATE_COMPLETION;
- s->loc[locty].r_offset = 0;
- s->loc[locty].w_offset = 0;
+ s->rw_offset = 0;
- tpm_tis_show_buffer(&s->loc[locty].r_buffer, "tpm_tis: From TPM");
+ tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
+ "tpm_tis: From TPM");
if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
tpm_tis_abort(s, locty);
@@ -432,23 +421,6 @@ static void tpm_tis_receive_bh(void *opaque)
TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
}
-static void tpm_tis_request_completed(TPMIf *ti)
-{
- TPMState *s = TPM(ti);
-
- bool is_selftest_done = s->cmd.selftest_done;
- uint8_t locty = s->cmd.locty;
- uint8_t l;
-
- if (is_selftest_done) {
- for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
- s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
- }
- }
-
- qemu_bh_schedule(s->bh);
-}
-
/*
* Read a byte of response data
*/
@@ -458,16 +430,17 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
uint16_t len;
if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
- len = tpm_tis_get_size_from_buffer(&s->loc[locty].r_buffer);
+ len = MIN(tpm_cmd_get_size(&s->buffer),
+ s->be_buffer_size);
- ret = s->loc[locty].r_buffer.buffer[s->loc[locty].r_offset++];
- if (s->loc[locty].r_offset >= len) {
+ ret = s->buffer[s->rw_offset++];
+ if (s->rw_offset >= len) {
/* got last byte */
tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
}
DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
- ret, s->loc[locty].r_offset - 1);
+ ret, s->rw_offset - 1);
}
return ret;
@@ -502,27 +475,15 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr)
(int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
}
- DPRINTF("tpm_tis: read offset : %d\n"
+ DPRINTF("tpm_tis: r/w offset : %d\n"
"tpm_tis: result buffer : ",
- s->loc[locty].r_offset);
- for (idx = 0;
- idx < tpm_tis_get_size_from_buffer(&s->loc[locty].r_buffer);
- idx++) {
- DPRINTF("%c%02x%s",
- s->loc[locty].r_offset == idx ? '>' : ' ',
- s->loc[locty].r_buffer.buffer[idx],
- ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
- }
- DPRINTF("\n"
- "tpm_tis: write offset : %d\n"
- "tpm_tis: request buffer: ",
- s->loc[locty].w_offset);
+ s->rw_offset);
for (idx = 0;
- idx < tpm_tis_get_size_from_buffer(&s->loc[locty].w_buffer);
+ idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size);
idx++) {
DPRINTF("%c%02x%s",
- s->loc[locty].w_offset == idx ? '>' : ' ',
- s->loc[locty].w_buffer.buffer[idx],
+ s->rw_offset == idx ? '>' : ' ',
+ s->buffer[idx],
((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
}
DPRINTF("\n");
@@ -584,11 +545,11 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
if (s->active_locty == locty) {
if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
val = TPM_TIS_BURST_COUNT(
- tpm_tis_get_size_from_buffer(&s->loc[locty].r_buffer)
- - s->loc[locty].r_offset) | s->loc[locty].sts;
+ MIN(tpm_cmd_get_size(&s->buffer),
+ s->be_buffer_size)
+ - s->rw_offset) | s->loc[locty].sts;
} else {
- avail = s->loc[locty].w_buffer.size
- - s->loc[locty].w_offset;
+ avail = s->be_buffer_size - s->rw_offset;
/*
* byte-sized reads should not return 0x00 for 0x100
* available bytes.
@@ -852,8 +813,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
switch (s->loc[locty].state) {
case TPM_TIS_STATE_READY:
- s->loc[locty].w_offset = 0;
- s->loc[locty].r_offset = 0;
+ s->rw_offset = 0;
break;
case TPM_TIS_STATE_IDLE:
@@ -871,8 +831,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
break;
case TPM_TIS_STATE_COMPLETION:
- s->loc[locty].w_offset = 0;
- s->loc[locty].r_offset = 0;
+ s->rw_offset = 0;
/* shortcut to ready state with C/R set */
s->loc[locty].state = TPM_TIS_STATE_READY;
if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
@@ -898,7 +857,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
} else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
switch (s->loc[locty].state) {
case TPM_TIS_STATE_COMPLETION:
- s->loc[locty].r_offset = 0;
+ s->rw_offset = 0;
tpm_tis_sts_set(&s->loc[locty],
TPM_TIS_STS_VALID|
TPM_TIS_STS_DATA_AVAILABLE);
@@ -936,9 +895,9 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
}
while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
- if (s->loc[locty].w_offset < s->loc[locty].w_buffer.size) {
- s->loc[locty].w_buffer.
- buffer[s->loc[locty].w_offset++] = (uint8_t)val;
+ if (s->rw_offset < s->be_buffer_size) {
+ s->buffer[s->rw_offset++] =
+ (uint8_t)val;
val >>= 8;
size--;
} else {
@@ -947,13 +906,13 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
}
/* check for complete packet */
- if (s->loc[locty].w_offset > 5 &&
+ if (s->rw_offset > 5 &&
(s->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
/* we have a packet length - see if we have all of it */
bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID);
- len = tpm_tis_get_size_from_buffer(&s->loc[locty].w_buffer);
- if (len > s->loc[locty].w_offset) {
+ len = tpm_cmd_get_size(&s->buffer);
+ if (len > s->rw_offset) {
tpm_tis_sts_set(&s->loc[locty],
TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
} else {
@@ -986,27 +945,17 @@ static const MemoryRegionOps tpm_tis_memory_ops = {
},
};
-static int tpm_tis_do_startup_tpm(TPMState *s)
+static int tpm_tis_do_startup_tpm(TPMState *s, size_t buffersize)
{
- return tpm_backend_startup_tpm(s->be_driver);
-}
-
-static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb)
-{
- size_t wanted_size = 4096; /* Linux tpm.c buffer size */
-
- if (sb->size != wanted_size) {
- sb->buffer = g_realloc(sb->buffer, wanted_size);
- sb->size = wanted_size;
- }
+ return tpm_backend_startup_tpm(s->be_driver, buffersize);
}
/*
* Get the TPMVersion of the backend device being used
*/
-TPMVersion tpm_tis_get_tpm_version(Object *obj)
+static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
{
- TPMState *s = TPM(obj);
+ TPMState *s = TPM(ti);
if (tpm_backend_had_startup_error(s->be_driver)) {
return TPM_VERSION_UNSPEC;
@@ -1025,6 +974,8 @@ static void tpm_tis_reset(DeviceState *dev)
int c;
s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
+ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
+ TPM_TIS_BUFFER_MAX);
tpm_backend_reset(s->be_driver);
@@ -1050,13 +1001,10 @@ static void tpm_tis_reset(DeviceState *dev)
s->loc[c].ints = 0;
s->loc[c].state = TPM_TIS_STATE_IDLE;
- s->loc[c].w_offset = 0;
- tpm_tis_realloc_buffer(&s->loc[c].w_buffer);
- s->loc[c].r_offset = 0;
- tpm_tis_realloc_buffer(&s->loc[c].r_buffer);
+ s->rw_offset = 0;
}
- tpm_tis_do_startup_tpm(s);
+ tpm_tis_do_startup_tpm(s, s->be_buffer_size);
}
static const VMStateDescription vmstate_tpm_tis = {
@@ -1066,7 +1014,7 @@ static const VMStateDescription vmstate_tpm_tis = {
static Property tpm_tis_properties[] = {
DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
- DEFINE_PROP_STRING("tpmdev", TPMState, backend),
+ DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1074,29 +1022,21 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
{
TPMState *s = TPM(dev);
- s->be_driver = qemu_find_tpm(s->backend);
- if (!s->be_driver) {
- error_setg(errp, "tpm_tis: backend driver with id %s could not be "
- "found", s->backend);
+ if (!tpm_find()) {
+ error_setg(errp, "at most one TPM device is permitted");
return;
}
- s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
-
- if (tpm_backend_init(s->be_driver, s)) {
- error_setg(errp, "tpm_tis: backend driver with id %s could not be "
- "initialized", s->backend);
+ if (!s->be_driver) {
+ error_setg(errp, "'tpmdev' property is required");
return;
}
-
if (s->irq_num > 15) {
- error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
- "of 0 to 15", s->irq_num);
+ error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
+ s->irq_num);
return;
}
- s->bh = qemu_bh_new(tpm_tis_receive_bh, s);
-
isa_init_irq(&s->busdev, &s->irq, s->irq_num);
memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
@@ -1121,6 +1061,8 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data)
dc->props = tpm_tis_properties;
dc->reset = tpm_tis_reset;
dc->vmsd = &vmstate_tpm_tis;
+ tc->model = TPM_MODEL_TPM_TIS;
+ tc->get_version = tpm_tis_get_tpm_version;
tc->request_completed = tpm_tis_request_completed;
}
@@ -1139,7 +1081,6 @@ static const TypeInfo tpm_tis_info = {
static void tpm_tis_register(void)
{
type_register_static(&tpm_tis_info);
- tpm_register_model(TPM_MODEL_TPM_TIS);
}
type_init(tpm_tis_register)
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
index daf1faa63d..747075e244 100644
--- a/hw/tpm/tpm_util.c
+++ b/hw/tpm/tpm_util.c
@@ -20,9 +20,85 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
#include "tpm_util.h"
#include "tpm_int.h"
#include "exec/memory.h"
+#include "sysemu/tpm_backend.h"
+#include "hw/qdev.h"
+
+#define DEBUG_TPM 0
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_TPM) { \
+ fprintf(stderr, "tpm-util:"fmt"\n", ## __VA_ARGS__); \
+ } \
+} while (0)
+
+/* tpm backend property */
+
+static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ TPMBackend **be = qdev_get_prop_ptr(dev, opaque);
+ char *p;
+
+ p = g_strdup(*be ? (*be)->id : "");
+ visit_type_str(v, name, &p, errp);
+ g_free(p);
+}
+
+static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Error *local_err = NULL;
+ Property *prop = opaque;
+ TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
+ char *str;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ s = qemu_find_tpm_be(str);
+ if (s == NULL) {
+ error_setg(errp, "Property '%s.%s' can't find value '%s'",
+ object_get_typename(obj), prop->name, str);
+ } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) {
+ *be = s; /* weak reference, avoid cyclic ref */
+ }
+ g_free(str);
+}
+
+static void release_tpm(Object *obj, const char *name, void *opaque)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ TPMBackend **be = qdev_get_prop_ptr(dev, prop);
+
+ if (*be) {
+ tpm_backend_reset(*be);
+ }
+}
+
+const PropertyInfo qdev_prop_tpm = {
+ .name = "str",
+ .description = "ID of a tpm to use as a backend",
+ .get = get_tpm,
+ .set = set_tpm,
+ .release = release_tpm,
+};
/*
* Write an error message in the given output buffer.
@@ -50,13 +126,13 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
}
/*
- * A basic test of a TPM device. We expect a well formatted response header
- * (error response is fine) within one second.
+ * Send request to a TPM device. We expect a response within one second.
*/
-static int tpm_util_test(int fd,
- unsigned char *request,
- size_t requestlen,
- uint16_t *return_tag)
+static int tpm_util_request(int fd,
+ unsigned char *request,
+ size_t requestlen,
+ unsigned char *response,
+ size_t responselen)
{
struct tpm_resp_hdr *resp;
fd_set readfds;
@@ -65,7 +141,6 @@ static int tpm_util_test(int fd,
.tv_sec = 1,
.tv_usec = 0,
};
- unsigned char buf[1024];
n = write(fd, request, requestlen);
if (n < 0) {
@@ -84,17 +159,40 @@ static int tpm_util_test(int fd,
return -errno;
}
- n = read(fd, &buf, sizeof(buf));
+ n = read(fd, response, responselen);
if (n < sizeof(struct tpm_resp_hdr)) {
return -EFAULT;
}
- resp = (struct tpm_resp_hdr *)buf;
+ resp = (struct tpm_resp_hdr *)response;
/* check the header */
if (be32_to_cpu(resp->len) != n) {
return -EMSGSIZE;
}
+ return 0;
+}
+
+/*
+ * A basic test of a TPM device. We expect a well formatted response header
+ * (error response is fine).
+ */
+static int tpm_util_test(int fd,
+ unsigned char *request,
+ size_t requestlen,
+ uint16_t *return_tag)
+{
+ struct tpm_resp_hdr *resp;
+ unsigned char buf[1024];
+ ssize_t ret;
+
+ ret = tpm_util_request(fd, request, requestlen,
+ buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ resp = (struct tpm_resp_hdr *)buf;
*return_tag = be16_to_cpu(resp->tag);
return 0;
@@ -151,3 +249,116 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
return 1;
}
+
+int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
+ size_t *buffersize)
+{
+ unsigned char buf[1024];
+ int ret;
+
+ switch (tpm_version) {
+ case TPM_VERSION_1_2: {
+ const struct tpm_req_get_buffer_size {
+ struct tpm_req_hdr hdr;
+ uint32_t capability;
+ uint32_t len;
+ uint32_t subcap;
+ } QEMU_PACKED tpm_get_buffer_size = {
+ .hdr = {
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
+ .len = cpu_to_be32(sizeof(tpm_get_buffer_size)),
+ .ordinal = cpu_to_be32(TPM_ORD_GetCapability),
+ },
+ .capability = cpu_to_be32(TPM_CAP_PROPERTY),
+ .len = cpu_to_be32(sizeof(uint32_t)),
+ .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER),
+ };
+ struct tpm_resp_get_buffer_size {
+ struct tpm_resp_hdr hdr;
+ uint32_t len;
+ uint32_t buffersize;
+ } QEMU_PACKED *tpm_resp = (struct tpm_resp_get_buffer_size *)buf;
+
+ ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm_get_buffer_size,
+ sizeof(tpm_get_buffer_size), buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (be32_to_cpu(tpm_resp->hdr.len) != sizeof(*tpm_resp) ||
+ be32_to_cpu(tpm_resp->len) != sizeof(uint32_t)) {
+ DPRINTF("tpm_resp->hdr.len = %u, expected = %zu\n",
+ be32_to_cpu(tpm_resp->hdr.len), sizeof(*tpm_resp));
+ DPRINTF("tpm_resp->len = %u, expected = %zu\n",
+ be32_to_cpu(tpm_resp->len), sizeof(uint32_t));
+ error_report("tpm_util: Got unexpected response to "
+ "TPM_GetCapability; errcode: 0x%x",
+ be32_to_cpu(tpm_resp->hdr.errcode));
+ return -EFAULT;
+ }
+ *buffersize = be32_to_cpu(tpm_resp->buffersize);
+ break;
+ }
+ case TPM_VERSION_2_0: {
+ const struct tpm2_req_get_buffer_size {
+ struct tpm_req_hdr hdr;
+ uint32_t capability;
+ uint32_t property;
+ uint32_t count;
+ } QEMU_PACKED tpm2_get_buffer_size = {
+ .hdr = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)),
+ .ordinal = cpu_to_be32(TPM2_CC_GetCapability),
+ },
+ .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES),
+ .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE),
+ .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */
+ };
+ struct tpm2_resp_get_buffer_size {
+ struct tpm_resp_hdr hdr;
+ uint8_t more;
+ uint32_t capability;
+ uint32_t count;
+ uint32_t property1;
+ uint32_t value1;
+ uint32_t property2;
+ uint32_t value2;
+ } QEMU_PACKED *tpm2_resp = (struct tpm2_resp_get_buffer_size *)buf;
+
+ ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm2_get_buffer_size,
+ sizeof(tpm2_get_buffer_size), buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (be32_to_cpu(tpm2_resp->hdr.len) != sizeof(*tpm2_resp) ||
+ be32_to_cpu(tpm2_resp->count) != 2) {
+ DPRINTF("tpm2_resp->hdr.len = %u, expected = %zu\n",
+ be32_to_cpu(tpm2_resp->hdr.len), sizeof(*tpm2_resp));
+ DPRINTF("tpm2_resp->len = %u, expected = %u\n",
+ be32_to_cpu(tpm2_resp->count), 2);
+ error_report("tpm_util: Got unexpected response to "
+ "TPM2_GetCapability; errcode: 0x%x",
+ be32_to_cpu(tpm2_resp->hdr.errcode));
+ return -EFAULT;
+ }
+ *buffersize = MAX(be32_to_cpu(tpm2_resp->value1),
+ be32_to_cpu(tpm2_resp->value2));
+ break;
+ }
+ case TPM_VERSION_UNSPEC:
+ return -EFAULT;
+ }
+
+ DPRINTF("buffersize of device: %zu\n", *buffersize);
+
+ return 0;
+}
+
+void tpm_sized_buffer_reset(TPMSizedBuffer *tsb)
+{
+ g_free(tsb->buffer);
+ tsb->buffer = NULL;
+ tsb->size = 0;
+}
diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
index 2f7c96146d..19b28474ae 100644
--- a/hw/tpm/tpm_util.h
+++ b/hw/tpm/tpm_util.h
@@ -22,7 +22,8 @@
#ifndef TPM_TPM_UTIL_H
#define TPM_TPM_UTIL_H
-#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm.h"
+#include "qemu/bswap.h"
void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len);
@@ -30,4 +31,22 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
+static inline uint32_t tpm_cmd_get_size(const void *b)
+{
+ return be32_to_cpu(*(const uint32_t *)(b + 2));
+}
+
+int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
+ size_t *buffersize);
+
+#define DEFINE_PROP_TPMBE(_n, _s, _f) \
+ DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *)
+
+typedef struct TPMSizedBuffer {
+ uint32_t size;
+ uint8_t *buffer;
+} TPMSizedBuffer;
+
+void tpm_sized_buffer_reset(TPMSizedBuffer *tsb);
+
#endif /* TPM_TPM_UTIL_H */
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index 1b39cc035b..db26959a1d 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -11,16 +11,11 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "cpu.h"
#include "ui/console.h"
-#include "elf.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/i386/pc.h"
-#include "qemu/error-report.h"
#include "sysemu/qtest.h"
#undef DEBUG_PUV3
@@ -29,6 +24,16 @@
#define KERNEL_LOAD_ADDR 0x03000000
#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
+/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
+#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */
+
+/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
+#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */
+#define PUV3_INTC_BASE (0xee600000) /* APB-6 */
+#define PUV3_OST_BASE (0xee800000) /* APB-8 */
+#define PUV3_PM_BASE (0xeea00000) /* APB-10 */
+#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */
+
static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
{
UniCore32CPU *cpu = opaque;
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index e56dc3348a..11f7720d71 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -559,28 +559,6 @@ int usb_device_detach(USBDevice *dev)
return 0;
}
-int usb_device_delete_addr(int busnr, int addr)
-{
- USBBus *bus;
- USBPort *port;
- USBDevice *dev;
-
- bus = usb_bus_find(busnr);
- if (!bus)
- return -1;
-
- QTAILQ_FOREACH(port, &bus->used, next) {
- if (port->dev->addr == addr)
- break;
- }
- if (!port)
- return -1;
- dev = port->dev;
-
- object_unparent(OBJECT(dev));
- return 0;
-}
-
static const char *usb_speed(unsigned int speed)
{
static const char *txt[] = {
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 8a61ec94c8..9722ac854c 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -596,12 +596,11 @@ static void usb_msd_unrealize_storage(USBDevice *dev, Error **errp)
object_unref(OBJECT(&s->bus));
}
-static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
+static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
{
MSDState *s = USB_STORAGE_DEV(dev);
BlockBackend *blk = s->conf.blk;
SCSIDevice *scsi_dev;
- Error *err = NULL;
if (!blk) {
error_setg(errp, "drive property not set");
@@ -610,9 +609,8 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
blkconf_serial(&s->conf, &dev->serial);
blkconf_blocksizes(&s->conf);
- blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &err);
- if (err) {
- error_propagate(errp, err);
+ if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
+ errp)) {
return;
}
@@ -636,24 +634,23 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
&usb_msd_scsi_info_storage, NULL);
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
s->conf.bootindex, dev->serial,
- &err);
+ errp);
blk_unref(blk);
if (!scsi_dev) {
- error_propagate(errp, err);
return;
}
usb_msd_handle_reset(dev);
s->scsi_dev = scsi_dev;
}
-static void usb_msd_unrealize_bot(USBDevice *dev, Error **errp)
+static void usb_msd_bot_unrealize(USBDevice *dev, Error **errp)
{
MSDState *s = USB_STORAGE_DEV(dev);
object_unref(OBJECT(&s->bus));
}
-static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
+static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
{
MSDState *s = USB_STORAGE_DEV(dev);
DeviceState *d = DEVICE(dev);
@@ -767,12 +764,12 @@ static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_usb_msd;
}
-static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
+static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- uc->realize = usb_msd_realize_storage;
+ uc->realize = usb_msd_storage_realize;
uc->unrealize = usb_msd_unrealize_storage;
dc->props = msd_properties;
}
@@ -831,26 +828,26 @@ static void usb_msd_instance_init(Object *obj)
object_property_set_int(obj, -1, "bootindex", NULL);
}
-static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
+static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
{
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- uc->realize = usb_msd_realize_bot;
- uc->unrealize = usb_msd_unrealize_bot;
+ uc->realize = usb_msd_bot_realize;
+ uc->unrealize = usb_msd_bot_unrealize;
uc->attached_settable = true;
}
static const TypeInfo msd_info = {
.name = "usb-storage",
.parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_initfn_storage,
+ .class_init = usb_msd_class_storage_initfn,
.instance_init = usb_msd_instance_init,
};
static const TypeInfo bot_info = {
.name = "usb-bot",
.parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_initfn_bot,
+ .class_init = usb_msd_class_bot_initfn,
};
static void usb_msd_register_types(void)
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 636729c03d..16713f2c52 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -11,11 +11,11 @@
* directory.
*/
+#include "qemu/osdep.h"
#include <linux/vfio.h>
#include <linux/vfio_ccw.h>
#include <sys/ioctl.h>
-#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/vfio/vfio.h"
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 7b2924c0ef..b77be3a8b3 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -968,6 +968,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
group->container = container;
QLIST_INSERT_HEAD(&container->group_list, group, container_next);
+ vfio_kvm_device_add_group(group);
return 0;
}
}
@@ -990,6 +991,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
container = g_malloc0(sizeof(*container));
container->space = space;
container->fd = fd;
+ QLIST_INIT(&container->giommu_list);
+ QLIST_INIT(&container->hostwin_list);
if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) ||
ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) {
bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU);
@@ -1040,6 +1043,11 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
v2 ? VFIO_SPAPR_TCE_v2_IOMMU : VFIO_SPAPR_TCE_IOMMU;
ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type);
if (ret) {
+ container->iommu_type = VFIO_SPAPR_TCE_IOMMU;
+ v2 = false;
+ ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type);
+ }
+ if (ret) {
error_setg_errno(errp, errno, "failed to set iommu for container");
ret = -errno;
goto free_container_exit;
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index 502a5755b9..a8fb3b3422 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -93,8 +93,6 @@ typedef struct VFIOMSIXInfo {
uint16_t entries;
uint32_t table_offset;
uint32_t pba_offset;
- MemoryRegion mmap_mem;
- void *mmap;
unsigned long *pending;
} VFIOMSIXInfo;
diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
index 5ec1c6a2a2..aa5af927e1 100644
--- a/hw/virtio/vhost-vsock.c
+++ b/hw/virtio/vhost-vsock.c
@@ -11,8 +11,8 @@
* top-level directory.
*/
-#include <sys/ioctl.h>
#include "qemu/osdep.h"
+#include <sys/ioctl.h>
#include "standard-headers/linux/virtio_vsock.h"
#include "qapi/error.h"
#include "hw/virtio/virtio-bus.h"
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 37cde38982..14e08d20d0 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -18,7 +18,7 @@
#include "qemu/timer.h"
#include "qemu-common.h"
#include "hw/virtio/virtio.h"
-#include "hw/i386/pc.h"
+#include "hw/mem/pc-dimm.h"
#include "sysemu/balloon.h"
#include "hw/virtio/virtio-balloon.h"
#include "sysemu/kvm.h"
diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c
index 532afe89e7..d045032bf4 100644
--- a/hw/watchdog/wdt_ib700.c
+++ b/hw/watchdog/wdt_ib700.c
@@ -25,7 +25,6 @@
#include "sysemu/watchdog.h"
#include "hw/hw.h"
#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
/*#define IB700_DEBUG 1*/
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index 752b6f6d5c..f662f30370 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -946,6 +946,7 @@ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
k->exit = xen_pt_unregister_device;
k->config_read = xen_pt_pci_read_config;
k->config_write = xen_pt_pci_write_config;
+ k->is_express = 1; /* We might be */
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "Assign an host PCI device with Xen";
dc->props = xen_pci_passthrough_properties;