aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/cofs.c48
-rw-r--r--hw/9pfs/virtio-9p-handle.c9
-rw-r--r--hw/9pfs/virtio-9p-local.c288
-rw-r--r--hw/9pfs/virtio-9p-posix-acl.c52
-rw-r--r--hw/9pfs/virtio-9p-xattr-user.c27
-rw-r--r--hw/9pfs/virtio-9p-xattr.c9
-rw-r--r--hw/9pfs/virtio-9p-xattr.h27
-rw-r--r--hw/9pfs/virtio-9p.h6
-rw-r--r--hw/Makefile.objs2
-rw-r--r--hw/arm/musicpal.c6
-rw-r--r--hw/arm/omap1.c24
-rw-r--r--hw/arm/pxa2xx.c6
-rw-r--r--hw/arm/pxa2xx_gpio.c2
-rw-r--r--hw/arm/pxa2xx_pic.c4
-rw-r--r--hw/block/dataplane/virtio-blk.c2
-rw-r--r--hw/core/loader.c30
-rw-r--r--hw/core/qdev.c20
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/blizzard.c2
-rw-r--r--hw/display/cg3.c385
-rw-r--r--hw/display/cirrus_vga.c4
-rw-r--r--hw/display/exynos4210_fimd.c2
-rw-r--r--hw/display/g364fb.c2
-rw-r--r--hw/display/jazz_led.c2
-rw-r--r--hw/display/milkymist-vgafb.c2
-rw-r--r--hw/display/omap_lcdc.c2
-rw-r--r--hw/display/pl110.c2
-rw-r--r--hw/display/pxa2xx_lcd.c2
-rw-r--r--hw/display/qxl.c4
-rw-r--r--hw/display/sm501.c2
-rw-r--r--hw/display/ssd0303.c2
-rw-r--r--hw/display/ssd0323.c2
-rw-r--r--hw/display/tc6393xb.c2
-rw-r--r--hw/display/tcx.c4
-rw-r--r--hw/display/vga-isa-mm.c2
-rw-r--r--hw/display/vga-isa.c2
-rw-r--r--hw/display/vga-pci.c2
-rw-r--r--hw/display/vmware_vga.c2
-rw-r--r--hw/display/xenfb.c2
-rw-r--r--hw/i386/acpi-build.c143
-rw-r--r--hw/i386/acpi-dsdt.dsl33
-rw-r--r--hw/i386/acpi-dsdt.hex.generated224
-rw-r--r--hw/i386/pc_piix.c8
-rw-r--r--hw/i386/q35-acpi-dsdt.dsl25
-rw-r--r--hw/i386/q35-acpi-dsdt.hex.generated128
-rw-r--r--hw/i386/ssdt-pcihp.dsl50
-rw-r--r--hw/i386/ssdt-pcihp.hex.generated161
-rw-r--r--hw/ide/ahci.h10
-rw-r--r--hw/input/pckbd.c2
-rw-r--r--hw/intc/Makefile.objs1
-rw-r--r--hw/intc/ioapic.c3
-rw-r--r--hw/intc/openpic_kvm.c2
-rw-r--r--hw/intc/s390_flic.c322
-rw-r--r--hw/intc/xics.c15
-rw-r--r--hw/intc/xics_kvm.c10
-rw-r--r--hw/moxie/moxiesim.c2
-rw-r--r--hw/net/Makefile.objs3
-rw-r--r--hw/net/fsl_etsec/etsec.c465
-rw-r--r--hw/net/fsl_etsec/etsec.h174
-rw-r--r--hw/net/fsl_etsec/miim.c146
-rw-r--r--hw/net/fsl_etsec/registers.c295
-rw-r--r--hw/net/fsl_etsec/registers.h320
-rw-r--r--hw/net/fsl_etsec/rings.c650
-rw-r--r--hw/net/spapr_llan.c2
-rw-r--r--hw/net/virtio-net.c7
-rw-r--r--hw/pci-host/pam.c2
-rw-r--r--hw/pci/pcie.c16
-rw-r--r--hw/ppc/e500.c7
-rw-r--r--hw/ppc/ppc.c22
-rw-r--r--hw/ppc/spapr.c56
-rw-r--r--hw/ppc/spapr_hcall.c87
-rw-r--r--hw/ppc/spapr_iommu.c37
-rw-r--r--hw/ppc/spapr_pci.c15
-rw-r--r--hw/ppc/spapr_rtas.c14
-rw-r--r--hw/ppc/virtex_ml507.c34
-rw-r--r--hw/s390x/css.c10
-rw-r--r--hw/s390x/css.h2
-rw-r--r--hw/s390x/event-facility.c93
-rw-r--r--hw/s390x/ipl.c25
-rw-r--r--hw/s390x/s390-virtio-ccw.c8
-rw-r--r--hw/s390x/s390-virtio-hcall.c14
-rw-r--r--hw/s390x/s390-virtio.c2
-rw-r--r--hw/s390x/sclp.c69
-rw-r--r--hw/s390x/virtio-ccw.c102
-rw-r--r--hw/s390x/virtio-ccw.h4
-rw-r--r--hw/scsi/scsi-bus.c7
-rw-r--r--hw/scsi/scsi-disk.c29
-rw-r--r--hw/scsi/scsi-generic.c2
-rw-r--r--hw/scsi/spapr_vscsi.c61
-rw-r--r--hw/sparc/sun4m.c62
-rw-r--r--hw/ssi/xilinx_spips.c4
-rw-r--r--hw/timer/slavio_timer.c25
-rw-r--r--hw/unicore32/puv3.c2
-rw-r--r--hw/usb/ccid-card-emulated.c8
94 files changed, 4316 insertions, 698 deletions
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 3891050748..42ee614e27 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,35 +17,55 @@
#include "block/coroutine.h"
#include "virtio-9p-coth.h"
+static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
+{
+ ssize_t len, maxlen = PATH_MAX;
+
+ buf->data = g_malloc(PATH_MAX);
+ for(;;) {
+ len = s->ops->readlink(&s->ctx, path, buf->data, maxlen);
+ if (len < 0) {
+ g_free(buf->data);
+ buf->data = NULL;
+ buf->size = 0;
+ break;
+ } else if (len == maxlen) {
+ /*
+ * We dodn't have space to put the NULL or we have more
+ * to read. Increase the size and try again
+ */
+ maxlen *= 2;
+ g_free(buf->data);
+ buf->data = g_malloc(maxlen);
+ continue;
+ }
+ /*
+ * Null terminate the readlink output
+ */
+ buf->data[len] = '\0';
+ buf->size = len;
+ break;
+ }
+ return len;
+}
+
int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
{
int err;
- ssize_t len;
V9fsState *s = pdu->s;
if (v9fs_request_cancelled(pdu)) {
return -EINTR;
}
- buf->data = g_malloc(PATH_MAX);
v9fs_path_read_lock(s);
v9fs_co_run_in_worker(
{
- len = s->ops->readlink(&s->ctx, path,
- buf->data, PATH_MAX - 1);
- if (len > -1) {
- buf->size = len;
- buf->data[len] = 0;
- err = 0;
- } else {
+ err = __readlink(s, path, buf);
+ if (err < 0) {
err = -errno;
}
});
v9fs_path_unlock(s);
- if (err) {
- g_free(buf->data);
- buf->data = NULL;
- buf->size = 0;
- }
return err;
}
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index 17002a3d28..4b79cefd13 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -498,7 +498,7 @@ static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
const char *name, V9fsPath *target)
{
- char buffer[PATH_MAX];
+ char *buffer;
struct file_handle *fh;
int dirfd, ret, mnt_id;
struct handle_data *data = (struct handle_data *)ctx->private;
@@ -513,7 +513,9 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
} else {
/* relative to export root */
- dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
+ buffer = rpath(ctx, ".");
+ dirfd = open(buffer, O_DIRECTORY);
+ g_free(buffer);
}
if (dirfd < 0) {
return dirfd;
@@ -521,7 +523,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
fh->handle_bytes = data->handle_bytes;
/* add a "./" at the beginning of the path */
- snprintf(buffer, PATH_MAX, "./%s", name);
+ buffer = g_strdup_printf("./%s", name);
/* flag = 0 imply don't follow symlink */
ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
if (!ret) {
@@ -531,6 +533,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
g_free(fh);
}
close(dirfd);
+ g_free(buffer);
return ret;
}
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index df0dbffa7a..56b302c122 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -42,18 +42,18 @@
#define VIRTFS_META_DIR ".virtfs_metadata"
-static const char *local_mapped_attr_path(FsContext *ctx,
- const char *path, char *buffer)
+static char *local_mapped_attr_path(FsContext *ctx, const char *path)
{
char *dir_name;
char *tmp_path = g_strdup(path);
char *base_name = basename(tmp_path);
+ char *buffer;
/* NULL terminate the directory */
dir_name = tmp_path;
*(base_name - 1) = '\0';
- snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
+ buffer = g_strdup_printf("%s/%s/%s/%s",
ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
g_free(tmp_path);
return buffer;
@@ -92,10 +92,11 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path,
{
FILE *fp;
char buf[ATTR_MAX];
- char attr_path[PATH_MAX];
+ char *attr_path;
- local_mapped_attr_path(ctx, path, attr_path);
+ attr_path = local_mapped_attr_path(ctx, path);
fp = local_fopen(attr_path, "r");
+ g_free(attr_path);
if (!fp) {
return;
}
@@ -118,12 +119,13 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path,
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
int err;
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
- err = lstat(rpath(fs_ctx, path, buffer), stbuf);
+ buffer = rpath(fs_ctx, path);
+ err = lstat(buffer, stbuf);
if (err) {
- return err;
+ goto err_out;
}
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
/* Actual credentials are part of extended attrs */
@@ -131,41 +133,42 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
gid_t tmp_gid;
mode_t tmp_mode;
dev_t tmp_dev;
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
- sizeof(uid_t)) > 0) {
+ if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
stbuf->st_uid = tmp_uid;
}
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
- sizeof(gid_t)) > 0) {
+ if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
stbuf->st_gid = tmp_gid;
}
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
+ if (getxattr(buffer, "user.virtfs.mode",
&tmp_mode, sizeof(mode_t)) > 0) {
stbuf->st_mode = tmp_mode;
}
- if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
- sizeof(dev_t)) > 0) {
+ if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
stbuf->st_rdev = tmp_dev;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
local_mapped_file_attr(fs_ctx, path, stbuf);
}
+
+err_out:
+ g_free(buffer);
return err;
}
static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
{
int err;
- char attr_dir[PATH_MAX];
+ char *attr_dir;
char *tmp_path = g_strdup(path);
- snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
+ attr_dir = g_strdup_printf("%s/%s/%s",
ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
err = mkdir(attr_dir, 0700);
if (err < 0 && errno == EEXIST) {
err = 0;
}
+ g_free(attr_dir);
g_free(tmp_path);
return err;
}
@@ -176,10 +179,11 @@ static int local_set_mapped_file_attr(FsContext *ctx,
FILE *fp;
int ret = 0;
char buf[ATTR_MAX];
- char attr_path[PATH_MAX];
+ char *attr_path;
int uid = -1, gid = -1, mode = -1, rdev = -1;
- fp = local_fopen(local_mapped_attr_path(ctx, path, attr_path), "r");
+ attr_path = local_mapped_attr_path(ctx, path);
+ fp = local_fopen(attr_path, "r");
if (!fp) {
goto create_map_file;
}
@@ -241,6 +245,7 @@ update_map_file:
fclose(fp);
err_out:
+ g_free(attr_path);
return ret;
}
@@ -282,36 +287,43 @@ static int local_set_xattr(const char *path, FsCred *credp)
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
FsCred *credp)
{
- char buffer[PATH_MAX];
+ char *buffer;
- if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
- credp->fc_gid) < 0) {
+ buffer = rpath(fs_ctx, path);
+ if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
/*
* If we fail to change ownership and if we are
* using security model none. Ignore the error
*/
if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
- return -1;
+ goto err;
}
}
- if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
- return -1;
+ if (chmod(buffer, credp->fc_mode & 07777) < 0) {
+ goto err;
}
+
+ g_free(buffer);
return 0;
+err:
+ g_free(buffer);
+ return -1;
}
static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
char *buf, size_t bufsz)
{
ssize_t tsize = -1;
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
int fd;
- fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, O_RDONLY | O_NOFOLLOW);
+ g_free(buffer);
if (fd == -1) {
return -1;
}
@@ -322,7 +334,9 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
return tsize;
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
+ buffer = rpath(fs_ctx, path);
+ tsize = readlink(buffer, buf, bufsz);
+ g_free(buffer);
}
return tsize;
}
@@ -340,20 +354,24 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
static int local_open(FsContext *ctx, V9fsPath *fs_path,
int flags, V9fsFidOpenState *fs)
{
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
- fs->fd = open(rpath(ctx, path, buffer), flags | O_NOFOLLOW);
+ buffer = rpath(ctx, path);
+ fs->fd = open(buffer, flags | O_NOFOLLOW);
+ g_free(buffer);
return fs->fd;
}
static int local_opendir(FsContext *ctx,
V9fsPath *fs_path, V9fsFidOpenState *fs)
{
- char buffer[PATH_MAX];
+ char *buffer;
char *path = fs_path->data;
- fs->dir = opendir(rpath(ctx, path, buffer));
+ buffer = rpath(ctx, path);
+ fs->dir = opendir(buffer);
+ g_free(buffer);
if (!fs->dir) {
return -1;
}
@@ -441,18 +459,23 @@ static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret = -1;
char *path = fs_path->data;
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ buffer = rpath(fs_ctx, path);
+ ret = local_set_xattr(buffer, credp);
+ g_free(buffer);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
return local_set_mapped_file_attr(fs_ctx, path, credp);
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
+ buffer = rpath(fs_ctx, path);
+ ret = chmod(buffer, credp->fc_mode);
+ g_free(buffer);
}
- return -1;
+ return ret;
}
static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
@@ -462,7 +485,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
int err = -1;
int serrno = 0;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
@@ -470,21 +493,23 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- err = mknod(rpath(fs_ctx, path, buffer),
- SM_LOCAL_MODE_BITS|S_IFREG, 0);
+ buffer = rpath(fs_ctx, path);
+ err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
+ g_free(buffer);
goto out;
}
- err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = mknod(rpath(fs_ctx, path, buffer),
- SM_LOCAL_MODE_BITS|S_IFREG, 0);
+ buffer = rpath(fs_ctx, path);
+ err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
+ g_free(buffer);
goto out;
}
err = local_set_mapped_file_attr(fs_ctx, path, credp);
@@ -494,9 +519,10 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
- credp->fc_rdev);
+ buffer = rpath(fs_ctx, path);
+ err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
if (err == -1) {
+ g_free(buffer);
goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
@@ -508,8 +534,9 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
goto out;
err_end:
- remove(rpath(fs_ctx, path, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -522,7 +549,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
int err = -1;
int serrno = 0;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
@@ -530,19 +557,23 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
+ g_free(buffer);
goto out;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
- err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
+ g_free(buffer);
goto out;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
@@ -553,8 +584,10 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
+ buffer = rpath(fs_ctx, path);
+ err = mkdir(buffer, credp->fc_mode);
if (err == -1) {
+ g_free(buffer);
goto out;
}
err = local_post_create_passthrough(fs_ctx, path, credp);
@@ -566,8 +599,9 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
goto out;
err_end:
- remove(rpath(fs_ctx, path, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -626,7 +660,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
int err = -1;
int serrno = 0;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
/*
* Mark all the open to not follow symlinks
@@ -639,21 +673,25 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
/* Determine the security model */
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
credp->fc_mode = credp->fc_mode|S_IFREG;
/* Set cleint credentials in xattr */
- err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -666,8 +704,10 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
+ buffer = rpath(fs_ctx, path);
+ fd = open(buffer, flags, credp->fc_mode);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -683,8 +723,9 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
err_end:
close(fd);
- remove(rpath(fs_ctx, path, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -698,7 +739,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
int serrno = 0;
char *newpath;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
@@ -708,10 +749,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
int fd;
ssize_t oldpath_size, write_size;
- fd = open(rpath(fs_ctx, newpath, buffer),
- O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
- SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, newpath);
+ fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -730,7 +771,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
close(fd);
/* Set cleint credentials in symlink's xattr */
credp->fc_mode = credp->fc_mode|S_IFLNK;
- err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
+ err = local_set_xattr(buffer, credp);
if (err == -1) {
serrno = errno;
goto err_end;
@@ -738,10 +779,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
int fd;
ssize_t oldpath_size, write_size;
- fd = open(rpath(fs_ctx, newpath, buffer),
- O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
- SM_LOCAL_MODE_BITS);
+ buffer = rpath(fs_ctx, newpath);
+ fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
if (fd == -1) {
+ g_free(buffer);
err = fd;
goto out;
}
@@ -767,12 +808,13 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
}
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
+ buffer = rpath(fs_ctx, newpath);
+ err = symlink(oldpath, buffer);
if (err) {
+ g_free(buffer);
goto out;
}
- err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
- credp->fc_gid);
+ err = lchown(buffer, credp->fc_uid, credp->fc_gid);
if (err == -1) {
/*
* If we fail to change ownership and if we are
@@ -788,8 +830,9 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
goto out;
err_end:
- remove(rpath(fs_ctx, newpath, buffer));
+ remove(buffer);
errno = serrno;
+ g_free(buffer);
out:
v9fs_string_free(&fullname);
return err;
@@ -800,13 +843,16 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
{
int ret;
V9fsString newpath;
- char buffer[PATH_MAX], buffer1[PATH_MAX];
+ char *buffer, *buffer1;
v9fs_string_init(&newpath);
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
- ret = link(rpath(ctx, oldpath->data, buffer),
- rpath(ctx, newpath.data, buffer1));
+ buffer = rpath(ctx, oldpath->data);
+ buffer1 = rpath(ctx, newpath.data);
+ ret = link(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
/* now link the virtfs_metadata files */
if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
@@ -815,8 +861,11 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
if (ret < 0) {
goto err_out;
}
- ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer),
- local_mapped_attr_path(ctx, newpath.data, buffer1));
+ buffer = local_mapped_attr_path(ctx, oldpath->data);
+ buffer1 = local_mapped_attr_path(ctx, newpath.data);
+ ret = link(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
if (ret < 0 && errno != ENOENT) {
goto err_out;
}
@@ -828,17 +877,21 @@ err_out:
static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
char *path = fs_path->data;
- return truncate(rpath(ctx, path, buffer), size);
+ buffer = rpath(ctx, path);
+ ret = truncate(buffer, size);
+ g_free(buffer);
+ return ret;
}
static int local_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
int err;
- char buffer[PATH_MAX], buffer1[PATH_MAX];
+ char *buffer, *buffer1;
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
err = local_create_mapped_attr_dir(ctx, newpath);
@@ -846,50 +899,69 @@ static int local_rename(FsContext *ctx, const char *oldpath,
return err;
}
/* rename the .virtfs_metadata files */
- err = rename(local_mapped_attr_path(ctx, oldpath, buffer),
- local_mapped_attr_path(ctx, newpath, buffer1));
+ buffer = local_mapped_attr_path(ctx, oldpath);
+ buffer1 = local_mapped_attr_path(ctx, newpath);
+ err = rename(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
if (err < 0 && errno != ENOENT) {
return err;
}
}
- return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+
+ buffer = rpath(ctx, oldpath);
+ buffer1 = rpath(ctx, newpath);
+ err = rename(buffer, buffer1);
+ g_free(buffer);
+ g_free(buffer1);
+ return err;
}
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret = -1;
char *path = fs_path->data;
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
(fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
- return lchown(rpath(fs_ctx, path, buffer),
- credp->fc_uid, credp->fc_gid);
+ buffer = rpath(fs_ctx, path);
+ ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
+ g_free(buffer);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+ buffer = rpath(fs_ctx, path);
+ ret = local_set_xattr(buffer, credp);
+ g_free(buffer);
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
return local_set_mapped_file_attr(fs_ctx, path, credp);
}
- return -1;
+ return ret;
}
static int local_utimensat(FsContext *s, V9fsPath *fs_path,
const struct timespec *buf)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
char *path = fs_path->data;
- return qemu_utimens(rpath(s, path, buffer), buf);
+ buffer = rpath(s, path);
+ ret = qemu_utimens(buffer, buf);
+ g_free(buffer);
+ return ret;
}
static int local_remove(FsContext *ctx, const char *path)
{
int err;
struct stat stbuf;
- char buffer[PATH_MAX];
+ char *buffer;
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = lstat(rpath(ctx, path, buffer), &stbuf);
+ buffer = rpath(ctx, path);
+ err = lstat(buffer, &stbuf);
+ g_free(buffer);
if (err) {
goto err_out;
}
@@ -898,8 +970,10 @@ static int local_remove(FsContext *ctx, const char *path)
* directory
*/
if (S_ISDIR(stbuf.st_mode)) {
- sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR);
+ buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
+ path, VIRTFS_META_DIR);
err = remove(buffer);
+ g_free(buffer);
if (err < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -912,7 +986,9 @@ static int local_remove(FsContext *ctx, const char *path)
* Now remove the name from parent directory
* .virtfs_metadata directory
*/
- err = remove(local_mapped_attr_path(ctx, path, buffer));
+ buffer = local_mapped_attr_path(ctx, path);
+ err = remove(buffer);
+ g_free(buffer);
if (err < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -921,7 +997,10 @@ static int local_remove(FsContext *ctx, const char *path)
goto err_out;
}
}
- return remove(rpath(ctx, path, buffer));
+
+ buffer = rpath(ctx, path);
+ err = remove(buffer);
+ g_free(buffer);
err_out:
return err;
}
@@ -946,10 +1025,14 @@ static int local_fsync(FsContext *ctx, int fid_type,
static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
char *path = fs_path->data;
- return statfs(rpath(s, path, buffer), stbuf);
+ buffer = rpath(s, path);
+ ret = statfs(buffer, stbuf);
+ g_free(buffer);
+ return ret;
}
static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
@@ -1022,7 +1105,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
{
int ret;
V9fsString fullname;
- char buffer[PATH_MAX];
+ char *buffer;
v9fs_string_init(&fullname);
@@ -1033,9 +1116,10 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
* If directory remove .virtfs_metadata contained in the
* directory
*/
- sprintf(buffer, "%s/%s/%s", ctx->fs_root,
- fullname.data, VIRTFS_META_DIR);
+ buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
+ fullname.data, VIRTFS_META_DIR);
ret = remove(buffer);
+ g_free(buffer);
if (ret < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -1048,7 +1132,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
* Now remove the name from parent directory
* .virtfs_metadata directory.
*/
- ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer));
+ buffer = local_mapped_attr_path(ctx, fullname.data);
+ ret = remove(buffer);
+ g_free(buffer);
if (ret < 0 && errno != ENOENT) {
/*
* We didn't had the .virtfs_metadata file. May be file created
@@ -1058,10 +1144,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
}
}
/* Remove the name finally */
- ret = remove(rpath(ctx, fullname.data, buffer));
- v9fs_string_free(&fullname);
+ buffer = rpath(ctx, fullname.data);
+ ret = remove(buffer);
+ g_free(buffer);
err_out:
+ v9fs_string_free(&fullname);
return ret;
}
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
index 339c5ecae4..803d9d94f3 100644
--- a/hw/9pfs/virtio-9p-posix-acl.c
+++ b/hw/9pfs/virtio-9p-posix-acl.c
@@ -26,8 +26,13 @@
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
- return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size);
+ char *buffer;
+ ssize_t ret;
+
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
+ g_free(buffer);
+ return ret;
}
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
@@ -52,17 +57,23 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- char buffer[PATH_MAX];
- return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
- size, flags);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static int mp_pacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- char buffer[PATH_MAX];
- ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
+ char *buffer;
+
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(buffer, MAP_ACL_ACCESS);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
@@ -72,14 +83,20 @@ static int mp_pacl_removexattr(FsContext *ctx,
errno = 0;
ret = 0;
}
+ g_free(buffer);
return ret;
}
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
- return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size);
+ char *buffer;
+ ssize_t ret;
+
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
+ g_free(buffer);
+ return ret;
}
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
@@ -104,17 +121,23 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- char buffer[PATH_MAX];
- return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
- size, flags);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static int mp_dacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- char buffer[PATH_MAX];
- ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
+ char *buffer;
+
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
@@ -124,6 +147,7 @@ static int mp_dacl_removexattr(FsContext *ctx,
errno = 0;
ret = 0;
}
+ g_free(buffer);
return ret;
}
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
index e0c92ebf9e..46133e06db 100644
--- a/hw/9pfs/virtio-9p-xattr-user.c
+++ b/hw/9pfs/virtio-9p-xattr-user.c
@@ -21,7 +21,9 @@
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ ssize_t ret;
+
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -30,7 +32,10 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
errno = ENOATTR;
return -1;
}
- return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, name, value, size);
+ g_free(buffer);
+ return ret;
}
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
@@ -69,7 +74,9 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
+
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -78,13 +85,18 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
errno = EACCES;
return -1;
}
- return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, name, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static int mp_user_removexattr(FsContext *ctx,
const char *path, const char *name)
{
- char buffer[PATH_MAX];
+ char *buffer;
+ int ret;
+
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -93,7 +105,10 @@ static int mp_user_removexattr(FsContext *ctx,
errno = EACCES;
return -1;
}
- return lremovexattr(rpath(ctx, path, buffer), name);
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(buffer, name);
+ g_free(buffer);
+ return ret;
}
XattrOperations mapped_user_xattr = {
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
index 3fae557a84..07183887c5 100644
--- a/hw/9pfs/virtio-9p-xattr.c
+++ b/hw/9pfs/virtio-9p-xattr.c
@@ -67,21 +67,24 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
void *value, size_t vsize)
{
ssize_t size = 0;
- char buffer[PATH_MAX];
+ char *buffer;
void *ovalue = value;
XattrOperations *xops;
char *orig_value, *orig_value_start;
ssize_t xattr_len, parsed_len = 0, attr_len;
/* Get the actual len */
- xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
+ buffer = rpath(ctx, path);
+ xattr_len = llistxattr(buffer, value, 0);
if (xattr_len <= 0) {
+ g_free(buffer);
return xattr_len;
}
/* Now fetch the xattr and find the actual size */
orig_value = g_malloc(xattr_len);
- xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
+ xattr_len = llistxattr(buffer, orig_value, xattr_len);
+ g_free(buffer);
/* store the orig pointer */
orig_value_start = orig_value;
diff --git a/hw/9pfs/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h
index 41cc6cbc7b..327b32b5aa 100644
--- a/hw/9pfs/virtio-9p-xattr.h
+++ b/hw/9pfs/virtio-9p-xattr.h
@@ -54,23 +54,38 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- char buffer[PATH_MAX];
- return lgetxattr(rpath(ctx, path, buffer), name, value, size);
+ char *buffer;
+ ssize_t ret;
+
+ buffer = rpath(ctx, path);
+ ret = lgetxattr(buffer, name, value, size);
+ g_free(buffer);
+ return ret;
}
static inline int pt_setxattr(FsContext *ctx, const char *path,
const char *name, void *value,
size_t size, int flags)
{
- char buffer[PATH_MAX];
- return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lsetxattr(buffer, name, value, size, flags);
+ g_free(buffer);
+ return ret;
}
static inline int pt_removexattr(FsContext *ctx,
const char *path, const char *name)
{
- char buffer[PATH_MAX];
- return lremovexattr(rpath(ctx, path, buffer), name);
+ char *buffer;
+ int ret;
+
+ buffer = rpath(ctx, path);
+ ret = lremovexattr(path, name);
+ g_free(buffer);
+ return ret;
}
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 1d6eedb7d8..2c3603aed0 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -6,6 +6,7 @@
#include <sys/time.h>
#include <utime.h>
#include <sys/resource.h>
+#include <glib.h>
#include "hw/virtio/virtio.h"
#include "fsdev/file-op-9p.h"
#include "fsdev/virtio-9p-marshal.h"
@@ -112,10 +113,9 @@ enum p9_proto_version {
#define FID_REFERENCED 0x1
#define FID_NON_RECLAIMABLE 0x2
-static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
+static inline char *rpath(FsContext *ctx, const char *path)
{
- snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
- return buffer;
+ return g_strdup_printf("%s/%s", ctx->fs_root, path);
}
/*
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 05a00dc401..d178b65de4 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,4 +1,4 @@
-devices-dirs-$(CONFIG_REALLY_VIRTFS) += 9pfs/
+devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
devices-dirs-$(CONFIG_ACPI) += acpi/
devices-dirs-$(CONFIG_SOFTMMU) += audio/
devices-dirs-$(CONFIG_SOFTMMU) += block/
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index cce7127598..de542010aa 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -110,10 +110,10 @@
#define MP_PHY_88E3015 0x01410E20
/* TX descriptor status */
-#define MP_ETH_TX_OWN (1 << 31)
+#define MP_ETH_TX_OWN (1U << 31)
/* RX descriptor status */
-#define MP_ETH_RX_OWN (1 << 31)
+#define MP_ETH_RX_OWN (1U << 31)
/* Interrupt cause/mask bits */
#define MP_ETH_IRQ_RX_BIT 0
@@ -630,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd)
"musicpal-lcd", MP_LCD_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
- s->con = graphic_console_init(dev, &musicpal_gfx_ops, s);
+ s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
qemu_console_resize(s->con, 128*3, 64*3);
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 47511d2cae..b433748c60 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -809,22 +809,26 @@ static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s,
uint32_t diff, uint32_t value)
{
if (s->compat1509) {
- if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */
- omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"),
- (value >> 31) & 1);
- if (diff & (1 << 1)) /* CLK32K */
- omap_clk_onoff(omap_findclk(s, "clk32k_out"),
- (~value >> 1) & 1);
+ if (diff & (1U << 31)) {
+ /* MCBSP3_CLK_HIZ_DI */
+ omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), (value >> 31) & 1);
+ }
+ if (diff & (1 << 1)) {
+ /* CLK32K */
+ omap_clk_onoff(omap_findclk(s, "clk32k_out"), (~value >> 1) & 1);
+ }
}
}
static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
uint32_t diff, uint32_t value)
{
- if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */
- omap_clk_reparent(omap_findclk(s, "uart3_ck"),
- omap_findclk(s, ((value >> 31) & 1) ?
- "ck_48m" : "armper_ck"));
+ if (diff & (1U << 31)) {
+ /* CONF_MOD_UART3_CLK_MODE_R */
+ omap_clk_reparent(omap_findclk(s, "uart3_ck"),
+ omap_findclk(s, ((value >> 31) & 1) ?
+ "ck_48m" : "armper_ck"));
+ }
if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */
omap_clk_reparent(omap_findclk(s, "uart2_ck"),
omap_findclk(s, ((value >> 30) & 1) ?
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 904277a9da..04291488e4 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -259,7 +259,7 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
case 1:
/* Idle */
- if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */
+ if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */
cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
break;
}
@@ -496,7 +496,7 @@ typedef struct {
#define SSCR0_SSE (1 << 7)
#define SSCR0_RIM (1 << 22)
#define SSCR0_TIM (1 << 23)
-#define SSCR0_MOD (1 << 31)
+#define SSCR0_MOD (1U << 31)
#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
#define SSCR1_RIE (1 << 0)
#define SSCR1_TIE (1 << 1)
@@ -1006,7 +1006,7 @@ static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
switch (addr) {
case RTTR:
- if (!(s->rttr & (1 << 31))) {
+ if (!(s->rttr & (1U << 31))) {
pxa2xx_rtc_hzupdate(s);
s->rttr = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
index ca77f56c9f..07274285ab 100644
--- a/hw/arm/pxa2xx_gpio.c
+++ b/hw/arm/pxa2xx_gpio.c
@@ -110,7 +110,7 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level)
}
bank = line >> 5;
- mask = 1 << (line & 31);
+ mask = 1U << (line & 31);
if (level) {
s->status[bank] |= s->rising[bank] & mask &
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
index 345fa4a491..d37fb543e8 100644
--- a/hw/arm/pxa2xx_pic.c
+++ b/hw/arm/pxa2xx_pic.c
@@ -105,7 +105,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
irq = s->priority[i] & 0x3f;
- if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
+ if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) {
/* Source peripheral ID is valid. */
bit = 1 << (irq & 31);
int_set = (irq >= 32);
@@ -119,7 +119,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
/* IRQ asserted */
ichp &= 0x0000ffff;
- ichp |= (1 << 31) | (irq << 16);
+ ichp |= (1U << 31) | (irq << 16);
}
}
}
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 2237edb4eb..d1c7ad4574 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -358,7 +358,7 @@ static void start_data_plane_bh(void *opaque)
qemu_bh_delete(s->start_bh);
s->start_bh = NULL;
- qemu_thread_create(&s->thread, data_plane_thread,
+ qemu_thread_create(&s->thread, "data_plane", data_plane_thread,
s, QEMU_THREAD_JOINABLE);
}
diff --git a/hw/core/loader.c b/hw/core/loader.c
index e1c3f3a860..b323c0c7b8 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size)
#define SZ 64
#include "hw/elf_ops.h"
+const char *load_elf_strerror(int error)
+{
+ switch (error) {
+ case 0:
+ return "No error";
+ case ELF_LOAD_FAILED:
+ return "Failed to load ELF";
+ case ELF_LOAD_NOT_ELF:
+ return "The image is not ELF";
+ case ELF_LOAD_WRONG_ARCH:
+ return "The image is from incompatible architecture";
+ case ELF_LOAD_WRONG_ENDIAN:
+ return "The image has incorrect endianness";
+ default:
+ return "Unknown error";
+ }
+}
+
/* return < 0 if error, otherwise the number of bytes loaded in memory */
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
{
- int fd, data_order, target_data_order, must_swab, ret;
+ int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
uint8_t e_ident[EI_NIDENT];
fd = open(filename, O_RDONLY | O_BINARY);
@@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
if (e_ident[0] != ELFMAG0 ||
e_ident[1] != ELFMAG1 ||
e_ident[2] != ELFMAG2 ||
- e_ident[3] != ELFMAG3)
+ e_ident[3] != ELFMAG3) {
+ ret = ELF_LOAD_NOT_ELF;
goto fail;
+ }
#ifdef HOST_WORDS_BIGENDIAN
data_order = ELFDATA2MSB;
#else
@@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
}
if (target_data_order != e_ident[EI_DATA]) {
+ ret = ELF_LOAD_WRONG_ENDIAN;
goto fail;
}
@@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
}
- close(fd);
- return ret;
-
fail:
close(fd);
- return -1;
+ return ret;
}
static void bswap_uboot_header(uboot_image_header_t *hdr)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index c0b857fbd4..380976a066 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -440,27 +440,33 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
+ BusClass *bc;
char *buf;
- int i,len;
+ int i, len, bus_id;
bus->parent = parent;
if (name) {
bus->name = g_strdup(name);
} else if (bus->parent && bus->parent->id) {
- /* parent device has id -> use it for bus name */
+ /* parent device has id -> use it plus parent-bus-id for bus name */
+ bus_id = bus->parent->num_child_bus;
+
len = strlen(bus->parent->id) + 16;
buf = g_malloc(len);
- snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
+ snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
bus->name = buf;
} else {
- /* no id -> use lowercase bus type for bus name */
+ /* no id -> use lowercase bus type plus global bus-id for bus name */
+ bc = BUS_GET_CLASS(bus);
+ bus_id = bc->automatic_ids++;
+
len = strlen(typename) + 16;
buf = g_malloc(len);
- len = snprintf(buf, len, "%s.%d", typename,
- bus->parent ? bus->parent->num_child_bus : 0);
- for (i = 0; i < len; i++)
+ len = snprintf(buf, len, "%s.%d", typename, bus_id);
+ for (i = 0; i < len; i++) {
buf[i] = qemu_tolower(buf[i]);
+ }
bus->name = buf;
}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 540df82600..7ed76a9c24 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
obj-$(CONFIG_SM501) += sm501.o
obj-$(CONFIG_TCX) += tcx.o
+obj-$(CONFIG_CG3) += cg3.o
obj-$(CONFIG_VGA) += vga.o
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
index 4a466c8323..55c0ddf00b 100644
--- a/hw/display/blizzard.c
+++ b/hw/display/blizzard.c
@@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int)
s->fb = g_malloc(0x180000);
- s->con = graphic_console_init(NULL, &blizzard_ops, s);
+ s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
new file mode 100644
index 0000000000..a042b9ecbe
--- /dev/null
+++ b/hw/display/cg3.c
@@ -0,0 +1,385 @@
+/*
+ * QEMU CG3 Frame buffer
+ *
+ * Copyright (c) 2012 Bob Breuer
+ * Copyright (c) 2013 Mark Cave-Ayland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "ui/console.h"
+#include "hw/sysbus.h"
+#include "hw/loader.h"
+
+/* Change to 1 to enable debugging */
+#define DEBUG_CG3 0
+
+#define CG3_ROM_FILE "QEMU,cgthree.bin"
+#define FCODE_MAX_ROM_SIZE 0x10000
+
+#define CG3_REG_SIZE 0x20
+
+#define CG3_REG_BT458_ADDR 0x0
+#define CG3_REG_BT458_COLMAP 0x4
+#define CG3_REG_FBC_CTRL 0x10
+#define CG3_REG_FBC_STATUS 0x11
+#define CG3_REG_FBC_CURSTART 0x12
+#define CG3_REG_FBC_CUREND 0x13
+#define CG3_REG_FBC_VCTRL 0x14
+
+/* Control register flags */
+#define CG3_CR_ENABLE_INTS 0x80
+
+/* Status register flags */
+#define CG3_SR_PENDING_INT 0x80
+#define CG3_SR_1152_900_76_B 0x60
+#define CG3_SR_ID_COLOR 0x01
+
+#define CG3_VRAM_SIZE 0x100000
+#define CG3_VRAM_OFFSET 0x800000
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_CG3) { \
+ printf("CG3: " fmt , ## __VA_ARGS__); \
+ } \
+} while (0);
+
+#define TYPE_CG3 "cgthree"
+#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
+
+typedef struct CG3State {
+ SysBusDevice parent_obj;
+
+ QemuConsole *con;
+ qemu_irq irq;
+ hwaddr prom_addr;
+ MemoryRegion vram_mem;
+ MemoryRegion rom;
+ MemoryRegion reg;
+ uint32_t vram_size;
+ int full_update;
+ uint8_t regs[16];
+ uint8_t r[256], g[256], b[256];
+ uint16_t width, height, depth;
+ uint8_t dac_index, dac_state;
+} CG3State;
+
+static void cg3_update_display(void *opaque)
+{
+ CG3State *s = opaque;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ const uint8_t *pix;
+ uint32_t *data;
+ uint32_t dval;
+ int x, y, y_start;
+ unsigned int width, height;
+ ram_addr_t page, page_min, page_max;
+
+ if (surface_bits_per_pixel(surface) != 32) {
+ return;
+ }
+ width = s->width;
+ height = s->height;
+
+ y_start = -1;
+ page_min = -1;
+ page_max = 0;
+ page = 0;
+ pix = memory_region_get_ram_ptr(&s->vram_mem);
+ data = (uint32_t *)surface_data(surface);
+
+ for (y = 0; y < height; y++) {
+ int update = s->full_update;
+
+ page = (y * width) & TARGET_PAGE_MASK;
+ update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
+ DIRTY_MEMORY_VGA);
+ if (update) {
+ if (y_start < 0) {
+ y_start = y;
+ }
+ if (page < page_min) {
+ page_min = page;
+ }
+ if (page > page_max) {
+ page_max = page;
+ }
+
+ for (x = 0; x < width; x++) {
+ dval = *pix++;
+ dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
+ *data++ = dval;
+ }
+ } else {
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ y_start = -1;
+ }
+ pix += width;
+ data += width;
+ }
+ }
+ s->full_update = 0;
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ }
+ if (page_max >= page_min) {
+ memory_region_reset_dirty(&s->vram_mem,
+ page_min, page_max - page_min + TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
+ }
+ /* vsync interrupt? */
+ if (s->regs[0] & CG3_CR_ENABLE_INTS) {
+ s->regs[1] |= CG3_SR_PENDING_INT;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void cg3_invalidate_display(void *opaque)
+{
+ CG3State *s = opaque;
+
+ memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
+}
+
+static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
+{
+ CG3State *s = opaque;
+ int val;
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ case CG3_REG_BT458_COLMAP:
+ val = 0;
+ break;
+ case CG3_REG_FBC_CTRL:
+ val = s->regs[0];
+ break;
+ case CG3_REG_FBC_STATUS:
+ /* monitor ID 6, board type = 1 (color) */
+ val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ val = s->regs[addr - 0x10];
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register read "
+ "reg 0x%" HWADDR_PRIx " size 0x%x\n",
+ addr, size);
+ val = 0;
+ break;
+ }
+ DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
+ return val;
+}
+
+static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ CG3State *s = opaque;
+ uint8_t regval;
+ int i;
+
+ DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
+ val, addr, size);
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ s->dac_index = val;
+ s->dac_state = 0;
+ break;
+ case CG3_REG_BT458_COLMAP:
+ /* This register can be written to as either a long word or a byte */
+ if (size == 1) {
+ val <<= 24;
+ }
+
+ for (i = 0; i < size; i++) {
+ regval = val >> 24;
+
+ switch (s->dac_state) {
+ case 0:
+ s->r[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 1:
+ s->g[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 2:
+ s->b[s->dac_index] = regval;
+ /* Index autoincrement */
+ s->dac_index = (s->dac_index + 1) & 0xff;
+ default:
+ s->dac_state = 0;
+ break;
+ }
+ val <<= 8;
+ }
+ s->full_update = 1;
+ break;
+ case CG3_REG_FBC_CTRL:
+ s->regs[0] = val;
+ break;
+ case CG3_REG_FBC_STATUS:
+ if (s->regs[1] & CG3_SR_PENDING_INT) {
+ /* clear interrupt */
+ s->regs[1] &= ~CG3_SR_PENDING_INT;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ s->regs[addr - 0x10] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register write "
+ "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
+ addr, size, val);
+ break;
+ }
+}
+
+static const MemoryRegionOps cg3_reg_ops = {
+ .read = cg3_reg_read,
+ .write = cg3_reg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const GraphicHwOps cg3_ops = {
+ .invalidate = cg3_invalidate_display,
+ .gfx_update = cg3_update_display,
+};
+
+static void cg3_realizefn(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ CG3State *s = CG3(dev);
+ int ret;
+ char *fcode_filename;
+
+ /* FCode ROM */
+ memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
+ vmstate_register_ram_global(&s->rom);
+ memory_region_set_readonly(&s->rom, true);
+ sysbus_init_mmio(sbd, &s->rom);
+
+ fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
+ if (fcode_filename) {
+ ret = load_image_targphys(fcode_filename, s->prom_addr,
+ FCODE_MAX_ROM_SIZE);
+ if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
+ error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
+ }
+ }
+
+ memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
+ CG3_REG_SIZE);
+ sysbus_init_mmio(sbd, &s->reg);
+
+ memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
+ vmstate_register_ram_global(&s->vram_mem);
+ sysbus_init_mmio(sbd, &s->vram_mem);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
+ qemu_console_resize(s->con, s->width, s->height);
+}
+
+static int vmstate_cg3_post_load(void *opaque, int version_id)
+{
+ CG3State *s = opaque;
+
+ cg3_invalidate_display(s);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_cg3 = {
+ .name = "cg3",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = vmstate_cg3_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(height, CG3State),
+ VMSTATE_UINT16(width, CG3State),
+ VMSTATE_UINT16(depth, CG3State),
+ VMSTATE_BUFFER(r, CG3State),
+ VMSTATE_BUFFER(g, CG3State),
+ VMSTATE_BUFFER(b, CG3State),
+ VMSTATE_UINT8(dac_index, CG3State),
+ VMSTATE_UINT8(dac_state, CG3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void cg3_reset(DeviceState *d)
+{
+ CG3State *s = CG3(d);
+
+ /* Initialize palette */
+ memset(s->r, 0, 256);
+ memset(s->g, 0, 256);
+ memset(s->b, 0, 256);
+
+ s->dac_state = 0;
+ s->full_update = 1;
+ qemu_irq_lower(s->irq);
+}
+
+static Property cg3_properties[] = {
+ DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
+ DEFINE_PROP_UINT16("width", CG3State, width, -1),
+ DEFINE_PROP_UINT16("height", CG3State, height, -1),
+ DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
+ DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cg3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = cg3_realizefn;
+ dc->reset = cg3_reset;
+ dc->vmsd = &vmstate_cg3;
+ dc->props = cg3_properties;
+}
+
+static const TypeInfo cg3_info = {
+ .name = TYPE_CG3,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CG3State),
+ .class_init = cg3_class_init,
+};
+
+static void cg3_register_types(void)
+{
+ type_register_static(&cg3_info);
+}
+
+type_init(cg3_register_types)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 3a8fc0bf8e..0d3127da21 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
- s->con = graphic_console_init(dev, s->hw_ops, s);
+ s->con = graphic_console_init(dev, 0, s->hw_ops, s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
/* FIXME not qdev yet */
@@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
vga_common_init(&s->vga, OBJECT(dev));
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
- s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga);
+ s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
/* setup PCI */
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 65cca1d707..9750330c25 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
"exynos4210.fimd", FIMD_REGS_SIZE);
sysbus_init_mmio(dev, &s->iomem);
- s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s);
+ s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
return 0;
}
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index bc909bb3de..5c6a2d3605 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
{
s->vram = g_malloc0(s->vram_size);
- s->con = graphic_console_init(dev, &g364fb_ops, s);
+ s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index 8407e6c2ef..f9e7d7c981 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
sysbus_init_mmio(dev, &s->iomem);
- s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
return 0;
}
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
index 5150cb48b7..603537aabb 100644
--- a/hw/display/milkymist-vgafb.c
+++ b/hw/display/milkymist-vgafb.c
@@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
"milkymist-vgafb", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
- s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
return 0;
}
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index c3b9b68971..fda81baff0 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
memory_region_add_subregion(sysmem, base, &s->iomem);
- s->con = graphic_console_init(NULL, &omap_ops, s);
+ s->con = graphic_console_init(NULL, 0, &omap_ops, s);
return s;
}
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index ab689e9aae..c574cf1a81 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd)
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
- s->con = graphic_console_init(dev, &pl110_gfx_ops, s);
+ s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
return 0;
}
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index 990931ae45..09cdf17ab9 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
"pxa2xx-lcd-controller", 0x00100000);
memory_region_add_subregion(sysmem, base, &s->iomem);
- s->con = graphic_console_init(NULL, &pxa2xx_ops, s);
+ s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 2a559ebcc9..47bbf1f1fe 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2069,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev)
portio_list_set_flush_coalesced(qxl_vga_port_list);
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
- vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
+ vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
qemu_spice_display_init_common(&qxl->ssd);
rc = qxl_init_common(qxl);
@@ -2094,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev)
qxl->vga.vram_size);
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
- qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
+ qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
return qxl_init_common(qxl);
}
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 0b5f993594..eedf2d48e0 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
}
/* create qemu graphic console */
- s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
}
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index 89804e108b..c2eea04934 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c)
{
ssd0303_state *s = SSD0303(i2c);
- s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s);
+ s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
return 0;
}
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index c3231c6116..46c3b40c79 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev)
s->col_end = 63;
s->row_end = 79;
- s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 3dd9b98eca..f4011d2db0 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
s->scr_width = 480;
s->scr_height = 640;
- s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s);
+ s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
return s;
}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index e60769c2c9..2b37ffac4c 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev)
&s->vram_mem, vram_offset, size);
sysbus_init_mmio(dev, &s->vram_cplane);
- s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
} else {
/* THC 8 bit (dummy) */
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
TCX_THC_NREGS_8);
sysbus_init_mmio(dev, &s->thc8);
- s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
}
qemu_console_resize(s->con, s->width, s->height);
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index 8b514cc39d..afc46b8c9d 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base,
vga_common_init(&s->vga, NULL);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
- s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s);
+ s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
vga_init_vbe(&s->vga, NULL, address_space);
return 0;
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index c2a19ad6ba..1d9ea6b51d 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
isa_mem_base + 0x000a0000,
vga_io_memory, 1);
memory_region_set_coalescing(vga_io_memory);
- s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
/* ROM BIOS */
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index f74fc43aa6..574ea0e7f9 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
- s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
/* XXX: VGA_RAM_SIZE must be a power of two */
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 334e71856e..bd2c108c42 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
s->scratch_size = SVGA_SCRATCH_SIZE;
s->scratch = g_malloc(s->scratch_size * 4);
- s->vga.con = graphic_console_init(dev, &vmsvga_ops, s);
+ s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
s->fifo_size = SVGA_FIFO_SIZE;
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index cb9d456814..032eb7a9a5 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -992,7 +992,7 @@ wait_more:
/* vfb */
fb = container_of(xfb, struct XenFB, c.xendev);
- fb->c.con = graphic_console_init(NULL, &xenfb_ops, fb);
+ fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
fb->have_console = 1;
/* vkbd */
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b1a7ebb8e3..b667d31de5 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -643,6 +643,21 @@ static inline char acpi_get_hex(uint32_t val)
#define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
#define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
+#define ACPI_PCINOHP_OFFSET_HEX (*ssdt_pcinohp_name - *ssdt_pcinohp_start + 1)
+#define ACPI_PCINOHP_OFFSET_ADR (*ssdt_pcinohp_adr - *ssdt_pcinohp_start)
+#define ACPI_PCINOHP_SIZEOF (*ssdt_pcinohp_end - *ssdt_pcinohp_start)
+#define ACPI_PCINOHP_AML (ssdp_pcihp_aml + *ssdt_pcinohp_start)
+
+#define ACPI_PCIVGA_OFFSET_HEX (*ssdt_pcivga_name - *ssdt_pcivga_start + 1)
+#define ACPI_PCIVGA_OFFSET_ADR (*ssdt_pcivga_adr - *ssdt_pcivga_start)
+#define ACPI_PCIVGA_SIZEOF (*ssdt_pcivga_end - *ssdt_pcivga_start)
+#define ACPI_PCIVGA_AML (ssdp_pcihp_aml + *ssdt_pcivga_start)
+
+#define ACPI_PCIQXL_OFFSET_HEX (*ssdt_pciqxl_name - *ssdt_pciqxl_start + 1)
+#define ACPI_PCIQXL_OFFSET_ADR (*ssdt_pciqxl_adr - *ssdt_pciqxl_start)
+#define ACPI_PCIQXL_SIZEOF (*ssdt_pciqxl_end - *ssdt_pciqxl_start)
+#define ACPI_PCIQXL_AML (ssdp_pcihp_aml + *ssdt_pciqxl_start)
+
#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */
#define ACPI_SSDT_HEADER_LENGTH 36
@@ -677,6 +692,33 @@ static void patch_pcihp(int slot, uint8_t *ssdt_ptr)
ssdt_ptr[ACPI_PCIHP_OFFSET_ADR + 2] = slot;
}
+static void patch_pcinohp(int slot, uint8_t *ssdt_ptr)
+{
+ unsigned devfn = PCI_DEVFN(slot, 0);
+
+ ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
+ ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX + 1] = acpi_get_hex(devfn);
+ ssdt_ptr[ACPI_PCINOHP_OFFSET_ADR + 2] = slot;
+}
+
+static void patch_pcivga(int slot, uint8_t *ssdt_ptr)
+{
+ unsigned devfn = PCI_DEVFN(slot, 0);
+
+ ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
+ ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX + 1] = acpi_get_hex(devfn);
+ ssdt_ptr[ACPI_PCIVGA_OFFSET_ADR + 2] = slot;
+}
+
+static void patch_pciqxl(int slot, uint8_t *ssdt_ptr)
+{
+ unsigned devfn = PCI_DEVFN(slot, 0);
+
+ ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX] = acpi_get_hex(devfn >> 4);
+ ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX + 1] = acpi_get_hex(devfn);
+ ssdt_ptr[ACPI_PCIQXL_OFFSET_ADR + 2] = slot;
+}
+
/* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug.
*/
@@ -737,6 +779,10 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
AcpiBuildPciBusHotplugState *parent = child->parent;
GArray *bus_table = build_alloc_array();
DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_present, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_system, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_vga, PCI_SLOT_MAX);
+ DECLARE_BITMAP(slot_device_qxl, PCI_SLOT_MAX);
uint8_t op;
int i;
QObject *bsel;
@@ -764,40 +810,82 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
build_append_byte(bus_table, 0x08); /* NameOp */
build_append_nameseg(bus_table, "BSEL");
build_append_int(bus_table, qint_get_int(qobject_to_qint(bsel)));
-
memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable);
+ } else {
+ /* No bsel - no slots are hot-pluggable */
+ memset(slot_hotplug_enable, 0x00, sizeof slot_hotplug_enable);
+ }
- for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
- DeviceClass *dc;
- PCIDeviceClass *pc;
- PCIDevice *pdev = bus->devices[i];
+ memset(slot_device_present, 0x00, sizeof slot_device_present);
+ memset(slot_device_system, 0x00, sizeof slot_device_present);
+ memset(slot_device_vga, 0x00, sizeof slot_device_vga);
+ memset(slot_device_qxl, 0x00, sizeof slot_device_qxl);
- if (!pdev) {
- continue;
- }
+ for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) {
+ DeviceClass *dc;
+ PCIDeviceClass *pc;
+ PCIDevice *pdev = bus->devices[i];
+ int slot = PCI_SLOT(i);
- pc = PCI_DEVICE_GET_CLASS(pdev);
- dc = DEVICE_GET_CLASS(pdev);
+ if (!pdev) {
+ continue;
+ }
- if (!dc->hotpluggable || pc->is_bridge) {
- int slot = PCI_SLOT(i);
+ set_bit(slot, slot_device_present);
+ pc = PCI_DEVICE_GET_CLASS(pdev);
+ dc = DEVICE_GET_CLASS(pdev);
- clear_bit(slot, slot_hotplug_enable);
- }
+ if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
+ set_bit(slot, slot_device_system);
}
- /* Append Device object for each slot which supports eject */
- for (i = 0; i < PCI_SLOT_MAX; i++) {
- bool can_eject = test_bit(i, slot_hotplug_enable);
- if (can_eject) {
- void *pcihp = acpi_data_push(bus_table,
- ACPI_PCIHP_SIZEOF);
- memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
- patch_pcihp(i, pcihp);
- bus_hotplug_support = true;
+ if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
+ set_bit(slot, slot_device_vga);
+
+ if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) {
+ set_bit(slot, slot_device_qxl);
}
}
+ if (!dc->hotpluggable || pc->is_bridge) {
+ clear_bit(slot, slot_hotplug_enable);
+ }
+ }
+
+ /* Append Device object for each slot */
+ for (i = 0; i < PCI_SLOT_MAX; i++) {
+ bool can_eject = test_bit(i, slot_hotplug_enable);
+ bool present = test_bit(i, slot_device_present);
+ bool vga = test_bit(i, slot_device_vga);
+ bool qxl = test_bit(i, slot_device_qxl);
+ bool system = test_bit(i, slot_device_system);
+ if (can_eject) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCIHP_SIZEOF);
+ memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
+ patch_pcihp(i, pcihp);
+ bus_hotplug_support = true;
+ } else if (qxl) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCIQXL_SIZEOF);
+ memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF);
+ patch_pciqxl(i, pcihp);
+ } else if (vga) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCIVGA_SIZEOF);
+ memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF);
+ patch_pcivga(i, pcihp);
+ } else if (system) {
+ /* Nothing to do: system devices are in DSDT. */
+ } else if (present) {
+ void *pcihp = acpi_data_push(bus_table,
+ ACPI_PCINOHP_SIZEOF);
+ memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF);
+ patch_pcinohp(i, pcihp);
+ }
+ }
+
+ if (bsel) {
method = build_alloc_method("DVNT", 2);
for (i = 0; i < PCI_SLOT_MAX; i++) {
@@ -976,7 +1064,14 @@ build_ssdt(GArray *table_data, GArray *linker,
{
AcpiBuildPciBusHotplugState hotplug_state;
- PCIBus *bus = find_i440fx(); /* TODO: Q35 support */
+ Object *pci_host;
+ PCIBus *bus = NULL;
+ bool ambiguous;
+
+ pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
+ if (!ambiguous && pci_host) {
+ bus = PCI_HOST_BRIDGE(pci_host)->bus;
+ }
build_pci_bus_state_init(&hotplug_state, NULL);
diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl
index b23d5e0eac..0a1e252d21 100644
--- a/hw/i386/acpi-dsdt.dsl
+++ b/hw/i386/acpi-dsdt.dsl
@@ -80,6 +80,8 @@ DefinitionBlock (
Name(_HID, EisaId("PNP0A03"))
Name(_ADR, 0x00)
Name(_UID, 1)
+//#define PX13 S0B_
+// External(PX13, DeviceObj)
}
}
@@ -88,34 +90,6 @@ DefinitionBlock (
/****************************************************************
- * VGA
- ****************************************************************/
-
- Scope(\_SB.PCI0) {
- Device(VGA) {
- Name(_ADR, 0x00020000)
- OperationRegion(PCIC, PCI_Config, Zero, 0x4)
- Field(PCIC, DWordAcc, NoLock, Preserve) {
- VEND, 32
- }
- Method(_S1D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S2D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S3D, 0, NotSerialized) {
- If (LEqual(VEND, 0x1001b36)) {
- Return (0x03) // QXL
- } Else {
- Return (0x00)
- }
- }
- }
- }
-
-
-/****************************************************************
* PIIX4 PM
****************************************************************/
@@ -132,6 +106,9 @@ DefinitionBlock (
****************************************************************/
Scope(\_SB.PCI0) {
+
+ External(ISA, DeviceObj)
+
Device(ISA) {
Name(_ADR, 0x00010000)
diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated
index 1e58801b2a..94c6e8e114 100644
--- a/hw/i386/acpi-dsdt.hex.generated
+++ b/hw/i386/acpi-dsdt.hex.generated
@@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x44,
0x54,
-0x87,
+0x85,
0x11,
0x0,
0x0,
0x1,
-0xb8,
+0x8b,
0x42,
0x58,
0x50,
@@ -146,7 +146,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x1,
0x10,
0x4e,
-0x15,
+0x18,
0x2e,
0x5f,
0x53,
@@ -163,9 +163,9 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x11,
0x42,
-0x7,
0xa,
-0x6e,
+0xa,
+0x9e,
0x88,
0xd,
0x0,
@@ -217,11 +217,59 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x0,
0xd,
0xff,
+0xad,
+0x0,
+0x0,
+0x0,
+0xa1,
+0x88,
+0xd,
+0x0,
+0x1,
+0xc,
+0x3,
+0x0,
+0x0,
+0xf,
+0xae,
0xff,
+0xae,
+0x0,
0x0,
+0xf1,
0x0,
+0x88,
+0xd,
+0x0,
+0x1,
+0xc,
+0x3,
0x0,
-0xf3,
+0x0,
+0x20,
+0xaf,
+0xdf,
+0xaf,
+0x0,
+0x0,
+0xc0,
+0x0,
+0x88,
+0xd,
+0x0,
+0x1,
+0xc,
+0x3,
+0x0,
+0x0,
+0xe4,
+0xaf,
+0xff,
+0xff,
+0x0,
+0x0,
+0x1c,
+0x50,
0x87,
0x17,
0x0,
@@ -347,7 +395,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x45,
0x53,
0xa,
-0x5c,
+0x8c,
0x50,
0x53,
0x33,
@@ -358,7 +406,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x45,
0x53,
0xa,
-0x60,
+0x90,
0x50,
0x45,
0x33,
@@ -369,7 +417,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x45,
0x53,
0xa,
-0x68,
+0x98,
0x50,
0x4c,
0x33,
@@ -638,103 +686,6 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x79,
0x0,
0x10,
-0x40,
-0x6,
-0x2e,
-0x5f,
-0x53,
-0x42,
-0x5f,
-0x50,
-0x43,
-0x49,
-0x30,
-0x5b,
-0x82,
-0x43,
-0x5,
-0x56,
-0x47,
-0x41,
-0x5f,
-0x8,
-0x5f,
-0x41,
-0x44,
-0x52,
-0xc,
-0x0,
-0x0,
-0x2,
-0x0,
-0x5b,
-0x80,
-0x50,
-0x43,
-0x49,
-0x43,
-0x2,
-0x0,
-0xa,
-0x4,
-0x5b,
-0x81,
-0xb,
-0x50,
-0x43,
-0x49,
-0x43,
-0x3,
-0x56,
-0x45,
-0x4e,
-0x44,
-0x20,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x31,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x32,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x19,
-0x5f,
-0x53,
-0x33,
-0x44,
-0x0,
-0xa0,
-0xe,
-0x93,
-0x56,
-0x45,
-0x4e,
-0x44,
-0xc,
-0x36,
-0x1b,
-0x0,
-0x1,
-0xa4,
-0xa,
-0x3,
-0xa1,
-0x3,
-0xa4,
-0x0,
-0x10,
0x25,
0x2e,
0x5f,
@@ -860,7 +811,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x4e,
0x1,
0x10,
-0x4b,
+0x4a,
0x1e,
0x2f,
0x3,
@@ -878,7 +829,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x5f,
0x5b,
0x82,
-0x2d,
+0x2c,
0x53,
0x4d,
0x43,
@@ -898,9 +849,8 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x54,
0x41,
-0xb,
-0x0,
-0xff,
+0xa,
+0xf0,
0x8,
0x5f,
0x43,
@@ -4061,7 +4011,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x1,
0x10,
0x47,
-0xe,
+0x11,
0x5f,
0x53,
0x42,
@@ -4291,6 +4241,54 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x3,
0x75,
0x60,
+0x5b,
+0x82,
+0x2e,
+0x50,
+0x52,
+0x45,
+0x53,
+0x8,
+0x5f,
+0x48,
+0x49,
+0x44,
+0xd,
+0x41,
+0x43,
+0x50,
+0x49,
+0x30,
+0x30,
+0x30,
+0x34,
+0x0,
+0x8,
+0x5f,
+0x43,
+0x52,
+0x53,
+0x11,
+0xd,
+0xa,
+0xa,
+0x47,
+0x1,
+0x0,
+0xaf,
+0x0,
+0xaf,
+0x0,
+0x20,
+0x79,
+0x0,
+0x8,
+0x5f,
+0x53,
+0x54,
+0x41,
+0xa,
+0xb,
0x10,
0x42,
0xc,
@@ -4488,5 +4486,5 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x0
};
static unsigned short piix_dsdt_applesmc_sta[] = {
-0x384
+0x353
};
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index d5dc1ef336..ae1699d6db 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -221,10 +221,16 @@ static void pc_init1(QEMUMachineInitArgs *args,
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
+ char busname[] = "ide.0";
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
ide_irq[i],
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0");
+ /*
+ * The ide bus name is ide.0 for the first bus and ide.1 for the
+ * second one.
+ */
+ busname[4] = '0' + i;
+ idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
}
}
diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl
index d618e9e2d2..f4d2a2daee 100644
--- a/hw/i386/q35-acpi-dsdt.dsl
+++ b/hw/i386/q35-acpi-dsdt.dsl
@@ -72,6 +72,8 @@ DefinitionBlock (
Name(_ADR, 0x00)
Name(_UID, 1)
+ External(ISA, DeviceObj)
+
// _OSC: based on sample of ACPI3.0b spec
Name(SUPP, 0) // PCI _OSC Support Field value
Name(CTRL, 0) // PCI _OSC Control Field value
@@ -134,34 +136,13 @@ DefinitionBlock (
/****************************************************************
- * VGA
- ****************************************************************/
-
- Scope(\_SB.PCI0) {
- Device(VGA) {
- Name(_ADR, 0x00010000)
- Method(_S1D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S2D, 0, NotSerialized) {
- Return (0x00)
- }
- Method(_S3D, 0, NotSerialized) {
- Return (0x00)
- }
- }
- }
-
-
-/****************************************************************
* LPC ISA bridge
****************************************************************/
Scope(\_SB.PCI0) {
/* PCI D31:f0 LPC ISA bridge */
Device(ISA) {
- /* PCI D31:f0 */
- Name(_ADR, 0x001f0000)
+ Name (_ADR, 0x001F0000) // _ADR: Address
/* ICH9 PCI to ISA irq remapping */
OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C)
diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated
index 6d885a9055..6c29f3b6d2 100644
--- a/hw/i386/q35-acpi-dsdt.hex.generated
+++ b/hw/i386/q35-acpi-dsdt.hex.generated
@@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x53,
0x44,
0x54,
-0xdf,
+0xd7,
0x1c,
0x0,
0x0,
0x1,
-0xff,
+0x3e,
0x42,
0x58,
0x50,
@@ -415,11 +415,11 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x0,
0x0,
0x0,
-0xf7,
+0xd7,
0xc,
0x0,
0x0,
-0xf8,
+0xd8,
0xc,
0x88,
0xd,
@@ -853,61 +853,6 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x79,
0x0,
0x10,
-0x36,
-0x2e,
-0x5f,
-0x53,
-0x42,
-0x5f,
-0x50,
-0x43,
-0x49,
-0x30,
-0x5b,
-0x82,
-0x2a,
-0x56,
-0x47,
-0x41,
-0x5f,
-0x8,
-0x5f,
-0x41,
-0x44,
-0x52,
-0xc,
-0x0,
-0x0,
-0x1,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x31,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x32,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x14,
-0x8,
-0x5f,
-0x53,
-0x33,
-0x44,
-0x0,
-0xa4,
-0x0,
-0x10,
0x4c,
0x7,
0x2e,
@@ -1033,7 +978,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x4e,
0x1,
0x10,
-0x4b,
+0x4a,
0x1e,
0x2f,
0x3,
@@ -1051,7 +996,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x5f,
0x5b,
0x82,
-0x2d,
+0x2c,
0x53,
0x4d,
0x43,
@@ -1071,9 +1016,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x53,
0x54,
0x41,
-0xb,
-0x0,
-0xff,
+0xa,
+0xf0,
0x8,
0x5f,
0x43,
@@ -7016,7 +6960,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x1,
0x10,
0x47,
-0xe,
+0x11,
0x5f,
0x53,
0x42,
@@ -7121,8 +7065,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x54,
0x1,
0xb,
-0x0,
-0xaf,
+0xd8,
+0xc,
0xa,
0x20,
0x5b,
@@ -7246,6 +7190,54 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x3,
0x75,
0x60,
+0x5b,
+0x82,
+0x2e,
+0x50,
+0x52,
+0x45,
+0x53,
+0x8,
+0x5f,
+0x48,
+0x49,
+0x44,
+0xd,
+0x41,
+0x43,
+0x50,
+0x49,
+0x30,
+0x30,
+0x30,
+0x34,
+0x0,
+0x8,
+0x5f,
+0x43,
+0x52,
+0x53,
+0x11,
+0xd,
+0xa,
+0xa,
+0x47,
+0x1,
+0xd8,
+0xc,
+0xd8,
+0xc,
+0x0,
+0x20,
+0x79,
+0x0,
+0x8,
+0x5f,
+0x53,
+0x54,
+0x41,
+0xa,
+0xb,
0x10,
0x4f,
0x8,
@@ -7392,5 +7384,5 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
0x0
};
static unsigned short q35_dsdt_applesmc_sta[] = {
-0x431
+0x3fa
};
diff --git a/hw/i386/ssdt-pcihp.dsl b/hw/i386/ssdt-pcihp.dsl
index cc245c3e7c..ac91c05836 100644
--- a/hw/i386/ssdt-pcihp.dsl
+++ b/hw/i386/ssdt-pcihp.dsl
@@ -46,5 +46,55 @@ DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1)
}
}
+ ACPI_EXTRACT_DEVICE_START ssdt_pcinohp_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pcinohp_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pcinohp_name
+
+ // Extract the offsets of the device name, address dword and the slot
+ // name byte - we fill them in for each device.
+ Device(SBB) {
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcinohp_adr
+ Name(_ADR, 0xAA0000)
+ }
+
+ ACPI_EXTRACT_DEVICE_START ssdt_pcivga_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pcivga_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pcivga_name
+
+ // Extract the offsets of the device name, address dword and the slot
+ // name byte - we fill them in for each device.
+ Device(SCC) {
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcivga_adr
+ Name(_ADR, 0xAA0000)
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ }
+
+ ACPI_EXTRACT_DEVICE_START ssdt_pciqxl_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pciqxl_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pciqxl_name
+
+ // Extract the offsets of the device name, address dword and the slot
+ // name byte - we fill them in for each device.
+ Device(SDD) {
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pciqxl_adr
+ Name(_ADR, 0xAA0000)
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ Return (0x03) // QXL
+ }
+ }
}
}
diff --git a/hw/i386/ssdt-pcihp.hex.generated b/hw/i386/ssdt-pcihp.hex.generated
index 610a631fd1..b599b4663c 100644
--- a/hw/i386/ssdt-pcihp.hex.generated
+++ b/hw/i386/ssdt-pcihp.hex.generated
@@ -1,23 +1,38 @@
static unsigned char ssdt_pcihp_name[] = {
-0x33
+0x34
+};
+static unsigned char ssdt_pcivga_end[] = {
+0x99
+};
+static unsigned char ssdt_pcivga_name[] = {
+0x70
};
static unsigned char ssdt_pcihp_adr[] = {
-0x44
+0x45
+};
+static unsigned char ssdt_pcinohp_end[] = {
+0x6d
};
static unsigned char ssdt_pcihp_end[] = {
-0x5b
+0x5c
+};
+static unsigned char ssdt_pciqxl_start[] = {
+0x99
+};
+static unsigned char ssdt_pcinohp_name[] = {
+0x5f
};
static unsigned char ssdp_pcihp_aml[] = {
0x53,
0x53,
0x44,
0x54,
-0x5b,
+0xc6,
0x0,
0x0,
0x0,
0x1,
-0xe8,
+0x6b,
0x42,
0x58,
0x50,
@@ -45,7 +60,8 @@ static unsigned char ssdp_pcihp_aml[] = {
0x13,
0x20,
0x10,
-0x36,
+0x41,
+0xa,
0x5c,
0x2e,
0x5f,
@@ -98,11 +114,138 @@ static unsigned char ssdp_pcihp_aml[] = {
0x5f,
0x53,
0x55,
-0x4e
+0x4e,
+0x5b,
+0x82,
+0xf,
+0x53,
+0x42,
+0x42,
+0x5f,
+0x8,
+0x5f,
+0x41,
+0x44,
+0x52,
+0xc,
+0x0,
+0x0,
+0xaa,
+0x0,
+0x5b,
+0x82,
+0x2a,
+0x53,
+0x43,
+0x43,
+0x5f,
+0x8,
+0x5f,
+0x41,
+0x44,
+0x52,
+0xc,
+0x0,
+0x0,
+0xaa,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x31,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x32,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x33,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x5b,
+0x82,
+0x2b,
+0x53,
+0x44,
+0x44,
+0x5f,
+0x8,
+0x5f,
+0x41,
+0x44,
+0x52,
+0xc,
+0x0,
+0x0,
+0xaa,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x31,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x8,
+0x5f,
+0x53,
+0x32,
+0x44,
+0x0,
+0xa4,
+0x0,
+0x14,
+0x9,
+0x5f,
+0x53,
+0x33,
+0x44,
+0x0,
+0xa4,
+0xa,
+0x3
+};
+static unsigned char ssdt_pciqxl_adr[] = {
+0xa6
+};
+static unsigned char ssdt_pcinohp_adr[] = {
+0x69
+};
+static unsigned char ssdt_pcivga_adr[] = {
+0x7a
+};
+static unsigned char ssdt_pciqxl_name[] = {
+0x9c
+};
+static unsigned char ssdt_pcivga_start[] = {
+0x6d
+};
+static unsigned char ssdt_pciqxl_end[] = {
+0xc6
};
static unsigned char ssdt_pcihp_start[] = {
-0x30
+0x31
};
static unsigned char ssdt_pcihp_id[] = {
-0x3d
+0x3e
+};
+static unsigned char ssdt_pcinohp_start[] = {
+0x5c
};
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 20e412c240..9a4064f892 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -40,7 +40,7 @@
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
AHCI_RX_FIS_SZ)
-#define AHCI_IRQ_ON_SG (1 << 31)
+#define AHCI_IRQ_ON_SG (1U << 31)
#define AHCI_CMD_ATAPI (1 << 5)
#define AHCI_CMD_WRITE (1 << 6)
#define AHCI_CMD_PREFETCH (1 << 7)
@@ -61,7 +61,7 @@
/* HOST_CTL bits */
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
-#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
+#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
/* HOST_CAP bits */
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
@@ -69,7 +69,7 @@
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
-#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
+#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
@@ -89,7 +89,7 @@
#define PORT_RESERVED 0x3c /* reserved */
/* PORT_IRQ_{STAT,MASK} bits */
-#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
+#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
@@ -151,7 +151,7 @@
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
-#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
+#define PORT_IRQ_STAT_CPDS (1U << 31) /* Code Port Detect Status */
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 655b8c5011..29af3d741f 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -281,7 +281,7 @@ static void kbd_write_command(void *opaque, hwaddr addr,
kbd_update_irq(s);
break;
case KBD_CCMD_READ_INPORT:
- kbd_queue(s, 0x00, 0);
+ kbd_queue(s, 0x80, 0);
break;
case KBD_CCMD_READ_OUTPORT:
kbd_queue(s, s->outport, 0);
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 60eb936e0d..c8a2318d56 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
+obj-$(CONFIG_S390_FLIC) += s390_flic.o
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 652dd47a1c..b527932382 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -93,9 +93,6 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
- if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
- level = !level;
- }
if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
IOAPIC_TRIGGER_LEVEL) {
/* level triggered */
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index c7f7b8406c..87fdb126cf 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -228,7 +228,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
encap.cap = KVM_CAP_IRQ_MPIC;
encap.args[0] = opp->fd;
- encap.args[1] = cs->cpu_index;
+ encap.args[1] = kvm_arch_vcpu_id(cs);
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
}
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
new file mode 100644
index 0000000000..b2ef3e3f8e
--- /dev/null
+++ b/hw/intc/s390_flic.c
@@ -0,0 +1,322 @@
+/*
+ * QEMU S390x KVM floating interrupt controller (flic)
+ *
+ * Copyright 2014 IBM Corp.
+ * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include <sys/ioctl.h>
+#include "qemu/error-report.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "migration/qemu-file.h"
+#include "hw/s390x/s390_flic.h"
+#include "trace.h"
+
+#define FLIC_SAVE_INITIAL_SIZE getpagesize()
+#define FLIC_FAILED (-1UL)
+#define FLIC_SAVEVM_VERSION 1
+
+void s390_flic_init(void)
+{
+ DeviceState *dev;
+ int r;
+
+ if (kvm_enabled()) {
+ dev = qdev_create(NULL, "s390-flic");
+ object_property_add_child(qdev_get_machine(), "s390-flic",
+ OBJECT(dev), NULL);
+ r = qdev_init(dev);
+ if (r) {
+ error_report("flic: couldn't create qdev");
+ }
+ }
+}
+
+/**
+ * flic_get_all_irqs - store all pending irqs in buffer
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -ENOMEM if buffer is too small,
+ * -EINVAL if attr.group is invalid,
+ * -EFAULT if copying to userspace failed,
+ * on success return number of stored interrupts
+ */
+static int flic_get_all_irqs(KVMS390FLICState *flic,
+ void *buf, int len)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_GET_ALL_IRQS,
+ .addr = (uint64_t) buf,
+ .attr = len,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
+
+ return rc == -1 ? -errno : rc;
+}
+
+static void flic_enable_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_ENABLE,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't enable pfault\n");
+ }
+}
+
+static void flic_disable_wait_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't disable pfault\n");
+ }
+}
+
+/** flic_enqueue_irqs - returns 0 on success
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -EINVAL if attr.group is unknown
+ */
+static int flic_enqueue_irqs(void *buf, uint64_t len,
+ KVMS390FLICState *flic)
+{
+ int rc;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_ENQUEUE,
+ .addr = (uint64_t) buf,
+ .attr = len,
+ };
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ return rc ? -errno : 0;
+}
+
+/**
+ * __get_all_irqs - store all pending irqs in buffer
+ * @flic: pointer to flic device state
+ * @buf: pointer to pointer to a buffer
+ * @len: length of buffer
+ *
+ * Returns: return value of flic_get_all_irqs
+ * Note: Retry and increase buffer size until flic_get_all_irqs
+ * either returns a value >= 0 or a negative error code.
+ * -ENOMEM is an exception, which means the buffer is too small
+ * and we should try again. Other negative error codes can be
+ * -EFAULT and -EINVAL which we ignore at this point
+ */
+static int __get_all_irqs(KVMS390FLICState *flic,
+ void **buf, int len)
+{
+ int r;
+
+ do {
+ /* returns -ENOMEM if buffer is too small and number
+ * of queued interrupts on success */
+ r = flic_get_all_irqs(flic, *buf, len);
+ if (r >= 0) {
+ break;
+ }
+ len *= 2;
+ *buf = g_try_realloc(*buf, len);
+ if (!buf) {
+ return -ENOMEM;
+ }
+ } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
+
+ return r;
+}
+
+/**
+ * kvm_flic_save - Save pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ *
+ * Note: Pass buf and len to kernel. Start with one page and
+ * increase until buffer is sufficient or maxium size is
+ * reached
+ */
+static void kvm_flic_save(QEMUFile *f, void *opaque)
+{
+ KVMS390FLICState *flic = opaque;
+ int len = FLIC_SAVE_INITIAL_SIZE;
+ void *buf;
+ int count;
+
+ flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
+
+ buf = g_try_malloc0(len);
+ if (!buf) {
+ /* Storing FLIC_FAILED into the count field here will cause the
+ * target system to fail when attempting to load irqs from the
+ * migration state */
+ error_report("flic: couldn't allocate memory");
+ qemu_put_be64(f, FLIC_FAILED);
+ return;
+ }
+
+ count = __get_all_irqs(flic, &buf, len);
+ if (count < 0) {
+ error_report("flic: couldn't retrieve irqs from kernel, rc %d",
+ count);
+ /* Storing FLIC_FAILED into the count field here will cause the
+ * target system to fail when attempting to load irqs from the
+ * migration state */
+ qemu_put_be64(f, FLIC_FAILED);
+ } else {
+ qemu_put_be64(f, count);
+ qemu_put_buffer(f, (uint8_t *) buf,
+ count * sizeof(struct kvm_s390_irq));
+ }
+ g_free(buf);
+}
+
+/**
+ * kvm_flic_load - Load pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ * @version_id: version id for migration
+ *
+ * Returns: value of flic_enqueue_irqs, -EINVAL on error
+ * Note: Do nothing when no interrupts where stored
+ * in QEMUFile
+ */
+static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
+{
+ uint64_t len = 0;
+ uint64_t count = 0;
+ void *buf = NULL;
+ int r = 0;
+
+ if (version_id != FLIC_SAVEVM_VERSION) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ flic_enable_pfault((struct KVMS390FLICState *) opaque);
+
+ count = qemu_get_be64(f);
+ len = count * sizeof(struct kvm_s390_irq);
+ if (count == FLIC_FAILED) {
+ r = -EINVAL;
+ goto out;
+ }
+ if (count == 0) {
+ r = 0;
+ goto out;
+ }
+ buf = g_try_malloc0(len);
+ if (!buf) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
+ r = -EINVAL;
+ goto out_free;
+ }
+ r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
+
+out_free:
+ g_free(buf);
+out:
+ return r;
+}
+
+static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
+{
+ KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+ struct kvm_create_device cd = {0};
+ int ret;
+
+ flic_state->fd = -1;
+ if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+ trace_flic_no_device_api(errno);
+ return;
+ }
+
+ cd.type = KVM_DEV_TYPE_FLIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ trace_flic_create_device(errno);
+ return;
+ }
+ flic_state->fd = cd.fd;
+
+ /* Register savevm handler for floating interrupts */
+ register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
+ kvm_flic_load, (void *) flic_state);
+}
+
+static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
+{
+ KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+
+ unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
+}
+
+static void kvm_s390_flic_reset(DeviceState *dev)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(dev);
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_CLEAR_IRQS,
+ };
+ int rc = 0;
+
+ if (flic->fd == -1) {
+ return;
+ }
+
+ flic_disable_wait_pfault(flic);
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+ if (rc) {
+ trace_flic_reset_failed(errno);
+ }
+
+ flic_enable_pfault(flic);
+}
+
+static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = kvm_s390_flic_realize;
+ dc->unrealize = kvm_s390_flic_unrealize;
+ dc->reset = kvm_s390_flic_reset;
+}
+
+static const TypeInfo kvm_s390_flic_info = {
+ .name = TYPE_KVM_S390_FLIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMS390FLICState),
+ .class_init = kvm_s390_flic_class_init,
+};
+
+static void kvm_s390_flic_register_types(void)
+{
+ type_register_static(&kvm_s390_flic_info);
+}
+
+type_init(kvm_s390_flic_register_types)
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index b437563fb9..64aabe753d 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -33,6 +33,17 @@
#include "qemu/error-report.h"
#include "qapi/visitor.h"
+static int get_cpu_index_by_dt_id(int cpu_dt_id)
+{
+ PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
+
+ if (cpu) {
+ return cpu->parent_obj.cpu_index;
+ }
+
+ return -1;
+}
+
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
@@ -659,7 +670,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
- target_ulong server = args[0];
+ target_ulong server = get_cpu_index_by_dt_id(args[0]);
target_ulong mfrr = args[1];
if (server >= spapr->icp->nr_servers) {
@@ -728,7 +739,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
nr = rtas_ld(args, 0);
- server = rtas_ld(args, 1);
+ server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
priority = rtas_ld(args, 2);
if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index c203646bd6..a5bbc2406d 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -65,7 +65,7 @@ static void icp_get_kvm_state(ICPState *ss)
ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to retrieve KVM interrupt controller state"
- " for CPU %d: %s", ss->cs->cpu_index, strerror(errno));
+ " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
exit(1);
}
@@ -97,7 +97,7 @@ static int icp_set_kvm_state(ICPState *ss, int version_id)
ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to restore KVM interrupt controller state (0x%"
- PRIx64 ") for CPU %d: %s", state, ss->cs->cpu_index,
+ PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
strerror(errno));
return ret;
}
@@ -325,15 +325,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
struct kvm_enable_cap xics_enable_cap = {
.cap = KVM_CAP_IRQ_XICS,
.flags = 0,
- .args = {icpkvm->kernel_xics_fd, cs->cpu_index, 0, 0},
+ .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
};
ss->cs = cs;
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
if (ret < 0) {
- error_report("Unable to connect CPU%d to kernel XICS: %s",
- cs->cpu_index, strerror(errno));
+ error_report("Unable to connect CPU%ld to kernel XICS: %s",
+ kvm_arch_vcpu_id(cs), strerror(errno));
exit(1);
}
}
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index ef4f3a84d7..a87ca6ddcc 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -55,7 +55,7 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
&entry, &kernel_low, &kernel_high, 1,
ELF_MACHINE, 0);
- if (!kernel_size) {
+ if (kernel_size <= 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loader_params->kernel_filename);
exit(1);
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 75e80c2c48..ea93293122 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
obj-$(CONFIG_VIRTIO) += virtio-net.o
obj-y += vhost_net.o
+
+obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
+ fsl_etsec/rings.o fsl_etsec/miim.o
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
new file mode 100644
index 0000000000..d4b4429446
--- /dev/null
+++ b/hw/net/fsl_etsec/etsec.c
@@ -0,0 +1,465 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+
+/*
+ * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "hw/ptimer.h"
+#include "etsec.h"
+#include "registers.h"
+
+/* #define HEX_DUMP */
+/* #define DEBUG_REGISTER */
+
+#ifdef DEBUG_REGISTER
+static const int debug_etsec = 1;
+#else
+static const int debug_etsec;
+#endif
+
+#define DPRINTF(fmt, ...) do { \
+ if (debug_etsec) { \
+ qemu_log(fmt , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ eTSEC *etsec = opaque;
+ uint32_t reg_index = addr / 4;
+ eTSEC_Register *reg = NULL;
+ uint32_t ret = 0x0;
+
+ assert(reg_index < ETSEC_REG_NUMBER);
+
+ reg = &etsec->regs[reg_index];
+
+
+ switch (reg->access) {
+ case ACC_WO:
+ ret = 0x00000000;
+ break;
+
+ case ACC_RW:
+ case ACC_W1C:
+ case ACC_RO:
+ default:
+ ret = reg->value;
+ break;
+ }
+
+ DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx
+ " : %s (%s)\n",
+ ret, addr, reg->name, reg->desc);
+
+ return ret;
+}
+
+static void write_tstat(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ int i = 0;
+
+ for (i = 0; i < 8; i++) {
+ /* Check THLTi flag in TSTAT */
+ if (value & (1 << (31 - i))) {
+ etsec_walk_tx_ring(etsec, i);
+ }
+ }
+
+ /* Write 1 to clear */
+ reg->value &= ~value;
+}
+
+static void write_rstat(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ int i = 0;
+
+ for (i = 0; i < 8; i++) {
+ /* Check QHLTi flag in RSTAT */
+ if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
+ etsec_walk_rx_ring(etsec, i);
+ }
+ }
+
+ /* Write 1 to clear */
+ reg->value &= ~value;
+}
+
+static void write_tbasex(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value & ~0x7;
+
+ /* Copy this value in the ring's TxBD pointer */
+ etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
+}
+
+static void write_rbasex(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value & ~0x7;
+
+ /* Copy this value in the ring's RxBD pointer */
+ etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
+}
+
+static void write_ievent(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ /* Write 1 to clear */
+ reg->value &= ~value;
+
+ if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
+ qemu_irq_lower(etsec->tx_irq);
+ }
+ if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
+ qemu_irq_lower(etsec->rx_irq);
+ }
+
+ if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
+ IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
+ IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
+ IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
+ IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
+ IEVENT_MMRW))) {
+ qemu_irq_lower(etsec->err_irq);
+ }
+}
+
+static void write_dmactrl(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value;
+
+ if (value & DMACTRL_GRS) {
+
+ if (etsec->rx_buffer_len != 0) {
+ /* Graceful receive stop delayed until end of frame */
+ } else {
+ /* Graceful receive stop now */
+ etsec->regs[IEVENT].value |= IEVENT_GRSC;
+ if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
+ qemu_irq_raise(etsec->err_irq);
+ }
+ }
+ }
+
+ if (value & DMACTRL_GTS) {
+
+ if (etsec->tx_buffer_len != 0) {
+ /* Graceful transmit stop delayed until end of frame */
+ } else {
+ /* Graceful transmit stop now */
+ etsec->regs[IEVENT].value |= IEVENT_GTSC;
+ if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
+ qemu_irq_raise(etsec->err_irq);
+ }
+ }
+ }
+
+ if (!(value & DMACTRL_WOP)) {
+ /* Start polling */
+ ptimer_stop(etsec->ptimer);
+ ptimer_set_count(etsec->ptimer, 1);
+ ptimer_run(etsec->ptimer, 1);
+ }
+}
+
+static void etsec_write(void *opaque,
+ hwaddr addr,
+ uint64_t value,
+ unsigned size)
+{
+ eTSEC *etsec = opaque;
+ uint32_t reg_index = addr / 4;
+ eTSEC_Register *reg = NULL;
+ uint32_t before = 0x0;
+
+ assert(reg_index < ETSEC_REG_NUMBER);
+
+ reg = &etsec->regs[reg_index];
+ before = reg->value;
+
+ switch (reg_index) {
+ case IEVENT:
+ write_ievent(etsec, reg, reg_index, value);
+ break;
+
+ case DMACTRL:
+ write_dmactrl(etsec, reg, reg_index, value);
+ break;
+
+ case TSTAT:
+ write_tstat(etsec, reg, reg_index, value);
+ break;
+
+ case RSTAT:
+ write_rstat(etsec, reg, reg_index, value);
+ break;
+
+ case TBASE0 ... TBASE7:
+ write_tbasex(etsec, reg, reg_index, value);
+ break;
+
+ case RBASE0 ... RBASE7:
+ write_rbasex(etsec, reg, reg_index, value);
+ break;
+
+ case MIIMCFG ... MIIMIND:
+ etsec_write_miim(etsec, reg, reg_index, value);
+ break;
+
+ default:
+ /* Default handling */
+ switch (reg->access) {
+
+ case ACC_RW:
+ case ACC_WO:
+ reg->value = value;
+ break;
+
+ case ACC_W1C:
+ reg->value &= ~value;
+ break;
+
+ case ACC_RO:
+ default:
+ /* Read Only or Unknown register */
+ break;
+ }
+ }
+
+ DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
+ " val:0x%08x->0x%08x : %s (%s)\n",
+ (unsigned int)value, addr, before, reg->value,
+ reg->name, reg->desc);
+}
+
+static const MemoryRegionOps etsec_ops = {
+ .read = etsec_read,
+ .write = etsec_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void etsec_timer_hit(void *opaque)
+{
+ eTSEC *etsec = opaque;
+
+ ptimer_stop(etsec->ptimer);
+
+ if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
+
+ if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
+ etsec_walk_tx_ring(etsec, 0);
+ }
+ ptimer_set_count(etsec->ptimer, 1);
+ ptimer_run(etsec->ptimer, 1);
+ }
+}
+
+static void etsec_reset(DeviceState *d)
+{
+ eTSEC *etsec = ETSEC_COMMON(d);
+ int i = 0;
+ int reg_index = 0;
+
+ /* Default value for all registers */
+ for (i = 0; i < ETSEC_REG_NUMBER; i++) {
+ etsec->regs[i].name = "Reserved";
+ etsec->regs[i].desc = "";
+ etsec->regs[i].access = ACC_UNKNOWN;
+ etsec->regs[i].value = 0x00000000;
+ }
+
+ /* Set-up known registers */
+ for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
+
+ reg_index = eTSEC_registers_def[i].offset / 4;
+
+ etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
+ etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
+ etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
+ etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
+ }
+
+ etsec->tx_buffer = NULL;
+ etsec->tx_buffer_len = 0;
+ etsec->rx_buffer = NULL;
+ etsec->rx_buffer_len = 0;
+
+ etsec->phy_status =
+ MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
+ MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
+ MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
+ MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
+ MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
+}
+
+static void etsec_cleanup(NetClientState *nc)
+{
+ /* qemu_log("eTSEC cleanup\n"); */
+}
+
+static int etsec_can_receive(NetClientState *nc)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+ return etsec->rx_buffer_len == 0;
+}
+
+static ssize_t etsec_receive(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+#if defined(HEX_DUMP)
+ fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
+ qemu_hexdump(buf, stderr, "", size);
+#endif
+ etsec_rx_ring_write(etsec, buf, size);
+ return size;
+}
+
+
+static void etsec_set_link_status(NetClientState *nc)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+ etsec_miim_link_status(etsec, nc);
+}
+
+static NetClientInfo net_etsec_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = etsec_can_receive,
+ .receive = etsec_receive,
+ .cleanup = etsec_cleanup,
+ .link_status_changed = etsec_set_link_status,
+};
+
+static void etsec_realize(DeviceState *dev, Error **errp)
+{
+ eTSEC *etsec = ETSEC_COMMON(dev);
+
+ etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
+ object_get_typename(OBJECT(dev)), dev->id, etsec);
+ qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
+
+
+ etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
+ etsec->ptimer = ptimer_init(etsec->bh);
+ ptimer_set_freq(etsec->ptimer, 100);
+}
+
+static void etsec_instance_init(Object *obj)
+{
+ eTSEC *etsec = ETSEC_COMMON(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
+ "eTSEC", 0x1000);
+ sysbus_init_mmio(sbd, &etsec->io_area);
+
+ sysbus_init_irq(sbd, &etsec->tx_irq);
+ sysbus_init_irq(sbd, &etsec->rx_irq);
+ sysbus_init_irq(sbd, &etsec->err_irq);
+}
+
+static Property etsec_properties[] = {
+ DEFINE_NIC_PROPERTIES(eTSEC, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etsec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = etsec_realize;
+ dc->reset = etsec_reset;
+ dc->props = etsec_properties;
+}
+
+static TypeInfo etsec_info = {
+ .name = "eTSEC",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(eTSEC),
+ .class_init = etsec_class_init,
+ .instance_init = etsec_instance_init,
+};
+
+static void etsec_register_types(void)
+{
+ type_register_static(&etsec_info);
+}
+
+type_init(etsec_register_types)
+
+DeviceState *etsec_create(hwaddr base,
+ MemoryRegion * mr,
+ NICInfo * nd,
+ qemu_irq tx_irq,
+ qemu_irq rx_irq,
+ qemu_irq err_irq)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "eTSEC");
+ qdev_set_nic_properties(dev, nd);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
+
+ memory_region_add_subregion(mr, base,
+ SYS_BUS_DEVICE(dev)->mmio[0].memory);
+
+ return dev;
+}
diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h
new file mode 100644
index 0000000000..78d2c57ed3
--- /dev/null
+++ b/hw/net/fsl_etsec/etsec.h
@@ -0,0 +1,174 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef _ETSEC_H_
+#define _ETSEC_H_
+
+#include "hw/qdev.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/ptimer.h"
+
+/* Buffer Descriptors */
+
+typedef struct eTSEC_rxtx_bd {
+ uint16_t flags;
+ uint16_t length;
+ uint32_t bufptr;
+} eTSEC_rxtx_bd;
+
+#define BD_WRAP (1 << 13)
+#define BD_INTERRUPT (1 << 12)
+#define BD_LAST (1 << 11)
+
+#define BD_TX_READY (1 << 15)
+#define BD_TX_PADCRC (1 << 14)
+#define BD_TX_TC (1 << 10)
+#define BD_TX_PREDEF (1 << 9)
+#define BD_TX_HFELC (1 << 7)
+#define BD_TX_CFRL (1 << 6)
+#define BD_TX_RC_MASK 0xF
+#define BD_TX_RC_OFFSET 0x2
+#define BD_TX_TOEUN (1 << 1)
+#define BD_TX_TR (1 << 0)
+
+#define BD_RX_EMPTY (1 << 15)
+#define BD_RX_RO1 (1 << 14)
+#define BD_RX_FIRST (1 << 10)
+#define BD_RX_MISS (1 << 8)
+#define BD_RX_BROADCAST (1 << 7)
+#define BD_RX_MULTICAST (1 << 6)
+#define BD_RX_LG (1 << 5)
+#define BD_RX_NO (1 << 4)
+#define BD_RX_SH (1 << 3)
+#define BD_RX_CR (1 << 2)
+#define BD_RX_OV (1 << 1)
+#define BD_RX_TR (1 << 0)
+
+/* Tx FCB flags */
+#define FCB_TX_VLN (1 << 7)
+#define FCB_TX_IP (1 << 6)
+#define FCB_TX_IP6 (1 << 5)
+#define FCB_TX_TUP (1 << 4)
+#define FCB_TX_UDP (1 << 3)
+#define FCB_TX_CIP (1 << 2)
+#define FCB_TX_CTU (1 << 1)
+#define FCB_TX_NPH (1 << 0)
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* eTSEC */
+
+/* Number of register in the device */
+#define ETSEC_REG_NUMBER 1024
+
+typedef struct eTSEC_Register {
+ const char *name;
+ const char *desc;
+ uint32_t access;
+ uint32_t value;
+} eTSEC_Register;
+
+typedef struct eTSEC {
+ SysBusDevice busdev;
+
+ MemoryRegion io_area;
+
+ eTSEC_Register regs[ETSEC_REG_NUMBER];
+
+ NICState *nic;
+ NICConf conf;
+
+ /* Tx */
+
+ uint8_t *tx_buffer;
+ uint32_t tx_buffer_len;
+ eTSEC_rxtx_bd first_bd;
+
+ /* Rx */
+
+ uint8_t *rx_buffer;
+ uint32_t rx_buffer_len;
+ uint32_t rx_remaining_data;
+ uint8_t rx_first_in_frame;
+ uint8_t rx_fcb_size;
+ eTSEC_rxtx_bd rx_first_bd;
+ uint8_t rx_fcb[10];
+ uint32_t rx_padding;
+
+ /* IRQs */
+ qemu_irq tx_irq;
+ qemu_irq rx_irq;
+ qemu_irq err_irq;
+
+
+ uint16_t phy_status;
+ uint16_t phy_control;
+
+ /* Polling */
+ QEMUBH *bh;
+ struct ptimer_state *ptimer;
+
+} eTSEC;
+
+#define TYPE_ETSEC_COMMON "eTSEC"
+#define ETSEC_COMMON(obj) \
+ OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
+
+#define eTSEC_TRANSMIT 1
+#define eTSEC_RECEIVE 2
+
+DeviceState *etsec_create(hwaddr base,
+ MemoryRegion *mr,
+ NICInfo *nd,
+ qemu_irq tx_irq,
+ qemu_irq rx_irq,
+ qemu_irq err_irq);
+
+void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
+void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
+void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
+
+void etsec_write_miim(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value);
+
+void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
+
+#endif /* ! _ETSEC_H_ */
diff --git a/hw/net/fsl_etsec/miim.c b/hw/net/fsl_etsec/miim.c
new file mode 100644
index 0000000000..1931b74e6c
--- /dev/null
+++ b/hw/net/fsl_etsec/miim.c
@@ -0,0 +1,146 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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 "etsec.h"
+#include "registers.h"
+
+/* #define DEBUG_MIIM */
+
+#define MIIM_CONTROL 0
+#define MIIM_STATUS 1
+#define MIIM_PHY_ID_1 2
+#define MIIM_PHY_ID_2 3
+#define MIIM_T2_STATUS 10
+#define MIIM_EXT_STATUS 15
+
+static void miim_read_cycle(eTSEC *etsec)
+{
+ uint8_t phy;
+ uint8_t addr;
+ uint16_t value;
+
+ phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
+ (void)phy; /* Unreferenced */
+ addr = etsec->regs[MIIMADD].value & 0x1F;
+
+ switch (addr) {
+ case MIIM_CONTROL:
+ value = etsec->phy_control;
+ break;
+ case MIIM_STATUS:
+ value = etsec->phy_status;
+ break;
+ case MIIM_T2_STATUS:
+ value = 0x1800; /* Local and remote receivers OK */
+ break;
+ default:
+ value = 0x0;
+ break;
+ };
+
+#ifdef DEBUG_MIIM
+ qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
+#endif
+
+ etsec->regs[MIIMSTAT].value = value;
+}
+
+static void miim_write_cycle(eTSEC *etsec)
+{
+ uint8_t phy;
+ uint8_t addr;
+ uint16_t value;
+
+ phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
+ (void)phy; /* Unreferenced */
+ addr = etsec->regs[MIIMADD].value & 0x1F;
+ value = etsec->regs[MIIMCON].value & 0xffff;
+
+#ifdef DEBUG_MIIM
+ qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
+#endif
+
+ switch (addr) {
+ case MIIM_CONTROL:
+ etsec->phy_control = value & ~(0x8100);
+ break;
+ default:
+ break;
+ };
+}
+
+void etsec_write_miim(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+
+ switch (reg_index) {
+
+ case MIIMCOM:
+ /* Read and scan cycle */
+
+ if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
+ /* Read */
+ miim_read_cycle(etsec);
+ }
+ reg->value = value;
+ break;
+
+ case MIIMCON:
+ reg->value = value & 0xffff;
+ miim_write_cycle(etsec);
+ break;
+
+ default:
+ /* Default handling */
+ switch (reg->access) {
+
+ case ACC_RW:
+ case ACC_WO:
+ reg->value = value;
+ break;
+
+ case ACC_W1C:
+ reg->value &= ~value;
+ break;
+
+ case ACC_RO:
+ default:
+ /* Read Only or Unknown register */
+ break;
+ }
+ }
+
+}
+
+void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
+{
+ /* Set link status */
+ if (nc->link_down) {
+ etsec->phy_status &= ~MII_SR_LINK_STATUS;
+ } else {
+ etsec->phy_status |= MII_SR_LINK_STATUS;
+ }
+}
diff --git a/hw/net/fsl_etsec/registers.c b/hw/net/fsl_etsec/registers.c
new file mode 100644
index 0000000000..a7bbfa113f
--- /dev/null
+++ b/hw/net/fsl_etsec/registers.c
@@ -0,0 +1,295 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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 "registers.h"
+
+const eTSEC_Register_Definition eTSEC_registers_def[] = {
+{0x000, "TSEC_ID", "Controller ID register", ACC_RO, 0x01240000},
+{0x004, "TSEC_ID2", "Controller ID register 2", ACC_RO, 0x003000F0},
+{0x010, "IEVENT", "Interrupt event register", ACC_W1C, 0x00000000},
+{0x014, "IMASK", "Interrupt mask register", ACC_RW, 0x00000000},
+{0x018, "EDIS", "Error disabled register", ACC_RW, 0x00000000},
+{0x020, "ECNTRL", "Ethernet control register", ACC_RW, 0x00000040},
+{0x028, "PTV", "Pause time value register", ACC_RW, 0x00000000},
+{0x02C, "DMACTRL", "DMA control register", ACC_RW, 0x00000000},
+{0x030, "TBIPA", "TBI PHY address register", ACC_RW, 0x00000000},
+
+/* eTSEC FIFO Control and Status Registers */
+
+{0x058, "FIFO_RX_ALARM", "FIFO receive alarm start threshold register", ACC_RW, 0x00000040},
+{0x05C, "FIFO_RX_ALARM_SHUTOFF", "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080},
+{0x08C, "FIFO_TX_THR", "FIFO transmit threshold register", ACC_RW, 0x00000080},
+{0x098, "FIFO_TX_STARVE", "FIFO transmit starve register", ACC_RW, 0x00000040},
+{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register", ACC_RW, 0x00000080},
+
+/* eTSEC Transmit Control and Status Registers */
+
+{0x100, "TCTRL", "Transmit control register", ACC_RW, 0x00000000},
+{0x104, "TSTAT", "Transmit status register", ACC_W1C, 0x00000000},
+{0x108, "DFVLAN", "Default VLAN control word", ACC_RW, 0x81000000},
+{0x110, "TXIC", "Transmit interrupt coalescing register", ACC_RW, 0x00000000},
+{0x114, "TQUEUE", "Transmit queue control register", ACC_RW, 0x00008000},
+{0x140, "TR03WT", "TxBD Rings 0-3 round-robin weightings", ACC_RW, 0x00000000},
+{0x144, "TR47WT", "TxBD Rings 4-7 round-robin weightings", ACC_RW, 0x00000000},
+{0x180, "TBDBPH", "Tx data buffer pointer high bits", ACC_RW, 0x00000000},
+{0x184, "TBPTR0", "TxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0x18C, "TBPTR1", "TxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0x194, "TBPTR2", "TxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0x19C, "TBPTR3", "TxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0x1A4, "TBPTR4", "TxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0x1AC, "TBPTR5", "TxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0x1B4, "TBPTR6", "TxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0x1BC, "TBPTR7", "TxBD pointer for ring 7", ACC_RW, 0x00000000},
+{0x200, "TBASEH", "TxBD base address high bits", ACC_RW, 0x00000000},
+{0x204, "TBASE0", "TxBD base address of ring 0", ACC_RW, 0x00000000},
+{0x20C, "TBASE1", "TxBD base address of ring 1", ACC_RW, 0x00000000},
+{0x214, "TBASE2", "TxBD base address of ring 2", ACC_RW, 0x00000000},
+{0x21C, "TBASE3", "TxBD base address of ring 3", ACC_RW, 0x00000000},
+{0x224, "TBASE4", "TxBD base address of ring 4", ACC_RW, 0x00000000},
+{0x22C, "TBASE5", "TxBD base address of ring 5", ACC_RW, 0x00000000},
+{0x234, "TBASE6", "TxBD base address of ring 6", ACC_RW, 0x00000000},
+{0x23C, "TBASE7", "TxBD base address of ring 7", ACC_RW, 0x00000000},
+{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO, 0x00000000},
+{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO, 0x00000000},
+{0x2C0, "TMR_TXTS1_H", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
+{0x2C4, "TMR_TXTS1_L", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
+{0x2C8, "TMR_TXTS2_H", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
+{0x2CC, "TMR_TXTS2_L", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
+
+/* eTSEC Receive Control and Status Registers */
+
+{0x300, "RCTRL", "Receive control register", ACC_RW, 0x00000000},
+{0x304, "RSTAT", "Receive status register", ACC_W1C, 0x00000000},
+{0x310, "RXIC", "Receive interrupt coalescing register", ACC_RW, 0x00000000},
+{0x314, "RQUEUE", "Receive queue control register.", ACC_RW, 0x00800080},
+{0x330, "RBIFX", "Receive bit field extract control register", ACC_RW, 0x00000000},
+{0x334, "RQFAR", "Receive queue filing table address register", ACC_RW, 0x00000000},
+{0x338, "RQFCR", "Receive queue filing table control register", ACC_RW, 0x00000000},
+{0x33C, "RQFPR", "Receive queue filing table property register", ACC_RW, 0x00000000},
+{0x340, "MRBLR", "Maximum receive buffer length register", ACC_RW, 0x00000000},
+{0x380, "RBDBPH", "Rx data buffer pointer high bits", ACC_RW, 0x00000000},
+{0x384, "RBPTR0", "RxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0x38C, "RBPTR1", "RxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0x394, "RBPTR2", "RxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0x39C, "RBPTR3", "RxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0x3A4, "RBPTR4", "RxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0x3AC, "RBPTR5", "RxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0x3B4, "RBPTR6", "RxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0x3BC, "RBPTR7", "RxBD pointer for ring 7", ACC_RW, 0x00000000},
+{0x400, "RBASEH", "RxBD base address high bits", ACC_RW, 0x00000000},
+{0x404, "RBASE0", "RxBD base address of ring 0", ACC_RW, 0x00000000},
+{0x40C, "RBASE1", "RxBD base address of ring 1", ACC_RW, 0x00000000},
+{0x414, "RBASE2", "RxBD base address of ring 2", ACC_RW, 0x00000000},
+{0x41C, "RBASE3", "RxBD base address of ring 3", ACC_RW, 0x00000000},
+{0x424, "RBASE4", "RxBD base address of ring 4", ACC_RW, 0x00000000},
+{0x42C, "RBASE5", "RxBD base address of ring 5", ACC_RW, 0x00000000},
+{0x434, "RBASE6", "RxBD base address of ring 6", ACC_RW, 0x00000000},
+{0x43C, "RBASE7", "RxBD base address of ring 7", ACC_RW, 0x00000000},
+{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high", ACC_RW, 0x00000000},
+{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low", ACC_RW, 0x00000000},
+
+/* eTSEC MAC Registers */
+
+{0x500, "MACCFG1", "MAC configuration register 1", ACC_RW, 0x00000000},
+{0x504, "MACCFG2", "MAC configuration register 2", ACC_RW, 0x00007000},
+{0x508, "IPGIFG", "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060},
+{0x50C, "HAFDUP", "Half-duplex control", ACC_RW, 0x00A1F037},
+{0x510, "MAXFRM", "Maximum frame length", ACC_RW, 0x00000600},
+{0x520, "MIIMCFG", "MII management configuration", ACC_RW, 0x00000007},
+{0x524, "MIIMCOM", "MII management command", ACC_RW, 0x00000000},
+{0x528, "MIIMADD", "MII management address", ACC_RW, 0x00000000},
+{0x52C, "MIIMCON", "MII management control", ACC_WO, 0x00000000},
+{0x530, "MIIMSTAT", "MII management status", ACC_RO, 0x00000000},
+{0x534, "MIIMIND", "MII management indicator", ACC_RO, 0x00000000},
+{0x53C, "IFSTAT", "Interface status", ACC_RO, 0x00000000},
+{0x540, "MACSTNADDR1", "MAC station address register 1", ACC_RW, 0x00000000},
+{0x544, "MACSTNADDR2", "MAC station address register 2", ACC_RW, 0x00000000},
+{0x548, "MAC01ADDR1", "MAC exact match address 1, part 1", ACC_RW, 0x00000000},
+{0x54C, "MAC01ADDR2", "MAC exact match address 1, part 2", ACC_RW, 0x00000000},
+{0x550, "MAC02ADDR1", "MAC exact match address 2, part 1", ACC_RW, 0x00000000},
+{0x554, "MAC02ADDR2", "MAC exact match address 2, part 2", ACC_RW, 0x00000000},
+{0x558, "MAC03ADDR1", "MAC exact match address 3, part 1", ACC_RW, 0x00000000},
+{0x55C, "MAC03ADDR2", "MAC exact match address 3, part 2", ACC_RW, 0x00000000},
+{0x560, "MAC04ADDR1", "MAC exact match address 4, part 1", ACC_RW, 0x00000000},
+{0x564, "MAC04ADDR2", "MAC exact match address 4, part 2", ACC_RW, 0x00000000},
+{0x568, "MAC05ADDR1", "MAC exact match address 5, part 1", ACC_RW, 0x00000000},
+{0x56C, "MAC05ADDR2", "MAC exact match address 5, part 2", ACC_RW, 0x00000000},
+{0x570, "MAC06ADDR1", "MAC exact match address 6, part 1", ACC_RW, 0x00000000},
+{0x574, "MAC06ADDR2", "MAC exact match address 6, part 2", ACC_RW, 0x00000000},
+{0x578, "MAC07ADDR1", "MAC exact match address 7, part 1", ACC_RW, 0x00000000},
+{0x57C, "MAC07ADDR2", "MAC exact match address 7, part 2", ACC_RW, 0x00000000},
+{0x580, "MAC08ADDR1", "MAC exact match address 8, part 1", ACC_RW, 0x00000000},
+{0x584, "MAC08ADDR2", "MAC exact match address 8, part 2", ACC_RW, 0x00000000},
+{0x588, "MAC09ADDR1", "MAC exact match address 9, part 1", ACC_RW, 0x00000000},
+{0x58C, "MAC09ADDR2", "MAC exact match address 9, part 2", ACC_RW, 0x00000000},
+{0x590, "MAC10ADDR1", "MAC exact match address 10, part 1", ACC_RW, 0x00000000},
+{0x594, "MAC10ADDR2", "MAC exact match address 10, part 2", ACC_RW, 0x00000000},
+{0x598, "MAC11ADDR1", "MAC exact match address 11, part 1", ACC_RW, 0x00000000},
+{0x59C, "MAC11ADDR2", "MAC exact match address 11, part 2", ACC_RW, 0x00000000},
+{0x5A0, "MAC12ADDR1", "MAC exact match address 12, part 1", ACC_RW, 0x00000000},
+{0x5A4, "MAC12ADDR2", "MAC exact match address 12, part 2", ACC_RW, 0x00000000},
+{0x5A8, "MAC13ADDR1", "MAC exact match address 13, part 1", ACC_RW, 0x00000000},
+{0x5AC, "MAC13ADDR2", "MAC exact match address 13, part 2", ACC_RW, 0x00000000},
+{0x5B0, "MAC14ADDR1", "MAC exact match address 14, part 1", ACC_RW, 0x00000000},
+{0x5B4, "MAC14ADDR2", "MAC exact match address 14, part 2", ACC_RW, 0x00000000},
+{0x5B8, "MAC15ADDR1", "MAC exact match address 15, part 1", ACC_RW, 0x00000000},
+{0x5BC, "MAC15ADDR2", "MAC exact match address 15, part 2", ACC_RW, 0x00000000},
+
+/* eTSEC, "Transmit", "and", Receive, Counters */
+
+{0x680, "TR64", "Transmit and receive 64-byte frame counter ", ACC_RW, 0x00000000},
+{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter", ACC_RW, 0x00000000},
+{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter", ACC_RW, 0x00000000},
+{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter", ACC_RW, 0x00000000},
+{0x690, "TR1K", "Transmit and receive 512- to 1023-byte frame counter", ACC_RW, 0x00000000},
+{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter", ACC_RW, 0x00000000},
+{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000},
+
+/* eTSEC Receive Counters */
+
+{0x69C, "RBYT", "Receive byte counter", ACC_RW, 0x00000000},
+{0x6A0, "RPKT", "Receive packet counter", ACC_RW, 0x00000000},
+{0x6A4, "RFCS", "Receive FCS error counter", ACC_RW, 0x00000000},
+{0x6A8, "RMCA", "Receive multicast packet counter", ACC_RW, 0x00000000},
+{0x6AC, "RBCA", "Receive broadcast packet counter", ACC_RW, 0x00000000},
+{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
+{0x6B4, "RXPF", "Receive PAUSE frame packet counter", ACC_RW, 0x00000000},
+{0x6B8, "RXUO", "Receive unknown OP code counter ", ACC_RW, 0x00000000},
+{0x6BC, "RALN", "Receive alignment error counter ", ACC_RW, 0x00000000},
+{0x6C0, "RFLR", "Receive frame length error counter ", ACC_RW, 0x00000000},
+{0x6C4, "RCDE", "Receive code error counter ", ACC_RW, 0x00000000},
+{0x6C8, "RCSE", "Receive carrier sense error counter", ACC_RW, 0x00000000},
+{0x6CC, "RUND", "Receive undersize packet counter", ACC_RW, 0x00000000},
+{0x6D0, "ROVR", "Receive oversize packet counter ", ACC_RW, 0x00000000},
+{0x6D4, "RFRG", "Receive fragments counter", ACC_RW, 0x00000000},
+{0x6D8, "RJBR", "Receive jabber counter ", ACC_RW, 0x00000000},
+{0x6DC, "RDRP", "Receive drop counter", ACC_RW, 0x00000000},
+
+/* eTSEC Transmit Counters */
+
+{0x6E0, "TBYT", "Transmit byte counter", ACC_RW, 0x00000000},
+{0x6E4, "TPKT", "Transmit packet counter", ACC_RW, 0x00000000},
+{0x6E8, "TMCA", "Transmit multicast packet counter ", ACC_RW, 0x00000000},
+{0x6EC, "TBCA", "Transmit broadcast packet counter ", ACC_RW, 0x00000000},
+{0x6F0, "TXPF", "Transmit PAUSE control frame counter ", ACC_RW, 0x00000000},
+{0x6F4, "TDFR", "Transmit deferral packet counter ", ACC_RW, 0x00000000},
+{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000},
+{0x6FC, "TSCL", "Transmit single collision packet counter", ACC_RW, 0x00000000},
+{0x700, "TMCL", "Transmit multiple collision packet counter", ACC_RW, 0x00000000},
+{0x704, "TLCL", "Transmit late collision packet counter", ACC_RW, 0x00000000},
+{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000},
+{0x70C, "TNCL", "Transmit total collision counter ", ACC_RW, 0x00000000},
+{0x714, "TDRP", "Transmit drop frame counter", ACC_RW, 0x00000000},
+{0x718, "TJBR", "Transmit jabber frame counter ", ACC_RW, 0x00000000},
+{0x71C, "TFCS", "Transmit FCS error counter", ACC_RW, 0x00000000},
+{0x720, "TXCF", "Transmit control frame counter ", ACC_RW, 0x00000000},
+{0x724, "TOVR", "Transmit oversize frame counter", ACC_RW, 0x00000000},
+{0x728, "TUND", "Transmit undersize frame counter ", ACC_RW, 0x00000000},
+{0x72C, "TFRG", "Transmit fragments frame counter ", ACC_RW, 0x00000000},
+
+/* eTSEC Counter Control and TOE Statistics Registers */
+
+{0x730, "CAR1", "Carry register one register", ACC_W1C, 0x00000000},
+{0x734, "CAR2", "Carry register two register ", ACC_W1C, 0x00000000},
+{0x738, "CAM1", "Carry register one mask register ", ACC_RW, 0xFE03FFFF},
+{0x73C, "CAM2", "Carry register two mask register ", ACC_RW, 0x000FFFFD},
+{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW, 0x00000000},
+
+/* Hash Function Registers */
+
+{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
+{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
+{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
+{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
+{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
+{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
+{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
+{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
+{0x880, "GADDR0", "Group address register 0", ACC_RW, 0x00000000},
+{0x884, "GADDR1", "Group address register 1", ACC_RW, 0x00000000},
+{0x888, "GADDR2", "Group address register 2", ACC_RW, 0x00000000},
+{0x88C, "GADDR3", "Group address register 3", ACC_RW, 0x00000000},
+{0x890, "GADDR4", "Group address register 4", ACC_RW, 0x00000000},
+{0x894, "GADDR5", "Group address register 5", ACC_RW, 0x00000000},
+{0x898, "GADDR6", "Group address register 6", ACC_RW, 0x00000000},
+{0x89C, "GADDR7", "Group address register 7", ACC_RW, 0x00000000},
+
+/* eTSEC DMA Attribute Registers */
+
+{0xBF8, "ATTR", "Attribute register", ACC_RW, 0x00000000},
+{0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000},
+
+
+/* eTSEC Lossless Flow Control Registers */
+
+{0xC00, "RQPRM0", "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000},
+{0xC04, "RQPRM1", "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000},
+{0xC08, "RQPRM2", "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000},
+{0xC0C, "RQPRM3", "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000},
+{0xC10, "RQPRM4", "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000},
+{0xC14, "RQPRM5", "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000},
+{0xC18, "RQPRM6", "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000},
+{0xC1C, "RQPRM7", "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000},
+{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7", ACC_RW, 0x00000000},
+
+/* eTSEC Future Expansion Space */
+
+/* Reserved*/
+
+/* eTSEC IEEE 1588 Registers */
+
+{0xE00, "TMR_CTRL", "Timer control register", ACC_RW, 0x00010001},
+{0xE04, "TMR_TEVENT", "time stamp event register", ACC_W1C, 0x00000000},
+{0xE08, "TMR_TEMASK", "Timer event mask register", ACC_RW, 0x00000000},
+{0xE0C, "TMR_PEVENT", "time stamp event register", ACC_RW, 0x00000000},
+{0xE10, "TMR_PEMASK", "Timer event mask register", ACC_RW, 0x00000000},
+{0xE14, "TMR_STAT", "time stamp status register", ACC_RW, 0x00000000},
+{0xE18, "TMR_CNT_H", "timer counter high register", ACC_RW, 0x00000000},
+{0xE1C, "TMR_CNT_L", "timer counter low register", ACC_RW, 0x00000000},
+{0xE20, "TMR_ADD", "Timer drift compensation addend register", ACC_RW, 0x00000000},
+{0xE24, "TMR_ACC", "Timer accumulator register", ACC_RW, 0x00000000},
+{0xE28, "TMR_PRSC", "Timer prescale", ACC_RW, 0x00000002},
+{0xE30, "TMROFF_H", "Timer offset high", ACC_RW, 0x00000000},
+{0xE34, "TMROFF_L", "Timer offset low", ACC_RW, 0x00000000},
+{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
+{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
+{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
+{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
+{0xE80, "TMR_FIPER1", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xE84, "TMR_FIPER2", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xE88, "TMR_FIPER3", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xEA0, "TMR_ETTS1_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
+{0xEA4, "TMR_ETTS1_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
+{0xEA8, "TMR_ETTS2_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
+{0xEAC, "TMR_ETTS2_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
+
+/* End Of Table */
+{0x0, 0x0, 0x0, 0x0, 0x0}
+};
diff --git a/hw/net/fsl_etsec/registers.h b/hw/net/fsl_etsec/registers.h
new file mode 100644
index 0000000000..7ad7686470
--- /dev/null
+++ b/hw/net/fsl_etsec/registers.h
@@ -0,0 +1,320 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef _ETSEC_REGISTERS_H_
+#define _ETSEC_REGISTERS_H_
+
+#include <stdint.h>
+
+enum eTSEC_Register_Access_Type {
+ ACC_RW = 1, /* Read/Write */
+ ACC_RO = 2, /* Read Only */
+ ACC_WO = 3, /* Write Only */
+ ACC_W1C = 4, /* Write 1 to clear */
+ ACC_UNKNOWN = 5 /* Unknown register*/
+};
+
+typedef struct eTSEC_Register_Definition {
+ uint32_t offset;
+ const char *name;
+ const char *desc;
+ enum eTSEC_Register_Access_Type access;
+ uint32_t reset;
+} eTSEC_Register_Definition;
+
+extern const eTSEC_Register_Definition eTSEC_registers_def[];
+
+#define DMACTRL_LE (1 << 15)
+#define DMACTRL_GRS (1 << 4)
+#define DMACTRL_GTS (1 << 3)
+#define DMACTRL_WOP (1 << 0)
+
+#define IEVENT_PERR (1 << 0)
+#define IEVENT_DPE (1 << 1)
+#define IEVENT_FIQ (1 << 2)
+#define IEVENT_FIR (1 << 3)
+#define IEVENT_FGPI (1 << 4)
+#define IEVENT_RXF (1 << 7)
+#define IEVENT_GRSC (1 << 8)
+#define IEVENT_MMRW (1 << 9)
+#define IEVENT_MMRD (1 << 10)
+#define IEVENT_MAG (1 << 11)
+#define IEVENT_RXB (1 << 15)
+#define IEVENT_XFUN (1 << 16)
+#define IEVENT_CRL (1 << 17)
+#define IEVENT_LC (1 << 18)
+#define IEVENT_TXF (1 << 20)
+#define IEVENT_TXB (1 << 21)
+#define IEVENT_TXE (1 << 22)
+#define IEVENT_TXC (1 << 23)
+#define IEVENT_BABT (1 << 24)
+#define IEVENT_GTSC (1 << 25)
+#define IEVENT_MSRO (1 << 26)
+#define IEVENT_EBERR (1 << 28)
+#define IEVENT_BSY (1 << 29)
+#define IEVENT_RXC (1 << 30)
+#define IEVENT_BABR (1 << 31)
+
+#define IMASK_RXFEN (1 << 7)
+#define IMASK_GRSCEN (1 << 8)
+#define IMASK_RXBEN (1 << 15)
+#define IMASK_TXFEN (1 << 20)
+#define IMASK_TXBEN (1 << 21)
+#define IMASK_GTSCEN (1 << 25)
+
+#define MACCFG1_TX_EN (1 << 0)
+#define MACCFG1_RX_EN (1 << 2)
+
+#define MACCFG2_CRC_EN (1 << 1)
+#define MACCFG2_PADCRC (1 << 2)
+
+#define MIIMCOM_READ (1 << 0)
+#define MIIMCOM_SCAN (1 << 1)
+
+#define RCTRL_PRSDEP_MASK (0x3)
+#define RCTRL_PRSDEP_OFFSET (6)
+#define RCTRL_RSF (1 << 2)
+
+/* Index of each register */
+
+#define TSEC_ID (0x000 / 4)
+#define TSEC_ID2 (0x004 / 4)
+#define IEVENT (0x010 / 4)
+#define IMASK (0x014 / 4)
+#define EDIS (0x018 / 4)
+#define ECNTRL (0x020 / 4)
+#define PTV (0x028 / 4)
+#define DMACTRL (0x02C / 4)
+#define TBIPA (0x030 / 4)
+#define TCTRL (0x100 / 4)
+#define TSTAT (0x104 / 4)
+#define DFVLAN (0x108 / 4)
+#define TXIC (0x110 / 4)
+#define TQUEUE (0x114 / 4)
+#define TR03WT (0x140 / 4)
+#define TR47WT (0x144 / 4)
+#define TBDBPH (0x180 / 4)
+#define TBPTR0 (0x184 / 4)
+#define TBPTR1 (0x18C / 4)
+#define TBPTR2 (0x194 / 4)
+#define TBPTR3 (0x19C / 4)
+#define TBPTR4 (0x1A4 / 4)
+#define TBPTR5 (0x1AC / 4)
+#define TBPTR6 (0x1B4 / 4)
+#define TBPTR7 (0x1BC / 4)
+#define TBASEH (0x200 / 4)
+#define TBASE0 (0x204 / 4)
+#define TBASE1 (0x20C / 4)
+#define TBASE2 (0x214 / 4)
+#define TBASE3 (0x21C / 4)
+#define TBASE4 (0x224 / 4)
+#define TBASE5 (0x22C / 4)
+#define TBASE6 (0x234 / 4)
+#define TBASE7 (0x23C / 4)
+#define TMR_TXTS1_ID (0x280 / 4)
+#define TMR_TXTS2_ID (0x284 / 4)
+#define TMR_TXTS1_H (0x2C0 / 4)
+#define TMR_TXTS1_L (0x2C4 / 4)
+#define TMR_TXTS2_H (0x2C8 / 4)
+#define TMR_TXTS2_L (0x2CC / 4)
+#define RCTRL (0x300 / 4)
+#define RSTAT (0x304 / 4)
+#define RXIC (0x310 / 4)
+#define RQUEUE (0x314 / 4)
+#define RBIFX (0x330 / 4)
+#define RQFAR (0x334 / 4)
+#define RQFCR (0x338 / 4)
+#define RQFPR (0x33C / 4)
+#define MRBLR (0x340 / 4)
+#define RBDBPH (0x380 / 4)
+#define RBPTR0 (0x384 / 4)
+#define RBPTR1 (0x38C / 4)
+#define RBPTR2 (0x394 / 4)
+#define RBPTR3 (0x39C / 4)
+#define RBPTR4 (0x3A4 / 4)
+#define RBPTR5 (0x3AC / 4)
+#define RBPTR6 (0x3B4 / 4)
+#define RBPTR7 (0x3BC / 4)
+#define RBASEH (0x400 / 4)
+#define RBASE0 (0x404 / 4)
+#define RBASE1 (0x40C / 4)
+#define RBASE2 (0x414 / 4)
+#define RBASE3 (0x41C / 4)
+#define RBASE4 (0x424 / 4)
+#define RBASE5 (0x42C / 4)
+#define RBASE6 (0x434 / 4)
+#define RBASE7 (0x43C / 4)
+#define TMR_RXTS_H (0x4C0 / 4)
+#define TMR_RXTS_L (0x4C4 / 4)
+#define MACCFG1 (0x500 / 4)
+#define MACCFG2 (0x504 / 4)
+#define IPGIFG (0x508 / 4)
+#define HAFDUP (0x50C / 4)
+#define MAXFRM (0x510 / 4)
+#define MIIMCFG (0x520 / 4)
+#define MIIMCOM (0x524 / 4)
+#define MIIMADD (0x528 / 4)
+#define MIIMCON (0x52C / 4)
+#define MIIMSTAT (0x530 / 4)
+#define MIIMIND (0x534 / 4)
+#define IFSTAT (0x53C / 4)
+#define MACSTNADDR1 (0x540 / 4)
+#define MACSTNADDR2 (0x544 / 4)
+#define MAC01ADDR1 (0x548 / 4)
+#define MAC01ADDR2 (0x54C / 4)
+#define MAC02ADDR1 (0x550 / 4)
+#define MAC02ADDR2 (0x554 / 4)
+#define MAC03ADDR1 (0x558 / 4)
+#define MAC03ADDR2 (0x55C / 4)
+#define MAC04ADDR1 (0x560 / 4)
+#define MAC04ADDR2 (0x564 / 4)
+#define MAC05ADDR1 (0x568 / 4)
+#define MAC05ADDR2 (0x56C / 4)
+#define MAC06ADDR1 (0x570 / 4)
+#define MAC06ADDR2 (0x574 / 4)
+#define MAC07ADDR1 (0x578 / 4)
+#define MAC07ADDR2 (0x57C / 4)
+#define MAC08ADDR1 (0x580 / 4)
+#define MAC08ADDR2 (0x584 / 4)
+#define MAC09ADDR1 (0x588 / 4)
+#define MAC09ADDR2 (0x58C / 4)
+#define MAC10ADDR1 (0x590 / 4)
+#define MAC10ADDR2 (0x594 / 4)
+#define MAC11ADDR1 (0x598 / 4)
+#define MAC11ADDR2 (0x59C / 4)
+#define MAC12ADDR1 (0x5A0 / 4)
+#define MAC12ADDR2 (0x5A4 / 4)
+#define MAC13ADDR1 (0x5A8 / 4)
+#define MAC13ADDR2 (0x5AC / 4)
+#define MAC14ADDR1 (0x5B0 / 4)
+#define MAC14ADDR2 (0x5B4 / 4)
+#define MAC15ADDR1 (0x5B8 / 4)
+#define MAC15ADDR2 (0x5BC / 4)
+#define TR64 (0x680 / 4)
+#define TR127 (0x684 / 4)
+#define TR255 (0x688 / 4)
+#define TR511 (0x68C / 4)
+#define TR1K (0x690 / 4)
+#define TRMAX (0x694 / 4)
+#define TRMGV (0x698 / 4)
+#define RBYT (0x69C / 4)
+#define RPKT (0x6A0 / 4)
+#define RFCS (0x6A4 / 4)
+#define RMCA (0x6A8 / 4)
+#define RBCA (0x6AC / 4)
+#define RXCF (0x6B0 / 4)
+#define RXPF (0x6B4 / 4)
+#define RXUO (0x6B8 / 4)
+#define RALN (0x6BC / 4)
+#define RFLR (0x6C0 / 4)
+#define RCDE (0x6C4 / 4)
+#define RCSE (0x6C8 / 4)
+#define RUND (0x6CC / 4)
+#define ROVR (0x6D0 / 4)
+#define RFRG (0x6D4 / 4)
+#define RJBR (0x6D8 / 4)
+#define RDRP (0x6DC / 4)
+#define TBYT (0x6E0 / 4)
+#define TPKT (0x6E4 / 4)
+#define TMCA (0x6E8 / 4)
+#define TBCA (0x6EC / 4)
+#define TXPF (0x6F0 / 4)
+#define TDFR (0x6F4 / 4)
+#define TEDF (0x6F8 / 4)
+#define TSCL (0x6FC / 4)
+#define TMCL (0x700 / 4)
+#define TLCL (0x704 / 4)
+#define TXCL (0x708 / 4)
+#define TNCL (0x70C / 4)
+#define TDRP (0x714 / 4)
+#define TJBR (0x718 / 4)
+#define TFCS (0x71C / 4)
+#define TXCF (0x720 / 4)
+#define TOVR (0x724 / 4)
+#define TUND (0x728 / 4)
+#define TFRG (0x72C / 4)
+#define CAR1 (0x730 / 4)
+#define CAR2 (0x734 / 4)
+#define CAM1 (0x738 / 4)
+#define CAM2 (0x73C / 4)
+#define RREJ (0x740 / 4)
+#define IGADDR0 (0x800 / 4)
+#define IGADDR1 (0x804 / 4)
+#define IGADDR2 (0x808 / 4)
+#define IGADDR3 (0x80C / 4)
+#define IGADDR4 (0x810 / 4)
+#define IGADDR5 (0x814 / 4)
+#define IGADDR6 (0x818 / 4)
+#define IGADDR7 (0x81C / 4)
+#define GADDR0 (0x880 / 4)
+#define GADDR1 (0x884 / 4)
+#define GADDR2 (0x888 / 4)
+#define GADDR3 (0x88C / 4)
+#define GADDR4 (0x890 / 4)
+#define GADDR5 (0x894 / 4)
+#define GADDR6 (0x898 / 4)
+#define GADDR7 (0x89C / 4)
+#define ATTR (0xBF8 / 4)
+#define ATTRELI (0xBFC / 4)
+#define RQPRM0 (0xC00 / 4)
+#define RQPRM1 (0xC04 / 4)
+#define RQPRM2 (0xC08 / 4)
+#define RQPRM3 (0xC0C / 4)
+#define RQPRM4 (0xC10 / 4)
+#define RQPRM5 (0xC14 / 4)
+#define RQPRM6 (0xC18 / 4)
+#define RQPRM7 (0xC1C / 4)
+#define RFBPTR0 (0xC44 / 4)
+#define RFBPTR1 (0xC4C / 4)
+#define RFBPTR2 (0xC54 / 4)
+#define RFBPTR3 (0xC5C / 4)
+#define RFBPTR4 (0xC64 / 4)
+#define RFBPTR5 (0xC6C / 4)
+#define RFBPTR6 (0xC74 / 4)
+#define RFBPTR7 (0xC7C / 4)
+#define TMR_CTRL (0xE00 / 4)
+#define TMR_TEVENT (0xE04 / 4)
+#define TMR_TEMASK (0xE08 / 4)
+#define TMR_PEVENT (0xE0C / 4)
+#define TMR_PEMASK (0xE10 / 4)
+#define TMR_STAT (0xE14 / 4)
+#define TMR_CNT_H (0xE18 / 4)
+#define TMR_CNT_L (0xE1C / 4)
+#define TMR_ADD (0xE20 / 4)
+#define TMR_ACC (0xE24 / 4)
+#define TMR_PRSC (0xE28 / 4)
+#define TMROFF_H (0xE30 / 4)
+#define TMROFF_L (0xE34 / 4)
+#define TMR_ALARM1_H (0xE40 / 4)
+#define TMR_ALARM1_L (0xE44 / 4)
+#define TMR_ALARM2_H (0xE48 / 4)
+#define TMR_ALARM2_L (0xE4C / 4)
+#define TMR_FIPER1 (0xE80 / 4)
+#define TMR_FIPER2 (0xE84 / 4)
+#define TMR_FIPER3 (0xE88 / 4)
+#define TMR_ETTS1_H (0xEA0 / 4)
+#define TMR_ETTS1_L (0xEA4 / 4)
+#define TMR_ETTS2_H (0xEA8 / 4)
+#define TMR_ETTS2_L (0xEAC / 4)
+
+#endif /* ! _ETSEC_REGISTERS_H_ */
diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c
new file mode 100644
index 0000000000..77602722b3
--- /dev/null
+++ b/hw/net/fsl_etsec/rings.c
@@ -0,0 +1,650 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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 "net/checksum.h"
+
+#include "etsec.h"
+#include "registers.h"
+
+/* #define ETSEC_RING_DEBUG */
+/* #define HEX_DUMP */
+/* #define DEBUG_BD */
+
+#ifdef ETSEC_RING_DEBUG
+static const int debug_etsec = 1;
+#else
+static const int debug_etsec;
+#endif
+
+#define RING_DEBUG(fmt, ...) do { \
+ if (debug_etsec) { \
+ qemu_log(fmt , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#ifdef DEBUG_BD
+
+static void print_tx_bd_flags(uint16_t flags)
+{
+ qemu_log(" Ready: %d\n", !!(flags & BD_TX_READY));
+ qemu_log(" PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
+ qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
+ qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
+ qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
+ qemu_log(" Tx CRC: %d\n", !!(flags & BD_TX_TC));
+ qemu_log(" User-defined preamble / defer: %d\n",
+ !!(flags & BD_TX_PREDEF));
+ qemu_log(" Huge frame enable / Late collision: %d\n",
+ !!(flags & BD_TX_HFELC));
+ qemu_log(" Control frame / Retransmission Limit: %d\n",
+ !!(flags & BD_TX_CFRL));
+ qemu_log(" Retry count: %d\n",
+ (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
+ qemu_log(" Underrun / TCP/IP off-load enable: %d\n",
+ !!(flags & BD_TX_TOEUN));
+ qemu_log(" Truncation: %d\n", !!(flags & BD_TX_TR));
+}
+
+static void print_rx_bd_flags(uint16_t flags)
+{
+ qemu_log(" Empty: %d\n", !!(flags & BD_RX_EMPTY));
+ qemu_log(" Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
+ qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
+ qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
+ qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
+ qemu_log(" First in frame: %d\n", !!(flags & BD_RX_FIRST));
+ qemu_log(" Miss: %d\n", !!(flags & BD_RX_MISS));
+ qemu_log(" Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
+ qemu_log(" Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
+ qemu_log(" Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
+ qemu_log(" Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
+ qemu_log(" Short frame: %d\n", !!(flags & BD_RX_SH));
+ qemu_log(" Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
+ qemu_log(" Overrun: %d\n", !!(flags & BD_RX_OV));
+ qemu_log(" Truncation: %d\n", !!(flags & BD_RX_TR));
+}
+
+
+static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
+{
+ qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n",
+ mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
+ index);
+ qemu_log(" Flags : 0x%04x\n", bd.flags);
+ if (mode == eTSEC_TRANSMIT) {
+ print_tx_bd_flags(bd.flags);
+ } else {
+ print_rx_bd_flags(bd.flags);
+ }
+ qemu_log(" Length : 0x%04x\n", bd.length);
+ qemu_log(" Pointer : 0x%08x\n", bd.bufptr);
+}
+
+#endif /* DEBUG_BD */
+
+static void read_buffer_descriptor(eTSEC *etsec,
+ hwaddr addr,
+ eTSEC_rxtx_bd *bd)
+{
+ assert(bd != NULL);
+
+ RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
+ cpu_physical_memory_read(addr,
+ bd,
+ sizeof(eTSEC_rxtx_bd));
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
+ bd->flags = lduw_le_p(&bd->flags);
+ bd->length = lduw_le_p(&bd->length);
+ bd->bufptr = ldl_le_p(&bd->bufptr);
+ } else {
+ bd->flags = lduw_be_p(&bd->flags);
+ bd->length = lduw_be_p(&bd->length);
+ bd->bufptr = ldl_be_p(&bd->bufptr);
+ }
+}
+
+static void write_buffer_descriptor(eTSEC *etsec,
+ hwaddr addr,
+ eTSEC_rxtx_bd *bd)
+{
+ assert(bd != NULL);
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
+ stw_le_p(&bd->flags, bd->flags);
+ stw_le_p(&bd->length, bd->length);
+ stl_le_p(&bd->bufptr, bd->bufptr);
+ } else {
+ stw_be_p(&bd->flags, bd->flags);
+ stw_be_p(&bd->length, bd->length);
+ stl_be_p(&bd->bufptr, bd->bufptr);
+ }
+
+ RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
+ cpu_physical_memory_write(addr,
+ bd,
+ sizeof(eTSEC_rxtx_bd));
+}
+
+static void ievent_set(eTSEC *etsec,
+ uint32_t flags)
+{
+ etsec->regs[IEVENT].value |= flags;
+
+ if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN)
+ || (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) {
+ qemu_irq_raise(etsec->tx_irq);
+ RING_DEBUG("%s Raise Tx IRQ\n", __func__);
+ }
+
+ if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
+ || (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
+ qemu_irq_pulse(etsec->rx_irq);
+ RING_DEBUG("%s Raise Rx IRQ\n", __func__);
+ }
+}
+
+static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len)
+{
+ int add = min_frame_len - etsec->tx_buffer_len;
+
+ /* Padding */
+ if (add > 0) {
+ RING_DEBUG("pad:%u\n", add);
+ etsec->tx_buffer = g_realloc(etsec->tx_buffer,
+ etsec->tx_buffer_len + add);
+
+ memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add);
+ etsec->tx_buffer_len += add;
+ }
+
+ /* Never add CRC in QEMU */
+}
+
+static void process_tx_fcb(eTSEC *etsec)
+{
+ uint8_t flags = (uint8_t)(*etsec->tx_buffer);
+ /* L3 header offset from start of frame */
+ uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3);
+ /* L4 header offset from start of L3 header */
+ uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2);
+ /* L3 header */
+ uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset;
+ /* L4 header */
+ uint8_t *l4_header = l3_header + l4_header_offset;
+
+ /* if packet is IP4 and IP checksum is requested */
+ if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
+ /* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not sure
+ * if it also does IP4 checksum. */
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ }
+ /* TODO Check the correct usage of the PHCS field of the FCB in case the NPH
+ * flag is on */
+
+ /* if packet is IP4 and TCP or UDP */
+ if (flags & FCB_TX_IP && flags & FCB_TX_TUP) {
+ /* if UDP */
+ if (flags & FCB_TX_UDP) {
+ /* if checksum is requested */
+ if (flags & FCB_TX_CTU) {
+ /* do UDP checksum */
+
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ } else {
+ /* set checksum field to 0 */
+ l4_header[6] = 0;
+ l4_header[7] = 0;
+ }
+ } else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested */
+ /* do TCP checksum */
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ }
+ }
+}
+
+static void process_tx_bd(eTSEC *etsec,
+ eTSEC_rxtx_bd *bd)
+{
+ uint8_t *tmp_buff = NULL;
+ hwaddr tbdbth = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32;
+
+ if (bd->length == 0) {
+ /* ERROR */
+ return;
+ }
+
+ if (etsec->tx_buffer_len == 0) {
+ /* It's the first BD */
+ etsec->first_bd = *bd;
+ }
+
+ /* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/
+
+ /* Load this Data Buffer */
+ etsec->tx_buffer = g_realloc(etsec->tx_buffer,
+ etsec->tx_buffer_len + bd->length);
+ tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len;
+ cpu_physical_memory_read(bd->bufptr + tbdbth, tmp_buff, bd->length);
+
+ /* Update buffer length */
+ etsec->tx_buffer_len += bd->length;
+
+
+ if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) {
+ if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) {
+ /* MAC Transmit enabled */
+
+ /* Process offload Tx FCB */
+ if (etsec->first_bd.flags & BD_TX_TOEUN) {
+ process_tx_fcb(etsec);
+ }
+
+ if (etsec->first_bd.flags & BD_TX_PADCRC
+ || etsec->regs[MACCFG2].value & MACCFG2_PADCRC) {
+
+ /* Padding and CRC (Padding implies CRC) */
+ tx_padding_and_crc(etsec, 64);
+
+ } else if (etsec->first_bd.flags & BD_TX_TC
+ || etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) {
+
+ /* Only CRC */
+ /* Never add CRC in QEMU */
+ }
+
+#if defined(HEX_DUMP)
+ qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len);
+ qemu_hexdump(etsec->tx_buffer, stderr, "", etsec->tx_buffer_len);
+#endif /* ETSEC_RING_DEBUG */
+
+ if (etsec->first_bd.flags & BD_TX_TOEUN) {
+ qemu_send_packet(qemu_get_queue(etsec->nic),
+ etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ } else {
+ qemu_send_packet(qemu_get_queue(etsec->nic),
+ etsec->tx_buffer,
+ etsec->tx_buffer_len);
+ }
+
+ }
+
+ etsec->tx_buffer_len = 0;
+
+ if (bd->flags & BD_INTERRUPT) {
+ ievent_set(etsec, IEVENT_TXF);
+ }
+ } else {
+ if (bd->flags & BD_INTERRUPT) {
+ ievent_set(etsec, IEVENT_TXB);
+ }
+ }
+
+ /* Update DB flags */
+
+ /* Clear Ready */
+ bd->flags &= ~BD_TX_READY;
+
+ /* Clear Defer */
+ bd->flags &= ~BD_TX_PREDEF;
+
+ /* Clear Late Collision */
+ bd->flags &= ~BD_TX_HFELC;
+
+ /* Clear Retransmission Limit */
+ bd->flags &= ~BD_TX_CFRL;
+
+ /* Clear Retry Count */
+ bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET);
+
+ /* Clear Underrun */
+ bd->flags &= ~BD_TX_TOEUN;
+
+ /* Clear Truncation */
+ bd->flags &= ~BD_TX_TR;
+}
+
+void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr)
+{
+ hwaddr ring_base = 0;
+ hwaddr bd_addr = 0;
+ eTSEC_rxtx_bd bd;
+ uint16_t bd_flags;
+
+ if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) {
+ RING_DEBUG("%s: MAC Transmit not enabled\n", __func__);
+ return;
+ }
+
+ ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32;
+ ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7;
+ bd_addr = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7;
+
+ do {
+ read_buffer_descriptor(etsec, bd_addr, &bd);
+
+#ifdef DEBUG_BD
+ print_bd(bd,
+ eTSEC_TRANSMIT,
+ (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
+
+#endif /* DEBUG_BD */
+
+ /* Save flags before BD update */
+ bd_flags = bd.flags;
+
+ if (bd_flags & BD_TX_READY) {
+ process_tx_bd(etsec, &bd);
+
+ /* Write back BD after update */
+ write_buffer_descriptor(etsec, bd_addr, &bd);
+ }
+
+ /* Wrap or next BD */
+ if (bd_flags & BD_WRAP) {
+ bd_addr = ring_base;
+ } else {
+ bd_addr += sizeof(eTSEC_rxtx_bd);
+ }
+
+ } while (bd_addr != ring_base);
+
+ bd_addr = ring_base;
+
+ /* Save the Buffer Descriptor Pointers to current bd */
+ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
+
+ /* Set transmit halt THLTx */
+ etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr);
+}
+
+static void fill_rx_bd(eTSEC *etsec,
+ eTSEC_rxtx_bd *bd,
+ const uint8_t **buf,
+ size_t *size)
+{
+ uint16_t to_write;
+ hwaddr bufptr = bd->bufptr +
+ ((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32);
+ uint8_t padd[etsec->rx_padding];
+ uint8_t rem;
+
+ RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx
+ " size:%zu(padding + crc:%u) + fcb:%u\n",
+ bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
+
+ bd->length = 0;
+
+ /* This operation will only write FCB */
+ if (etsec->rx_fcb_size != 0) {
+
+ cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
+
+ bufptr += etsec->rx_fcb_size;
+ bd->length += etsec->rx_fcb_size;
+ etsec->rx_fcb_size = 0;
+
+ }
+
+ /* We remove padding from the computation of to_write because it is not
+ * allocated in the buffer.
+ */
+ to_write = MIN(*size - etsec->rx_padding,
+ etsec->regs[MRBLR].value - etsec->rx_fcb_size);
+
+ /* This operation can only write packet data and no padding */
+ if (to_write > 0) {
+ cpu_physical_memory_write(bufptr, *buf, to_write);
+
+ *buf += to_write;
+ bufptr += to_write;
+ *size -= to_write;
+
+ bd->flags &= ~BD_RX_EMPTY;
+ bd->length += to_write;
+ }
+
+ if (*size == etsec->rx_padding) {
+ /* The remaining bytes are only for padding which is not actually
+ * allocated in the data buffer.
+ */
+
+ rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
+
+ if (rem > 0) {
+ memset(padd, 0x0, sizeof(padd));
+ etsec->rx_padding -= rem;
+ *size -= rem;
+ bd->length += rem;
+ cpu_physical_memory_write(bufptr, padd, rem);
+ }
+ }
+}
+
+static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
+{
+ uint32_t fcb_size = 0;
+ uint8_t prsdep = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
+ & RCTRL_PRSDEP_MASK;
+
+ if (prsdep != 0) {
+ /* Prepend FCB (FCB size + RCTRL[PAL]) */
+ fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F);
+
+ etsec->rx_fcb_size = fcb_size;
+
+ /* TODO: fill_FCB(etsec); */
+ memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb));
+
+ } else {
+ etsec->rx_fcb_size = 0;
+ }
+
+ if (etsec->rx_buffer != NULL) {
+ g_free(etsec->rx_buffer);
+ }
+
+ /* Do not copy the frame for now */
+ etsec->rx_buffer = (uint8_t *)buf;
+ etsec->rx_buffer_len = size;
+
+ /* CRC padding (We don't have to compute the CRC) */
+ etsec->rx_padding = 4;
+
+ etsec->rx_first_in_frame = 1;
+ etsec->rx_remaining_data = etsec->rx_buffer_len;
+ RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__,
+ etsec->rx_buffer_len, etsec->rx_padding);
+}
+
+void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
+{
+ int ring_nbr = 0; /* Always use ring0 (no filer) */
+
+ if (etsec->rx_buffer_len != 0) {
+ RING_DEBUG("%s: We can't receive now,"
+ " a buffer is already in the pipe\n", __func__);
+ return;
+ }
+
+ if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
+ RING_DEBUG("%s: The ring is halted\n", __func__);
+ return;
+ }
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
+ RING_DEBUG("%s: Graceful receive stop\n", __func__);
+ return;
+ }
+
+ if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
+ RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
+ return;
+ }
+
+ if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
+ /* CRC is not in the packet yet, so short frame is below 60 bytes */
+ RING_DEBUG("%s: Drop short frame\n", __func__);
+ return;
+ }
+
+ rx_init_frame(etsec, buf, size);
+
+ etsec_walk_rx_ring(etsec, ring_nbr);
+}
+
+void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
+{
+ hwaddr ring_base = 0;
+ hwaddr bd_addr = 0;
+ hwaddr start_bd_addr = 0;
+ eTSEC_rxtx_bd bd;
+ uint16_t bd_flags;
+ size_t remaining_data;
+ const uint8_t *buf;
+ uint8_t *tmp_buf;
+ size_t size;
+
+ if (etsec->rx_buffer_len == 0) {
+ /* No frame to send */
+ RING_DEBUG("No frame to send\n");
+ return;
+ }
+
+ remaining_data = etsec->rx_remaining_data + etsec->rx_padding;
+ buf = etsec->rx_buffer
+ + (etsec->rx_buffer_len - etsec->rx_remaining_data);
+ size = etsec->rx_buffer_len + etsec->rx_padding;
+
+ ring_base = (hwaddr)(etsec->regs[RBASEH].value & 0xF) << 32;
+ ring_base += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
+ start_bd_addr = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;
+
+ do {
+ read_buffer_descriptor(etsec, bd_addr, &bd);
+
+#ifdef DEBUG_BD
+ print_bd(bd,
+ eTSEC_RECEIVE,
+ (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
+
+#endif /* DEBUG_BD */
+
+ /* Save flags before BD update */
+ bd_flags = bd.flags;
+
+ if (bd_flags & BD_RX_EMPTY) {
+ fill_rx_bd(etsec, &bd, &buf, &remaining_data);
+
+ if (etsec->rx_first_in_frame) {
+ bd.flags |= BD_RX_FIRST;
+ etsec->rx_first_in_frame = 0;
+ etsec->rx_first_bd = bd;
+ }
+
+ /* Last in frame */
+ if (remaining_data == 0) {
+
+ /* Clear flags */
+
+ bd.flags &= ~0x7ff;
+
+ bd.flags |= BD_LAST;
+
+ /* NOTE: non-octet aligned frame is impossible in qemu */
+
+ if (size >= etsec->regs[MAXFRM].value) {
+ /* frame length violation */
+ qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n",
+ __func__, size, etsec->regs[MAXFRM].value);
+
+ bd.flags |= BD_RX_LG;
+ }
+
+ if (size < 64) {
+ /* Short frame */
+ bd.flags |= BD_RX_SH;
+ }
+
+ /* TODO: Broadcast and Multicast */
+
+ if (bd.flags | BD_INTERRUPT) {
+ /* Set RXFx */
+ etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
+
+ /* Set IEVENT */
+ ievent_set(etsec, IEVENT_RXF);
+ }
+
+ } else {
+ if (bd.flags | BD_INTERRUPT) {
+ /* Set IEVENT */
+ ievent_set(etsec, IEVENT_RXB);
+ }
+ }
+
+ /* Write back BD after update */
+ write_buffer_descriptor(etsec, bd_addr, &bd);
+ }
+
+ /* Wrap or next BD */
+ if (bd_flags & BD_WRAP) {
+ bd_addr = ring_base;
+ } else {
+ bd_addr += sizeof(eTSEC_rxtx_bd);
+ }
+ } while (remaining_data != 0
+ && (bd_flags & BD_RX_EMPTY)
+ && bd_addr != start_bd_addr);
+
+ /* Reset ring ptr */
+ etsec->regs[RBPTR0 + ring_nbr].value = bd_addr;
+
+ /* The frame is too large to fit in the Rx ring */
+ if (remaining_data > 0) {
+
+ /* Set RSTAT[QHLTx] */
+ etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr);
+
+ /* Save remaining data to send the end of the frame when the ring will
+ * be restarted
+ */
+ etsec->rx_remaining_data = remaining_data;
+
+ /* Copy the frame */
+ tmp_buf = g_malloc(size);
+ memcpy(tmp_buf, etsec->rx_buffer, size);
+ etsec->rx_buffer = tmp_buf;
+
+ RING_DEBUG("no empty RxBD available any more\n");
+ } else {
+ etsec->rx_buffer_len = 0;
+ etsec->rx_buffer = NULL;
+ }
+
+ RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
+}
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 1bd6f50aaa..f6fbcb56bf 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -405,6 +405,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
dev->rx_bufs++;
+ qemu_flush_queued_packets(qemu_get_queue(dev->nic));
+
DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
" bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
(unsigned long long)buf);
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 3c0342e17a..fd23c4627e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -397,12 +397,15 @@ static int peer_detach(VirtIONet *n, int index)
static void virtio_net_set_queues(VirtIONet *n)
{
int i;
+ int r;
for (i = 0; i < n->max_queues; i++) {
if (i < n->curr_queues) {
- assert(!peer_attach(n, i));
+ r = peer_attach(n, i);
+ assert(!r);
} else {
- assert(!peer_detach(n, i));
+ r = peer_detach(n, i);
+ assert(!r);
}
}
}
diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
index ec6be4676c..e1e95aabcd 100644
--- a/hw/pci-host/pam.c
+++ b/hw/pci-host/pam.c
@@ -68,7 +68,7 @@ void init_pam(DeviceState *dev, MemoryRegion *ram_memory,
/* XXX: should distinguish read/write cases */
memory_region_init_alias(&mem->alias[0], OBJECT(dev), "pam-pci", pci_address_space,
start, size);
- memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", pci_address_space,
+ memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", ram_memory,
start, size);
for (i = 0; i < 4; ++i) {
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 8ecd11eca2..02cde6f96c 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -221,29 +221,23 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
DeviceState *dev,
uint8_t **exp_cap, Error **errp)
{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
- PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
+ PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: %d\n", state);
if (sltsta & PCI_EXP_SLTSTA_EIS) {
/* the slot is electromechanically locked.
* This error is propagated up to qdev and then to HMP/QMP.
*/
error_setg_errno(errp, -EBUSY, "slot is electromechanically locked");
}
-
- /* TODO: multifunction hot-plug.
- * Right now, only a device of function = 0 is allowed to be
- * hot plugged/unplugged.
- */
- assert(PCI_FUNC(pci_dev->devfn) == 0);
}
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
uint8_t *exp_cap;
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
@@ -256,6 +250,12 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
+ /* TODO: multifunction hot-plug.
+ * Right now, only a device of function = 0 is allowed to be
+ * hot plugged/unplugged.
+ */
+ assert(PCI_FUNC(pci_dev->devfn) == 0);
+
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b37ce9d633..8a08752613 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -238,6 +238,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
the first node as boot node and be happy */
for (i = smp_cpus - 1; i >= 0; i--) {
CPUState *cpu;
+ PowerPCCPU *pcpu;
char cpu_name[128];
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
@@ -246,14 +247,16 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
continue;
}
env = cpu->env_ptr;
+ pcpu = POWERPC_CPU(cpu);
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
- cpu->cpu_index);
+ ppc_get_vcpu_dt_id(pcpu));
qemu_fdt_add_subnode(fdt, cpu_name);
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
- qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
+ ppc_get_vcpu_dt_id(pcpu));
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
env->dcache_line_size);
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 114be64480..0e82719b69 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -26,6 +26,7 @@
#include "hw/ppc/ppc_e500.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
#include "hw/timer/m48t59.h"
#include "qemu/log.h"
#include "hw/loader.h"
@@ -1362,3 +1363,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
return 0;
}
+
+/* CPU device-tree ID helpers */
+int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
+{
+ return cpu->cpu_dt_id;
+}
+
+PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ if (cpu->cpu_dt_id == cpu_dt_id) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 93d02c1e50..bf46c380ec 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -49,6 +49,7 @@
#include "exec/address-spaces.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
+#include "qemu/error-report.h"
#include <libfdt.h>
@@ -206,19 +207,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
CPU_FOREACH(cpu) {
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
+ int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(cpu->numa_node),
- cpu_to_be32(cpu->cpu_index)};
+ cpu_to_be32(index)};
- if ((cpu->cpu_index % smt) != 0) {
+ if ((index % smt) != 0) {
continue;
}
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
- cpu->cpu_index);
+ index);
offset = fdt_path_offset(fdt, cpu_model);
if (offset < 0) {
@@ -367,7 +369,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
CPUPPCState *env = &cpu->env;
DeviceClass *dc = DEVICE_GET_CLASS(cs);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = cs->cpu_index;
+ int index = ppc_get_vcpu_dt_id(cpu);
uint32_t servers_prop[smp_threads];
uint32_t gservers_prop[smp_threads * 2];
char *nodename;
@@ -685,6 +687,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
if (shift > 0) {
/* Kernel handles htab, we don't need to allocate one */
spapr->htab_shift = shift;
+ kvmppc_kern_htab = true;
} else {
if (!spapr->htab) {
/* Allocate an htab if we don't yet have one */
@@ -740,8 +743,21 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
env->external_htab = (uint8_t *)spapr->htab;
+ if (kvm_enabled() && !env->external_htab) {
+ /*
+ * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
+ * functions do the right thing.
+ */
+ env->external_htab = (void *)1;
+ }
env->htab_base = -1;
- env->htab_mask = HTAB_SIZE(spapr) - 1;
+ /*
+ * htab_mask is the mask used to normalize hash value to PTEG index.
+ * htab_shift is log2 of hash table size.
+ * We have 8 hpte per group, and each hpte is 16 bytes.
+ * ie have 128 bytes per hpte entry.
+ */
+ env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
(spapr->htab_shift - 18);
}
@@ -1305,20 +1321,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
- if (kernel_size < 0) {
+ if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
kernel_size = load_elf(kernel_filename,
translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
kernel_le = kernel_size > 0;
}
if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- load_limit - KERNEL_LOAD_ADDR);
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ fprintf(stderr, "qemu: error loading %s: %s\n",
+ kernel_filename, load_elf_strerror(kernel_size));
exit(1);
}
@@ -1366,6 +1377,24 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
assert(spapr->fdt_skel != NULL);
}
+static int spapr_kvm_type(const char *vm_type)
+{
+ if (!vm_type) {
+ return 0;
+ }
+
+ if (!strcmp(vm_type, "HV")) {
+ return 1;
+ }
+
+ if (!strcmp(vm_type, "PR")) {
+ return 2;
+ }
+
+ error_report("Unknown kvm-type specified '%s'", vm_type);
+ exit(1);
+}
+
static QEMUMachine spapr_machine = {
.name = "pseries",
.desc = "pSeries Logical Partition (PAPR compliant)",
@@ -1376,6 +1405,7 @@ static QEMUMachine spapr_machine = {
.max_cpus = MAX_CPUS,
.no_parallel = 1,
.default_boot_order = NULL,
+ .kvm_type = spapr_kvm_type,
};
static void spapr_machine_init(void)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 3ffcc65f03..d918780746 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -40,6 +40,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
return rb;
}
+static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
+{
+ /*
+ * hash value/pteg group index is normalized by htab_mask
+ */
+ if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
+ return false;
+ }
+ return true;
+}
+
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -50,8 +61,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong ptel = args[3];
target_ulong page_shift = 12;
target_ulong raddr;
- target_ulong i;
- hwaddr hpte;
+ target_ulong index;
+ uint64_t token;
/* only handle 4k and 16M pages for now */
if (pteh & HPTE64_V_LARGE) {
@@ -91,33 +102,37 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
pteh &= ~0x60ULL;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
+
+ index = 0;
if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7ULL;
- hpte = pte_index * HASH_PTE_SIZE_64;
- for (i = 0; ; ++i) {
- if (i == 8) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ do {
+ if (index == 8) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
- if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
+ if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
break;
}
- hpte += HASH_PTE_SIZE_64;
- }
+ } while (index++);
+ ppc_hash64_stop_access(token);
} else {
- i = 0;
- hpte = pte_index * HASH_PTE_SIZE_64;
- if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
+ ppc_hash64_stop_access(token);
}
- ppc_hash64_store_hpte1(env, hpte, ptel);
- /* eieio(); FIXME: need some sort of barrier for smp? */
- ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
- args[0] = pte_index + i;
+ ppc_hash64_store_hpte(env, pte_index + index,
+ pteh | HPTE64_V_HPTE_DIRTY, ptel);
+
+ args[0] = pte_index + index;
return H_SUCCESS;
}
@@ -133,17 +148,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, ptex)) {
return REMOVE_PARM;
}
- hpte = ptex * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -152,7 +167,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
}
*vp = v;
*rp = r;
- ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@@ -259,17 +274,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
- hpte = pte_index * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(cpu, pte_index);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
@@ -282,11 +297,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index,
+ (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
ppc_tlb_invalidate_one(env, rb);
- ppc_hash64_store_hpte1(env, hpte, r);
/* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
return H_SUCCESS;
}
@@ -299,7 +314,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint8_t *hpte;
int i, ridx, n_entries = 1;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
@@ -467,13 +482,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong vpa = args[2];
target_ulong ret = H_PARAMETER;
CPUPPCState *tenv;
- CPUState *tcpu;
+ PowerPCCPU *tcpu;
- tcpu = qemu_get_cpu(procno);
+ tcpu = ppc_get_vcpu_by_dt_id(procno);
if (!tcpu) {
return H_PARAMETER;
}
- tenv = tcpu->env_ptr;
+ tenv = &tcpu->env;
switch (flags) {
case FLAGS_REGISTER_VPA:
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index ef45f4f0cc..d9fe946818 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -243,6 +243,42 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return ret;
}
+static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+ target_ulong *tce)
+{
+ if (ioba >= tcet->window_size) {
+ hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
+ TARGET_FMT_lx "\n", ioba);
+ return H_PARAMETER;
+ }
+
+ *tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce = 0;
+ target_ulong ret = H_PARAMETER;
+ sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+
+ ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
+
+ if (tcet) {
+ ret = get_tce_emu(tcet, ioba, &tce);
+ if (!ret) {
+ args[0] = tce;
+ }
+ }
+ trace_spapr_iommu_get(liobn, ioba, ret, tce);
+
+ return ret;
+}
+
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size)
{
@@ -295,6 +331,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
/* hcall-tce */
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+ spapr_register_hypercall(H_GET_TCE, h_get_tce);
}
static TypeInfo spapr_tce_table_info = {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 4c7c3aec12..cea9469872 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -469,6 +469,8 @@ static const MemoryRegionOps spapr_msi_ops = {
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
{
+ uint64_t window_size = 4096;
+
/*
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
* we need to allocate some memory to catch those writes coming
@@ -476,10 +478,19 @@ void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
* As MSIMessage:addr is going to be the same and MSIMessage:data
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
* be used.
+ *
+ * For KVM we want to ensure that this memory is a full page so that
+ * our memory slot is of page size granularity.
*/
+#ifdef CONFIG_KVM
+ if (kvm_enabled()) {
+ window_size = getpagesize();
+ }
+#endif
+
spapr->msi_win_addr = addr;
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
- "msi", getpagesize());
+ "msi", window_size);
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
&spapr->msiwindow);
}
@@ -728,6 +739,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->props = spapr_phb_properties;
dc->reset = spapr_phb_reset;
dc->vmsd = &vmstate_spapr_pci;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->cannot_instantiate_with_device_add_yet = false;
}
static const TypeInfo spapr_phb_info = {
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 1cb276de05..73860d0486 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -131,7 +131,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
uint32_t nret, target_ulong rets)
{
target_ulong id;
- CPUState *cpu;
+ PowerPCCPU *cpu;
if (nargs != 1 || nret != 2) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -139,9 +139,9 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
}
id = rtas_ld(args, 0);
- cpu = qemu_get_cpu(id);
+ cpu = ppc_get_vcpu_by_dt_id(id);
if (cpu != NULL) {
- if (cpu->halted) {
+ if (CPU(cpu)->halted) {
rtas_st(rets, 1, 0);
} else {
rtas_st(rets, 1, 2);
@@ -161,7 +161,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
target_ulong id, start, r3;
- CPUState *cs;
+ PowerPCCPU *cpu;
if (nargs != 3 || nret != 1) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -172,9 +172,9 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
start = rtas_ld(args, 1);
r3 = rtas_ld(args, 2);
- cs = qemu_get_cpu(id);
- if (cs != NULL) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
+ cpu = ppc_get_vcpu_by_dt_id(id);
+ if (cpu != NULL) {
+ CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
if (!cs->halted) {
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 85a0e537b9..ce8ea91e8b 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -174,6 +174,19 @@ static int xilinx_load_device_tree(hwaddr addr,
if (!fdt) {
return 0;
}
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-start");
+ }
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-end");
+ }
+
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -187,6 +200,8 @@ static void virtex_init(QEMUMachineInitArgs *args)
const char *cpu_model = args->cpu_model;
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
+ hwaddr initrd_base = 0;
+ int initrd_size = 0;
MemoryRegion *address_space_mem = get_system_memory();
DeviceState *dev;
PowerPCCPU *cpu;
@@ -259,10 +274,27 @@ static void virtex_init(QEMUMachineInitArgs *args)
boot_info.ima_size = kernel_size;
+ /* Load initrd. */
+ if (args->initrd_filename) {
+ initrd_base = high = ROUND_UP(high, 4);
+ initrd_size = load_image_targphys(args->initrd_filename,
+ high, ram_size - high);
+
+ if (initrd_size < 0) {
+ error_report("couldn't load ram disk '%s'",
+ args->initrd_filename);
+ exit(1);
+ }
+ high = ROUND_UP(high + initrd_size, 4);
+ }
+
/* Provide a device-tree. */
boot_info.fdt = high + (8192 * 2);
boot_info.fdt &= ~8191;
- xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+
+ xilinx_load_device_tree(boot_info.fdt, ram_size,
+ initrd_base, initrd_size,
+ kernel_cmdline);
}
env->load_info = &boot_info;
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 75b04b45af..7074d2b3d5 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -116,6 +116,15 @@ void css_conditional_io_interrupt(SubchDev *sch)
}
}
+void css_adapter_interrupt(uint8_t isc)
+{
+ S390CPU *cpu = s390_cpu_addr2state(0);
+ uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
+
+ trace_css_adapter_interrupt(isc);
+ s390_io_interrupt(cpu, 0, 0, 0, io_int_word);
+}
+
static void sch_handle_clear_func(SubchDev *sch)
{
PMCW *p = &sch->curr_status.pmcw;
@@ -1259,6 +1268,7 @@ void css_reset_sch(SubchDev *sch)
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
sch->orb = NULL;
+ sch->thinint_active = false;
}
void css_reset(void)
diff --git a/hw/s390x/css.h b/hw/s390x/css.h
index b536ab5957..e9b440540d 100644
--- a/hw/s390x/css.h
+++ b/hw/s390x/css.h
@@ -77,6 +77,7 @@ struct SubchDev {
CCW1 last_cmd;
bool last_cmd_valid;
ORB *orb;
+ bool thinint_active;
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
SenseId id;
@@ -97,4 +98,5 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
int hotplugged, int add);
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
+void css_adapter_interrupt(uint8_t isc);
#endif
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index a73c0b924a..0777a93916 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -21,13 +21,13 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
-typedef struct EventTypesBus {
+typedef struct SCLPEventsBus {
BusState qbus;
-} EventTypesBus;
+} SCLPEventsBus;
struct SCLPEventFacility {
- EventTypesBus sbus;
- DeviceState *qdev;
+ SysBusDevice parent_obj;
+ SCLPEventsBus sbus;
/* guest' receive mask */
unsigned int receive_mask;
};
@@ -291,7 +291,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
{
}
-static const TypeInfo s390_sclp_events_bus_info = {
+static const TypeInfo sclp_events_bus_info = {
.name = TYPE_SCLP_EVENTS_BUS,
.parent = TYPE_BUS,
.class_init = sclp_events_bus_class_init,
@@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = {
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
{
- switch (code) {
+ switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMD_READ_EVENT_DATA:
read_event_data(ef, sccb);
break;
@@ -315,21 +315,26 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
}
}
-static int init_event_facility(S390SCLPDevice *sdev)
+static const VMStateDescription vmstate_event_facility = {
+ .name = "vmstate-event-facility",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(receive_mask, SCLPEventFacility),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int init_event_facility(SCLPEventFacility *event_facility)
{
- SCLPEventFacility *event_facility;
+ DeviceState *sdev = DEVICE(event_facility);
DeviceState *quiesce;
- event_facility = g_malloc0(sizeof(SCLPEventFacility));
- sdev->ef = event_facility;
- sdev->sclp_command_handler = command_handler;
- sdev->event_pending = event_pending;
-
- /* Spawn a new sclp-events facility */
+ /* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
- TYPE_SCLP_EVENTS_BUS, DEVICE(sdev), NULL);
+ TYPE_SCLP_EVENTS_BUS, sdev, NULL);
event_facility->sbus.qbus.allow_hotplug = 0;
- event_facility->qdev = (DeviceState *) sdev;
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
if (!quiesce) {
@@ -346,43 +351,57 @@ static int init_event_facility(S390SCLPDevice *sdev)
static void reset_event_facility(DeviceState *dev)
{
- S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
+ SCLPEventFacility *sdev = EVENT_FACILITY(dev);
- sdev->ef->receive_mask = 0;
+ sdev->receive_mask = 0;
}
static void init_event_facility_class(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(sbdc);
+ SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
dc->reset = reset_event_facility;
+ dc->vmsd = &vmstate_event_facility;
k->init = init_event_facility;
+ k->command_handler = command_handler;
+ k->event_pending = event_pending;
}
-static const TypeInfo s390_sclp_event_facility_info = {
- .name = "s390-sclp-event-facility",
- .parent = TYPE_DEVICE_S390_SCLP,
- .instance_size = sizeof(S390SCLPDevice),
+static const TypeInfo sclp_event_facility_info = {
+ .name = TYPE_SCLP_EVENT_FACILITY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SCLPEventFacility),
.class_init = init_event_facility_class,
+ .class_size = sizeof(SCLPEventFacilityClass),
};
-static int event_qdev_init(DeviceState *qdev)
+static void event_realize(DeviceState *qdev, Error **errp)
{
- SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEvent *event = SCLP_EVENT(qdev);
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
- return child->init(event);
+ if (child->init) {
+ int rc = child->init(event);
+ if (rc < 0) {
+ error_setg(errp, "SCLP event initialization failed.");
+ return;
+ }
+ }
}
-static int event_qdev_exit(DeviceState *qdev)
+static void event_unrealize(DeviceState *qdev, Error **errp)
{
- SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEvent *event = SCLP_EVENT(qdev);
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
if (child->exit) {
- child->exit(event);
+ int rc = child->exit(event);
+ if (rc < 0) {
+ error_setg(errp, "SCLP event exit failed.");
+ return;
+ }
}
- return 0;
}
static void event_class_init(ObjectClass *klass, void *data)
@@ -391,11 +410,11 @@ static void event_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_SCLP_EVENTS_BUS;
dc->unplug = qdev_simple_unplug_cb;
- dc->init = event_qdev_init;
- dc->exit = event_qdev_exit;
+ dc->realize = event_realize;
+ dc->unrealize = event_unrealize;
}
-static const TypeInfo s390_sclp_event_type_info = {
+static const TypeInfo sclp_event_type_info = {
.name = TYPE_SCLP_EVENT,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SCLPEvent),
@@ -406,9 +425,9 @@ static const TypeInfo s390_sclp_event_type_info = {
static void register_types(void)
{
- type_register_static(&s390_sclp_events_bus_info);
- type_register_static(&s390_sclp_event_facility_info);
- type_register_static(&s390_sclp_event_type_info);
+ type_register_static(&sclp_events_bus_info);
+ type_register_static(&sclp_event_facility_info);
+ type_register_static(&sclp_event_type_info);
}
type_init(register_types)
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 1a6397b88e..32d38a08f6 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -95,24 +95,29 @@ static int s390_ipl_init(SysBusDevice *dev)
}
return 0;
} else {
- kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
+ uint64_t pentry = KERN_IMAGE_START;
+ kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
NULL, 1, ELF_MACHINE, 0);
- if (kernel_size == -1) {
+ if (kernel_size < 0) {
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
}
- if (kernel_size == -1) {
+ if (kernel_size < 0) {
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
return -1;
}
- /* we have to overwrite values in the kernel image, which are "rom" */
- strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
-
/*
- * we can not rely on the ELF entry point, since up to 3.2 this
- * value was 0x800 (the SALIPL loader) and it wont work. For
- * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
+ * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
+ * kernel parameters here as well. Note: For old kernels (up to 3.2)
+ * we can not rely on the ELF entry point - it was 0x800 (the SALIPL
+ * loader) and it won't work. For this case we force it to 0x10000, too.
*/
- ipl->start_addr = KERN_IMAGE_START;
+ if (pentry == KERN_IMAGE_START || pentry == 0x800) {
+ ipl->start_addr = KERN_IMAGE_START;
+ /* Overwrite parameters in the kernel image, which are "rom" */
+ strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
+ } else {
+ ipl->start_addr = pentry;
+ }
}
if (ipl->initrd) {
ram_addr_t initrd_offset;
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 733d988871..0d4f6ae2f3 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -13,13 +13,14 @@
#include "exec/address-spaces.h"
#include "s390-virtio.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
#include "ioinst.h"
#include "css.h"
#include "virtio-ccw.h"
void io_subsystem_reset(void)
{
- DeviceState *css, *sclp;
+ DeviceState *css, *sclp, *flic;
css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
if (css) {
@@ -30,6 +31,10 @@ void io_subsystem_reset(void)
if (sclp) {
qdev_reset_all(sclp);
}
+ flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
+ if (flic) {
+ qdev_reset_all(flic);
+ }
}
static int virtio_ccw_hcall_notify(const uint64_t *args)
@@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
s390_sclp_init();
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
args->initrd_filename, "s390-ccw.img");
+ s390_flic_init();
/* register hypercalls */
virtio_ccw_register_hcalls();
diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c
index ee626493c6..c7bdc2005d 100644
--- a/hw/s390x/s390-virtio-hcall.c
+++ b/hw/s390x/s390-virtio-hcall.c
@@ -26,11 +26,15 @@ void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
int s390_virtio_hypercall(CPUS390XState *env)
{
- s390_virtio_fn fn = s390_diag500_table[env->regs[1]];
-
- if (!fn) {
- return -EINVAL;
+ s390_virtio_fn fn;
+
+ if (env->regs[1] < MAX_DIAG_SUBCODES) {
+ fn = s390_diag500_table[env->regs[1]];
+ if (fn) {
+ env->regs[2] = fn(&env->regs[2]);
+ return 0;
+ }
}
- return fn(&env->regs[2]);
+ return -EINVAL;
}
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 9eeda97920..0f03fd18b9 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -36,6 +36,7 @@
#include "hw/s390x/s390-virtio-bus.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio.h"
//#define DEBUG_S390
@@ -251,6 +252,7 @@ static void s390_init(QEMUMachineInitArgs *args)
s390_sclp_init();
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
args->initrd_filename, ZIPL_FILENAME);
+ s390_flic_init();
/* register hypercalls */
s390_virtio_register_hcalls();
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 4e0c564c5c..d8ddf35e58 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -18,11 +18,12 @@
#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
-static inline S390SCLPDevice *get_event_facility(void)
+static inline SCLPEventFacility *get_event_facility(void)
{
ObjectProperty *op = object_property_find(qdev_get_machine(),
- "s390-sclp-event-facility",
+ TYPE_SCLP_EVENT_FACILITY,
NULL);
assert(op);
return op->opaque;
@@ -89,9 +90,10 @@ static void sclp_read_cpu_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void sclp_execute(SCCB *sccb, uint64_t code)
+static void sclp_execute(SCCB *sccb, uint32_t code)
{
- S390SCLPDevice *sdev = get_event_facility();
+ SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
@@ -102,12 +104,12 @@ static void sclp_execute(SCCB *sccb, uint64_t code)
sclp_read_cpu_info(sccb);
break;
default:
- sdev->sclp_command_handler(sdev->ef, sccb, code);
+ efc->command_handler(ef, sccb, code);
break;
}
}
-int sclp_service_call(uint32_t sccb, uint64_t code)
+int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
{
int r = 0;
SCCB work_sccb;
@@ -115,11 +117,16 @@ int sclp_service_call(uint32_t sccb, uint64_t code)
hwaddr sccb_len = sizeof(SCCB);
/* first some basic checks on program checks */
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ r = -PGM_PRIVILEGED;
+ goto out;
+ }
if (cpu_physical_memory_is_io(sccb)) {
r = -PGM_ADDRESSING;
goto out;
}
- if (sccb & ~0x7ffffff8ul) {
+ if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
+ || (sccb & ~0x7ffffff8UL) != 0) {
r = -PGM_SPECIFICATION;
goto out;
}
@@ -151,11 +158,13 @@ out:
void sclp_service_interrupt(uint32_t sccb)
{
- S390SCLPDevice *sdev = get_event_facility();
+ SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
+
uint32_t param = sccb & ~3;
/* Indicate whether an event is still pending */
- param |= sdev->event_pending(sdev->ef) ? 1 : 0;
+ param |= efc->event_pending(ef) ? 1 : 0;
if (!param) {
/* No need to send an interrupt, there's nothing to be notified about */
@@ -168,47 +177,9 @@ void sclp_service_interrupt(uint32_t sccb)
void s390_sclp_init(void)
{
- DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility");
+ DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY);
- object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
+ object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY,
OBJECT(dev), NULL);
qdev_init_nofail(dev);
}
-
-static int s390_sclp_dev_init(SysBusDevice *dev)
-{
- int r;
- S390SCLPDevice *sdev = (S390SCLPDevice *)dev;
- S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev);
-
- r = sclp->init(sdev);
- if (!r) {
- assert(sdev->event_pending);
- assert(sdev->sclp_command_handler);
- }
-
- return r;
-}
-
-static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->init = s390_sclp_dev_init;
-}
-
-static const TypeInfo s390_sclp_device_info = {
- .name = TYPE_DEVICE_S390_SCLP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(S390SCLPDevice),
- .class_init = s390_sclp_device_class_init,
- .class_size = sizeof(S390SCLPDeviceClass),
- .abstract = true,
-};
-
-static void s390_sclp_register_types(void)
-{
- type_register_static(&s390_sclp_device_info);
-}
-
-type_init(s390_sclp_register_types)
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index f6e0e3e4ae..a01801e342 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -1,7 +1,7 @@
/*
* virtio ccw target implementation
*
- * Copyright 2012 IBM Corp.
+ * Copyright 2012,2014 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
@@ -188,6 +188,13 @@ typedef struct VirtioFeatDesc {
uint8_t index;
} QEMU_PACKED VirtioFeatDesc;
+typedef struct VirtioThinintInfo {
+ hwaddr summary_indicator;
+ hwaddr device_indicator;
+ uint64_t ind_bit;
+ uint8_t isc;
+} QEMU_PACKED VirtioThinintInfo;
+
/* Specify where the virtqueues for the subchannel are in guest memory. */
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
uint16_t index, uint16_t num)
@@ -237,6 +244,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
bool check_len;
int len;
hwaddr hw_len;
+ VirtioThinintInfo *thinint;
if (!dev) {
return -EINVAL;
@@ -428,6 +436,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EINVAL;
break;
}
+ if (sch->thinint_active) {
+ /* Trigger a command reject. */
+ ret = -ENOSYS;
+ break;
+ }
if (!ccw.cda) {
ret = -EFAULT;
} else {
@@ -480,6 +493,42 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = 0;
}
break;
+ case CCW_CMD_SET_IND_ADAPTER:
+ if (check_len) {
+ if (ccw.count != sizeof(*thinint)) {
+ ret = -EINVAL;
+ break;
+ }
+ } else if (ccw.count < sizeof(*thinint)) {
+ /* Can't execute command. */
+ ret = -EINVAL;
+ break;
+ }
+ len = sizeof(*thinint);
+ hw_len = len;
+ if (!ccw.cda) {
+ ret = -EFAULT;
+ } else if (dev->indicators && !sch->thinint_active) {
+ /* Trigger a command reject. */
+ ret = -ENOSYS;
+ } else {
+ thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
+ if (!thinint) {
+ ret = -EFAULT;
+ } else {
+ len = hw_len;
+ dev->summary_indicator = thinint->summary_indicator;
+ dev->indicators = thinint->device_indicator;
+ dev->thinint_isc = thinint->isc;
+ dev->ind_bit = thinint->ind_bit;
+ cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
+ sch->thinint_active = ((dev->indicators != 0) &&
+ (dev->summary_indicator != 0));
+ sch->curr_status.scsw.count = ccw.count - len;
+ ret = 0;
+ }
+ }
+ break;
default:
ret = -ENOSYS;
break;
@@ -511,6 +560,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
sch->orb = NULL;
+ sch->thinint_active = false;
/*
* Use a device number if provided. Otherwise, fall back to subchannel
* number.
@@ -858,6 +908,28 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
return container_of(d, VirtioCcwDevice, parent_obj);
}
+static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
+ uint8_t to_be_set)
+{
+ uint8_t ind_old, ind_new;
+ hwaddr len = 1;
+ uint8_t *ind_addr;
+
+ ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
+ if (!ind_addr) {
+ error_report("%s(%x.%x.%04x): unable to access indicator",
+ __func__, sch->cssid, sch->ssid, sch->schid);
+ return -1;
+ }
+ do {
+ ind_old = *ind_addr;
+ ind_new = ind_old | to_be_set;
+ } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
+ cpu_physical_memory_unmap(ind_addr, len, 1, len);
+
+ return ind_old;
+}
+
static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
{
VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
@@ -872,9 +944,26 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
if (!dev->indicators) {
return;
}
- indicators = ldq_phys(&address_space_memory, dev->indicators);
- indicators |= 1ULL << vector;
- stq_phys(&address_space_memory, dev->indicators, indicators);
+ if (sch->thinint_active) {
+ /*
+ * In the adapter interrupt case, indicators points to a
+ * memory area that may be (way) larger than 64 bit and
+ * ind_bit indicates the start of the indicators in a big
+ * endian notation.
+ */
+ virtio_set_ind_atomic(sch, dev->indicators +
+ (dev->ind_bit + vector) / 8,
+ 0x80 >> ((dev->ind_bit + vector) % 8));
+ if (!virtio_set_ind_atomic(sch, dev->summary_indicator,
+ 0x01)) {
+ css_adapter_interrupt(dev->thinint_isc);
+ }
+ } else {
+ indicators = ldq_phys(&address_space_memory, dev->indicators);
+ indicators |= 1ULL << vector;
+ stq_phys(&address_space_memory, dev->indicators, indicators);
+ css_conditional_io_interrupt(sch);
+ }
} else {
if (!dev->indicators2) {
return;
@@ -883,10 +972,8 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
indicators = ldq_phys(&address_space_memory, dev->indicators2);
indicators |= 1ULL << vector;
stq_phys(&address_space_memory, dev->indicators2, indicators);
+ css_conditional_io_interrupt(sch);
}
-
- css_conditional_io_interrupt(sch);
-
}
static unsigned virtio_ccw_get_features(DeviceState *d)
@@ -907,6 +994,7 @@ static void virtio_ccw_reset(DeviceState *d)
css_reset_sch(dev->sch);
dev->indicators = 0;
dev->indicators2 = 0;
+ dev->summary_indicator = 0;
}
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 00932c746d..4393e44814 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -38,6 +38,7 @@
#define CCW_CMD_SET_IND 0x43
#define CCW_CMD_SET_CONF_IND 0x53
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_SET_IND_ADAPTER 0x73
#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
#define VIRTIO_CCW_DEVICE(obj) \
@@ -83,9 +84,12 @@ struct VirtioCcwDevice {
bool ioeventfd_started;
bool ioeventfd_disabled;
uint32_t flags;
+ uint8_t thinint_isc;
/* Guest provided values: */
hwaddr indicators;
hwaddr indicators2;
+ hwaddr summary_indicator;
+ uint64_t ind_bit;
};
/* virtual css bus type */
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 50b89ad4aa..50a0acf1fe 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -909,7 +909,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
case VERIFY_16:
if ((buf[1] & 2) == 0) {
cmd->xfer = 0;
- } else if ((buf[1] & 4) == 1) {
+ } else if ((buf[1] & 4) != 0) {
cmd->xfer = 1;
}
cmd->xfer *= dev->blocksize;
@@ -1367,6 +1367,11 @@ const struct SCSISense sense_code_WRITE_PROTECTED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
};
+/* Data Protection, Space Allocation Failed Write Protect */
+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+ .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
+};
+
/*
* scsi_build_sense
*
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index b4fadd2f24..48a28ae199 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -75,6 +75,8 @@ struct SCSIDiskState
bool media_event;
bool eject_request;
uint64_t wwn;
+ uint64_t port_wwn;
+ uint16_t port_index;
uint64_t max_unmap_size;
QEMUBH *bh;
char *version;
@@ -428,6 +430,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
case EINVAL:
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
break;
+ case ENOSPC:
+ scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
+ break;
default:
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
@@ -617,6 +622,24 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
stq_be_p(&outbuf[buflen], s->wwn);
buflen += 8;
}
+
+ if (s->port_wwn) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x93; // PIV / Target port / NAA
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 8;
+ stq_be_p(&outbuf[buflen], s->port_wwn);
+ buflen += 8;
+ }
+
+ if (s->port_index) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 4;
+ stw_be_p(&outbuf[buflen + 2], s->port_index);
+ buflen += 4;
+ }
break;
}
case 0xb0: /* block limits */
@@ -2536,6 +2559,8 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
@@ -2584,6 +2609,8 @@ static const TypeInfo scsi_hd_info = {
static Property scsi_cd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2647,6 +2674,8 @@ static Property scsi_disk_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f08b64e177..8d92e0da15 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -37,8 +37,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
#include "block/scsi.h"
-#define SCSI_SENSE_BUF_SIZE 96
-
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index c0c46d7f7c..b3835c821d 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -60,9 +60,10 @@
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
-#define SCSI_SENSE_BUF_SIZE 96
#define SRP_RSP_SENSE_DATA_LEN 18
+#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
+
typedef union vscsi_crq {
struct viosrp_crq s;
uint8_t raw[16];
@@ -720,12 +721,70 @@ static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
}
}
+static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
+{
+ BusChild *kid;
+ int i, len, n, rc;
+ uint8_t *resp_data;
+ bool found_lun0;
+
+ n = 0;
+ found_lun0 = false;
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ SCSIDevice *dev = SCSI_DEVICE(kid->child);
+
+ n += 8;
+ if (dev->channel == 0 && dev->id == 0 && dev->lun == 0) {
+ found_lun0 = true;
+ }
+ }
+ if (!found_lun0) {
+ n += 8;
+ }
+ len = n+8;
+
+ resp_data = g_malloc0(len);
+ memset(resp_data, 0, len);
+ stl_be_p(resp_data, n);
+ i = found_lun0 ? 8 : 16;
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+ if (dev->id == 0 && dev->channel == 0) {
+ resp_data[i] = 0; /* Use simple LUN for 0 (SAM5 4.7.7.1) */
+ } else {
+ resp_data[i] = (2 << 6); /* Otherwise LUN addressing (4.7.7.4) */
+ }
+ resp_data[i] |= dev->id;
+ resp_data[i+1] = (dev->channel << 5);
+ resp_data[i+1] |= dev->lun;
+ i += 8;
+ }
+
+ vscsi_preprocess_desc(req);
+ rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+ g_free(resp_data);
+ if (rc < 0) {
+ vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+ vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+ } else {
+ vscsi_send_rsp(s, req, 0, len - rc, 0);
+ }
+}
+
static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
union srp_iu *srp = &req->iu.srp;
SCSIDevice *sdev;
int n, lun;
+ if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN)
+ && srp->cmd.cdb[0] == REPORT_LUNS) {
+ vscsi_report_luns(s, req);
+ return 0;
+ }
+
sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
if (!sdev) {
DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n",
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 2957d90177..75adb68abc 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "hw/sysbus.h"
+#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "hw/sparc/sun4m.h"
#include "hw/timer/m48t59.h"
@@ -561,6 +562,31 @@ static void tcx_init(hwaddr addr, int vram_size, int width,
}
}
+static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
+ int height, int depth)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "cgthree");
+ qdev_prop_set_uint32(dev, "vram-size", vram_size);
+ qdev_prop_set_uint16(dev, "width", width);
+ qdev_prop_set_uint16(dev, "height", height);
+ qdev_prop_set_uint16(dev, "depth", depth);
+ qdev_prop_set_uint64(dev, "prom-addr", addr);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+
+ /* FCode ROM */
+ sysbus_mmio_map(s, 0, addr);
+ /* DAC */
+ sysbus_mmio_map(s, 1, addr + 0x400000ULL);
+ /* 8-bit plane */
+ sysbus_mmio_map(s, 2, addr + 0x800000ULL);
+
+ sysbus_connect_irq(s, 0, irq);
+}
+
/* NCR89C100/MACIO Internal ID register */
#define TYPE_MACIO_ID_REGISTER "macio_idreg"
@@ -914,13 +940,43 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
slavio_irq[16], iommu, &ledma_irq, 1);
if (graphic_depth != 8 && graphic_depth != 24) {
- fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+ error_report("Unsupported depth: %d", graphic_depth);
exit (1);
}
num_vsimms = 0;
if (num_vsimms == 0) {
- tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
- graphic_depth);
+ if (vga_interface_type == VGA_CG3) {
+ if (graphic_depth != 8) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768) &&
+ !(graphic_width == 1152 && graphic_height == 900)) {
+ error_report("Unsupported resolution: %d x %d", graphic_width,
+ graphic_height);
+ exit(1);
+ }
+
+ /* sbus irq 5 */
+ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
+ graphic_width, graphic_height, graphic_depth);
+ } else {
+ /* If no display specified, default to TCX */
+ if (graphic_depth != 8 && graphic_depth != 24) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768)) {
+ error_report("Unsupported resolution: %d x %d",
+ graphic_width, graphic_height);
+ exit(1);
+ }
+
+ tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+ graphic_depth);
+ }
}
for (i = num_vsimms; i < MAX_VSIMMS; i++) {
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 6a287464bf..8977243725 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -43,7 +43,7 @@
/* config register */
#define R_CONFIG (0x00 / 4)
-#define IFMODE (1 << 31)
+#define IFMODE (1U << 31)
#define ENDIAN (1 << 26)
#define MODEFAIL_GEN_EN (1 << 17)
#define MAN_START_COM (1 << 16)
@@ -87,7 +87,7 @@
#define R_LQSPI_CFG (0xa0 / 4)
#define R_LQSPI_CFG_RESET 0x03A002EB
-#define LQSPI_CFG_LQ_MODE (1 << 31)
+#define LQSPI_CFG_LQ_MODE (1U << 31)
#define LQSPI_CFG_TWO_MEM (1 << 30)
#define LQSPI_CFG_SEP_BUS (1 << 30)
#define LQSPI_CFG_U_PAGE (1 << 28)
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index f75b914951..e4dcceaf23 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -51,7 +51,7 @@ typedef struct CPUTimerState {
ptimer_state *timer;
uint32_t count, counthigh, reached;
/* processor only */
- uint32_t running;
+ uint32_t run;
uint64_t limit;
} CPUTimerState;
@@ -177,7 +177,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
// only available in processor counter/timer
// read start/stop status
if (timer_index > 0) {
- ret = t->running;
+ ret = t->run;
} else {
ret = 0;
}
@@ -260,16 +260,15 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_STATUS:
if (slavio_timer_is_user(tc)) {
// start/stop user counter
- if ((val & 1) && !t->running) {
+ if (val & 1) {
trace_slavio_timer_mem_writel_status_start(timer_index);
ptimer_run(t->timer, 0);
- t->running = 1;
- } else if (!(val & 1) && t->running) {
+ } else {
trace_slavio_timer_mem_writel_status_stop(timer_index);
ptimer_stop(t->timer);
- t->running = 0;
}
}
+ t->run = val & 1;
break;
case TIMER_MODE:
if (timer_index == 0) {
@@ -284,8 +283,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
if (val & processor) { // counter -> user timer
qemu_irq_lower(curr_timer->irq);
// counters are always running
- ptimer_stop(curr_timer->timer);
- curr_timer->running = 0;
+ if (!curr_timer->run) {
+ ptimer_stop(curr_timer->timer);
+ }
// user timer limit is always the same
curr_timer->limit = TIMER_MAX_COUNT64;
ptimer_set_limit(curr_timer->timer,
@@ -296,13 +296,8 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
s->cputimer_mode |= processor;
trace_slavio_timer_mem_writel_mode_user(timer_index);
} else { // user timer -> counter
- // stop the user timer if it is running
- if (curr_timer->running) {
- ptimer_stop(curr_timer->timer);
- }
// start the counter
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
// clear this processors user timer bit in config
// register
s->cputimer_mode &= ~processor;
@@ -340,7 +335,7 @@ static const VMStateDescription vmstate_timer = {
VMSTATE_UINT32(count, CPUTimerState),
VMSTATE_UINT32(counthigh, CPUTimerState),
VMSTATE_UINT32(reached, CPUTimerState),
- VMSTATE_UINT32(running, CPUTimerState),
+ VMSTATE_UINT32(run , CPUTimerState),
VMSTATE_PTIMER(timer, CPUTimerState),
VMSTATE_END_OF_LIST()
}
@@ -373,7 +368,7 @@ static void slavio_timer_reset(DeviceState *d)
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
+ curr_timer->run = 1;
}
}
s->cputimer_mode = 0;
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index e05cbc131e..42913b6a5a 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -98,7 +98,7 @@ static void puv3_load_kernel(const char *kernel_filename)
}
/* cheat curses that we have a graphic console, only under ocd console */
- graphic_console_init(NULL, &no_ops, NULL);
+ graphic_console_init(NULL, 0, &no_ops, NULL);
}
static void puv3_init(QEMUMachineInitArgs *args)
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index aa913df853..7213c8909c 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -546,10 +546,10 @@ static int emulated_initfn(CCIDCardState *base)
printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
return -1;
}
- qemu_thread_create(&card->event_thread_id, event_thread, card,
- QEMU_THREAD_JOINABLE);
- qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card,
- QEMU_THREAD_JOINABLE);
+ qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
+ card, QEMU_THREAD_JOINABLE);
+ qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
+ card, QEMU_THREAD_JOINABLE);
return 0;
}