diff options
114 files changed, 2863 insertions, 1824 deletions
diff --git a/.gitignore b/.gitignore index 27ad002970..9c234a383b 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,9 @@ fsdev/virtfs-proxy-helper.pod *.swp *.orig .pc +*.patch +*.gcda +*.gcno patches pc-bios/bios-pq/status pc-bios/vgabios-pq/status @@ -676,7 +676,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, assert(drv != NULL); assert(bs->file == NULL); - assert(options == NULL || bs->options != options); + assert(options != NULL && bs->options != options); trace_bdrv_open_common(bs, filename, flags, drv->format_name); @@ -688,7 +688,11 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bdrv_enable_copy_on_read(bs); } - pstrcpy(bs->filename, sizeof(bs->filename), filename); + if (filename != NULL) { + pstrcpy(bs->filename, sizeof(bs->filename), filename); + } else { + bs->filename[0] = '\0'; + } if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) { return -ENOTSUP; @@ -708,7 +712,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bdrv_swap(file, bs); ret = 0; } else { - ret = drv->bdrv_file_open(bs, filename, open_flags); + assert(drv->bdrv_parse_filename || filename != NULL); + ret = drv->bdrv_file_open(bs, filename, options, open_flags); } } else { assert(file != NULL); @@ -727,6 +732,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, #ifndef _WIN32 if (bs->is_temporary) { + assert(filename != NULL); unlink(filename); } #endif @@ -742,27 +748,92 @@ free_and_fail: /* * Opens a file using a protocol (file, host_device, nbd, ...) + * + * options is a QDict of options to pass to the block drivers, or NULL for an + * empty set of options. The reference to the QDict belongs to the block layer + * after the call (even on failure), so if the caller intends to reuse the + * dictionary, it needs to use QINCREF() before calling bdrv_file_open. */ -int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) +int bdrv_file_open(BlockDriverState **pbs, const char *filename, + QDict *options, int flags) { BlockDriverState *bs; BlockDriver *drv; + const char *drvname; int ret; - drv = bdrv_find_protocol(filename); - if (!drv) { - return -ENOENT; + /* NULL means an empty set of options */ + if (options == NULL) { + options = qdict_new(); } bs = bdrv_new(""); - ret = bdrv_open_common(bs, NULL, filename, NULL, flags, drv); + bs->options = options; + options = qdict_clone_shallow(options); + + /* Find the right block driver */ + drvname = qdict_get_try_str(options, "driver"); + if (drvname) { + drv = bdrv_find_whitelisted_format(drvname); + qdict_del(options, "driver"); + } else if (filename) { + drv = bdrv_find_protocol(filename); + } else { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "Must specify either driver or file"); + drv = NULL; + } + + if (!drv) { + ret = -ENOENT; + goto fail; + } + + /* Parse the filename and open it */ + if (drv->bdrv_parse_filename && filename) { + Error *local_err = NULL; + drv->bdrv_parse_filename(filename, options, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + ret = -EINVAL; + goto fail; + } + } else if (!drv->bdrv_parse_filename && !filename) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "The '%s' block driver requires a file name", + drv->format_name); + ret = -EINVAL; + goto fail; + } + + ret = bdrv_open_common(bs, NULL, filename, options, flags, drv); if (ret < 0) { - bdrv_delete(bs); - return ret; + goto fail; } + + /* Check if any unknown options were used */ + if (qdict_size(options) != 0) { + const QDictEntry *entry = qdict_first(options); + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block protocol '%s' doesn't " + "support the option '%s'", + drv->format_name, entry->key); + ret = -EINVAL; + goto fail; + } + QDECREF(options); + bs->growable = 1; *pbs = bs; return 0; + +fail: + QDECREF(options); + if (!bs->drv) { + QDECREF(bs->options); + } + bdrv_delete(bs); + return ret; } int bdrv_open_backing_file(BlockDriverState *bs) @@ -802,6 +873,25 @@ int bdrv_open_backing_file(BlockDriverState *bs) return 0; } +static void extract_subqdict(QDict *src, QDict **dst, const char *start) +{ + const QDictEntry *entry, *next; + const char *p; + + *dst = qdict_new(); + entry = qdict_first(src); + + while (entry != NULL) { + next = qdict_next(src, entry); + if (strstart(entry->key, start, &p)) { + qobject_incref(entry->value); + qdict_put_obj(*dst, p, entry->value); + qdict_del(src, entry->key); + } + entry = next; + } +} + /* * Opens a disk image (raw, qcow2, vmdk, ...) * @@ -817,6 +907,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ char tmp_filename[PATH_MAX + 1]; BlockDriverState *file = NULL; + QDict *file_options = NULL; /* NULL means an empty set of options */ if (options == NULL) { @@ -830,11 +921,17 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; int64_t total_size; - int is_protocol = 0; BlockDriver *bdrv_qcow2; - QEMUOptionParameter *options; + QEMUOptionParameter *create_options; char backing_filename[PATH_MAX]; + if (qdict_size(options) != 0) { + error_report("Can't use snapshot=on with driver-specific options"); + ret = -EINVAL; + goto fail; + } + assert(filename != NULL); + /* if snapshot, we create a temporary backing file and open it instead of opening 'filename' directly */ @@ -847,9 +944,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK; - if (bs1->drv && bs1->drv->protocol_name) - is_protocol = 1; - bdrv_delete(bs1); ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename)); @@ -858,7 +952,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } /* Real path is meaningless for protocols */ - if (is_protocol) { + if (path_has_protocol(filename)) { snprintf(backing_filename, sizeof(backing_filename), "%s", filename); } else if (!realpath(filename, backing_filename)) { @@ -867,17 +961,19 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } bdrv_qcow2 = bdrv_find_format("qcow2"); - options = parse_option_parameters("", bdrv_qcow2->create_options, NULL); + create_options = parse_option_parameters("", bdrv_qcow2->create_options, + NULL); - set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size); - set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename); + set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size); + set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE, + backing_filename); if (drv) { - set_option_parameter(options, BLOCK_OPT_BACKING_FMT, + set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT, drv->format_name); } - ret = bdrv_create(bdrv_qcow2, tmp_filename, options); - free_option_parameters(options); + ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options); + free_option_parameters(create_options); if (ret < 0) { goto fail; } @@ -892,7 +988,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, flags |= BDRV_O_ALLOW_RDWR; } - ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags)); + extract_subqdict(options, &file_options, "file."); + + ret = bdrv_file_open(&file, filename, file_options, + bdrv_open_flags(bs, flags)); if (ret < 0) { goto fail; } @@ -2491,10 +2590,6 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) return -EACCES; if (bdrv_in_use(bs)) return -EBUSY; - - /* There better not be any in-flight IOs when we truncate the device. */ - bdrv_drain_all(); - ret = drv->bdrv_truncate(bs, offset); if (ret == 0) { ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); diff --git a/block/blkdebug.c b/block/blkdebug.c index 6f7463772b..37cfbc7fc8 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -304,7 +304,8 @@ fail: } /* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */ -static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) +static int blkdebug_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVBlkdebugState *s = bs->opaque; int ret; @@ -335,7 +336,7 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) s->state = 1; /* Open the backing file */ - ret = bdrv_file_open(&bs->file, filename, flags); + ret = bdrv_file_open(&bs->file, filename, NULL, flags); if (ret < 0) { return ret; } diff --git a/block/blkverify.c b/block/blkverify.c index 2086d97234..59e3b0562b 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -69,7 +69,8 @@ static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb, } /* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */ -static int blkverify_open(BlockDriverState *bs, const char *filename, int flags) +static int blkverify_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVBlkverifyState *s = bs->opaque; int ret; @@ -89,7 +90,7 @@ static int blkverify_open(BlockDriverState *bs, const char *filename, int flags) raw = g_strdup(filename); raw[c - filename] = '\0'; - ret = bdrv_file_open(&bs->file, raw, flags); + ret = bdrv_file_open(&bs->file, raw, NULL, flags); g_free(raw); if (ret < 0) { return ret; diff --git a/block/cow.c b/block/cow.c index d73e08cf92..9f94599661 100644 --- a/block/cow.c +++ b/block/cow.c @@ -279,7 +279,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options) return ret; } - ret = bdrv_file_open(&cow_bs, filename, BDRV_O_RDWR); + ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR); if (ret < 0) { return ret; } diff --git a/block/curl.c b/block/curl.c index 98947dac32..186e3b08ab 100644 --- a/block/curl.c +++ b/block/curl.c @@ -335,7 +335,8 @@ static void curl_clean_state(CURLState *s) s->in_use = 0; } -static int curl_open(BlockDriverState *bs, const char *filename, int flags) +static int curl_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVCURLState *s = bs->opaque; CURLState *state = NULL; diff --git a/block/dmg.c b/block/dmg.c index c1066df13a..3141cb5b88 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -51,9 +51,16 @@ typedef struct BDRVDMGState { static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) { - int len=strlen(filename); - if(len>4 && !strcmp(filename+len-4,".dmg")) - return 2; + int len; + + if (!filename) { + return 0; + } + + len = strlen(filename); + if (len > 4 && !strcmp(filename + len - 4, ".dmg")) { + return 2; + } return 0; } diff --git a/block/gluster.c b/block/gluster.c index ccd684d360..9ccd4d443d 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -283,7 +283,7 @@ static int qemu_gluster_aio_flush_cb(void *opaque) } static int qemu_gluster_open(BlockDriverState *bs, const char *filename, - int bdrv_flags) + QDict *options, int bdrv_flags) { BDRVGlusterState *s = bs->opaque; int open_flags = O_BINARY; diff --git a/block/iscsi.c b/block/iscsi.c index 3d529213ff..51a2889452 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1007,7 +1007,8 @@ out: * We support iscsi url's on the form * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun> */ -static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) +static int iscsi_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = NULL; @@ -1203,7 +1204,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) bs.opaque = g_malloc0(sizeof(struct IscsiLun)); iscsilun = bs.opaque; - ret = iscsi_open(&bs, filename, 0); + ret = iscsi_open(&bs, filename, NULL, 0); if (ret != 0) { goto out; } diff --git a/block/nbd.c b/block/nbd.c index a5812948d2..3d711b2735 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -32,6 +32,8 @@ #include "block/block_int.h" #include "qemu/module.h" #include "qemu/sockets.h" +#include "qapi/qmp/qjson.h" +#include "qapi/qmp/qint.h" #include <sys/types.h> #include <unistd.h> @@ -65,17 +67,19 @@ typedef struct BDRVNBDState { Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; struct nbd_reply reply; - int is_unix; - char *host_spec; + bool is_unix; + QemuOpts *socket_opts; + char *export_name; /* An NBD server may export several devices */ } BDRVNBDState; -static int nbd_parse_uri(BDRVNBDState *s, const char *filename) +static int nbd_parse_uri(const char *filename, QDict *options) { URI *uri; const char *p; QueryParams *qp = NULL; int ret = 0; + bool is_unix; uri = uri_parse(filename); if (!uri) { @@ -84,11 +88,11 @@ static int nbd_parse_uri(BDRVNBDState *s, const char *filename) /* transport */ if (!strcmp(uri->scheme, "nbd")) { - s->is_unix = false; + is_unix = false; } else if (!strcmp(uri->scheme, "nbd+tcp")) { - s->is_unix = false; + is_unix = false; } else if (!strcmp(uri->scheme, "nbd+unix")) { - s->is_unix = true; + is_unix = true; } else { ret = -EINVAL; goto out; @@ -97,32 +101,35 @@ static int nbd_parse_uri(BDRVNBDState *s, const char *filename) p = uri->path ? uri->path : "/"; p += strspn(p, "/"); if (p[0]) { - s->export_name = g_strdup(p); + qdict_put(options, "export", qstring_from_str(p)); } qp = query_params_parse(uri->query); - if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) { + if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) { ret = -EINVAL; goto out; } - if (s->is_unix) { + if (is_unix) { /* nbd+unix:///export?socket=path */ if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) { ret = -EINVAL; goto out; } - s->host_spec = g_strdup(qp->p[0].value); + qdict_put(options, "path", qstring_from_str(qp->p[0].value)); } else { - /* nbd[+tcp]://host:port/export */ + /* nbd[+tcp]://host[:port]/export */ if (!uri->server) { ret = -EINVAL; goto out; } - if (!uri->port) { - uri->port = NBD_DEFAULT_PORT; + + qdict_put(options, "host", qstring_from_str(uri->server)); + if (uri->port) { + char* port_str = g_strdup_printf("%d", uri->port); + qdict_put(options, "port", qstring_from_str(port_str)); + g_free(port_str); } - s->host_spec = g_strdup_printf("%s:%d", uri->server, uri->port); } out: @@ -133,16 +140,29 @@ out: return ret; } -static int nbd_config(BDRVNBDState *s, const char *filename) +static void nbd_parse_filename(const char *filename, QDict *options, + Error **errp) { char *file; char *export_name; const char *host_spec; const char *unixpath; - int err = -EINVAL; + + if (qdict_haskey(options, "host") + || qdict_haskey(options, "port") + || qdict_haskey(options, "path")) + { + error_setg(errp, "host/port/path and a file name may not be specified " + "at the same time"); + return; + } if (strstr(filename, "://")) { - return nbd_parse_uri(s, filename); + int ret = nbd_parse_uri(filename, options); + if (ret < 0) { + error_setg(errp, "No valid URL specified"); + } + return; } file = g_strdup(filename); @@ -154,34 +174,79 @@ static int nbd_config(BDRVNBDState *s, const char *filename) } export_name[0] = 0; /* truncate 'file' */ export_name += strlen(EN_OPTSTR); - s->export_name = g_strdup(export_name); + + qdict_put(options, "export", qstring_from_str(export_name)); } /* extract the host_spec - fail if it's not nbd:... */ if (!strstart(file, "nbd:", &host_spec)) { + error_setg(errp, "File name string for NBD must start with 'nbd:'"); + goto out; + } + + if (!*host_spec) { goto out; } /* are we a UNIX or TCP socket? */ if (strstart(host_spec, "unix:", &unixpath)) { - s->is_unix = true; - s->host_spec = g_strdup(unixpath); + qdict_put(options, "path", qstring_from_str(unixpath)); } else { - s->is_unix = false; - s->host_spec = g_strdup(host_spec); - } + InetSocketAddress *addr = NULL; - err = 0; + addr = inet_parse(host_spec, errp); + if (error_is_set(errp)) { + goto out; + } + + qdict_put(options, "host", qstring_from_str(addr->host)); + qdict_put(options, "port", qstring_from_str(addr->port)); + qapi_free_InetSocketAddress(addr); + } out: g_free(file); - if (err != 0) { - g_free(s->export_name); - g_free(s->host_spec); +} + +static int nbd_config(BDRVNBDState *s, QDict *options) +{ + Error *local_err = NULL; + + if (qdict_haskey(options, "path")) { + if (qdict_haskey(options, "host")) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, "path and host may not " + "be used at the same time."); + return -EINVAL; + } + s->is_unix = true; + } else if (qdict_haskey(options, "host")) { + s->is_unix = false; + } else { + return -EINVAL; } - return err; + + s->socket_opts = qemu_opts_create_nofail(&socket_optslist); + + qemu_opts_absorb_qdict(s->socket_opts, options, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + return -EINVAL; + } + + if (!qemu_opt_get(s->socket_opts, "port")) { + qemu_opt_set_number(s->socket_opts, "port", NBD_DEFAULT_PORT); + } + + s->export_name = g_strdup(qdict_get_try_str(options, "export")); + if (s->export_name) { + qdict_del(options, "export"); + } + + return 0; } + static void nbd_coroutine_start(BDRVNBDState *s, struct nbd_request *request) { int i; @@ -328,9 +393,9 @@ static int nbd_establish_connection(BlockDriverState *bs) size_t blocksize; if (s->is_unix) { - sock = unix_socket_outgoing(s->host_spec); + sock = unix_socket_outgoing(qemu_opt_get(s->socket_opts, "path")); } else { - sock = tcp_socket_outgoing_spec(s->host_spec); + sock = tcp_socket_outgoing_opts(s->socket_opts); } /* Failed to establish connection */ @@ -376,7 +441,8 @@ static void nbd_teardown_connection(BlockDriverState *bs) closesocket(s->sock); } -static int nbd_open(BlockDriverState *bs, const char* filename, int flags) +static int nbd_open(BlockDriverState *bs, const char* filename, + QDict *options, int flags) { BDRVNBDState *s = bs->opaque; int result; @@ -385,7 +451,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags) qemu_co_mutex_init(&s->free_sema); /* Pop the config into our state object. Exit if invalid. */ - result = nbd_config(s, filename); + result = nbd_config(s, options); if (result != 0) { return result; } @@ -549,7 +615,7 @@ static void nbd_close(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; g_free(s->export_name); - g_free(s->host_spec); + qemu_opts_del(s->socket_opts); nbd_teardown_connection(bs); } @@ -565,6 +631,7 @@ static BlockDriver bdrv_nbd = { .format_name = "nbd", .protocol_name = "nbd", .instance_size = sizeof(BDRVNBDState), + .bdrv_parse_filename = nbd_parse_filename, .bdrv_file_open = nbd_open, .bdrv_co_readv = nbd_co_readv, .bdrv_co_writev = nbd_co_writev, @@ -578,6 +645,7 @@ static BlockDriver bdrv_nbd_tcp = { .format_name = "nbd", .protocol_name = "nbd+tcp", .instance_size = sizeof(BDRVNBDState), + .bdrv_parse_filename = nbd_parse_filename, .bdrv_file_open = nbd_open, .bdrv_co_readv = nbd_co_readv, .bdrv_co_writev = nbd_co_writev, @@ -591,6 +659,7 @@ static BlockDriver bdrv_nbd_unix = { .format_name = "nbd", .protocol_name = "nbd+unix", .instance_size = sizeof(BDRVNBDState), + .bdrv_parse_filename = nbd_parse_filename, .bdrv_file_open = nbd_open, .bdrv_co_readv = nbd_co_readv, .bdrv_co_writev = nbd_co_writev, diff --git a/block/qcow.c b/block/qcow.c index f6750a5bd3..13d396b89a 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -679,7 +679,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) return ret; } - ret = bdrv_file_open(&qcow_bs, filename, BDRV_O_RDWR); + ret = bdrv_file_open(&qcow_bs, filename, NULL, BDRV_O_RDWR); if (ret < 0) { return ret; } diff --git a/block/qcow2.c b/block/qcow2.c index 1f99866cf4..8ea696a1aa 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -29,6 +29,7 @@ #include "block/qcow2.h" #include "qemu/error-report.h" #include "qapi/qmp/qerror.h" +#include "qapi/qmp/qbool.h" #include "trace.h" /* @@ -520,7 +521,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) goto fail; } - s->use_lazy_refcounts = qemu_opt_get_bool(opts, "lazy_refcounts", + s->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS, (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS)); qemu_opts_del(opts); @@ -930,6 +931,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs) AES_KEY aes_encrypt_key; AES_KEY aes_decrypt_key; uint32_t crypt_method = 0; + QDict *options; /* * Backing files are read-only which makes all of their metadata immutable, @@ -944,8 +946,14 @@ static void qcow2_invalidate_cache(BlockDriverState *bs) qcow2_close(bs); + options = qdict_new(); + qdict_put(options, QCOW2_OPT_LAZY_REFCOUNTS, + qbool_from_int(s->use_lazy_refcounts)); + memset(s, 0, sizeof(BDRVQcowState)); - qcow2_open(bs, NULL, flags); + qcow2_open(bs, options, flags); + + QDECREF(options); if (crypt_method) { s->crypt_method = crypt_method; @@ -1246,7 +1254,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, return ret; } - ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR); + ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR); if (ret < 0) { return ret; } diff --git a/block/qcow2.h b/block/qcow2.h index 103abdb2c0..e4b5e11a91 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -58,6 +58,9 @@ #define DEFAULT_CLUSTER_SIZE 65536 + +#define QCOW2_OPT_LAZY_REFCOUNTS "lazy_refcounts" + typedef struct QCowHeader { uint32_t magic; uint32_t version; diff --git a/block/qed.c b/block/qed.c index 46e12b358b..4651403fef 100644 --- a/block/qed.c +++ b/block/qed.c @@ -558,7 +558,7 @@ static int qed_create(const char *filename, uint32_t cluster_size, return ret; } - ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR | BDRV_O_CACHE_WB); + ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB); if (ret < 0) { return ret; } diff --git a/block/raw-posix.c b/block/raw-posix.c index 8a3cdbc1f3..99ac869780 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -303,7 +303,8 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, return 0; } -static int raw_open(BlockDriverState *bs, const char *filename, int flags) +static int raw_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVRawState *s = bs->opaque; @@ -1292,7 +1293,8 @@ static int check_hdev_writable(BDRVRawState *s) return 0; } -static int hdev_open(BlockDriverState *bs, const char *filename, int flags) +static int hdev_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVRawState *s = bs->opaque; int ret; @@ -1530,7 +1532,8 @@ static BlockDriver bdrv_host_device = { }; #ifdef __linux__ -static int floppy_open(BlockDriverState *bs, const char *filename, int flags) +static int floppy_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVRawState *s = bs->opaque; int ret; @@ -1652,7 +1655,8 @@ static BlockDriver bdrv_host_floppy = { .bdrv_eject = floppy_eject, }; -static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) +static int cdrom_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVRawState *s = bs->opaque; @@ -1760,7 +1764,8 @@ static BlockDriver bdrv_host_cdrom = { #endif /* __linux__ */ #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) -static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) +static int cdrom_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { BDRVRawState *s = bs->opaque; int ret; diff --git a/block/sheepdog.c b/block/sheepdog.c index 4245328569..bb67c4c071 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -65,6 +65,7 @@ #define SD_RES_WAIT_FOR_FORMAT 0x16 /* Waiting for a format operation */ #define SD_RES_WAIT_FOR_JOIN 0x17 /* Waiting for other nodes joining */ #define SD_RES_JOIN_FAILED 0x18 /* Target node had failed to join sheepdog */ +#define SD_RES_HALT 0x19 /* Sheepdog is stopped serving IO request */ /* * Object ID rules @@ -344,6 +345,7 @@ static const char * sd_strerror(int err) {SD_RES_WAIT_FOR_FORMAT, "Sheepdog is waiting for a format operation"}, {SD_RES_WAIT_FOR_JOIN, "Sheepdog is waiting for other nodes joining"}, {SD_RES_JOIN_FAILED, "Target node had failed to join sheepdog"}, + {SD_RES_HALT, "Sheepdog is stopped serving IO request"}, }; for (i = 0; i < ARRAY_SIZE(errors); ++i) { @@ -1124,7 +1126,8 @@ static int write_object(int fd, char *buf, uint64_t oid, int copies, create, cache_flags); } -static int sd_open(BlockDriverState *bs, const char *filename, int flags) +static int sd_open(BlockDriverState *bs, const char *filename, + QDict *options, int flags) { int ret, fd; uint32_t vid = 0; @@ -1267,7 +1270,7 @@ static int sd_prealloc(const char *filename) void *buf = g_malloc0(SD_DATA_OBJ_SIZE); int ret; - ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR); + ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR); if (ret < 0) { goto out; } @@ -1365,7 +1368,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) goto out; } - ret = bdrv_file_open(&bs, backing_file, 0); + ret = bdrv_file_open(&bs, backing_file, NULL, 0); if (ret < 0) { goto out; } diff --git a/block/vmdk.c b/block/vmdk.c index e92104a830..7bad757a33 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -661,7 +661,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, path_combine(extent_path, sizeof(extent_path), desc_file_path, fname); - ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags); + ret = bdrv_file_open(&extent_file, extent_path, NULL, bs->open_flags); if (ret) { return ret; } diff --git a/block/vvfat.c b/block/vvfat.c index b8eb38ab36..ef74c30bfe 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -988,7 +988,8 @@ static void vvfat_rebind(BlockDriverState *bs) s->bs = bs; } -static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags) +static int vvfat_open(BlockDriverState *bs, const char* dirname, + QDict *options, int flags) { BDRVVVFATState *s = bs->opaque; int i, cyls, heads, secs; diff --git a/blockdev.c b/blockdev.c index 09f76b782f..8cdc9ce16a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -658,7 +658,11 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) abort(); } if (!file || !*file) { - return dinfo; + if (qdict_size(bs_opts)) { + file = NULL; + } else { + return dinfo; + } } if (snapshot) { /* always use cache=unsafe with snapshot */ @@ -697,10 +701,10 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) if (ret < 0) { if (ret == -EMEDIUMTYPE) { error_report("could not open disk image %s: not in %s format", - file, drv->format_name); + file ?: dinfo->id, drv->format_name); } else { error_report("could not open disk image %s: %s", - file, strerror(-ret)); + file ?: dinfo->id, strerror(-ret)); } goto err; } @@ -1127,6 +1131,9 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp) return; } + /* complete all in-flight operations before resizing the device */ + bdrv_drain_all(); + switch (bdrv_truncate(bs, size)) { case 0: break; @@ -171,7 +171,7 @@ struct HCIInfo *bt_host_hci(const char *id) hci_filter_all_ptypes(&flt); hci_filter_all_events(&flt); - if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + if (qemu_setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno); return 0; } @@ -1050,6 +1050,7 @@ echo " --mandir=PATH install man pages in PATH" echo " --datadir=PATH install firmware in PATH$confsuffix" echo " --docdir=PATH install documentation in PATH$confsuffix" echo " --bindir=PATH install binaries in PATH" +echo " --libdir=PATH install libraries in PATH" echo " --sysconfdir=PATH install config in PATH$confsuffix" echo " --localstatedir=PATH install local state in PATH" echo " --with-confsuffix=SUFFIX suffix for QEMU data inside datadir and sysconfdir [$confsuffix]" diff --git a/docs/usb-storage.txt b/docs/usb-storage.txt index fa93111cf6..c5a3866eeb 100644 --- a/docs/usb-storage.txt +++ b/docs/usb-storage.txt @@ -5,7 +5,7 @@ qemu usb storage emulation QEMU has three devices for usb storage emulation. Number one emulates the classic bulk-only transport protocol which is -used by 99% of the usb sticks on the marked today and is called +used by 99% of the usb sticks on the market today and is called "usb-storage". Usage (hooking up to xhci, other host controllers work too): @@ -36,7 +36,7 @@ It's called "usb-bot". It shares most code with "usb-storage", and the guest will not be able to see the difference. The qemu command line interface is simliar to usb-uas though, i.e. no automatic scsi disk creation. It also features support for up to 16 LUNs. The LUN -numbers must be continous, i.e. for three devices you must use 0+1+2. +numbers must be continuous, i.e. for three devices you must use 0+1+2. The 0+1+5 numbering from the "usb-uas" example isn't going to work with "usb-bot". @@ -781,7 +781,8 @@ static int cpu_gdb_write_register(CPUPPCState *env, uint8_t *mem_buf, int n) /* fpscr */ if (gdb_has_xml) return 0; - return 4; + store_fpscr(env, ldtul_p(mem_buf), 0xffffffff); + return sizeof(target_ulong); } } return 0; @@ -2887,7 +2888,7 @@ static int gdbserver_open(int port) /* allow fast reuse */ val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); + qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); diff --git a/hw/arm-misc.h b/hw/arm-misc.h index cba7553039..7b2b02daaf 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -14,7 +14,7 @@ #include "exec/memory.h" #include "hw/irq.h" -/* The CPU is also modeled as an interrupt controller. */ +/* The CPU is also modelled as an interrupt controller. */ #define ARM_PIC_CPU_IRQ 0 #define ARM_PIC_CPU_FIQ 1 qemu_irq *arm_pic_init_cpu(ARMCPU *cpu); diff --git a/hw/e1000.c b/hw/e1000.c index 80b6ee3c1a..3f18041b47 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1378,7 +1378,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) k->init = pci_e1000_init; k->exit = pci_e1000_uninit; - k->romfile = "pxe-e1000.rom"; + k->romfile = "efi-e1000.rom"; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = E1000_DEVID; k->revision = 0x03; diff --git a/hw/ne2000.c b/hw/ne2000.c index 7dadc1cea7..7f458311c6 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -766,7 +766,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) k->init = pci_ne2000_init; k->exit = pci_ne2000_exit; - k->romfile = "pxe-ne2k_pci.rom", + k->romfile = "efi-ne2k_pci.rom", k->vendor_id = PCI_VENDOR_ID_REALTEK; k->device_id = PCI_DEVICE_ID_REALTEK_8029; k->class_id = PCI_CLASS_NETWORK_ETHERNET; @@ -212,7 +212,7 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); .driver = "ide-drive",\ .property = "discard_granularity",\ .value = stringify(0),\ - },{\ + },{\ .driver = "virtio-blk-pci",\ .property = "discard_granularity",\ .value = stringify(0),\ @@ -221,6 +221,26 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); .property = "vectors",\ /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\ .value = stringify(0xFFFFFFFF),\ - } + },{\ + .driver = "e1000",\ + .property = "romfile",\ + .value = "pxe-e1000.rom",\ + },{\ + .driver = "ne2k_pci",\ + .property = "romfile",\ + .value = "pxe-ne2k_pci.rom",\ + },{\ + .driver = "pcnet",\ + .property = "romfile",\ + .value = "pxe-pcnet.rom",\ + },{\ + .driver = "rtl8139",\ + .property = "romfile",\ + .value = "pxe-rtl8139.rom",\ + },{\ + .driver = "virtio-net-pci",\ + .property = "romfile",\ + .value = "pxe-virtio.rom",\ + } #endif diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index daca1c1ea0..12254b18a9 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -38,7 +38,7 @@ do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0) * bit 0 - 7: offset in configuration space of a given pci device */ -/* the helper functio to get a PCIDeice* for a given pci address */ +/* the helper function to get a PCIDevice* for a given pci address */ static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr) { uint8_t bus_num = addr >> 16; diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 55f80ca671..61af57ed51 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -351,7 +351,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) k->init = pci_pcnet_init; k->exit = pci_pcnet_uninit; - k->romfile = "pxe-pcnet.rom", + k->romfile = "efi-pcnet.rom", k->vendor_id = PCI_VENDOR_ID_AMD; k->device_id = PCI_DEVICE_ID_AMD_LANCE; k->revision = 0x10; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f355a9bb84..7b2a11fbe4 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -629,7 +629,7 @@ static void ppc_spapr_reset(void) spapr->rtas_size); /* Set up the entry state */ - first_cpu_cpu = CPU(first_cpu); + first_cpu_cpu = ENV_GET_CPU(first_cpu); first_cpu->gpr[3] = spapr->fdt_addr; first_cpu->gpr[5] = 0; first_cpu_cpu->halted = 0; @@ -779,6 +779,11 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr->htab_shift++; } + /* Set up Interrupt Controller before we create the VCPUs */ + spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads, + XICS_IRQS); + spapr->next_irq = XICS_IRQ_BASE; + /* init CPUs */ if (cpu_model == NULL) { cpu_model = kvm_enabled() ? "host" : "POWER7"; @@ -791,6 +796,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } env = &cpu->env; + xics_cpu_setup(spapr->icp, cpu); + /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); @@ -830,11 +837,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } g_free(filename); - - /* Set up Interrupt Controller */ - spapr->icp = xics_system_init(XICS_IRQS); - spapr->next_irq = XICS_IRQ_BASE; - /* Set up EPOW events infrastructure */ spapr_events_init(spapr); @@ -856,7 +858,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Set up PCI */ spapr_pci_rtas_init(); - phb = spapr_create_phb(spapr, 0, "pci"); + phb = spapr_create_phb(spapr, 0); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index dd72743b52..22cfb7e674 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -3,39 +3,7 @@ #include "sysemu/sysemu.h" #include "helper_regs.h" #include "hw/spapr.h" - -#define HPTES_PER_GROUP 8 - -#define HPTE_V_SSIZE_SHIFT 62 -#define HPTE_V_AVPN_SHIFT 7 -#define HPTE_V_AVPN 0x3fffffffffffff80ULL -#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT) -#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL)) -#define HPTE_V_BOLTED 0x0000000000000010ULL -#define HPTE_V_LOCK 0x0000000000000008ULL -#define HPTE_V_LARGE 0x0000000000000004ULL -#define HPTE_V_SECONDARY 0x0000000000000002ULL -#define HPTE_V_VALID 0x0000000000000001ULL - -#define HPTE_R_PP0 0x8000000000000000ULL -#define HPTE_R_TS 0x4000000000000000ULL -#define HPTE_R_KEY_HI 0x3000000000000000ULL -#define HPTE_R_RPN_SHIFT 12 -#define HPTE_R_RPN 0x3ffffffffffff000ULL -#define HPTE_R_FLAGS 0x00000000000003ffULL -#define HPTE_R_PP 0x0000000000000003ULL -#define HPTE_R_N 0x0000000000000004ULL -#define HPTE_R_G 0x0000000000000008ULL -#define HPTE_R_M 0x0000000000000010ULL -#define HPTE_R_I 0x0000000000000020ULL -#define HPTE_R_W 0x0000000000000040ULL -#define HPTE_R_WIMG 0x0000000000000078ULL -#define HPTE_R_C 0x0000000000000080ULL -#define HPTE_R_R 0x0000000000000100ULL -#define HPTE_R_KEY_LO 0x0000000000000e00ULL - -#define HPTE_V_1TB_SEG 0x4000000000000000ULL -#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL +#include "mmu-hash64.h" static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, target_ulong pte_index) @@ -44,17 +12,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, rb = (v & ~0x7fULL) << 16; /* AVA field */ va_low = pte_index >> 3; - if (v & HPTE_V_SECONDARY) { + if (v & HPTE64_V_SECONDARY) { va_low = ~va_low; } /* xor vsid from AVA */ - if (!(v & HPTE_V_1TB_SEG)) { + if (!(v & HPTE64_V_1TB_SEG)) { va_low ^= v >> 12; } else { va_low ^= v >> 24; } va_low &= 0x7ff; - if (v & HPTE_V_LARGE) { + if (v & HPTE64_V_LARGE) { rb |= 1; /* L field */ #if 0 /* Disable that P7 specific bit for now */ if (r & 0xff000) { @@ -84,10 +52,10 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong page_shift = 12; target_ulong raddr; target_ulong i; - uint8_t *hpte; + hwaddr hpte; /* only handle 4k and 16M pages for now */ - if (pteh & HPTE_V_LARGE) { + if (pteh & HPTE64_V_LARGE) { #if 0 /* We don't support 64k pages yet */ if ((ptel & 0xf000) == 0x1000) { /* 64k page */ @@ -105,11 +73,11 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, } } - raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1); + raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << page_shift) - 1); if (raddr < spapr->ram_limit) { /* Regular RAM - should have WIMG=0010 */ - if ((ptel & HPTE_R_WIMG) != HPTE_R_M) { + if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { return H_PARAMETER; } } else { @@ -117,7 +85,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, /* FIXME: What WIMG combinations could be sensible for IO? * For now we allow WIMG=010x, but are there others? */ /* FIXME: Should we check against registered IO addresses? */ - if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) { + if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) { return H_PARAMETER; } } @@ -129,26 +97,26 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, } if (likely((flags & H_EXACT) == 0)) { pte_index &= ~7ULL; - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + hpte = pte_index * HASH_PTE_SIZE_64; for (i = 0; ; ++i) { if (i == 8) { return H_PTEG_FULL; } - if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { + if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) { break; } hpte += HASH_PTE_SIZE_64; } } else { i = 0; - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - if (ldq_p(hpte) & HPTE_V_VALID) { + hpte = pte_index * HASH_PTE_SIZE_64; + if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) { return H_PTEG_FULL; } } - stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel); + ppc_hash64_store_hpte1(env, hpte, ptel); /* eieio(); FIXME: need some sort of barrier for smp? */ - stq_p(hpte, pteh); + ppc_hash64_store_hpte0(env, hpte, pteh); args[0] = pte_index + i; return H_SUCCESS; @@ -166,26 +134,26 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, target_ulong flags, target_ulong *vp, target_ulong *rp) { - uint8_t *hpte; + hwaddr hpte; target_ulong v, r, rb; if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) { return REMOVE_PARM; } - hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64); + hpte = ptex * HASH_PTE_SIZE_64; - v = ldq_p(hpte); - r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + v = ppc_hash64_load_hpte0(env, hpte); + r = ppc_hash64_load_hpte1(env, hpte); - if ((v & HPTE_V_VALID) == 0 || + if ((v & HPTE64_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || ((flags & H_ANDCOND) && (v & avpn) != 0)) { return REMOVE_NOT_FOUND; } *vp = v; *rp = r; - stq_p(hpte, 0); + ppc_hash64_store_hpte0(env, hpte, 0); rb = compute_tlbie_rb(v, r, ptex); ppc_tlb_invalidate_one(env, rb); return REMOVE_SUCCESS; @@ -271,7 +239,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, switch (ret) { case REMOVE_SUCCESS: - *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43; + *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; break; case REMOVE_PARM: @@ -292,34 +260,34 @@ 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]; - uint8_t *hpte; + hwaddr hpte; target_ulong v, r, rb; if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { return H_PARAMETER; } - hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + hpte = pte_index * HASH_PTE_SIZE_64; - v = ldq_p(hpte); - r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + v = ppc_hash64_load_hpte0(env, hpte); + r = ppc_hash64_load_hpte1(env, hpte); - if ((v & HPTE_V_VALID) == 0 || + if ((v & HPTE64_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { return H_NOT_FOUND; } - r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | - HPTE_R_KEY_HI | HPTE_R_KEY_LO); - r |= (flags << 55) & HPTE_R_PP0; - r |= (flags << 48) & HPTE_R_KEY_HI; - r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO); + r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | + HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); + r |= (flags << 55) & HPTE64_R_PP0; + 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); - stq_p(hpte, v & ~HPTE_V_VALID); + ppc_hash64_store_hpte0(env, hpte, v & ~HPTE64_V_VALID); ppc_tlb_invalidate_one(env, rb); - stq_p(hpte + (HASH_PTE_SIZE_64/2), r); + ppc_hash64_store_hpte1(env, hpte, r); /* Don't need a memory barrier, due to qemu's global lock */ - stq_p(hpte, v); + ppc_hash64_store_hpte0(env, hpte, v); return H_SUCCESS; } diff --git a/hw/ppc/xics.c b/hw/ppc/xics.c index c3ef12fff4..374da5bbfd 100644 --- a/hw/ppc/xics.c +++ b/hw/ppc/xics.c @@ -521,45 +521,38 @@ static void xics_reset(void *opaque) } } -struct icp_state *xics_system_init(int nr_irqs) +void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu) { - CPUPPCState *env; - CPUState *cpu; - int max_server_num; - struct icp_state *icp; - struct ics_state *ics; + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + struct icp_server_state *ss = &icp->ss[cs->cpu_index]; - max_server_num = -1; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - if (cpu->cpu_index > max_server_num) { - max_server_num = cpu->cpu_index; - } - } + assert(cs->cpu_index < icp->nr_servers); - icp = g_malloc0(sizeof(*icp)); - icp->nr_servers = max_server_num + 1; - icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_POWER7: + ss->output = env->irq_inputs[POWER7_INPUT_INT]; + break; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - struct icp_server_state *ss = &icp->ss[cpu->cpu_index]; + case PPC_FLAGS_INPUT_970: + ss->output = env->irq_inputs[PPC970_INPUT_INT]; + break; - switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_POWER7: - ss->output = env->irq_inputs[POWER7_INPUT_INT]; - break; + default: + fprintf(stderr, "XICS interrupt controller does not support this CPU " + "bus model\n"); + abort(); + } +} - case PPC_FLAGS_INPUT_970: - ss->output = env->irq_inputs[PPC970_INPUT_INT]; - break; +struct icp_state *xics_system_init(int nr_servers, int nr_irqs) +{ + struct icp_state *icp; + struct ics_state *ics; - default: - hw_error("XICS interrupt model does not support this CPU bus " - "model\n"); - exit(1); - } - } + icp = g_malloc0(sizeof(*icp)); + icp->nr_servers = nr_servers; + icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); ics = g_malloc0(sizeof(*ics)); ics->nr_irqs = nr_irqs; @@ -117,11 +117,10 @@ DeviceState *qdev_create(BusState *bus, const char *name) if (bus) { error_report("Unknown device '%s' for bus '%s'", name, object_get_typename(OBJECT(bus))); - abort(); } else { error_report("Unknown device '%s' for default sysbus", name); - abort(); } + abort(); } return dev; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 786b875c58..9369507422 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3530,7 +3530,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) k->init = pci_rtl8139_init; k->exit = pci_rtl8139_uninit; - k->romfile = "pxe-rtl8139.rom"; + k->romfile = "efi-rtl8139.rom"; k->vendor_id = PCI_VENDOR_ID_REALTEK; k->device_id = PCI_DEVICE_ID_REALTEK_8139; k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */ diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index d9b7f83878..c5d5456fa1 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -162,16 +162,23 @@ static int s390_virtio_net_init(VirtIOS390Device *dev) return s390_virtio_device_init(dev, vdev); } -static int s390_virtio_blk_init(VirtIOS390Device *dev) +static int s390_virtio_blk_init(VirtIOS390Device *s390_dev) { - VirtIODevice *vdev; - - vdev = virtio_blk_init((DeviceState *)dev, &dev->blk); - if (!vdev) { + VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + virtio_blk_set_conf(vdev, &(dev->blk)); + qdev_set_parent_bus(vdev, BUS(&s390_dev->bus)); + if (qdev_init(vdev) < 0) { return -1; } + return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev)); +} - return s390_virtio_device_init(dev, vdev); +static void s390_virtio_blk_instance_init(Object *obj) +{ + VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj); + object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); } static int s390_virtio_serial_init(VirtIOS390Device *dev) @@ -428,12 +435,7 @@ static const TypeInfo s390_virtio_net = { }; static Property s390_virtio_blk_properties[] = { - DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, blk.conf), - DEFINE_BLOCK_CHS_PROPERTIES(VirtIOS390Device, blk.conf), - DEFINE_PROP_STRING("serial", VirtIOS390Device, blk.serial), -#ifdef __linux__ - DEFINE_PROP_BIT("scsi", VirtIOS390Device, blk.scsi, 0, true), -#endif + DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkS390, blk), DEFINE_PROP_END_OF_LIST(), }; @@ -449,7 +451,8 @@ static void s390_virtio_blk_class_init(ObjectClass *klass, void *data) static const TypeInfo s390_virtio_blk = { .name = "virtio-blk-s390", .parent = TYPE_VIRTIO_S390_DEVICE, - .instance_size = sizeof(VirtIOS390Device), + .instance_size = sizeof(VirtIOBlkS390), + .instance_init = s390_virtio_blk_instance_init, .class_init = s390_virtio_blk_class_init, }; @@ -588,7 +591,7 @@ void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev) BusState *qbus; qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_S390_BUS, qdev, NULL); qbus = BUS(bus); - qbus->allow_hotplug = 0; + qbus->allow_hotplug = 1; } static void virtio_s390_bus_class_init(ObjectClass *klass, void *data) diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h index 4aacf83998..1a634118d1 100644 --- a/hw/s390x/s390-virtio-bus.h +++ b/hw/s390x/s390-virtio-bus.h @@ -89,7 +89,6 @@ struct VirtIOS390Device { ram_addr_t feat_offs; uint8_t feat_len; VirtIODevice *vdev; - VirtIOBlkConf blk; NICConf nic; uint32_t host_features; virtio_serial_conf serial; @@ -120,5 +119,17 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem); void s390_virtio_device_sync(VirtIOS390Device *dev); void s390_virtio_reset_idx(VirtIOS390Device *dev); +/* virtio-blk-s390 */ + +#define TYPE_VIRTIO_BLK_S390 "virtio-blk-s390" +#define VIRTIO_BLK_S390(obj) \ + OBJECT_CHECK(VirtIOBlkS390, (obj), TYPE_VIRTIO_BLK_S390) + +typedef struct VirtIOBlkS390 { + VirtIOS390Device parent_obj; + VirtIOBlock vdev; + VirtIOBlkConf blk; +} VirtIOBlkS390; + #endif diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index d4361f6e3e..4c44b7e856 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -570,22 +570,24 @@ static int virtio_ccw_net_exit(VirtioCcwDevice *dev) return virtio_ccw_exit(dev); } -static int virtio_ccw_blk_init(VirtioCcwDevice *dev) +static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) { - VirtIODevice *vdev; - - vdev = virtio_blk_init((DeviceState *)dev, &dev->blk); - if (!vdev) { + VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + virtio_blk_set_conf(vdev, &(dev->blk)); + qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); + if (qdev_init(vdev) < 0) { return -1; } - return virtio_ccw_device_init(dev, vdev); + return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev)); } -static int virtio_ccw_blk_exit(VirtioCcwDevice *dev) +static void virtio_ccw_blk_instance_init(Object *obj) { - virtio_blk_exit(dev->vdev); - return virtio_ccw_exit(dev); + VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj); + object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); } static int virtio_ccw_serial_init(VirtioCcwDevice *dev) @@ -754,12 +756,8 @@ static const TypeInfo virtio_ccw_net = { static Property virtio_ccw_blk_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_BLOCK_PROPERTIES(VirtioCcwDevice, blk.conf), - DEFINE_PROP_STRING("serial", VirtioCcwDevice, blk.serial), -#ifdef __linux__ - DEFINE_PROP_BIT("scsi", VirtioCcwDevice, blk.scsi, 0, true), -#endif DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk), DEFINE_PROP_END_OF_LIST(), }; @@ -769,15 +767,16 @@ static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data) VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); k->init = virtio_ccw_blk_init; - k->exit = virtio_ccw_blk_exit; + k->exit = virtio_ccw_exit; dc->reset = virtio_ccw_reset; dc->props = virtio_ccw_blk_properties; } static const TypeInfo virtio_ccw_blk = { - .name = "virtio-blk-ccw", + .name = TYPE_VIRTIO_BLK_CCW, .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtioCcwDevice), + .instance_size = sizeof(VirtIOBlkCcw), + .instance_init = virtio_ccw_blk_instance_init, .class_init = virtio_ccw_blk_class_init, }; @@ -982,7 +981,7 @@ void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev) qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_CCW_BUS, qdev, NULL); qbus = BUS(bus); - qbus->allow_hotplug = 0; + qbus->allow_hotplug = 1; } static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 88c46c081b..3993bc53b0 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -72,7 +72,6 @@ struct VirtioCcwDevice { SubchDev *sch; VirtIODevice *vdev; char *bus_id; - VirtIOBlkConf blk; NICConf nic; uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE]; virtio_serial_conf serial; @@ -94,6 +93,19 @@ typedef struct VirtualCssBus { #define VIRTUAL_CSS_BUS(obj) \ OBJECT_CHECK(VirtualCssBus, (obj), TYPE_VIRTUAL_CSS_BUS) +/* virtio-blk-ccw */ + +#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw" +#define VIRTIO_BLK_CCW(obj) \ + OBJECT_CHECK(VirtIOBlkCcw, (obj), TYPE_VIRTIO_BLK_CCW) + +typedef struct VirtIOBlkCcw { + VirtioCcwDevice parent_obj; + VirtIOBlock vdev; + VirtIOBlkConf blk; +} VirtIOBlkCcw; + + VirtualCssBus *virtual_css_bus_init(void); void virtio_ccw_device_update_status(SubchDev *sch); VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch); diff --git a/hw/sdhci.c b/hw/sdhci.c index 93feada049..4a29e6cf7f 100644 --- a/hw/sdhci.c +++ b/hw/sdhci.c @@ -763,7 +763,7 @@ static void sdhci_do_adma(SDHCIState *s) } } - /* we have unfinished bussiness - reschedule to continue ADMA */ + /* we have unfinished business - reschedule to continue ADMA */ qemu_mod_timer(s->transfer_timer, qemu_get_clock_ns(vm_clock) + SDHC_TRANSFER_DELAY); } diff --git a/hw/serial.c b/hw/serial.c index 48a5eb62b9..0ccc499285 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -306,7 +306,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, SerialState *s = opaque; addr &= 7; - DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val); + DPRINTF("write addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 "\n", addr, val); switch(addr) { default: case 0: @@ -527,7 +527,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) ret = s->scr; break; } - DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret); + DPRINTF("read addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, ret); return ret; } diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 36adbc5592..42c8b61c74 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -518,6 +518,7 @@ static int spapr_phb_init(SysBusDevice *s) { sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); PCIHostState *phb = PCI_HOST_BRIDGE(s); + const char *busname; char *namebuf; int i; PCIBus *bus; @@ -575,9 +576,6 @@ static int spapr_phb_init(SysBusDevice *s) } sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid); - if (!sphb->busname) { - sphb->busname = sphb->dtbusname; - } namebuf = alloca(strlen(sphb->dtbusname) + 32); @@ -621,7 +619,26 @@ static int spapr_phb_init(SysBusDevice *s) &sphb->msiwindow); } - bus = pci_register_bus(DEVICE(s), sphb->busname, + /* + * Selecting a busname is more complex than you'd think, due to + * interacting constraints. If the user has specified an id + * explicitly for the phb , then we want to use the qdev default + * of naming the bus based on the bridge device (so the user can + * then assign devices to it in the way they expect). For the + * first / default PCI bus (index=0) we want to use just "pci" + * because libvirt expects there to be a bus called, simply, + * "pci". Otherwise, we use the same name as in the device tree, + * since it's unique by construction, and makes the guest visible + * BUID clear. + */ + if (s->qdev.id) { + busname = NULL; + } else if (sphb->index == 0) { + busname = "pci"; + } else { + busname = sphb->dtbusname; + } + bus = pci_register_bus(DEVICE(s), busname, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS); @@ -663,7 +680,6 @@ static void spapr_phb_reset(DeviceState *qdev) } static Property spapr_phb_properties[] = { - DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1), DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1), DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1), @@ -694,14 +710,12 @@ static const TypeInfo spapr_phb_info = { .class_init = spapr_phb_class_init, }; -PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index, - const char *busname) +PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index) { DeviceState *dev; dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); qdev_prop_set_uint32(dev, "index", index); - qdev_prop_set_string(dev, "busname", busname); qdev_init_nofail(dev); return PCI_HOST_BRIDGE(dev); diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 8bb3c62c3d..8bd8a663c5 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -39,7 +39,6 @@ typedef struct sPAPRPHBState { int32_t index; uint64_t buid; - char *busname; char *dtbusname; MemoryRegion memspace, iospace; @@ -82,8 +81,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq); } -PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index, - const char *busname); +PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index); int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t xics_phandle, diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 6bfcddc379..54a43728a5 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -29,21 +29,6 @@ #include <sys/mman.h> #endif -typedef struct VirtIOBalloon -{ - VirtIODevice vdev; - VirtQueue *ivq, *dvq, *svq; - uint32_t num_pages; - uint32_t actual; - uint64_t stats[VIRTIO_BALLOON_S_NR]; - VirtQueueElement stats_vq_elem; - size_t stats_vq_offset; - QEMUTimer *stats_timer; - int64_t stats_last_update; - int64_t stats_poll_interval; - DeviceState *qdev; -} VirtIOBalloon; - static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev) { return (VirtIOBalloon *)vdev; diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h index f37f31b4d7..b0070421ca 100644 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@ -52,4 +52,18 @@ typedef struct VirtIOBalloonStat { uint64_t val; } QEMU_PACKED VirtIOBalloonStat; +typedef struct VirtIOBalloon { + VirtIODevice vdev; + VirtQueue *ivq, *dvq, *svq; + uint32_t num_pages; + uint32_t actual; + uint64_t stats[VIRTIO_BALLOON_S_NR]; + VirtQueueElement stats_vq_elem; + size_t stats_vq_offset; + QEMUTimer *stats_timer; + int64_t stats_last_update; + int64_t stats_poll_interval; + DeviceState *qdev; +} VirtIOBalloon; + #endif diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 6b69236655..f2143fded3 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -17,35 +17,11 @@ #include "hw/block-common.h" #include "sysemu/blockdev.h" #include "hw/virtio-blk.h" -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE -#include "dataplane/virtio-blk.h" -#endif #include "hw/scsi-defs.h" #ifdef __linux__ # include <scsi/sg.h> #endif - -typedef struct VirtIOBlock -{ - VirtIODevice vdev; - BlockDriverState *bs; - VirtQueue *vq; - void *rq; - QEMUBH *bh; - BlockConf *conf; - VirtIOBlkConf *blk; - unsigned short sector_mask; - DeviceState *qdev; - VMChangeStateEntry *change; -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE - VirtIOBlockDataPlane *dataplane; -#endif -} VirtIOBlock; - -static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) -{ - return (VirtIOBlock *)vdev; -} +#include "hw/virtio-bus.h" typedef struct VirtIOBlockReq { @@ -62,12 +38,13 @@ typedef struct VirtIOBlockReq static void virtio_blk_req_complete(VirtIOBlockReq *req, int status) { VirtIOBlock *s = req->dev; + VirtIODevice *vdev = VIRTIO_DEVICE(s); trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in)); - virtio_notify(&s->vdev, s->vq); + virtio_notify(vdev, s->vq); } static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, @@ -171,7 +148,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) */ req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; - if (!req->dev->blk->scsi) { + if (!req->dev->blk.scsi) { status = VIRTIO_BLK_S_UNSUPP; goto fail; } @@ -391,7 +368,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, * terminated by '\0' only when shorter than buffer. */ strncpy(req->elem.in_sg[0].iov_base, - s->blk->serial ? s->blk->serial : "", + s->blk.serial ? s->blk.serial : "", MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES)); virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); g_free(req); @@ -412,7 +389,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) { - VirtIOBlock *s = to_virtio_blk(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); VirtIOBlockReq *req; MultiReqBuffer mrb = { .num_writes = 0, @@ -480,7 +457,7 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, static void virtio_blk_reset(VirtIODevice *vdev) { #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE - VirtIOBlock *s = to_virtio_blk(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); if (s->dataplane) { virtio_blk_data_plane_stop(s->dataplane); @@ -498,7 +475,7 @@ static void virtio_blk_reset(VirtIODevice *vdev) */ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) { - VirtIOBlock *s = to_virtio_blk(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); struct virtio_blk_config blkcfg; uint64_t capacity; int blk_size = s->conf->logical_block_size; @@ -537,7 +514,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) { - VirtIOBlock *s = to_virtio_blk(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); struct virtio_blk_config blkcfg; memcpy(&blkcfg, config, sizeof(blkcfg)); @@ -546,7 +523,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) { - VirtIOBlock *s = to_virtio_blk(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); features |= (1 << VIRTIO_BLK_F_SEG_MAX); features |= (1 << VIRTIO_BLK_F_GEOMETRY); @@ -554,7 +531,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_BLK_SIZE); features |= (1 << VIRTIO_BLK_F_SCSI); - if (s->blk->config_wce) { + if (s->blk.config_wce) { features |= (1 << VIRTIO_BLK_F_CONFIG_WCE); } if (bdrv_enable_write_cache(s->bs)) @@ -568,7 +545,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) { - VirtIOBlock *s = to_virtio_blk(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); uint32_t features; #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE @@ -589,9 +566,10 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) static void virtio_blk_save(QEMUFile *f, void *opaque) { VirtIOBlock *s = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(s); VirtIOBlockReq *req = s->rq; - virtio_save(&s->vdev, f); + virtio_save(vdev, f); while (req) { qemu_put_sbyte(f, 1); @@ -604,12 +582,13 @@ static void virtio_blk_save(QEMUFile *f, void *opaque) static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(s); int ret; if (version_id != 2) return -EINVAL; - ret = virtio_load(&s->vdev, f); + ret = virtio_load(vdev, f); if (ret) { return ret; } @@ -631,80 +610,120 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) static void virtio_blk_resize(void *opaque) { - VirtIOBlock *s = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(opaque); - virtio_notify_config(&s->vdev); + virtio_notify_config(vdev); } static const BlockDevOps virtio_block_ops = { .resize_cb = virtio_blk_resize, }; -VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) +void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk) { - VirtIOBlock *s; + VirtIOBlock *s = VIRTIO_BLK(dev); + memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf)); +} + +static int virtio_blk_device_init(VirtIODevice *vdev) +{ + DeviceState *qdev = DEVICE(vdev); + VirtIOBlock *s = VIRTIO_BLK(vdev); + VirtIOBlkConf *blk = &(s->blk); static int virtio_blk_id; if (!blk->conf.bs) { error_report("drive property not set"); - return NULL; + return -1; } if (!bdrv_is_inserted(blk->conf.bs)) { error_report("Device needs media, but drive is empty"); - return NULL; + return -1; } blkconf_serial(&blk->conf, &blk->serial); if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) { - return NULL; + return -1; } - s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, - sizeof(struct virtio_blk_config), - sizeof(VirtIOBlock)); + virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, + sizeof(struct virtio_blk_config)); - s->vdev.get_config = virtio_blk_update_config; - s->vdev.set_config = virtio_blk_set_config; - s->vdev.get_features = virtio_blk_get_features; - s->vdev.set_status = virtio_blk_set_status; - s->vdev.reset = virtio_blk_reset; + vdev->get_config = virtio_blk_update_config; + vdev->set_config = virtio_blk_set_config; + vdev->get_features = virtio_blk_get_features; + vdev->set_status = virtio_blk_set_status; + vdev->reset = virtio_blk_reset; s->bs = blk->conf.bs; s->conf = &blk->conf; - s->blk = blk; + memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf)); s->rq = NULL; s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; - s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output); + s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE - if (!virtio_blk_data_plane_create(&s->vdev, blk, &s->dataplane)) { - virtio_cleanup(&s->vdev); - return NULL; + if (!virtio_blk_data_plane_create(vdev, blk, &s->dataplane)) { + virtio_common_cleanup(vdev); + return -1; } #endif s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); - s->qdev = dev; - register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, + register_savevm(qdev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); - add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0"); - return &s->vdev; + add_boot_device_path(s->conf->bootindex, qdev, "/disk@0,0"); + return 0; } -void virtio_blk_exit(VirtIODevice *vdev) +static int virtio_blk_device_exit(DeviceState *dev) { - VirtIOBlock *s = to_virtio_blk(vdev); - + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOBlock *s = VIRTIO_BLK(dev); #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; #endif qemu_del_vm_change_state_handler(s->change); - unregister_savevm(s->qdev, "virtio-blk", s); + unregister_savevm(dev, "virtio-blk", s); blockdev_mark_auto_del(s->bs); - virtio_cleanup(vdev); + virtio_common_cleanup(vdev); + return 0; +} + +static Property virtio_blk_properties[] = { + DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlock, blk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_blk_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + dc->exit = virtio_blk_device_exit; + dc->props = virtio_blk_properties; + vdc->init = virtio_blk_device_init; + vdc->get_config = virtio_blk_update_config; + vdc->set_config = virtio_blk_set_config; + vdc->get_features = virtio_blk_get_features; + vdc->set_status = virtio_blk_set_status; + vdc->reset = virtio_blk_reset; } + +static const TypeInfo virtio_device_info = { + .name = TYPE_VIRTIO_BLK, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOBlock), + .class_init = virtio_blk_class_init, +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_device_info); +} + +type_init(virtio_register_types) diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 7ef2f35852..8c6c78b191 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -16,6 +16,13 @@ #include "hw/virtio.h" #include "hw/block-common.h" +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE +#include "dataplane/virtio-blk.h" +#endif + +#define TYPE_VIRTIO_BLK "virtio-blk" +#define VIRTIO_BLK(obj) \ + OBJECT_CHECK(VirtIOBlock, (obj), TYPE_VIRTIO_BLK) /* from Linux's linux/virtio_blk.h */ @@ -108,7 +115,39 @@ struct VirtIOBlkConf uint32_t data_plane; }; +typedef struct VirtIOBlock { + VirtIODevice parent_obj; + BlockDriverState *bs; + VirtQueue *vq; + void *rq; + QEMUBH *bh; + BlockConf *conf; + VirtIOBlkConf blk; + unsigned short sector_mask; + VMChangeStateEntry *change; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + VirtIOBlockDataPlane *dataplane; +#endif +} VirtIOBlock; + #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) +#ifdef __linux__ +#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \ + DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \ + DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \ + DEFINE_PROP_STRING("serial", _state, _field.serial), \ + DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \ + DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true) +#else +#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \ + DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \ + DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \ + DEFINE_PROP_STRING("serial", _state, _field.serial), \ + DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true) +#endif /* __linux__ */ + +void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk); + #endif diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 8c9d8713f3..4bb49eb545 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -26,56 +26,6 @@ #define MAC_TABLE_ENTRIES 64 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ -typedef struct VirtIONetQueue { - VirtQueue *rx_vq; - VirtQueue *tx_vq; - QEMUTimer *tx_timer; - QEMUBH *tx_bh; - int tx_waiting; - struct { - VirtQueueElement elem; - ssize_t len; - } async_tx; - struct VirtIONet *n; -} VirtIONetQueue; - -typedef struct VirtIONet -{ - VirtIODevice vdev; - uint8_t mac[ETH_ALEN]; - uint16_t status; - VirtIONetQueue *vqs; - VirtQueue *ctrl_vq; - NICState *nic; - uint32_t tx_timeout; - int32_t tx_burst; - uint32_t has_vnet_hdr; - size_t host_hdr_len; - size_t guest_hdr_len; - uint8_t has_ufo; - int mergeable_rx_bufs; - uint8_t promisc; - uint8_t allmulti; - uint8_t alluni; - uint8_t nomulti; - uint8_t nouni; - uint8_t nobcast; - uint8_t vhost_started; - struct { - int in_use; - int first_multi; - uint8_t multi_overflow; - uint8_t uni_overflow; - uint8_t *macs; - } mac_table; - uint32_t *vlans; - DeviceState *qdev; - int multiqueue; - uint16_t max_queues; - uint16_t curr_queues; - size_t config_size; -} VirtIONet; - /* * Calculate the number of bytes up to and including the given 'field' of * 'container'. diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 0c83ca5cfe..4d1a8cdca0 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -134,6 +134,56 @@ struct virtio_net_ctrl_mac { uint32_t entries; uint8_t macs[][ETH_ALEN]; }; + +typedef struct VirtIONetQueue { + VirtQueue *rx_vq; + VirtQueue *tx_vq; + QEMUTimer *tx_timer; + QEMUBH *tx_bh; + int tx_waiting; + struct { + VirtQueueElement elem; + ssize_t len; + } async_tx; + struct VirtIONet *n; +} VirtIONetQueue; + +typedef struct VirtIONet { + VirtIODevice vdev; + uint8_t mac[ETH_ALEN]; + uint16_t status; + VirtIONetQueue *vqs; + VirtQueue *ctrl_vq; + NICState *nic; + uint32_t tx_timeout; + int32_t tx_burst; + uint32_t has_vnet_hdr; + size_t host_hdr_len; + size_t guest_hdr_len; + uint8_t has_ufo; + int mergeable_rx_bufs; + uint8_t promisc; + uint8_t allmulti; + uint8_t alluni; + uint8_t nomulti; + uint8_t nouni; + uint8_t nobcast; + uint8_t vhost_started; + struct { + int in_use; + int first_multi; + uint8_t multi_overflow; + uint8_t uni_overflow; + uint8_t *macs; + } mac_table; + uint32_t *vlans; + DeviceState *qdev; + int multiqueue; + uint16_t max_queues; + uint16_t curr_queues; + size_t config_size; +} VirtIONet; + #define VIRTIO_NET_CTRL_MAC 1 #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 #define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 39c1966cfc..f3ece78954 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -924,26 +924,6 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev) proxy->host_features = vdev->get_features(vdev, proxy->host_features); } -static int virtio_blk_init_pci(PCIDevice *pci_dev) -{ - VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); - VirtIODevice *vdev; - - if (proxy->class_code != PCI_CLASS_STORAGE_SCSI && - proxy->class_code != PCI_CLASS_STORAGE_OTHER) - proxy->class_code = PCI_CLASS_STORAGE_SCSI; - - vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk); - if (!vdev) { - return -1; - } - vdev->nvectors = proxy->nvectors; - virtio_init_pci(proxy, vdev); - /* make the actual value visible */ - proxy->nvectors = vdev->nvectors; - return 0; -} - static void virtio_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); @@ -952,15 +932,6 @@ static void virtio_exit_pci(PCIDevice *pci_dev) msix_uninit_exclusive_bar(pci_dev); } -static void virtio_blk_exit_pci(PCIDevice *pci_dev) -{ - VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); - - virtio_pci_stop_ioeventfd(proxy); - virtio_blk_exit(proxy->vdev); - virtio_exit_pci(pci_dev); -} - static int virtio_serial_init_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); @@ -1082,46 +1053,6 @@ static void virtio_rng_exit_pci(PCIDevice *pci_dev) virtio_exit_pci(pci_dev); } -static Property virtio_blk_properties[] = { - DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), - DEFINE_BLOCK_CHS_PROPERTIES(VirtIOPCIProxy, blk.conf), - DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial), -#ifdef __linux__ - DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true), -#endif - DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true), - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), -#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE - DEFINE_PROP_BIT("x-data-plane", VirtIOPCIProxy, blk.data_plane, 0, false), -#endif - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_blk_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = virtio_blk_init_pci; - k->exit = virtio_blk_exit_pci; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; - k->revision = VIRTIO_PCI_ABI_VERSION; - k->class_id = PCI_CLASS_STORAGE_SCSI; - dc->reset = virtio_pci_reset; - dc->props = virtio_blk_properties; -} - -static const TypeInfo virtio_blk_info = { - .name = "virtio-blk-pci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VirtIOPCIProxy), - .class_init = virtio_blk_class_init, -}; - static Property virtio_net_properties[] = { DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), @@ -1140,7 +1071,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) k->init = virtio_net_init_pci; k->exit = virtio_net_exit_pci; - k->romfile = "pxe-virtio.rom"; + k->romfile = "efi-virtio.rom"; k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; k->device_id = PCI_DEVICE_ID_VIRTIO_NET; k->revision = VIRTIO_PCI_ABI_VERSION; @@ -1412,13 +1343,6 @@ static void virtio_pci_device_plugged(DeviceState *d) proxy->host_features); } -/* This is called by virtio-bus just before the device is unplugged. */ -static void virtio_pci_device_unplug(DeviceState *d) -{ - VirtIOPCIProxy *dev = VIRTIO_PCI(d); - virtio_pci_stop_ioeventfd(dev); -} - static int virtio_pci_init(PCIDevice *pci_dev) { VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev); @@ -1433,10 +1357,7 @@ static int virtio_pci_init(PCIDevice *pci_dev) static void virtio_pci_exit(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); - VirtioBusState *bus = VIRTIO_BUS(&proxy->bus); - BusState *qbus = BUS(&proxy->bus); - virtio_bus_destroy_device(bus); - qbus_free(qbus); + virtio_pci_stop_ioeventfd(proxy); virtio_exit_pci(pci_dev); } @@ -1476,6 +1397,62 @@ static const TypeInfo virtio_pci_info = { .abstract = true, }; +/* virtio-blk-pci */ + +static Property virtio_blk_pci_properties[] = { + DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + DEFINE_PROP_BIT("x-data-plane", VirtIOBlkPCI, blk.data_plane, 0, false), +#endif + DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk), + DEFINE_PROP_END_OF_LIST(), +}; + +static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev) +{ + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + virtio_blk_set_conf(vdev, &(dev->blk)); + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + if (qdev_init(vdev) < 0) { + return -1; + } + return 0; +} + +static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + dc->props = virtio_blk_pci_properties; + k->init = virtio_blk_pci_init; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void virtio_blk_pci_instance_init(Object *obj) +{ + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); + object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); +} + +static const TypeInfo virtio_blk_pci_info = { + .name = TYPE_VIRTIO_BLK_PCI, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VirtIOBlkPCI), + .instance_init = virtio_blk_pci_instance_init, + .class_init = virtio_blk_pci_class_init, +}; + /* virtio-pci-bus */ void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev) @@ -1484,7 +1461,7 @@ void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev) BusState *qbus; qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev, NULL); qbus = BUS(bus); - qbus->allow_hotplug = 0; + qbus->allow_hotplug = 1; } static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) @@ -1503,7 +1480,6 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->vmstate_change = virtio_pci_vmstate_change; k->device_plugged = virtio_pci_device_plugged; - k->device_unplug = virtio_pci_device_unplug; } static const TypeInfo virtio_pci_bus_info = { @@ -1515,7 +1491,6 @@ static const TypeInfo virtio_pci_bus_info = { static void virtio_pci_register_types(void) { - type_register_static(&virtio_blk_info); type_register_static(&virtio_net_info); type_register_static(&virtio_serial_info); type_register_static(&virtio_balloon_info); @@ -1526,6 +1501,7 @@ static void virtio_pci_register_types(void) #ifdef CONFIG_VIRTFS type_register_static(&virtio_9p_info); #endif + type_register_static(&virtio_blk_pci_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index 2ae96f84d6..a9dbffffea 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -25,6 +25,7 @@ #include "hw/9pfs/virtio-9p-device.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; +typedef struct VirtIOBlkPCI VirtIOBlkPCI; /* virtio-pci-bus */ @@ -73,7 +74,6 @@ struct VirtIOPCIProxy { uint32_t flags; uint32_t class_code; uint32_t nvectors; - VirtIOBlkConf blk; NICConf nic; uint32_t host_features; #ifdef CONFIG_VIRTFS @@ -90,6 +90,19 @@ struct VirtIOPCIProxy { VirtioBusState bus; }; +/* + * virtio-blk-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci" +#define VIRTIO_BLK_PCI(obj) \ + OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI) + +struct VirtIOBlkPCI { + VirtIOPCIProxy parent_obj; + VirtIOBlock vdev; + VirtIOBlkConf blk; +}; + void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev); diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index 54c1421f86..fa8e8f3f9a 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -16,25 +16,6 @@ #include "hw/virtio-rng.h" #include "qemu/rng.h" -typedef struct VirtIORNG { - VirtIODevice vdev; - - DeviceState *qdev; - - /* Only one vq - guest puts buffer(s) on it when it needs entropy */ - VirtQueue *vq; - - VirtIORNGConf *conf; - - RngBackend *rng; - - /* We purposefully don't migrate this state. The quota will reset on the - * destination as a result. Rate limiting is host state, not guest state. - */ - QEMUTimer *rate_limit_timer; - int64_t quota_remaining; -} VirtIORNG; - static bool is_guest_ready(VirtIORNG *vrng) { if (virtio_queue_ready(vrng->vq) diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h index f42d748eba..3711c97a70 100644 --- a/hw/virtio-rng.h +++ b/hw/virtio-rng.h @@ -25,4 +25,23 @@ struct VirtIORNGConf { RndRandom *default_backend; }; +typedef struct VirtIORNG { + VirtIODevice vdev; + + DeviceState *qdev; + + /* Only one vq - guest puts buffer(s) on it when it needs entropy */ + VirtQueue *vq; + + VirtIORNGConf *conf; + + RngBackend *rng; + + /* We purposefully don't migrate this state. The quota will reset on the + * destination as a result. Rate limiting is host state, not guest state. + */ + QEMUTimer *rate_limit_timer; + int64_t quota_remaining; +} VirtIORNG; + #endif diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 72cc5198d4..86207124a2 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -130,21 +130,6 @@ typedef struct { uint32_t max_lun; } QEMU_PACKED VirtIOSCSIConfig; -typedef struct { - VirtIODevice vdev; - DeviceState *qdev; - VirtIOSCSIConf *conf; - - SCSIBus bus; - uint32_t sense_size; - uint32_t cdb_size; - int resetting; - bool events_dropped; - VirtQueue *ctrl_vq; - VirtQueue *event_vq; - VirtQueue *cmd_vqs[0]; -} VirtIOSCSI; - typedef struct VirtIOSCSIReq { VirtIOSCSI *dev; VirtQueue *vq; diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h index 81b3279a57..ccf1e4207c 100644 --- a/hw/virtio-scsi.h +++ b/hw/virtio-scsi.h @@ -16,6 +16,7 @@ #include "hw/virtio.h" #include "hw/pci/pci.h" +#include "hw/scsi.h" /* The ID for virtio_scsi */ #define VIRTIO_ID_SCSI 8 @@ -31,6 +32,21 @@ struct VirtIOSCSIConf { uint32_t cmd_per_lun; }; +typedef struct VirtIOSCSI { + VirtIODevice vdev; + DeviceState *qdev; + VirtIOSCSIConf *conf; + + SCSIBus bus; + uint32_t sense_size; + uint32_t cdb_size; + int resetting; + bool events_dropped; + VirtQueue *ctrl_vq; + VirtQueue *event_vq; + VirtQueue *cmd_vqs[0]; +} VirtIOSCSI; + #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _features_field, _conf_field) \ DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \ DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 7d0515f551..ab7168ed32 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -25,47 +25,6 @@ #include "trace.h" #include "hw/virtio-serial.h" -/* The virtio-serial bus on top of which the ports will ride as devices */ -struct VirtIOSerialBus { - BusState qbus; - - /* This is the parent device that provides the bus for ports. */ - VirtIOSerial *vser; - - /* The maximum number of ports that can ride on top of this bus */ - uint32_t max_nr_ports; -}; - -typedef struct VirtIOSerialPostLoad { - QEMUTimer *timer; - uint32_t nr_active_ports; - struct { - VirtIOSerialPort *port; - uint8_t host_connected; - } *connected; -} VirtIOSerialPostLoad; - -struct VirtIOSerial { - VirtIODevice vdev; - - VirtQueue *c_ivq, *c_ovq; - /* Arrays of ivqs and ovqs: one per port */ - VirtQueue **ivqs, **ovqs; - - VirtIOSerialBus bus; - - DeviceState *qdev; - - QTAILQ_HEAD(, VirtIOSerialPort) ports; - - /* bitmap for identifying active ports */ - uint32_t *ports_map; - - struct virtio_console_config config; - - struct VirtIOSerialPostLoad *post_load; -}; - static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) { VirtIOSerialPort *port; diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index d2d9fb773e..484dcfef2c 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -173,6 +173,47 @@ struct VirtIOSerialPort { bool throttled; }; +/* The virtio-serial bus on top of which the ports will ride as devices */ +struct VirtIOSerialBus { + BusState qbus; + + /* This is the parent device that provides the bus for ports. */ + VirtIOSerial *vser; + + /* The maximum number of ports that can ride on top of this bus */ + uint32_t max_nr_ports; +}; + +typedef struct VirtIOSerialPostLoad { + QEMUTimer *timer; + uint32_t nr_active_ports; + struct { + VirtIOSerialPort *port; + uint8_t host_connected; + } *connected; +} VirtIOSerialPostLoad; + +struct VirtIOSerial { + VirtIODevice vdev; + + VirtQueue *c_ivq, *c_ovq; + /* Arrays of ivqs and ovqs: one per port */ + VirtQueue **ivqs, **ovqs; + + VirtIOSerialBus bus; + + DeviceState *qdev; + + QTAILQ_HEAD(, VirtIOSerialPort) ports; + + /* bitmap for identifying active ports */ + uint32_t *ports_map; + + struct virtio_console_config config; + + struct VirtIOSerialPostLoad *post_load; +}; + /* Interface to the virtio-serial bus */ /* diff --git a/hw/virtio.h b/hw/virtio.h index ca43fd70cd..fdbe9313a0 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -240,7 +240,6 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, /* Base devices. */ typedef struct VirtIOBlkConf VirtIOBlkConf; -VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk); struct virtio_net_conf; VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, struct virtio_net_conf *net, @@ -258,7 +257,6 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); void virtio_net_exit(VirtIODevice *vdev); -void virtio_blk_exit(VirtIODevice *vdev); void virtio_serial_exit(VirtIODevice *vdev); void virtio_balloon_exit(VirtIODevice *vdev); void virtio_scsi_exit(VirtIODevice *vdev); @@ -35,6 +35,7 @@ struct icp_state; qemu_irq xics_get_qirq(struct icp_state *icp, int irq); void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); -struct icp_state *xics_system_init(int nr_irqs); +struct icp_state *xics_system_init(int nr_servers, int nr_irqs); +void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu); #endif /* __XICS_H__ */ diff --git a/include/block/block.h b/include/block/block.h index d4f34d6462..9dc6aada99 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -135,7 +135,8 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); void bdrv_delete(BlockDriverState *bs); int bdrv_parse_cache_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags); -int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_file_open(BlockDriverState **pbs, const char *filename, + QDict *options, int flags); int bdrv_open_backing_file(BlockDriverState *bs); int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, int flags, BlockDriver *drv); diff --git a/include/block/block_int.h b/include/block/block_int.h index ce0aa26b8e..0986a2d6ac 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -76,6 +76,10 @@ struct BlockDriver { int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); int (*bdrv_probe_device)(const char *filename); + /* Any driver implementing this callback is expected to be able to handle + * NULL file names in its .bdrv_open() implementation */ + void (*bdrv_parse_filename)(const char *filename, QDict *options, Error **errp); + /* For handling image reopen for split or non-split files */ int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp); @@ -83,7 +87,8 @@ struct BlockDriver { void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags); - int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, + QDict *options, int flags); int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, diff --git a/include/block/nbd.h b/include/block/nbd.h index 344f05b794..0903d7a603 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -22,6 +22,7 @@ #include <sys/types.h> #include "qemu-common.h" +#include "qemu/option.h" struct nbd_request { uint32_t magic; @@ -60,10 +61,9 @@ enum { #define NBD_BUFFER_SIZE (1024*1024) ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); -int tcp_socket_outgoing(const char *address, uint16_t port); int tcp_socket_incoming(const char *address, uint16_t port); -int tcp_socket_outgoing_spec(const char *address_and_port); int tcp_socket_incoming_spec(const char *address_and_port); +int tcp_socket_outgoing_opts(QemuOpts *opts); int unix_socket_outgoing(const char *path); int unix_socket_incoming(const char *path); diff --git a/include/char/char.h b/include/char/char.h index d6a03513bf..0326b2a47b 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -153,8 +153,8 @@ void qemu_chr_fe_close(struct CharDriverState *chr); void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3); -guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, - GIOFunc func, void *user_data); +int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + GIOFunc func, void *user_data); /** * @qemu_chr_fe_write: diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index ae5c21cba3..d225f6dd74 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -30,6 +30,8 @@ int inet_aton(const char *cp, struct in_addr *ia); #include "qapi/error.h" #include "qapi/qmp/qerror.h" +extern QemuOptsList socket_optslist; + /* misc helpers */ int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); @@ -45,6 +47,7 @@ int recv_all(int fd, void *buf, int len1, bool single_read); */ typedef void NonBlockingConnectHandler(int fd, void *opaque); +InetSocketAddress *inet_parse(const char *str, Error **errp); int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp); diff --git a/include/qom/object.h b/include/qom/object.h index cf094e7142..d0f99c5782 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -202,7 +202,7 @@ typedef struct InterfaceInfo InterfaceInfo; * Methods are always <emphasis>virtual</emphasis>. Overriding a method in * #TypeInfo.class_init of a subclass leads to any user of the class obtained * via OBJECT_GET_CLASS() accessing the overridden function. - * The original function is not automatically invoked. It is the responsability + * The original function is not automatically invoked. It is the responsibility * of the overriding class to determine whether and when to invoke the method * being overridden. * @@ -1321,7 +1321,7 @@ static void memory_region_add_subregion_common(MemoryRegion *mr, if (subregion->may_overlap || other->may_overlap) { continue; } - if (int128_gt(int128_make64(offset), + if (int128_ge(int128_make64(offset), int128_add(int128_make64(other->addr), other->size)) || int128_le(int128_add(int128_make64(offset), subregion->size), int128_make64(other->addr))) { @@ -261,11 +261,30 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, } } +static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + monitor_flush(opaque); + return FALSE; +} + void monitor_flush(Monitor *mon) { + int rc; + if (mon && mon->outbuf_index != 0 && !mon->mux_out) { - qemu_chr_fe_write(mon->chr, mon->outbuf, mon->outbuf_index); - mon->outbuf_index = 0; + rc = qemu_chr_fe_write(mon->chr, mon->outbuf, mon->outbuf_index); + if (rc == mon->outbuf_index) { + /* all flushed */ + mon->outbuf_index = 0; + return; + } + if (rc > 0) { + /* partinal write */ + memmove(mon->outbuf, mon->outbuf + rc, mon->outbuf_index - rc); + mon->outbuf_index -= rc; + } + qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, monitor_unblocked, mon); } } @@ -2941,10 +2960,6 @@ static const MonitorDef monitor_defs[] = { { "xer", 0, &monitor_get_xer, }, { "tbu", 0, &monitor_get_tbu, }, { "tbl", 0, &monitor_get_tbl, }, -#if defined(TARGET_PPC64) - /* Address space register */ - { "asr", offsetof(CPUPPCState, asr) }, -#endif /* Segment registers */ { "sdr1", offsetof(CPUPPCState, spr[SPR_SDR1]) }, { "sr0", offsetof(CPUPPCState, sr[0]) }, @@ -3541,10 +3556,10 @@ static const mon_cmd_t *qmp_find_cmd(const char *cmdname) * If @cmdline is blank, return NULL. * If it can't be parsed, report to @mon, and return NULL. * Else, insert command arguments into @qdict, and return the command. - * If sub-command table exist, and if @cmdline contains addtional string for - * sub-command, this function will try search sub-command table. if no - * addtional string for sub-command exist, this function will return the found - * one in @table. + * If a sub-command table exists, and if @cmdline contains an additional string + * for a sub-command, this function will try to search the sub-command table. + * If no additional string for a sub-command is present, this function will + * return the command found in @table. * Do not assume the returned command points into @table! It doesn't * when the command is a sub-command. */ @@ -199,22 +199,15 @@ static void combine_addr(char *buf, size_t len, const char* address, } } -int tcp_socket_outgoing(const char *address, uint16_t port) -{ - char address_and_port[128]; - combine_addr(address_and_port, 128, address, port); - return tcp_socket_outgoing_spec(address_and_port); -} - -int tcp_socket_outgoing_spec(const char *address_and_port) +int tcp_socket_outgoing_opts(QemuOpts *opts) { Error *local_err = NULL; - int fd = inet_connect(address_and_port, &local_err); - + int fd = inet_connect_opts(opts, &local_err, NULL, NULL); if (local_err != NULL) { qerror_report_err(local_err); error_free(local_err); } + return fd; } diff --git a/net/socket.c b/net/socket.c index 396dc8c0b1..d8b35a23cb 100644 --- a/net/socket.c +++ b/net/socket.c @@ -262,8 +262,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr } val = 1; - ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&val, sizeof(val)); + ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); goto fail; @@ -283,8 +282,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr imr.imr_interface.s_addr = htonl(INADDR_ANY); } - ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (const char *)&imr, sizeof(struct ip_mreq)); + ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &imr, sizeof(struct ip_mreq)); if (ret < 0) { perror("setsockopt(IP_ADD_MEMBERSHIP)"); goto fail; @@ -292,8 +291,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr /* Force mcast msgs to loopback (eg. several QEMUs in same host */ loop = 1; - ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - (const char *)&loop, sizeof(loop)); + ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop, sizeof(loop)); if (ret < 0) { perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); goto fail; @@ -301,8 +300,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr /* If a bind address is given, only send packets from that address */ if (localaddr != NULL) { - ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - (const char *)localaddr, sizeof(*localaddr)); + ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, + localaddr, sizeof(*localaddr)); if (ret < 0) { perror("setsockopt(IP_MULTICAST_IF)"); goto fail; @@ -521,7 +520,7 @@ static int net_socket_listen_init(NetClientState *peer, /* allow fast reuse */ val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { @@ -659,8 +658,8 @@ static int net_socket_udp_init(NetClientState *peer, return -1; } val = 1; - ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&val, sizeof(val)); + ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + &val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); closesocket(fd); @@ -696,7 +696,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, /* QEMU vlans does not support multiqueue tap, in this case peer is set. * For -netdev, peer is always NULL. */ if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) { - error_report("Multiqueue tap cannnot be used with QEMU vlans"); + error_report("Multiqueue tap cannot be used with QEMU vlans"); return -1; } diff --git a/pc-bios/efi-e1000.rom b/pc-bios/efi-e1000.rom Binary files differnew file mode 100644 index 0000000000..7dfcea364a --- /dev/null +++ b/pc-bios/efi-e1000.rom diff --git a/pc-bios/efi-eepro100.rom b/pc-bios/efi-eepro100.rom Binary files differnew file mode 100644 index 0000000000..e5134a2fe5 --- /dev/null +++ b/pc-bios/efi-eepro100.rom diff --git a/pc-bios/efi-ne2k_pci.rom b/pc-bios/efi-ne2k_pci.rom Binary files differnew file mode 100644 index 0000000000..8aa11c370d --- /dev/null +++ b/pc-bios/efi-ne2k_pci.rom diff --git a/pc-bios/efi-pcnet.rom b/pc-bios/efi-pcnet.rom Binary files differnew file mode 100644 index 0000000000..200b5d298e --- /dev/null +++ b/pc-bios/efi-pcnet.rom diff --git a/pc-bios/efi-rtl8139.rom b/pc-bios/efi-rtl8139.rom Binary files differnew file mode 100644 index 0000000000..8bcd3c79c6 --- /dev/null +++ b/pc-bios/efi-rtl8139.rom diff --git a/pc-bios/efi-virtio.rom b/pc-bios/efi-virtio.rom Binary files differnew file mode 100644 index 0000000000..25c5c6998d --- /dev/null +++ b/pc-bios/efi-virtio.rom diff --git a/qemu-char.c b/qemu-char.c index e6337971a5..4e011df3ec 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3397,8 +3397,8 @@ void qemu_chr_fe_close(struct CharDriverState *chr) } } -guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, - GIOFunc func, void *user_data) +int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + GIOFunc func, void *user_data) { GSource *src; guint tag; @@ -1766,7 +1766,7 @@ static int openfile(char *name, int flags, int growable) } if (growable) { - if (bdrv_file_open(&bs, name, flags)) { + if (bdrv_file_open(&bs, name, NULL, flags)) { fprintf(stderr, "%s: can't open device %s\n", progname, name); return 1; } diff --git a/qemu-options.hx b/qemu-options.hx index 30fb85d619..d7afeab8b0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -161,14 +161,14 @@ ETEXI DEF("boot", HAS_ARG, QEMU_OPTION_boot, "-boot [order=drives][,once=drives][,menu=on|off]\n" - " [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time]\n" + " [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time][,strict=on|off]\n" " 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n" " 'sp_name': the file's name that would be passed to bios as logo picture, if menu=on\n" " 'sp_time': the period that splash picture last if menu=on, unit is ms\n" " 'rb_timeout': the timeout before guest reboot when boot failed, unit is ms\n", QEMU_ARCH_ALL) STEXI -@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}][,reboot-timeout=@var{rb_timeout}] +@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}][,reboot-timeout=@var{rb_timeout}][,strict=on|off] @findex -boot Specify boot order @var{drives} as a string of drive letters. Valid drive letters depend on the target achitecture. The x86 PC uses: a, b @@ -192,6 +192,10 @@ when boot failed, then reboot. If @var{rb_timeout} is '-1', guest will not reboot, qemu passes '-1' to bios by default. Currently Seabios for X86 system support it. +Do strict boot via @option{strict=on} as far as firmware/BIOS +supports it. This only effects when boot priority is changed by +bootindex options. The default is non-strict boot. + @example # try to boot from network first, then from hard disk qemu-system-i386 -boot order=nc @@ -1119,7 +1123,7 @@ is a TCP port number, not a display number. @item websocket Opens an additional TCP listening port dedicated to VNC Websocket connections. -By defintion the Websocket port is 5700+@var{display}. If @var{host} is +By definition the Websocket port is 5700+@var{display}. If @var{host} is specified connections will only be allowed from this host. As an alternative the Websocket port could be specified by using @code{websocket}=@var{port}. diff --git a/qga/commands-posix.c b/qga/commands-posix.c index d7da850615..3b5c536e41 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -120,7 +120,7 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) return; } - /* succeded */ + /* succeeded */ } int64_t qmp_guest_get_time(Error **errp) diff --git a/roms/Makefile b/roms/Makefile index 5e645bc7d1..3dc560921d 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -1,5 +1,30 @@ vgabios_variants := stdvga cirrus vmware qxl +pxerom_variants := e1000 eepro100 ne2k_pci pcnet rtl8139 virtio + +pxe-rom-e1000 efi-rom-e1000 : VID := 8086 +pxe-rom-e1000 efi-rom-e1000 : DID := 100e +pxe-rom-eepro100 efi-rom-eepro100 : VID := 8086 +pxe-rom-eepro100 efi-rom-eepro100 : DID := 1209 +pxe-rom-ne2k_pci efi-rom-ne2k_pci : VID := 1050 +pxe-rom-ne2k_pci efi-rom-ne2k_pci : DID := 0940 +pxe-rom-pcnet efi-rom-pcnet : VID := 1022 +pxe-rom-pcnet efi-rom-pcnet : DID := 2000 +pxe-rom-rtl8139 efi-rom-rtl8139 : VID := 10ec +pxe-rom-rtl8139 efi-rom-rtl8139 : DID := 8139 +pxe-rom-virtio efi-rom-virtio : VID := 1af4 +pxe-rom-virtio efi-rom-virtio : DID := 1000 + +# +# EfiRom utility is shipped with edk2 / tianocore, in BaseTools/ +# +# We need that to combine multiple images (legacy bios, +# efi ia32, efi x64) into a single rom binary. +# +# We try to find it in the path. You can also pass the location on +# the command line, i.e. "make EFIROM=/path/to/EfiRom efirom" +# +EFIROM ?= $(shell which EfiRom 2>/dev/null) default: @echo "nothing is build by default" @@ -7,6 +32,9 @@ default: @echo " bios -- update bios.bin (seabios)" @echo " seavgabios -- update vgabios binaries (seabios)" @echo " lgplvgabios -- update vgabios binaries (lgpl)" + @echo " pxerom -- update nic roms (bios only)" + @echo " efirom -- update nic roms (bios+efi, this needs" + @echo " the EfiRom utility from edk2 / tianocore)" bios: config.seabios sh configure-seabios.sh $< @@ -26,3 +54,21 @@ lgplvgabios: $(patsubst %,lgplvgabios-%,$(vgabios_variants)) lgplvgabios-%: make -C vgabios vgabios-$*.bin cp vgabios/VGABIOS-lgpl-latest.$*.bin ../pc-bios/vgabios-$*.bin + +pxerom: $(patsubst %,pxe-rom-%,$(pxerom_variants)) + +pxe-rom-%: + make -C ipxe/src bin/$(VID)$(DID).rom + cp ipxe/src/bin/$(VID)$(DID).rom ../pc-bios/pxe-$*.rom + +efirom: $(patsubst %,efi-rom-%,$(pxerom_variants)) + +efi-rom-%: + make -C ipxe/src bin/$(VID)$(DID).rom + make -C ipxe/src bin-i386-efi/$(VID)$(DID).efidrv + make -C ipxe/src bin-x86_64-efi/$(VID)$(DID).efidrv + $(EFIROM) -f "0x$(VID)" -i "0x$(DID)" -l 0x02 \ + -b ipxe/src/bin/$(VID)$(DID).rom \ + -ec ipxe/src/bin-i386-efi/$(VID)$(DID).efidrv \ + -ec ipxe/src/bin-x86_64-efi/$(VID)$(DID).efidrv \ + -o ../pc-bios/efi-$*.rom diff --git a/roms/ipxe b/roms/ipxe -Subproject 7aee315f61aaf1be6d2fff26339f28a1137231a +Subproject 09c5109b8585178172c7608de8d52e9d9af0b68 diff --git a/slirp/misc.c b/slirp/misc.c index d4df972d13..6b9c2c405b 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -212,9 +212,9 @@ fork_exec(struct socket *so, const char *ex, int do_pty) } while (so->s < 0 && errno == EINTR); closesocket(s); opt = 1; - setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)); + qemu_setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); opt = 1; - setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int)); + qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); socket_set_nonblock(so->s); /* Append the telnet options now */ diff --git a/slirp/socket.c b/slirp/socket.c index bb639aed9c..8e8819cf30 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -627,7 +627,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, addr.sin_port = hport; if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) || - (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || + (qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ @@ -642,7 +642,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, #endif return NULL; } - setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); getsockname(s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 7b7ad60aea..84a6bb560b 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -338,9 +338,9 @@ int tcp_fconnect(struct socket *so) socket_set_nonblock(s); opt = 1; - setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); + qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); opt = 1; - setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); + qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == @@ -427,9 +427,9 @@ void tcp_connect(struct socket *inso) } socket_set_nonblock(s); opt = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)); + qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); opt = 1; - setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int)); + qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); socket_set_nodelay(s); so->so_fport = addr.sin_port; diff --git a/slirp/udp.c b/slirp/udp.c index 9286cb7d31..b105f871f3 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -372,7 +372,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, udp_detach(so); return NULL; } - setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + qemu_setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; diff --git a/target-i386/translate.c b/target-i386/translate.c index 705147a00b..c9cc2ffff5 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4746,7 +4746,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } s->pc++; - /* 4.1.1-4.1.3: No preceeding lock, 66, f2, f3, or rex prefixes. */ + /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_LOCK | PREFIX_DATA)) { goto illegal_op; diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index 1c62f3c68f..f2cb88b3ed 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -500,7 +500,7 @@ void cpu_unassigned_access(CPUMBState *env, hwaddr addr, { qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n", addr, is_write, is_exec); - if (!(env->sregs[SR_MSR] & MSR_EE)) { + if (!env || !(env->sregs[SR_MSR] & MSR_EE)) { return; } diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 00ac4adc51..2c43c34a5c 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -1,11 +1,14 @@ obj-y += cpu-models.o obj-y += translate.o -obj-$(CONFIG_SOFTMMU) += machine.o +ifeq ($(CONFIG_SOFTMMU),y) +obj-y += machine.o mmu_helper.o mmu-hash32.o +obj-$(TARGET_PPC64) += mmu-hash64.o +endif obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o -obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o obj-y += mem_helper.o +obj-$(CONFIG_USER_ONLY) += user_only_helper.o diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 20ca84e614..17f56b7504 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -1101,9 +1101,9 @@ "PowerPC 7457A v1.2 (G4)") /* 64 bits PowerPC */ #if defined (TARGET_PPC64) +#if defined(TODO) POWERPC_DEF("620", CPU_POWERPC_620, 620, "PowerPC 620") -#if defined(TODO) POWERPC_DEF("630", CPU_POWERPC_630, 630, "PowerPC 630 (POWER3)") #endif diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 09bfae3d54..c27cef7e32 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -68,6 +68,10 @@ typedef struct PowerPCCPUClass { #endif void (*init_proc)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env); +#if defined(CONFIG_SOFTMMU) + int (*handle_mmu_fault)(CPUPPCState *env, target_ulong eaddr, int rwx, + int mmu_idx); +#endif } PowerPCCPUClass; /** diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6886666d6e..42c36e2829 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -113,13 +113,13 @@ enum powerpc_mmu_t { #if defined(TARGET_PPC64) #define POWERPC_MMU_64 0x00010000 #define POWERPC_MMU_1TSEG 0x00020000 +#define POWERPC_MMU_AMR 0x00040000 /* 64 bits PowerPC MMU */ POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001, - /* 620 variant (no segment exceptions) */ - POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002, /* Architecture 2.06 variant */ - POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003, - /* Architecture 2.06 "degraded" (no 1T segments) */ + POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG + | POWERPC_MMU_AMR | 0x00000003, + /* Architecture 2.06 "degraded" (no 1T segments or AMR) */ POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003, #endif /* defined(TARGET_PPC64) */ }; @@ -396,36 +396,12 @@ union ppc_tlb_t { #define SDR_64_HTABSIZE 0x000000000000001FULL #endif /* defined(TARGET_PPC64 */ -#define HASH_PTE_SIZE_32 8 -#define HASH_PTE_SIZE_64 16 - typedef struct ppc_slb_t ppc_slb_t; struct ppc_slb_t { uint64_t esid; uint64_t vsid; }; -/* Bits in the SLB ESID word */ -#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL -#define SLB_ESID_V 0x0000000008000000ULL /* valid */ - -/* Bits in the SLB VSID word */ -#define SLB_VSID_SHIFT 12 -#define SLB_VSID_SHIFT_1T 24 -#define SLB_VSID_SSIZE_SHIFT 62 -#define SLB_VSID_B 0xc000000000000000ULL -#define SLB_VSID_B_256M 0x0000000000000000ULL -#define SLB_VSID_B_1T 0x4000000000000000ULL -#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL -#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID) -#define SLB_VSID_KS 0x0000000000000800ULL -#define SLB_VSID_KP 0x0000000000000400ULL -#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */ -#define SLB_VSID_L 0x0000000000000100ULL -#define SLB_VSID_C 0x0000000000000080ULL /* class */ -#define SLB_VSID_LP 0x0000000000000030ULL -#define SLB_VSID_ATTR 0x0000000000000FFFULL - #define SEGMENT_SHIFT_256M 28 #define SEGMENT_MASK_256M (~((1ULL << SEGMENT_SHIFT_256M) - 1)) @@ -965,8 +941,6 @@ struct CPUPPCState { /* MMU context - only relevant for full system emulation */ #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) - /* Address space register */ - target_ulong asr; /* PowerPC 64 SLB area */ ppc_slb_t slb[64]; int slb_nr; @@ -1105,20 +1079,6 @@ do { \ env->wdt_period[3] = (d_); \ } while (0) -#if !defined(CONFIG_USER_ONLY) -/* Context used internally during MMU translations */ -typedef struct mmu_ctx_t mmu_ctx_t; -struct mmu_ctx_t { - hwaddr raddr; /* Real address */ - hwaddr eaddr; /* Effective address */ - int prot; /* Protection bits */ - hwaddr hash[2]; /* Pagetable hash values */ - target_ulong ptem; /* Virtual segment ID | API */ - int key; /* Access key */ - int nx; /* Non-execute area */ -}; -#endif - #include "cpu-qom.h" /*****************************************************************************/ @@ -1130,17 +1090,14 @@ int cpu_ppc_exec (CPUPPCState *s); is returned if the signal was handled by the virtual CPU. */ int cpu_ppc_signal_handler (int host_signum, void *pinfo, void *puc); -int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, - int mmu_idx); -#define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault void ppc_hw_interrupt (CPUPPCState *env); +#if defined(CONFIG_USER_ONLY) +int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx); +#endif #if !defined(CONFIG_USER_ONLY) void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); -#if defined(TARGET_PPC64) -void ppc_store_asr (CPUPPCState *env, target_ulong value); -int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); -#endif /* defined(TARGET_PPC64) */ #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr (CPUPPCState *env, target_ulong value); @@ -1172,14 +1129,13 @@ void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); -int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, - hwaddr *raddrp, target_ulong address, - uint32_t pid); void ppc_tlb_invalidate_all (CPUPPCState *env); void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); #endif #endif +void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask); + static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) { uint64_t gprv; @@ -1270,6 +1226,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_601_UDECR (0x006) #define SPR_LR (0x008) #define SPR_CTR (0x009) +#define SPR_UAMR (0x00C) #define SPR_DSCR (0x011) #define SPR_DSISR (0x012) #define SPR_DAR (0x013) /* DAE for PowerPC 601 */ @@ -1307,6 +1264,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_MPC_CMPH (0x09B) #define SPR_MPC_LCTRL1 (0x09C) #define SPR_MPC_LCTRL2 (0x09D) +#define SPR_UAMOR (0x09D) #define SPR_MPC_ICTRL (0x09E) #define SPR_MPC_BAR (0x09F) #define SPR_VRSAVE (0x100) @@ -1489,11 +1447,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_RCPU_MI_RBA2 (0x302) #define SPR_MPC_MI_AP (0x302) #define SPR_PERF3 (0x303) -#define SPR_620_PMC1R (0x303) #define SPR_RCPU_MI_RBA3 (0x303) #define SPR_MPC_MI_EPN (0x303) #define SPR_PERF4 (0x304) -#define SPR_620_PMC2R (0x304) #define SPR_PERF5 (0x305) #define SPR_MPC_MI_TWC (0x305) #define SPR_PERF6 (0x306) @@ -1509,7 +1465,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_RCPU_L2U_RBA2 (0x30A) #define SPR_MPC_MD_AP (0x30A) #define SPR_PERFB (0x30B) -#define SPR_620_MMCR0R (0x30B) #define SPR_RCPU_L2U_RBA3 (0x30B) #define SPR_MPC_MD_EPN (0x30B) #define SPR_PERFC (0x30C) @@ -1524,9 +1479,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_UPERF1 (0x311) #define SPR_UPERF2 (0x312) #define SPR_UPERF3 (0x313) -#define SPR_620_PMC1W (0x313) #define SPR_UPERF4 (0x314) -#define SPR_620_PMC2W (0x314) #define SPR_UPERF5 (0x315) #define SPR_UPERF6 (0x316) #define SPR_UPERF7 (0x317) @@ -1534,7 +1487,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_UPERF9 (0x319) #define SPR_UPERFA (0x31A) #define SPR_UPERFB (0x31B) -#define SPR_620_MMCR0W (0x31B) #define SPR_UPERFC (0x31C) #define SPR_UPERFD (0x31D) #define SPR_UPERFE (0x31E) @@ -1606,49 +1558,33 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_USDA (0x3AF) #define SPR_40x_ZPR (0x3B0) #define SPR_BOOKE_MAS7 (0x3B0) -#define SPR_620_PMR0 (0x3B0) #define SPR_MMCR2 (0x3B0) #define SPR_PMC5 (0x3B1) #define SPR_40x_PID (0x3B1) -#define SPR_620_PMR1 (0x3B1) #define SPR_PMC6 (0x3B2) #define SPR_440_MMUCR (0x3B2) -#define SPR_620_PMR2 (0x3B2) #define SPR_4xx_CCR0 (0x3B3) #define SPR_BOOKE_EPLC (0x3B3) -#define SPR_620_PMR3 (0x3B3) #define SPR_405_IAC3 (0x3B4) #define SPR_BOOKE_EPSC (0x3B4) -#define SPR_620_PMR4 (0x3B4) #define SPR_405_IAC4 (0x3B5) -#define SPR_620_PMR5 (0x3B5) #define SPR_405_DVC1 (0x3B6) -#define SPR_620_PMR6 (0x3B6) #define SPR_405_DVC2 (0x3B7) -#define SPR_620_PMR7 (0x3B7) #define SPR_BAMR (0x3B7) #define SPR_MMCR0 (0x3B8) -#define SPR_620_PMR8 (0x3B8) #define SPR_PMC1 (0x3B9) #define SPR_40x_SGR (0x3B9) -#define SPR_620_PMR9 (0x3B9) #define SPR_PMC2 (0x3BA) #define SPR_40x_DCWR (0x3BA) -#define SPR_620_PMRA (0x3BA) #define SPR_SIAR (0x3BB) #define SPR_405_SLER (0x3BB) -#define SPR_620_PMRB (0x3BB) #define SPR_MMCR1 (0x3BC) #define SPR_405_SU0R (0x3BC) -#define SPR_620_PMRC (0x3BC) #define SPR_401_SKR (0x3BC) #define SPR_PMC3 (0x3BD) #define SPR_405_DBCR1 (0x3BD) -#define SPR_620_PMRD (0x3BD) #define SPR_PMC4 (0x3BE) -#define SPR_620_PMRE (0x3BE) #define SPR_SDA (0x3BF) -#define SPR_620_PMRF (0x3BF) #define SPR_403_VTBL (0x3CC) #define SPR_403_VTBU (0x3CD) #define SPR_DMISS (0x3D0) @@ -1716,15 +1652,12 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define SPR_LDSTCR (0x3F8) #define SPR_L2PMCR (0x3F8) #define SPR_750FX_HID2 (0x3F8) -#define SPR_620_BUSCSR (0x3F8) #define SPR_Exxx_L1FINV0 (0x3F8) #define SPR_L2CR (0x3F9) -#define SPR_620_L2CR (0x3F9) #define SPR_L3CR (0x3FA) #define SPR_750_TDCH (0x3FA) #define SPR_IABR2 (0x3FA) #define SPR_40x_DCCR (0x3FA) -#define SPR_620_L2SR (0x3FA) #define SPR_ICTC (0x3FB) #define SPR_40x_ICCR (0x3FB) #define SPR_THRM1 (0x3FC) diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index 9d67926209..9e779eace6 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -463,6 +463,11 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) fpscr_set_rounding_mode(env); } +void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) +{ + helper_store_fpscr(env, arg, mask); +} + void helper_float_check_status(CPUPPCState *env) { if (env->exception_index == POWERPC_EXCP_PROGRAM && diff --git a/target-ppc/helper.h b/target-ppc/helper.h index fcf372ab45..d33ee66b53 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -382,7 +382,6 @@ DEF_HELPER_1(load_601_rtcl, tl, env) DEF_HELPER_1(load_601_rtcu, tl, env) #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) -DEF_HELPER_2(store_asr, void, env, tl) DEF_HELPER_1(load_purr, tl, env) #endif DEF_HELPER_2(store_sdr1, void, env, tl) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index e663ff0acb..597066f5a0 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -32,6 +32,7 @@ #include "sysemu/device_tree.h" #include "hw/sysbus.h" #include "hw/spapr.h" +#include "mmu-hash64.h" #include "hw/sysbus.h" #include "hw/spapr.h" @@ -1077,7 +1078,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) dprintf("handle halt\n"); ret = kvmppc_handle_halt(cpu); break; -#ifdef CONFIG_PSERIES +#if defined(TARGET_PPC64) case KVM_EXIT_PAPR_HCALL: dprintf("handle PAPR hypercall\n"); run->papr_hcall.ret = spapr_hypercall(cpu, diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 708a840da7..235b0d5f49 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &fpscr); qemu_put_sbe32s(f, &env->access_type); #if defined(TARGET_PPC64) - qemu_put_betls(f, &env->asr); + qemu_put_betls(f, &env->spr[SPR_ASR]); qemu_put_sbe32s(f, &env->slb_nr); #endif qemu_put_betls(f, &env->spr[SPR_SDR1]); @@ -125,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->fpscr = fpscr; qemu_get_sbe32s(f, &env->access_type); #if defined(TARGET_PPC64) - qemu_get_betls(f, &env->asr); + qemu_get_betls(f, &env->spr[SPR_ASR]); qemu_get_sbe32s(f, &env->slb_nr); #endif qemu_get_betls(f, &sdr1); diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index ba383c8f11..9783e52b0c 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -252,41 +252,3 @@ STVE(stvewx, cpu_stl_data, bswap32, u32) #undef HI_IDX #undef LO_IDX - -/*****************************************************************************/ -/* Softmmu support */ -#if !defined(CONFIG_USER_ONLY) - -#define MMUSUFFIX _mmu - -#define SHIFT 0 -#include "exec/softmmu_template.h" - -#define SHIFT 1 -#include "exec/softmmu_template.h" - -#define SHIFT 2 -#include "exec/softmmu_template.h" - -#define SHIFT 3 -#include "exec/softmmu_template.h" - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx, - uintptr_t retaddr) -{ - int ret; - - ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx); - if (unlikely(ret != 0)) { - if (likely(retaddr)) { - /* now we have a real cpu fault */ - cpu_restore_state(env, retaddr); - } - helper_raise_exception_err(env, env->exception_index, env->error_code); - } -} -#endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index 26edcca2df..616aab6fb6 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -35,12 +35,6 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn) env->spr[sprn]); } #if !defined(CONFIG_USER_ONLY) -#if defined(TARGET_PPC64) -void helper_store_asr(CPUPPCState *env, target_ulong val) -{ - ppc_store_asr(env, val); -} -#endif void helper_store_sdr1(CPUPPCState *env, target_ulong val) { diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c new file mode 100644 index 0000000000..f6adf2245e --- /dev/null +++ b/target-ppc/mmu-hash32.c @@ -0,0 +1,560 @@ +/* + * PowerPC MMU, TLB and BAT emulation helpers for QEMU. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright (c) 2013 David Gibson, IBM Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "helper.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" +#include "mmu-hash32.h" + +//#define DEBUG_MMU +//#define DEBUG_BAT + +#ifdef DEBUG_MMU +# define LOG_MMU(...) qemu_log(__VA_ARGS__) +# define LOG_MMU_STATE(env) log_cpu_state((env), 0) +#else +# define LOG_MMU(...) do { } while (0) +# define LOG_MMU_STATE(...) do { } while (0) +#endif + +#ifdef DEBUG_BATS +# define LOG_BATS(...) qemu_log(__VA_ARGS__) +#else +# define LOG_BATS(...) do { } while (0) +#endif + +struct mmu_ctx_hash32 { + hwaddr raddr; /* Real address */ + int prot; /* Protection bits */ + int key; /* Access key */ +}; + +static int ppc_hash32_pp_prot(int key, int pp, int nx) +{ + int prot; + + if (key == 0) { + switch (pp) { + case 0x0: + case 0x1: + case 0x2: + prot = PAGE_READ | PAGE_WRITE; + break; + + case 0x3: + prot = PAGE_READ; + break; + + default: + abort(); + } + } else { + switch (pp) { + case 0x0: + prot = 0; + break; + + case 0x1: + case 0x3: + prot = PAGE_READ; + break; + + case 0x2: + prot = PAGE_READ | PAGE_WRITE; + break; + + default: + abort(); + } + } + if (nx == 0) { + prot |= PAGE_EXEC; + } + + return prot; +} + +static int ppc_hash32_pte_prot(CPUPPCState *env, + target_ulong sr, ppc_hash_pte32_t pte) +{ + unsigned pp, key; + + key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS)); + pp = pte.pte1 & HPTE32_R_PP; + + return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX)); +} + +static target_ulong hash32_bat_size(CPUPPCState *env, + target_ulong batu, target_ulong batl) +{ + if ((msr_pr && !(batu & BATU32_VP)) + || (!msr_pr && !(batu & BATU32_VS))) { + return 0; + } + + return BATU32_BEPI & ~((batu & BATU32_BL) << 15); +} + +static int hash32_bat_prot(CPUPPCState *env, + target_ulong batu, target_ulong batl) +{ + int pp, prot; + + prot = 0; + pp = batl & BATL32_PP; + if (pp != 0) { + prot = PAGE_READ | PAGE_EXEC; + if (pp == 0x2) { + prot |= PAGE_WRITE; + } + } + return prot; +} + +static target_ulong hash32_bat_601_size(CPUPPCState *env, + target_ulong batu, target_ulong batl) +{ + if (!(batl & BATL32_601_V)) { + return 0; + } + + return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17); +} + +static int hash32_bat_601_prot(CPUPPCState *env, + target_ulong batu, target_ulong batl) +{ + int key, pp; + + pp = batu & BATU32_601_PP; + if (msr_pr == 0) { + key = !!(batu & BATU32_601_KS); + } else { + key = !!(batu & BATU32_601_KP); + } + return ppc_hash32_pp_prot(key, pp, 0); +} + +static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx, + int *prot) +{ + target_ulong *BATlt, *BATut; + int i; + + LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, + rwx == 2 ? 'I' : 'D', ea); + if (rwx == 2) { + BATlt = env->IBAT[1]; + BATut = env->IBAT[0]; + } else { + BATlt = env->DBAT[1]; + BATut = env->DBAT[0]; + } + for (i = 0; i < env->nb_BATs; i++) { + target_ulong batu = BATut[i]; + target_ulong batl = BATlt[i]; + target_ulong mask; + + if (unlikely(env->mmu_model == POWERPC_MMU_601)) { + mask = hash32_bat_601_size(env, batu, batl); + } else { + mask = hash32_bat_size(env, batu, batl); + } + LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl); + + if (mask && ((ea & mask) == (batu & BATU32_BEPI))) { + hwaddr raddr = (batl & mask) | (ea & ~mask); + + if (unlikely(env->mmu_model == POWERPC_MMU_601)) { + *prot = hash32_bat_601_prot(env, batu, batl); + } else { + *prot = hash32_bat_prot(env, batu, batl); + } + + return raddr & TARGET_PAGE_MASK; + } + } + + /* No hit */ +#if defined(DEBUG_BATS) + if (qemu_log_enabled()) { + LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea); + for (i = 0; i < 4; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & BATU32_BEPIU; + BEPIl = *BATu & BATU32_BEPIL; + bl = (*BATu & 0x00001FFC) << 15; + LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx + " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " + TARGET_FMT_lx " " TARGET_FMT_lx "\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea, + *BATu, *BATl, BEPIu, BEPIl, bl); + } + } +#endif + + return -1; +} + +static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr, + target_ulong eaddr, int rwx, + hwaddr *raddr, int *prot) +{ + int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS)); + + LOG_MMU("direct store...\n"); + + if ((sr & 0x1FF00000) >> 20 == 0x07f) { + /* Memory-forced I/O controller interface access */ + /* If T=1 and BUID=x'07F', the 601 performs a memory access + * to SR[28-31] LA[4-31], bypassing all protection mechanisms. + */ + *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return 0; + } + + if (rwx == 2) { + /* No code fetch is allowed in direct-store areas */ + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; + return 1; + } + + switch (env->access_type) { + case ACCESS_INT: + /* Integer load/store : only access allowed */ + break; + case ACCESS_FLOAT: + /* Floating point load/store */ + env->exception_index = POWERPC_EXCP_ALIGN; + env->error_code = POWERPC_EXCP_ALIGN_FP; + env->spr[SPR_DAR] = eaddr; + return 1; + case ACCESS_RES: + /* lwarx, ldarx or srwcx. */ + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x06000000; + } else { + env->spr[SPR_DSISR] = 0x04000000; + } + return 1; + case ACCESS_CACHE: + /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */ + /* Should make the instruction do no-op. + * As it already do no-op, it's quite easy :-) + */ + *raddr = eaddr; + return 0; + case ACCESS_EXT: + /* eciwx or ecowx */ + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x06100000; + } else { + env->spr[SPR_DSISR] = 0x04100000; + } + return 1; + default: + qemu_log("ERROR: instruction should not need " + "address translation\n"); + abort(); + } + if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) { + *raddr = eaddr; + return 0; + } else { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x0a000000; + } else { + env->spr[SPR_DSISR] = 0x08000000; + } + return 1; + } +} + +hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash) +{ + return (hash * HASH_PTEG_SIZE_32) & env->htab_mask; +} + +static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off, + bool secondary, target_ulong ptem, + ppc_hash_pte32_t *pte) +{ + hwaddr pte_offset = pteg_off; + target_ulong pte0, pte1; + int i; + + for (i = 0; i < HPTES_PER_GROUP; i++) { + pte0 = ppc_hash32_load_hpte0(env, pte_offset); + pte1 = ppc_hash32_load_hpte1(env, pte_offset); + + if ((pte0 & HPTE32_V_VALID) + && (secondary == !!(pte0 & HPTE32_V_SECONDARY)) + && HPTE32_V_COMPARE(pte0, ptem)) { + pte->pte0 = pte0; + pte->pte1 = pte1; + return pte_offset; + } + + pte_offset += HASH_PTE_SIZE_32; + } + + return -1; +} + +static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env, + target_ulong sr, target_ulong eaddr, + ppc_hash_pte32_t *pte) +{ + hwaddr pteg_off, pte_offset; + hwaddr hash; + uint32_t vsid, pgidx, ptem; + + vsid = sr & SR32_VSID; + pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS; + hash = vsid ^ pgidx; + ptem = (vsid << 7) | (pgidx >> 10); + + /* Page address translation */ + LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + " hash " TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, hash); + + /* Primary PTEG lookup */ + LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=%" PRIx32 " ptem=%" PRIx32 + " hash=" TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, vsid, ptem, hash); + pteg_off = get_pteg_offset32(env, hash); + pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte); + if (pte_offset == -1) { + /* Secondary PTEG lookup */ + LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=%" PRIx32 " api=%" PRIx32 + " hash=" TARGET_FMT_plx "\n", env->htab_base, + env->htab_mask, vsid, ptem, ~hash); + pteg_off = get_pteg_offset32(env, ~hash); + pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte); + } + + return pte_offset; +} + +static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte, + target_ulong eaddr) +{ + hwaddr rpn = pte.pte1 & HPTE32_R_RPN; + hwaddr mask = ~TARGET_PAGE_MASK; + + return (rpn & ~mask) | (eaddr & mask); +} + +int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr, int rwx, + int mmu_idx) +{ + target_ulong sr; + hwaddr pte_offset; + ppc_hash_pte32_t pte; + int prot; + uint32_t new_pte1; + const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; + hwaddr raddr; + + assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + + /* 1. Handle real mode accesses */ + if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { + /* Translation is off */ + raddr = eaddr; + tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx, + TARGET_PAGE_SIZE); + return 0; + } + + /* 2. Check Block Address Translation entries (BATs) */ + if (env->nb_BATs != 0) { + raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &prot); + if (raddr != -1) { + if (need_prot[rwx] & ~prot) { + if (rwx == 2) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x08000000; + } else { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x0a000000; + } else { + env->spr[SPR_DSISR] = 0x08000000; + } + } + return 1; + } + + tlb_set_page(env, eaddr & TARGET_PAGE_MASK, + raddr & TARGET_PAGE_MASK, prot, mmu_idx, + TARGET_PAGE_SIZE); + return 0; + } + } + + /* 3. Look up the Segment Register */ + sr = env->sr[eaddr >> 28]; + + /* 4. Handle direct store segments */ + if (sr & SR32_T) { + if (ppc_hash32_direct_store(env, sr, eaddr, rwx, + &raddr, &prot) == 0) { + tlb_set_page(env, eaddr & TARGET_PAGE_MASK, + raddr & TARGET_PAGE_MASK, prot, mmu_idx, + TARGET_PAGE_SIZE); + return 0; + } else { + return 1; + } + } + + /* 5. Check for segment level no-execute violation */ + if ((rwx == 2) && (sr & SR32_NX)) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; + return 1; + } + + /* 6. Locate the PTE in the hash table */ + pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte); + if (pte_offset == -1) { + if (rwx == 2) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x42000000; + } else { + env->spr[SPR_DSISR] = 0x40000000; + } + } + + return 1; + } + LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); + + /* 7. Check access permissions */ + + prot = ppc_hash32_pte_prot(env, sr, pte); + + if (need_prot[rwx] & ~prot) { + /* Access right violation */ + LOG_MMU("PTE access rejected\n"); + if (rwx == 2) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x08000000; + } else { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x0a000000; + } else { + env->spr[SPR_DSISR] = 0x08000000; + } + } + return 1; + } + + LOG_MMU("PTE access granted !\n"); + + /* 8. Update PTE referenced and changed bits if necessary */ + + new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */ + if (rwx == 1) { + new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */ + } else { + /* Treat the page as read-only for now, so that a later write + * will pass through this function again to set the C bit */ + prot &= ~PAGE_WRITE; + } + + if (new_pte1 != pte.pte1) { + ppc_hash32_store_hpte1(env, pte_offset, new_pte1); + } + + /* 9. Determine the real address from the PTE */ + + raddr = ppc_hash32_pte_raddr(sr, pte, eaddr); + + tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, + prot, mmu_idx, TARGET_PAGE_SIZE); + + return 0; +} + +hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong eaddr) +{ + target_ulong sr; + hwaddr pte_offset; + ppc_hash_pte32_t pte; + int prot; + + if (msr_dr == 0) { + /* Translation is off */ + return eaddr; + } + + if (env->nb_BATs != 0) { + hwaddr raddr = ppc_hash32_bat_lookup(env, eaddr, 0, &prot); + if (raddr != -1) { + return raddr; + } + } + + sr = env->sr[eaddr >> 28]; + + if (sr & SR32_T) { + /* FIXME: Add suitable debug support for Direct Store segments */ + return -1; + } + + pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte); + if (pte_offset == -1) { + return -1; + } + + return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK; +} diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h new file mode 100644 index 0000000000..884786b97a --- /dev/null +++ b/target-ppc/mmu-hash32.h @@ -0,0 +1,102 @@ +#if !defined (__MMU_HASH32_H__) +#define __MMU_HASH32_H__ + +#ifndef CONFIG_USER_ONLY + +hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash); +hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr); +int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx); + +/* + * Segment register definitions + */ + +#define SR32_T 0x80000000 +#define SR32_KS 0x40000000 +#define SR32_KP 0x20000000 +#define SR32_NX 0x10000000 +#define SR32_VSID 0x00ffffff + +/* + * Block Address Translation (BAT) definitions + */ + +#define BATU32_BEPI 0xfffe0000 +#define BATU32_BL 0x00001ffc +#define BATU32_VS 0x00000002 +#define BATU32_VP 0x00000001 + + +#define BATL32_BRPN 0xfffe0000 +#define BATL32_WIMG 0x00000078 +#define BATL32_PP 0x00000003 + +/* PowerPC 601 has slightly different BAT registers */ + +#define BATU32_601_KS 0x00000008 +#define BATU32_601_KP 0x00000004 +#define BATU32_601_PP 0x00000003 + +#define BATL32_601_V 0x00000040 +#define BATL32_601_BL 0x0000003f + +/* + * Hash page table definitions + */ + +#define HPTES_PER_GROUP 8 +#define HASH_PTE_SIZE_32 8 +#define HASH_PTEG_SIZE_32 (HASH_PTE_SIZE_32 * HPTES_PER_GROUP) + +#define HPTE32_V_VALID 0x80000000 +#define HPTE32_V_VSID 0x7fffff80 +#define HPTE32_V_SECONDARY 0x00000040 +#define HPTE32_V_API 0x0000003f +#define HPTE32_V_COMPARE(x, y) (!(((x) ^ (y)) & 0x7fffffbf)) + +#define HPTE32_R_RPN 0xfffff000 +#define HPTE32_R_R 0x00000100 +#define HPTE32_R_C 0x00000080 +#define HPTE32_R_W 0x00000040 +#define HPTE32_R_I 0x00000020 +#define HPTE32_R_M 0x00000010 +#define HPTE32_R_G 0x00000008 +#define HPTE32_R_WIMG 0x00000078 +#define HPTE32_R_PP 0x00000003 + +static inline target_ulong ppc_hash32_load_hpte0(CPUPPCState *env, + hwaddr pte_offset) +{ + assert(!env->external_htab); /* Not supported on 32-bit for now */ + return ldl_phys(env->htab_base + pte_offset); +} + +static inline target_ulong ppc_hash32_load_hpte1(CPUPPCState *env, + hwaddr pte_offset) +{ + assert(!env->external_htab); /* Not supported on 32-bit for now */ + return ldl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2); +} + +static inline void ppc_hash32_store_hpte0(CPUPPCState *env, + hwaddr pte_offset, target_ulong pte0) +{ + assert(!env->external_htab); /* Not supported on 32-bit for now */ + stl_phys(env->htab_base + pte_offset, pte0); +} + +static inline void ppc_hash32_store_hpte1(CPUPPCState *env, + hwaddr pte_offset, target_ulong pte1) +{ + assert(!env->external_htab); /* Not supported on 32-bit for now */ + stl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2, pte1); +} + +typedef struct { + uint32_t pte0, pte1; +} ppc_hash_pte32_t; + +#endif /* CONFIG_USER_ONLY */ + +#endif /* __MMU_HASH32_H__ */ diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c new file mode 100644 index 0000000000..43ccf456e3 --- /dev/null +++ b/target-ppc/mmu-hash64.c @@ -0,0 +1,546 @@ +/* + * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright (c) 2013 David Gibson, IBM Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "cpu.h" +#include "helper.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" +#include "mmu-hash64.h" + +//#define DEBUG_MMU +//#define DEBUG_SLB + +#ifdef DEBUG_MMU +# define LOG_MMU(...) qemu_log(__VA_ARGS__) +# define LOG_MMU_STATE(env) log_cpu_state((env), 0) +#else +# define LOG_MMU(...) do { } while (0) +# define LOG_MMU_STATE(...) do { } while (0) +#endif + +#ifdef DEBUG_SLB +# define LOG_SLB(...) qemu_log(__VA_ARGS__) +#else +# define LOG_SLB(...) do { } while (0) +#endif + +/* + * SLB handling + */ + +static ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) +{ + uint64_t esid_256M, esid_1T; + int n; + + LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); + + esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; + esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V; + + for (n = 0; n < env->slb_nr; n++) { + ppc_slb_t *slb = &env->slb[n]; + + LOG_SLB("%s: slot %d %016" PRIx64 " %016" + PRIx64 "\n", __func__, n, slb->esid, slb->vsid); + /* We check for 1T matches on all MMUs here - if the MMU + * doesn't have 1T segment support, we will have prevented 1T + * entries from being inserted in the slbmte code. */ + if (((slb->esid == esid_256M) && + ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) + || ((slb->esid == esid_1T) && + ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) { + return slb; + } + } + + return NULL; +} + +void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) +{ + int i; + uint64_t slbe, slbv; + + cpu_synchronize_state(env); + + cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n"); + for (i = 0; i < env->slb_nr; i++) { + slbe = env->slb[i].esid; + slbv = env->slb[i].vsid; + if (slbe == 0 && slbv == 0) { + continue; + } + cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", + i, slbe, slbv); + } +} + +void helper_slbia(CPUPPCState *env) +{ + int n, do_invalidate; + + do_invalidate = 0; + /* XXX: Warning: slbia never invalidates the first segment */ + for (n = 1; n < env->slb_nr; n++) { + ppc_slb_t *slb = &env->slb[n]; + + if (slb->esid & SLB_ESID_V) { + slb->esid &= ~SLB_ESID_V; + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in QEMU, we just invalidate all TLBs + */ + do_invalidate = 1; + } + } + if (do_invalidate) { + tlb_flush(env, 1); + } +} + +void helper_slbie(CPUPPCState *env, target_ulong addr) +{ + ppc_slb_t *slb; + + slb = slb_lookup(env, addr); + if (!slb) { + return; + } + + if (slb->esid & SLB_ESID_V) { + slb->esid &= ~SLB_ESID_V; + + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in QEMU, we just invalidate all TLBs + */ + tlb_flush(env, 1); + } +} + +int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (rb & (0x1000 - env->slb_nr)) { + return -1; /* Reserved bits set or slot too high */ + } + if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) { + return -1; /* Bad segment size */ + } + if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) { + return -1; /* 1T segment on MMU that doesn't support it */ + } + + /* Mask out the slot number as we store the entry */ + slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V); + slb->vsid = rs; + + LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 + " %016" PRIx64 "\n", __func__, slot, rb, rs, + slb->esid, slb->vsid); + + return 0; +} + +static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, + target_ulong *rt) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + *rt = slb->esid; + return 0; +} + +static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, + target_ulong *rt) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + *rt = slb->vsid; + return 0; +} + +void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) +{ + if (ppc_store_slb(env, rb, rs) < 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); + } +} + +target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) +{ + target_ulong rt = 0; + + if (ppc_load_slb_esid(env, rb, &rt) < 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); + } + return rt; +} + +target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) +{ + target_ulong rt = 0; + + if (ppc_load_slb_vsid(env, rb, &rt) < 0) { + helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL); + } + return rt; +} + +/* + * 64-bit hash table MMU handling + */ + +static int ppc_hash64_pte_prot(CPUPPCState *env, + ppc_slb_t *slb, ppc_hash_pte64_t pte) +{ + unsigned pp, key; + /* Some pp bit combinations have undefined behaviour, so default + * to no access in those cases */ + int prot = 0; + + key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP) + : (slb->vsid & SLB_VSID_KS)); + pp = (pte.pte1 & HPTE64_R_PP) | ((pte.pte1 & HPTE64_R_PP0) >> 61); + + if (key == 0) { + switch (pp) { + case 0x0: + case 0x1: + case 0x2: + prot = PAGE_READ | PAGE_WRITE; + break; + + case 0x3: + case 0x6: + prot = PAGE_READ; + break; + } + } else { + switch (pp) { + case 0x0: + case 0x6: + prot = 0; + break; + + case 0x1: + case 0x3: + prot = PAGE_READ; + break; + + case 0x2: + prot = PAGE_READ | PAGE_WRITE; + break; + } + } + + /* No execute if either noexec or guarded bits set */ + if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G) + || (slb->vsid & SLB_VSID_N)) { + prot |= PAGE_EXEC; + } + + return prot; +} + +static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte) +{ + int key, amrbits; + int prot = PAGE_EXEC; + + + /* Only recent MMUs implement Virtual Page Class Key Protection */ + if (!(env->mmu_model & POWERPC_MMU_AMR)) { + return PAGE_READ | PAGE_WRITE | PAGE_EXEC; + } + + key = HPTE64_R_KEY(pte.pte1); + amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3; + + /* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */ + /* env->spr[SPR_AMR]); */ + + if (amrbits & 0x2) { + prot |= PAGE_WRITE; + } + if (amrbits & 0x1) { + prot |= PAGE_READ; + } + + return prot; +} + +static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off, + bool secondary, target_ulong ptem, + ppc_hash_pte64_t *pte) +{ + hwaddr pte_offset = pteg_off; + target_ulong pte0, pte1; + int i; + + for (i = 0; i < HPTES_PER_GROUP; i++) { + pte0 = ppc_hash64_load_hpte0(env, pte_offset); + pte1 = ppc_hash64_load_hpte1(env, pte_offset); + + if ((pte0 & HPTE64_V_VALID) + && (secondary == !!(pte0 & HPTE64_V_SECONDARY)) + && HPTE64_V_COMPARE(pte0, ptem)) { + pte->pte0 = pte0; + pte->pte1 = pte1; + return pte_offset; + } + + pte_offset += HASH_PTE_SIZE_64; + } + + return -1; +} + +static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env, + ppc_slb_t *slb, target_ulong eaddr, + ppc_hash_pte64_t *pte) +{ + hwaddr pteg_off, pte_offset; + hwaddr hash; + uint64_t vsid, epnshift, epnmask, epn, ptem; + + /* Page size according to the SLB, which we use to generate the + * EPN for hash table lookup.. When we implement more recent MMU + * extensions this might be different from the actual page size + * encoded in the PTE */ + epnshift = (slb->vsid & SLB_VSID_L) + ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; + epnmask = ~((1ULL << epnshift) - 1); + + if (slb->vsid & SLB_VSID_B) { + /* 1TB segment */ + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T; + epn = (eaddr & ~SEGMENT_MASK_1T) & epnmask; + hash = vsid ^ (vsid << 25) ^ (epn >> epnshift); + } else { + /* 256M segment */ + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + epn = (eaddr & ~SEGMENT_MASK_256M) & epnmask; + hash = vsid ^ (epn >> epnshift); + } + ptem = (slb->vsid & SLB_VSID_PTEM) | ((epn >> 16) & HPTE64_V_AVPN); + + /* Page address translation */ + LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + " hash " TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, hash); + + /* Primary PTEG lookup */ + LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, vsid, ptem, hash); + pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask; + pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte); + + if (pte_offset == -1) { + /* Secondary PTEG lookup */ + LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx "\n", env->htab_base, + env->htab_mask, vsid, ptem, ~hash); + + pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask; + pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte); + } + + return pte_offset; +} + +static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte, + target_ulong eaddr) +{ + hwaddr rpn = pte.pte1 & HPTE64_R_RPN; + /* FIXME: Add support for SLLP extended page sizes */ + int target_page_bits = (slb->vsid & SLB_VSID_L) + ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; + hwaddr mask = (1ULL << target_page_bits) - 1; + + return (rpn & ~mask) | (eaddr & mask); +} + +int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr, + int rwx, int mmu_idx) +{ + ppc_slb_t *slb; + hwaddr pte_offset; + ppc_hash_pte64_t pte; + int pp_prot, amr_prot, prot; + uint64_t new_pte1; + const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; + hwaddr raddr; + + assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + + /* 1. Handle real mode accesses */ + if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { + /* Translation is off */ + /* In real mode the top 4 effective address bits are ignored */ + raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; + tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx, + TARGET_PAGE_SIZE); + return 0; + } + + /* 2. Translation is on, so look up the SLB */ + slb = slb_lookup(env, eaddr); + + if (!slb) { + if (rwx == 2) { + env->exception_index = POWERPC_EXCP_ISEG; + env->error_code = 0; + } else { + env->exception_index = POWERPC_EXCP_DSEG; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + } + return 1; + } + + /* 3. Check for segment level no-execute violation */ + if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; + return 1; + } + + /* 4. Locate the PTE in the hash table */ + pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte); + if (pte_offset == -1) { + if (rwx == 2) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x42000000; + } else { + env->spr[SPR_DSISR] = 0x40000000; + } + } + return 1; + } + LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); + + /* 5. Check access permissions */ + + pp_prot = ppc_hash64_pte_prot(env, slb, pte); + amr_prot = ppc_hash64_amr_prot(env, pte); + prot = pp_prot & amr_prot; + + if ((need_prot[rwx] & ~prot) != 0) { + /* Access right violation */ + LOG_MMU("PTE access rejected\n"); + if (rwx == 2) { + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x08000000; + } else { + target_ulong dsisr = 0; + + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (need_prot[rwx] & ~pp_prot) { + dsisr |= 0x08000000; + } + if (rwx == 1) { + dsisr |= 0x02000000; + } + if (need_prot[rwx] & ~amr_prot) { + dsisr |= 0x00200000; + } + env->spr[SPR_DSISR] = dsisr; + } + return 1; + } + + LOG_MMU("PTE access granted !\n"); + + /* 6. Update PTE referenced and changed bits if necessary */ + + new_pte1 = pte.pte1 | HPTE64_R_R; /* set referenced bit */ + if (rwx == 1) { + new_pte1 |= HPTE64_R_C; /* set changed (dirty) bit */ + } else { + /* Treat the page as read-only for now, so that a later write + * will pass through this function again to set the C bit */ + prot &= ~PAGE_WRITE; + } + + if (new_pte1 != pte.pte1) { + ppc_hash64_store_hpte1(env, pte_offset, new_pte1); + } + + /* 7. Determine the real address from the PTE */ + + raddr = ppc_hash64_pte_raddr(slb, pte, eaddr); + + tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, + prot, mmu_idx, TARGET_PAGE_SIZE); + + return 0; +} + +hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr) +{ + ppc_slb_t *slb; + hwaddr pte_offset; + ppc_hash_pte64_t pte; + + if (msr_dr == 0) { + /* In real mode the top 4 effective address bits are ignored */ + return addr & 0x0FFFFFFFFFFFFFFFULL; + } + + slb = slb_lookup(env, addr); + if (!slb) { + return -1; + } + + pte_offset = ppc_hash64_htab_lookup(env, slb, addr, &pte); + if (pte_offset == -1) { + return -1; + } + + return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK; +} diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h new file mode 100644 index 0000000000..55f5a230fd --- /dev/null +++ b/target-ppc/mmu-hash64.h @@ -0,0 +1,124 @@ +#if !defined (__MMU_HASH64_H__) +#define __MMU_HASH64_H__ + +#ifndef CONFIG_USER_ONLY + +#ifdef TARGET_PPC64 +void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); +int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); +hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr); +int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx); +#endif + +/* + * SLB definitions + */ + +/* Bits in the SLB ESID word */ +#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL +#define SLB_ESID_V 0x0000000008000000ULL /* valid */ + +/* Bits in the SLB VSID word */ +#define SLB_VSID_SHIFT 12 +#define SLB_VSID_SHIFT_1T 24 +#define SLB_VSID_SSIZE_SHIFT 62 +#define SLB_VSID_B 0xc000000000000000ULL +#define SLB_VSID_B_256M 0x0000000000000000ULL +#define SLB_VSID_B_1T 0x4000000000000000ULL +#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL +#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID) +#define SLB_VSID_KS 0x0000000000000800ULL +#define SLB_VSID_KP 0x0000000000000400ULL +#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */ +#define SLB_VSID_L 0x0000000000000100ULL +#define SLB_VSID_C 0x0000000000000080ULL /* class */ +#define SLB_VSID_LP 0x0000000000000030ULL +#define SLB_VSID_ATTR 0x0000000000000FFFULL + +/* + * Hash page table definitions + */ + +#define HPTES_PER_GROUP 8 +#define HASH_PTE_SIZE_64 16 +#define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP) + +#define HPTE64_V_SSIZE_SHIFT 62 +#define HPTE64_V_AVPN_SHIFT 7 +#define HPTE64_V_AVPN 0x3fffffffffffff80ULL +#define HPTE64_V_AVPN_VAL(x) (((x) & HPTE64_V_AVPN) >> HPTE64_V_AVPN_SHIFT) +#define HPTE64_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80ULL)) +#define HPTE64_V_LARGE 0x0000000000000004ULL +#define HPTE64_V_SECONDARY 0x0000000000000002ULL +#define HPTE64_V_VALID 0x0000000000000001ULL + +#define HPTE64_R_PP0 0x8000000000000000ULL +#define HPTE64_R_TS 0x4000000000000000ULL +#define HPTE64_R_KEY_HI 0x3000000000000000ULL +#define HPTE64_R_RPN_SHIFT 12 +#define HPTE64_R_RPN 0x0ffffffffffff000ULL +#define HPTE64_R_FLAGS 0x00000000000003ffULL +#define HPTE64_R_PP 0x0000000000000003ULL +#define HPTE64_R_N 0x0000000000000004ULL +#define HPTE64_R_G 0x0000000000000008ULL +#define HPTE64_R_M 0x0000000000000010ULL +#define HPTE64_R_I 0x0000000000000020ULL +#define HPTE64_R_W 0x0000000000000040ULL +#define HPTE64_R_WIMG 0x0000000000000078ULL +#define HPTE64_R_C 0x0000000000000080ULL +#define HPTE64_R_R 0x0000000000000100ULL +#define HPTE64_R_KEY_LO 0x0000000000000e00ULL +#define HPTE64_R_KEY(x) ((((x) & HPTE64_R_KEY_HI) >> 60) | \ + (((x) & HPTE64_R_KEY_LO) >> 9)) + +#define HPTE64_V_1TB_SEG 0x4000000000000000ULL +#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL + +static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env, + hwaddr pte_offset) +{ + if (env->external_htab) { + return ldq_p(env->external_htab + pte_offset); + } else { + return ldq_phys(env->htab_base + pte_offset); + } +} + +static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env, + hwaddr pte_offset) +{ + if (env->external_htab) { + return ldq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2); + } else { + return ldq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2); + } +} + +static inline void ppc_hash64_store_hpte0(CPUPPCState *env, + hwaddr pte_offset, target_ulong pte0) +{ + if (env->external_htab) { + stq_p(env->external_htab + pte_offset, pte0); + } else { + stq_phys(env->htab_base + pte_offset, pte0); + } +} + +static inline void ppc_hash64_store_hpte1(CPUPPCState *env, + hwaddr pte_offset, target_ulong pte1) +{ + if (env->external_htab) { + stq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2, pte1); + } else { + stq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2, pte1); + } +} + +typedef struct { + uint64_t pte0, pte1; +} ppc_hash_pte64_t; + +#endif /* CONFIG_USER_ONLY */ + +#endif /* !defined (__MMU_HASH64_H__) */ diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 1cc1c1649a..acf01331f1 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -20,10 +20,11 @@ #include "helper.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" +#include "mmu-hash64.h" +#include "mmu-hash32.h" //#define DEBUG_MMU //#define DEBUG_BATS -//#define DEBUG_SLB //#define DEBUG_SOFTWARE_TLB //#define DUMP_PAGE_TABLES //#define DEBUG_SOFTWARE_TLB @@ -49,39 +50,21 @@ # define LOG_BATS(...) do { } while (0) #endif -#ifdef DEBUG_SLB -# define LOG_SLB(...) qemu_log(__VA_ARGS__) -#else -# define LOG_SLB(...) do { } while (0) -#endif - /*****************************************************************************/ /* PowerPC MMU emulation */ -#if defined(CONFIG_USER_ONLY) -int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, - int mmu_idx) -{ - int exception, error_code; - if (rw == 2) { - exception = POWERPC_EXCP_ISI; - error_code = 0x40000000; - } else { - exception = POWERPC_EXCP_DSI; - error_code = 0x40000000; - if (rw) { - error_code |= 0x02000000; - } - env->spr[SPR_DAR] = address; - env->spr[SPR_DSISR] = error_code; - } - env->exception_index = exception; - env->error_code = error_code; - - return 1; -} +/* Context used internally during MMU translations */ +typedef struct mmu_ctx_t mmu_ctx_t; +struct mmu_ctx_t { + hwaddr raddr; /* Real address */ + hwaddr eaddr; /* Effective address */ + int prot; /* Protection bits */ + hwaddr hash[2]; /* Pagetable hash values */ + target_ulong ptem; /* Virtual segment ID | API */ + int key; /* Access key */ + int nx; /* Non-execute area */ +}; -#else /* Common routines used by software and hardware TLBs emulation */ static inline int pte_is_valid(target_ulong pte0) { @@ -93,31 +76,14 @@ static inline void pte_invalidate(target_ulong *pte0) *pte0 &= ~0x80000000; } -#if defined(TARGET_PPC64) -static inline int pte64_is_valid(target_ulong pte0) -{ - return pte0 & 0x0000000000000001ULL ? 1 : 0; -} - -static inline void pte64_invalidate(target_ulong *pte0) -{ - *pte0 &= ~0x0000000000000001ULL; -} -#endif - #define PTE_PTEM_MASK 0x7FFFFFBF #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) -#if defined(TARGET_PPC64) -#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL -#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) -#endif -static inline int pp_check(int key, int pp, int nx) +static int pp_check(int key, int pp, int nx) { int access; /* Compute access rights */ - /* When pp is 3/7, the result is undefined. Set it to noaccess */ access = 0; if (key == 0) { switch (pp) { @@ -127,14 +93,12 @@ static inline int pp_check(int key, int pp, int nx) access |= PAGE_WRITE; /* No break here */ case 0x3: - case 0x6: access |= PAGE_READ; break; } } else { switch (pp) { case 0x0: - case 0x6: access = 0; break; case 0x1: @@ -153,7 +117,7 @@ static inline int pp_check(int key, int pp, int nx) return access; } -static inline int check_prot(int prot, int rw, int access_type) +static int check_prot(int prot, int rw, int access_type) { int ret; @@ -180,40 +144,21 @@ static inline int check_prot(int prot, int rw, int access_type) return ret; } -static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) +static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) { target_ulong ptem, mmask; int access, ret, pteh, ptev, pp; ret = -1; /* Check validity and table match */ -#if defined(TARGET_PPC64) - if (is_64b) { - ptev = pte64_is_valid(pte0); - pteh = (pte0 >> 1) & 1; - } else -#endif - { - ptev = pte_is_valid(pte0); - pteh = (pte0 >> 6) & 1; - } + ptev = pte_is_valid(pte0); + pteh = (pte0 >> 6) & 1; if (ptev && h == pteh) { /* Check vsid & api */ -#if defined(TARGET_PPC64) - if (is_64b) { - ptem = pte0 & PTE64_PTEM_MASK; - mmask = PTE64_CHECK_MASK; - pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004); - ctx->nx = (pte1 >> 2) & 1; /* No execute bit */ - ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */ - } else -#endif - { - ptem = pte0 & PTE_PTEM_MASK; - mmask = PTE_CHECK_MASK; - pp = pte1 & 0x00000003; - } + ptem = pte0 & PTE_PTEM_MASK; + mmask = PTE_CHECK_MASK; + pp = pte1 & 0x00000003; if (ptem == ctx->ptem) { if (ctx->raddr != (hwaddr)-1ULL) { /* all matches should have equal RPN, WIMG & PP */ @@ -241,22 +186,8 @@ static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0, return ret; } -static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) -{ - return pte_check(ctx, 0, pte0, pte1, h, rw, type); -} - -#if defined(TARGET_PPC64) -static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) -{ - return pte_check(ctx, 1, pte0, pte1, h, rw, type); -} -#endif - -static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, - int ret, int rw) +static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, + int ret, int rw) { int store = 0; @@ -392,7 +323,7 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, pte_is_valid(tlb->pte0) ? "valid" : "inval", tlb->EPN, eaddr, tlb->pte1, rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); - switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { + switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { case -3: /* TLB inconsistency */ return -1; @@ -454,34 +385,8 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, *protp = prot; } -static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp, - int *validp, int *protp, - target_ulong *BATu, target_ulong *BATl) -{ - target_ulong bl; - int key, pp, valid, prot; - - bl = (*BATl & 0x0000003F) << 17; - LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n", - (uint8_t)(*BATl & 0x0000003F), bl, ~bl); - prot = 0; - valid = (*BATl >> 6) & 1; - if (valid) { - pp = *BATu & 0x00000003; - if (msr_pr == 0) { - key = (*BATu >> 3) & 1; - } else { - key = (*BATu >> 2) & 1; - } - prot = pp_check(key, pp, 0); - } - *blp = bl; - *validp = valid; - *protp = prot; -} - -static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong virtual, int rw, int type) +static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong virtual, int rw, int type) { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong BEPIl, BEPIu, bl; @@ -505,11 +410,7 @@ static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, BATl = &BATlt[i]; BEPIu = *BATu & 0xF0000000; BEPIl = *BATu & 0x0FFE0000; - if (unlikely(env->mmu_model == POWERPC_MMU_601)) { - bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); - } else { - bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); - } + bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); @@ -556,332 +457,35 @@ static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -static inline hwaddr get_pteg_offset(CPUPPCState *env, - hwaddr hash, - int pte_size) -{ - return (hash * pte_size * 8) & env->htab_mask; -} - -/* PTE table lookup */ -static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, - int rw, int type, int target_page_bits) -{ - hwaddr pteg_off; - target_ulong pte0, pte1; - int i, good = -1; - int ret, r; - - ret = -1; /* No entry found */ - pteg_off = get_pteg_offset(env, ctx->hash[h], - is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32); - for (i = 0; i < 8; i++) { -#if defined(TARGET_PPC64) - if (is_64b) { - if (env->external_htab) { - pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); - pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); - } else { - pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); - pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); - } - - r = pte64_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " " - TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h, - (int)((pte0 >> 1) & 1), ctx->ptem); - } else -#endif - { - if (env->external_htab) { - pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); - pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); - } else { - pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); - pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); - } - r = pte32_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " " - TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, - (int)((pte0 >> 6) & 1), ctx->ptem); - } - switch (r) { - case -3: - /* PTE inconsistency */ - return -1; - case -2: - /* Access violation */ - ret = -2; - good = i; - break; - case -1: - default: - /* No PTE match */ - break; - case 0: - /* access granted */ - /* XXX: we should go on looping to check all PTEs consistency - * but if we can speed-up the whole thing as the - * result would be undefined if PTEs are not consistent. - */ - ret = 0; - good = i; - goto done; - } - } - if (good != -1) { - done: - LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n", - ctx->raddr, ctx->prot, ret); - /* Update page flags */ - pte1 = ctx->raddr; - if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { -#if defined(TARGET_PPC64) - if (is_64b) { - if (env->external_htab) { - stq_p(env->external_htab + pteg_off + (good * 16) + 8, - pte1); - } else { - stq_phys_notdirty(env->htab_base + pteg_off + - (good * 16) + 8, pte1); - } - } else -#endif - { - if (env->external_htab) { - stl_p(env->external_htab + pteg_off + (good * 8) + 4, - pte1); - } else { - stl_phys_notdirty(env->htab_base + pteg_off + - (good * 8) + 4, pte1); - } - } - } - } - - /* We have a TLB that saves 4K pages, so let's - * split a huge page to 4k chunks */ - if (target_page_bits != TARGET_PAGE_BITS) { - ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) - & TARGET_PAGE_MASK; - } - return ret; -} - -static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw, - int type, int target_page_bits) -{ -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - return find_pte2(env, ctx, 1, h, rw, type, target_page_bits); - } -#endif - - return find_pte2(env, ctx, 0, h, rw, type, target_page_bits); -} - -#if defined(TARGET_PPC64) -static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) -{ - uint64_t esid_256M, esid_1T; - int n; - - LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); - - esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; - esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V; - - for (n = 0; n < env->slb_nr; n++) { - ppc_slb_t *slb = &env->slb[n]; - - LOG_SLB("%s: slot %d %016" PRIx64 " %016" - PRIx64 "\n", __func__, n, slb->esid, slb->vsid); - /* We check for 1T matches on all MMUs here - if the MMU - * doesn't have 1T segment support, we will have prevented 1T - * entries from being inserted in the slbmte code. */ - if (((slb->esid == esid_256M) && - ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) - || ((slb->esid == esid_1T) && - ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) { - return slb; - } - } - - return NULL; -} - -/*****************************************************************************/ -/* SPR accesses */ - -void helper_slbia(CPUPPCState *env) -{ - int n, do_invalidate; - - do_invalidate = 0; - /* XXX: Warning: slbia never invalidates the first segment */ - for (n = 1; n < env->slb_nr; n++) { - ppc_slb_t *slb = &env->slb[n]; - - if (slb->esid & SLB_ESID_V) { - slb->esid &= ~SLB_ESID_V; - /* XXX: given the fact that segment size is 256 MB or 1TB, - * and we still don't have a tlb_flush_mask(env, n, mask) - * in QEMU, we just invalidate all TLBs - */ - do_invalidate = 1; - } - } - if (do_invalidate) { - tlb_flush(env, 1); - } -} - -void helper_slbie(CPUPPCState *env, target_ulong addr) -{ - ppc_slb_t *slb; - - slb = slb_lookup(env, addr); - if (!slb) { - return; - } - - if (slb->esid & SLB_ESID_V) { - slb->esid &= ~SLB_ESID_V; - - /* XXX: given the fact that segment size is 256 MB or 1TB, - * and we still don't have a tlb_flush_mask(env, n, mask) - * in QEMU, we just invalidate all TLBs - */ - tlb_flush(env, 1); - } -} - -int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) -{ - int slot = rb & 0xfff; - ppc_slb_t *slb = &env->slb[slot]; - - if (rb & (0x1000 - env->slb_nr)) { - return -1; /* Reserved bits set or slot too high */ - } - if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) { - return -1; /* Bad segment size */ - } - if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) { - return -1; /* 1T segment on MMU that doesn't support it */ - } - - /* Mask out the slot number as we store the entry */ - slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V); - slb->vsid = rs; - - LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 - " %016" PRIx64 "\n", __func__, slot, rb, rs, - slb->esid, slb->vsid); - - return 0; -} - -static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, - target_ulong *rt) -{ - int slot = rb & 0xfff; - ppc_slb_t *slb = &env->slb[slot]; - - if (slot >= env->slb_nr) { - return -1; - } - - *rt = slb->esid; - return 0; -} - -static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, - target_ulong *rt) -{ - int slot = rb & 0xfff; - ppc_slb_t *slb = &env->slb[slot]; - - if (slot >= env->slb_nr) { - return -1; - } - - *rt = slb->vsid; - return 0; -} -#endif /* defined(TARGET_PPC64) */ - /* Perform segment based translation */ -static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int type) +static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type) { hwaddr hash; target_ulong vsid; int ds, pr, target_page_bits; - int ret, ret2; + int ret; + target_ulong sr, pgidx; pr = msr_pr; ctx->eaddr = eaddr; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - ppc_slb_t *slb; - target_ulong pageaddr; - int segment_bits; - - LOG_MMU("Check SLBs\n"); - slb = slb_lookup(env, eaddr); - if (!slb) { - return -5; - } - - if (slb->vsid & SLB_VSID_B) { - vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T; - segment_bits = 40; - } else { - vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; - segment_bits = 28; - } - target_page_bits = (slb->vsid & SLB_VSID_L) - ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; - ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) - : (slb->vsid & SLB_VSID_KS)); - ds = 0; - ctx->nx = !!(slb->vsid & SLB_VSID_N); + sr = env->sr[eaddr >> 28]; + ctx->key = (((sr & 0x20000000) && (pr != 0)) || + ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; + ds = sr & 0x80000000 ? 1 : 0; + ctx->nx = sr & 0x10000000 ? 1 : 0; + vsid = sr & 0x00FFFFFF; + target_page_bits = TARGET_PAGE_BITS; + LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" + TARGET_FMT_lx " lr=" TARGET_FMT_lx + " ir=%d dr=%d pr=%d %d t=%d\n", + eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, + (int)msr_dr, pr != 0 ? 1 : 0, rw, type); + pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; + hash = vsid ^ pgidx; + ctx->ptem = (vsid << 7) | (pgidx >> 10); - pageaddr = eaddr & ((1ULL << segment_bits) - - (1ULL << target_page_bits)); - if (slb->vsid & SLB_VSID_B) { - hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits); - } else { - hash = vsid ^ (pageaddr >> target_page_bits); - } - /* Only 5 bits of the page index are used in the AVPN */ - ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | - ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80)); - } else -#endif /* defined(TARGET_PPC64) */ - { - target_ulong sr, pgidx; - - sr = env->sr[eaddr >> 28]; - ctx->key = (((sr & 0x20000000) && (pr != 0)) || - ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; - ds = sr & 0x80000000 ? 1 : 0; - ctx->nx = sr & 0x10000000 ? 1 : 0; - vsid = sr & 0x00FFFFFF; - target_page_bits = TARGET_PAGE_BITS; - LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" - TARGET_FMT_lx " lr=" TARGET_FMT_lx - " ir=%d dr=%d pr=%d %d t=%d\n", - eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, - (int)msr_dr, pr != 0 ? 1 : 0, rw, type); - pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; - hash = vsid ^ pgidx; - ctx->ptem = (vsid << 7) | (pgidx >> 10); - } LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid); ret = -1; @@ -897,33 +501,8 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx, /* Initialize real address with an invalid value */ ctx->raddr = (hwaddr)-1ULL; - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx || - env->mmu_model == POWERPC_MMU_SOFT_74xx)) { - /* Software TLB search */ - ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); - } else { - LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx - " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx "\n", - env->htab_base, env->htab_mask, vsid, ctx->ptem, - ctx->hash[0]); - /* Primary table lookup */ - ret = find_pte(env, ctx, 0, rw, type, target_page_bits); - if (ret < 0) { - /* Secondary table lookup */ - if (eaddr != 0xEFFFFFFF) { - LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx - " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx "\n", env->htab_base, - env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); - } - ret2 = find_pte(env, ctx, 1, rw, type, - target_page_bits); - if (ret2 != -1) { - ret = ret2; - } - } - } + /* Software TLB search */ + ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); #if defined(DUMP_PAGE_TABLES) if (qemu_log_enabled()) { hwaddr curaddr; @@ -1309,8 +888,8 @@ static hwaddr booke206_tlb_to_page_size(CPUPPCState *env, } /* TLB check function for MAS based SoftTLBs */ -int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, - hwaddr *raddrp, +static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, + hwaddr *raddrp, target_ulong address, uint32_t pid) { target_ulong mask; @@ -1597,28 +1176,6 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf, } } -#if defined(TARGET_PPC64) -static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf, - CPUPPCState *env) -{ - int i; - uint64_t slbe, slbv; - - cpu_synchronize_state(env); - - cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n"); - for (i = 0; i < env->slb_nr; i++) { - slbe = env->slb[i].esid; - slbv = env->slb[i].vsid; - if (slbe == 0 && slbv == 0) { - continue; - } - cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n", - i, slbe, slbv); - } -} -#endif - void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) { switch (env->mmu_model) { @@ -1632,7 +1189,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: case POWERPC_MMU_2_06d: - mmubooks_dump_mmu(f, cpu_fprintf, env); + dump_slb(f, cpu_fprintf, env); break; #endif default: @@ -1649,8 +1206,6 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, ctx->prot = PAGE_READ | PAGE_EXEC; ret = 0; switch (env->mmu_model) { - case POWERPC_MMU_32B: - case POWERPC_MMU_601: case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: case POWERPC_MMU_SOFT_4xx: @@ -1658,16 +1213,7 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, case POWERPC_MMU_BOOKE: ctx->prot |= PAGE_WRITE; break; -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - case POWERPC_MMU_2_06d: - /* Real address are 60 bits long */ - ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; - ctx->prot |= PAGE_WRITE; - break; -#endif + case POWERPC_MMU_SOFT_4xx_Z: if (unlikely(msr_pe != 0)) { /* 403 family add some particular protections, @@ -1692,15 +1238,10 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, } } break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_BOOKE206: - cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n"); - break; + default: - cpu_abort(env, "Unknown or invalid MMU model\n"); + /* Caller's checks mean we should never get here for other models */ + abort(); return -1; } @@ -1710,71 +1251,62 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int access_type) { - int ret; + int ret = -1; + bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0) + || (access_type != ACCESS_CODE && msr_dr == 0); #if 0 qemu_log("%s\n", __func__); #endif - if ((access_type == ACCESS_CODE && msr_ir == 0) || - (access_type != ACCESS_CODE && msr_dr == 0)) { - if (env->mmu_model == POWERPC_MMU_BOOKE) { - /* The BookE MMU always performs address translation. The - IS and DS bits only affect the address space. */ - ret = mmubooke_get_physical_address(env, ctx, eaddr, - rw, access_type); - } else if (env->mmu_model == POWERPC_MMU_BOOKE206) { - ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); - } else { - /* No address translation. */ + + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: + if (real_mode) { ret = check_physical(env, ctx, eaddr, rw); - } - } else { - ret = -1; - switch (env->mmu_model) { - case POWERPC_MMU_32B: - case POWERPC_MMU_601: - case POWERPC_MMU_SOFT_6xx: - case POWERPC_MMU_SOFT_74xx: + } else { /* Try to find a BAT */ if (env->nb_BATs != 0) { - ret = get_bat(env, ctx, eaddr, rw, access_type); + ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type); } -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - case POWERPC_MMU_2_06d: -#endif if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ - ret = get_segment(env, ctx, eaddr, rw, access_type); + ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type); } - break; - case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_SOFT_4xx_Z: + } + break; + + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + if (real_mode) { + ret = check_physical(env, ctx, eaddr, rw); + } else { ret = mmu40x_get_physical_address(env, ctx, eaddr, rw, access_type); - break; - case POWERPC_MMU_BOOKE: - ret = mmubooke_get_physical_address(env, ctx, eaddr, - rw, access_type); - break; - case POWERPC_MMU_BOOKE206: - ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, + } + break; + case POWERPC_MMU_BOOKE: + ret = mmubooke_get_physical_address(env, ctx, eaddr, + rw, access_type); + break; + case POWERPC_MMU_BOOKE206: + ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, access_type); - break; - case POWERPC_MMU_MPC8xx: - /* XXX: TODO */ - cpu_abort(env, "MPC8xx MMU model is not implemented\n"); - break; - case POWERPC_MMU_REAL: + break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_REAL: + if (real_mode) { + ret = check_physical(env, ctx, eaddr, rw); + } else { cpu_abort(env, "PowerPC in real mode do not do any translation\n"); - return -1; - default: - cpu_abort(env, "Unknown or invalid MMU model\n"); - return -1; } + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; } #if 0 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n", @@ -1788,6 +1320,22 @@ hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr) { mmu_ctx_t ctx; + switch (env->mmu_model) { +#if defined(TARGET_PPC64) + case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06d: + return ppc_hash64_get_phys_page_debug(env, addr); +#endif + + case POWERPC_MMU_32B: + case POWERPC_MMU_601: + return ppc_hash32_get_phys_page_debug(env, addr); + + default: + ; + } + if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { return -1; } @@ -1836,8 +1384,8 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, } /* Perform address translation */ -int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, - int mmu_idx) +static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, + int rw, int mmu_idx) { mmu_ctx_t ctx; int access_type; @@ -1880,17 +1428,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, env->spr[SPR_40x_DEAR] = address; env->spr[SPR_40x_ESR] = 0x00000000; break; - case POWERPC_MMU_32B: - case POWERPC_MMU_601: -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - case POWERPC_MMU_2_06d: -#endif - env->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x40000000; - break; case POWERPC_MMU_BOOKE206: booke206_update_mas_tlb_miss(env, address, rw); /* fall through */ @@ -1932,19 +1469,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x10000000; break; -#if defined(TARGET_PPC64) - case -5: - /* No match in segment table */ - if (env->mmu_model == POWERPC_MMU_620) { - env->exception_index = POWERPC_EXCP_ISI; - /* XXX: this might be incorrect */ - env->error_code = 0x40000000; - } else { - env->exception_index = POWERPC_EXCP_ISEG; - env->error_code = 0; - } - break; -#endif } } else { switch (ret) { @@ -1964,9 +1488,9 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, tlb_miss: env->error_code |= ctx.key << 19; env->spr[SPR_HASH1] = env->htab_base + - get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32); + get_pteg_offset32(env, ctx.hash[0]); env->spr[SPR_HASH2] = env->htab_base + - get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32); + get_pteg_offset32(env, ctx.hash[1]); break; case POWERPC_MMU_SOFT_74xx: if (rw == 1) { @@ -1992,23 +1516,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, env->spr[SPR_40x_ESR] = 0x00000000; } break; - case POWERPC_MMU_32B: - case POWERPC_MMU_601: -#if defined(TARGET_PPC64) - case POWERPC_MMU_620: - case POWERPC_MMU_64B: - case POWERPC_MMU_2_06: - case POWERPC_MMU_2_06d: -#endif - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - env->spr[SPR_DAR] = address; - if (rw == 1) { - env->spr[SPR_DSISR] = 0x42000000; - } else { - env->spr[SPR_DSISR] = 0x40000000; - } - break; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ cpu_abort(env, "MPC8xx MMU model is not implemented\n"); @@ -2094,26 +1601,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, break; } break; -#if defined(TARGET_PPC64) - case -5: - /* No match in segment table */ - if (env->mmu_model == POWERPC_MMU_620) { - env->exception_index = POWERPC_EXCP_DSI; - env->error_code = 0; - env->spr[SPR_DAR] = address; - /* XXX: this might be incorrect */ - if (rw == 1) { - env->spr[SPR_DSISR] = 0x42000000; - } else { - env->spr[SPR_DSISR] = 0x40000000; - } - } else { - env->exception_index = POWERPC_EXCP_DSEG; - env->error_code = 0; - env->spr[SPR_DAR] = address; - } - break; -#endif } } #if 0 @@ -2326,7 +1813,6 @@ void ppc_tlb_invalidate_all(CPUPPCState *env) case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) - case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: case POWERPC_MMU_2_06d: @@ -2396,7 +1882,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) tlb_flush_page(env, addr | (0xF << 28)); break; #if defined(TARGET_PPC64) - case POWERPC_MMU_620: case POWERPC_MMU_64B: case POWERPC_MMU_2_06: case POWERPC_MMU_2_06d: @@ -2420,16 +1905,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) /*****************************************************************************/ /* Special registers manipulation */ -#if defined(TARGET_PPC64) -void ppc_store_asr(CPUPPCState *env, target_ulong value) -{ - if (env->asr != value) { - env->asr = value; - tlb_flush(env, 1); - } -} -#endif - void ppc_store_sdr1(CPUPPCState *env, target_ulong value) { LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value); @@ -2511,41 +1986,6 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) #endif } } -#endif /* !defined(CONFIG_USER_ONLY) */ - -#if !defined(CONFIG_USER_ONLY) -/* SLB management */ -#if defined(TARGET_PPC64) -void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs) -{ - if (ppc_store_slb(env, rb, rs) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); - } -} - -target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb) -{ - target_ulong rt = 0; - - if (ppc_load_slb_esid(env, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); - } - return rt; -} - -target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb) -{ - target_ulong rt = 0; - - if (ppc_load_slb_vsid(env, rb, &rt) < 0) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL); - } - return rt; -} -#endif /* defined(TARGET_PPC64) */ /* TLB management */ void helper_tlbia(CPUPPCState *env) @@ -3321,4 +2761,45 @@ void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type) booke206_flush_tlb(env, flags, 1); } -#endif + + +/*****************************************************************************/ + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "exec/softmmu_template.h" + +#define SHIFT 1 +#include "exec/softmmu_template.h" + +#define SHIFT 2 +#include "exec/softmmu_template.h" + +#define SHIFT 3 +#include "exec/softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) +{ + CPUState *cpu = ENV_GET_CPU(env); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + int ret; + + if (pcc->handle_mmu_fault) { + ret = pcc->handle_mmu_fault(env, addr, is_write, mmu_idx); + } else { + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx); + } + if (unlikely(ret != 0)) { + if (likely(retaddr)) { + /* now we have a real cpu fault */ + cpu_restore_state(env, retaddr); + } + helper_raise_exception_err(env, env->exception_index, env->error_code); + } +} diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 380a884131..5e741d1ab4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -204,6 +204,13 @@ typedef struct DisasContext { int singlestep_enabled; } DisasContext; +/* True when active word size < size of target_long. */ +#ifdef TARGET_PPC64 +# define NARROW_MODE(C) (!(C)->sf_mode) +#else +# define NARROW_MODE(C) 0 +#endif + struct opc_handler_t { /* invalid bits for instruction 1 (Rc(opcode) == 0) */ uint32_t inval1; @@ -260,12 +267,10 @@ static inline void gen_set_access_type(DisasContext *ctx, int access_type) static inline void gen_update_nip(DisasContext *ctx, target_ulong nip) { -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - tcg_gen_movi_tl(cpu_nip, nip); - else -#endif - tcg_gen_movi_tl(cpu_nip, (uint32_t)nip); + if (NARROW_MODE(ctx)) { + nip = (uint32_t)nip; + } + tcg_gen_movi_tl(cpu_nip, nip); } static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) @@ -627,7 +632,6 @@ static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf) tcg_temp_free(t0); } -#if defined(TARGET_PPC64) static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf) { TCGv t0, t1; @@ -651,68 +655,62 @@ static inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf) gen_op_cmp32(arg0, t0, s, crf); tcg_temp_free(t0); } -#endif static inline void gen_set_Rc0(DisasContext *ctx, TCGv reg) { -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode)) + if (NARROW_MODE(ctx)) { gen_op_cmpi32(reg, 0, 1, 0); - else -#endif + } else { gen_op_cmpi(reg, 0, 1, 0); + } } /* cmp */ static void gen_cmp(DisasContext *ctx) { -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) { gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], 1, crfD(ctx->opcode)); - else -#endif + } else { gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], 1, crfD(ctx->opcode)); + } } /* cmpi */ static void gen_cmpi(DisasContext *ctx) { -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) { gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode), 1, crfD(ctx->opcode)); - else -#endif + } else { gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode), 1, crfD(ctx->opcode)); + } } /* cmpl */ static void gen_cmpl(DisasContext *ctx) { -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) { gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], 0, crfD(ctx->opcode)); - else -#endif + } else { gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], 0, crfD(ctx->opcode)); + } } /* cmpli */ static void gen_cmpli(DisasContext *ctx) { -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode && (ctx->opcode & 0x00200000))) + if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) { gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode), 0, crfD(ctx->opcode)); - else -#endif + } else { gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode), 0, crfD(ctx->opcode)); + } } /* isel (PowerPC 2.03 specification) */ @@ -756,11 +754,9 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, tcg_gen_andc_tl(cpu_ov, cpu_ov, t0); } tcg_temp_free(t0); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32s_tl(cpu_ov, cpu_ov); } -#endif tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1); tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov); } @@ -778,14 +774,26 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, } if (compute_ca) { - TCGv zero = tcg_const_tl(0); - if (add_ca) { - tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero); - tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero); + if (NARROW_MODE(ctx)) { + TCGv t1 = tcg_temp_new(); + tcg_gen_ext32u_tl(t1, arg2); + tcg_gen_ext32u_tl(t0, arg1); + tcg_gen_add_tl(t0, t0, t1); + tcg_temp_free(t1); + if (add_ca) { + tcg_gen_add_tl(t0, t0, cpu_ca); + } + tcg_gen_shri_tl(cpu_ca, t0, 32); } else { - tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero); + TCGv zero = tcg_const_tl(0); + if (add_ca) { + tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero); + tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero); + } else { + tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero); + } + tcg_temp_free(zero); } - tcg_temp_free(zero); } else { tcg_gen_add_tl(t0, arg1, arg2); if (add_ca) { @@ -1114,14 +1122,25 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, { TCGv t0 = ret; - if (((add_ca && compute_ca) || compute_ov) - && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) { + if (compute_ov && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) { t0 = tcg_temp_new(); } - if (add_ca) { - /* dest = ~arg1 + arg2 + ca. */ - if (compute_ca) { + if (compute_ca) { + /* dest = ~arg1 + arg2 [+ ca]. */ + if (NARROW_MODE(ctx)) { + TCGv inv1 = tcg_temp_new(); + tcg_gen_not_tl(inv1, arg1); + tcg_gen_ext32u_tl(t0, arg2); + tcg_gen_ext32u_tl(inv1, inv1); + if (add_ca) { + tcg_gen_add_tl(t0, t0, cpu_ca); + } else { + tcg_gen_addi_tl(t0, t0, 1); + } + tcg_gen_add_tl(t0, t0, inv1); + tcg_gen_shri_tl(cpu_ca, t0, 32); + } else if (add_ca) { TCGv zero, inv1 = tcg_temp_new(); tcg_gen_not_tl(inv1, arg1); zero = tcg_const_tl(0); @@ -1130,14 +1149,16 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_temp_free(zero); tcg_temp_free(inv1); } else { + tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1); tcg_gen_sub_tl(t0, arg2, arg1); - tcg_gen_add_tl(t0, t0, cpu_ca); - tcg_gen_subi_tl(t0, t0, 1); } + } else if (add_ca) { + /* Since we're ignoring carry-out, we can simplify the + standard ~arg1 + arg2 + ca to arg2 - arg1 + ca - 1. */ + tcg_gen_sub_tl(t0, arg2, arg1); + tcg_gen_add_tl(t0, t0, cpu_ca); + tcg_gen_subi_tl(t0, t0, 1); } else { - if (compute_ca) { - tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1); - } tcg_gen_sub_tl(t0, arg2, arg1); } @@ -2311,45 +2332,37 @@ static inline void gen_addr_imm_index(DisasContext *ctx, TCGv EA, simm &= ~maskl; if (rA(ctx->opcode) == 0) { -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { - tcg_gen_movi_tl(EA, (uint32_t)simm); - } else -#endif + if (NARROW_MODE(ctx)) { + simm = (uint32_t)simm; + } tcg_gen_movi_tl(EA, simm); } else if (likely(simm != 0)) { tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(EA, EA); } -#endif } else { -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]); - } else -#endif - tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); + } else { + tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); + } } } static inline void gen_addr_reg_index(DisasContext *ctx, TCGv EA) { if (rA(ctx->opcode) == 0) { -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(EA, cpu_gpr[rB(ctx->opcode)]); - } else -#endif - tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]); + } else { + tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]); + } } else { tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(EA, EA); } -#endif } } @@ -2357,13 +2370,10 @@ static inline void gen_addr_register(DisasContext *ctx, TCGv EA) { if (rA(ctx->opcode) == 0) { tcg_gen_movi_tl(EA, 0); + } else if (NARROW_MODE(ctx)) { + tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]); } else { -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { - tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]); - } else -#endif - tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]); } } @@ -2371,11 +2381,9 @@ static inline void gen_addr_add(DisasContext *ctx, TCGv ret, TCGv arg1, target_long val) { tcg_gen_addi_tl(ret, arg1, val); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(ret, ret); } -#endif } static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask) @@ -3320,10 +3328,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) + if (NARROW_MODE(ctx)) { dest = (uint32_t) dest; -#endif + } if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); @@ -3351,12 +3358,10 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) static inline void gen_setlr(DisasContext *ctx, target_ulong nip) { -#if defined(TARGET_PPC64) - if (ctx->sf_mode == 0) - tcg_gen_movi_tl(cpu_lr, (uint32_t)nip); - else -#endif - tcg_gen_movi_tl(cpu_lr, nip); + if (NARROW_MODE(ctx)) { + nip = (uint32_t)nip; + } + tcg_gen_movi_tl(cpu_lr, nip); } /* b ba bl bla */ @@ -3366,18 +3371,16 @@ static void gen_b(DisasContext *ctx) ctx->exception = POWERPC_EXCP_BRANCH; /* sign extend LI */ -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - li = ((int64_t)LI(ctx->opcode) << 38) >> 38; - else -#endif - li = ((int32_t)LI(ctx->opcode) << 6) >> 6; - if (likely(AA(ctx->opcode) == 0)) + li = LI(ctx->opcode); + li = (li ^ 0x02000000) - 0x02000000; + if (likely(AA(ctx->opcode) == 0)) { target = ctx->nip + li - 4; - else + } else { target = li; - if (LK(ctx->opcode)) + } + if (LK(ctx->opcode)) { gen_setlr(ctx, ctx->nip); + } gen_update_cfar(ctx, ctx->nip); gen_goto_tb(ctx, 0, target); } @@ -3413,12 +3416,11 @@ static inline void gen_bcond(DisasContext *ctx, int type) return; } tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(temp, cpu_ctr); - else -#endif + } else { tcg_gen_mov_tl(temp, cpu_ctr); + } if (bo & 0x2) { tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1); } else { @@ -3452,20 +3454,14 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->nip); } else { -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode)) + if (NARROW_MODE(ctx)) { tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3); - else -#endif + } else { tcg_gen_andi_tl(cpu_nip, target, ~3); + } tcg_gen_exit_tb(0); gen_set_label(l1); -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode)) - tcg_gen_movi_tl(cpu_nip, (uint32_t)ctx->nip); - else -#endif - tcg_gen_movi_tl(cpu_nip, ctx->nip); + gen_update_nip(ctx, ctx->nip); tcg_gen_exit_tb(0); } } @@ -4324,15 +4320,14 @@ static void gen_tlbie(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; } -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); gen_helper_tlbie(cpu_env, t0); tcg_temp_free(t0); - } else -#endif + } else { gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); + } #endif } @@ -7577,11 +7572,9 @@ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) tcg_gen_movi_tl(EA, uimm << sh); } else { tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) { + if (NARROW_MODE(ctx)) { tcg_gen_ext32u_tl(EA, EA); } -#endif } } @@ -9428,7 +9421,6 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf, case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: #if defined(TARGET_PPC64) - case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 15eebe9177..781170fb05 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -25,6 +25,8 @@ #include "sysemu/arch_init.h" #include "sysemu/cpus.h" #include "cpu-models.h" +#include "mmu-hash32.h" +#include "mmu-hash64.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -365,7 +367,6 @@ static void spr_write_sdr1 (void *opaque, int sprn, int gprn) } /* 64 bits PowerPC specific SPRs */ -/* ASR */ #if defined(TARGET_PPC64) static void spr_read_hior (void *opaque, int gprn, int sprn) { @@ -379,16 +380,6 @@ static void spr_write_hior (void *opaque, int sprn, int gprn) tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); tcg_temp_free(t0); } - -static void spr_read_asr (void *opaque, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, asr)); -} - -static void spr_write_asr (void *opaque, int sprn, int gprn) -{ - gen_helper_store_asr(cpu_env, cpu_gpr[gprn]); -} #endif #endif @@ -1028,6 +1019,54 @@ static void gen_spr_7xx (CPUPPCState *env) 0x00000000); } +#ifdef TARGET_PPC64 +#ifndef CONFIG_USER_ONLY +static void spr_read_uamr (void *opaque, int gprn, int sprn) +{ + gen_load_spr(cpu_gpr[gprn], SPR_AMR); + spr_load_dump_spr(SPR_AMR); +} + +static void spr_write_uamr (void *opaque, int sprn, int gprn) +{ + gen_store_spr(SPR_AMR, cpu_gpr[gprn]); + spr_store_dump_spr(SPR_AMR); +} + +static void spr_write_uamr_pr (void *opaque, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + + gen_load_spr(t0, SPR_UAMOR); + tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); + gen_store_spr(SPR_AMR, t0); + spr_store_dump_spr(SPR_AMR); +} +#endif /* CONFIG_USER_ONLY */ + +static void gen_spr_amr (CPUPPCState *env) +{ +#ifndef CONFIG_USER_ONLY + /* Virtual Page Class Key protection */ + /* The AMR is accessible either via SPR 13 or SPR 29. 13 is + * userspace accessible, 29 is privileged. So we only need to set + * the kvm ONE_REG id on one of them, we use 29 */ + spr_register(env, SPR_UAMR, "UAMR", + &spr_read_uamr, &spr_write_uamr_pr, + &spr_read_uamr, &spr_write_uamr, + 0); + spr_register_kvm(env, SPR_AMR, "AMR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_AMR, 0xffffffffffffffffULL); + spr_register_kvm(env, SPR_UAMOR, "UAMOR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_UAMOR, 0); +#endif /* !CONFIG_USER_ONLY */ +} +#endif /* TARGET_PPC64 */ + static void gen_spr_thrm (CPUPPCState *env) { /* Thermal management */ @@ -2151,173 +2190,6 @@ static void gen_spr_compress (CPUPPCState *env) 0x00000000); } -#if defined (TARGET_PPC64) -/* SPR specific to PowerPC 620 */ -static void gen_spr_620 (CPUPPCState *env) -{ - /* Processor identification */ - spr_register(env, SPR_PIR, "PIR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_pir, - 0x00000000); - spr_register(env, SPR_ASR, "ASR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_asr, &spr_write_asr, - 0x00000000); - /* Breakpoints */ - /* XXX : not implemented */ - spr_register(env, SPR_IABR, "IABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_DABR, "DABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_SIAR, "SIAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_SDA, "SDA", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMC1R, "PMC1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_620_PMC1W, "PMC1", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMC2R, "PMC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_620_PMC2W, "PMC2", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_MMCR0R, "MMCR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_620_MMCR0W, "MMCR0", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, - 0x00000000); - /* External access control */ - /* XXX : not implemented */ - spr_register(env, SPR_EAR, "EAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -#if 0 // XXX: check this - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR0, "PMR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR1, "PMR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR2, "PMR2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR3, "PMR3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR4, "PMR4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR5, "PMR5", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR6, "PMR6", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR7, "PMR7", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR8, "PMR8", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMR9, "PMR9", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMRA, "PMR10", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMRB, "PMR11", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMRC, "PMR12", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMRD, "PMR13", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMRE, "PMR14", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_PMRF, "PMR15", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -#endif - /* XXX : not implemented */ - spr_register(env, SPR_620_BUSCSR, "BUSCSR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_620_L2SR, "L2SR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -} -#endif /* defined (TARGET_PPC64) */ - static void gen_spr_5xx_8xx (CPUPPCState *env) { /* Exception processing */ @@ -2993,31 +2865,6 @@ static void init_excp_604 (CPUPPCState *env) #endif } -#if defined(TARGET_PPC64) -static void init_excp_620 (CPUPPCState *env) -{ -#if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->hreset_excp_prefix = 0xFFF00000UL; - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; -#endif -} -#endif /* defined(TARGET_PPC64) */ - static void init_excp_7x0 (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -4951,6 +4798,9 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000000FD70ULL; pcc->mmu_model = POWERPC_MMU_601; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_601; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_601; @@ -4985,7 +4835,9 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000000FD70ULL; pcc->mmu_model = POWERPC_MMU_601; - pcc->excp_model = POWERPC_EXCP_601; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_601; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; @@ -5192,6 +5044,9 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_604; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_604; @@ -5258,6 +5113,9 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_604; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_604; @@ -5311,6 +5169,9 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_750; @@ -5372,6 +5233,9 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_750; @@ -5556,6 +5420,9 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_750; @@ -5621,6 +5488,9 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_750; @@ -5691,6 +5561,9 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_750; @@ -5761,6 +5634,9 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000005FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_750; @@ -5953,6 +5829,9 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_7400; @@ -6019,6 +5898,9 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x000000000205FF77ULL; pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_7400; @@ -6725,6 +6607,9 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x900000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_970; pcc->bus_model = PPC_FLAGS_INPUT_970; pcc->bfd_mach = bfd_mach_ppc64; @@ -6835,6 +6720,9 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x800000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_970; pcc->bus_model = PPC_FLAGS_INPUT_970; pcc->bfd_mach = bfd_mach_ppc64; @@ -6933,6 +6821,9 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x800000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_970; pcc->bus_model = PPC_FLAGS_INPUT_970; pcc->bfd_mach = bfd_mach_ppc64; @@ -7031,6 +6922,9 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC_NONE; pcc->msr_mask = 0x900000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_64B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_970; pcc->bus_model = PPC_FLAGS_INPUT_970; pcc->bfd_mach = bfd_mach_ppc64; @@ -7075,6 +6969,7 @@ static void init_proc_POWER7 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* TOFIX */ + gen_spr_amr(env); /* XXX : not implemented */ spr_register(env, SPR_CTRL, "SPR_CTRLT", SPR_NOACCESS, SPR_NOACCESS, @@ -7122,6 +7017,9 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX; pcc->msr_mask = 0x800000000204FF36ULL; pcc->mmu_model = POWERPC_MMU_2_06; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif pcc->excp_model = POWERPC_EXCP_POWER7; pcc->bus_model = PPC_FLAGS_INPUT_POWER7; pcc->bfd_mach = bfd_mach_ppc64; @@ -7129,55 +7027,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; } - -static void init_proc_620 (CPUPPCState *env) -{ - gen_spr_ne_601(env); - gen_spr_620(env); - /* Time base */ - gen_tbl(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - gen_low_BATs(env); - init_excp_620(env); - env->dcache_line_size = 64; - env->icache_line_size = 64; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); -} - -POWERPC_FAMILY(620)(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - - dc->desc = "PowerPC 620"; - pcc->init_proc = init_proc_620; - pcc->check_pow = check_pow_nocheck; /* Check this */ - pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | - PPC_FLOAT_STFIWX | - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | - PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | - PPC_SEGMENT | PPC_EXTERN | - PPC_64B | PPC_SLBI; - pcc->insns_flags2 = PPC_NONE; - pcc->msr_mask = 0x800000000005FF77ULL; - pcc->mmu_model = POWERPC_MMU_620; - pcc->excp_model = POWERPC_EXCP_970; - pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc64; - pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; -} - #endif /* defined (TARGET_PPC64) */ @@ -7693,7 +7542,7 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n) return 8; } if (n == 32) { - /* FPSCR not implemented */ + helper_store_fpscr(env, ldl_p(mem_buf), 0xffffffff); return 4; } return 0; @@ -7915,9 +7764,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) case POWERPC_MMU_64B: mmu_model = "PowerPC 64"; break; - case POWERPC_MMU_620: - mmu_model = "PowerPC 620"; - break; #endif default: mmu_model = "Unknown or invalid"; diff --git a/target-ppc/user_only_helper.c b/target-ppc/user_only_helper.c new file mode 100644 index 0000000000..56e686efd1 --- /dev/null +++ b/target-ppc/user_only_helper.c @@ -0,0 +1,44 @@ +/* + * PowerPC MMU stub handling for user mode emulation + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright (c) 2013 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" + +int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw, + int mmu_idx) +{ + int exception, error_code; + + if (rw == 2) { + exception = POWERPC_EXCP_ISI; + error_code = 0x40000000; + } else { + exception = POWERPC_EXCP_DSI; + error_code = 0x40000000; + if (rw) { + error_code |= 0x02000000; + } + env->spr[SPR_DAR] = address; + env->spr[SPR_DSISR] = error_code; + } + env->exception_index = exception; + env->error_code = error_code; + + return 1; +} diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 88e481cdbc..a4f2194ec7 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1142,7 +1142,7 @@ struct DisasInsn { }; /* ====================================================================== */ -/* Miscelaneous helpers, used by several operations. */ +/* Miscellaneous helpers, used by several operations. */ static void help_l2_shift(DisasContext *s, DisasFields *f, DisasOps *o, int mask) diff --git a/tcg/README b/tcg/README index 934e7afc96..063aeb95ea 100644 --- a/tcg/README +++ b/tcg/README @@ -14,6 +14,10 @@ the emulated architecture. As TCG started as a generic C backend used for cross compiling, it is assumed that the TCG target is different from the host, although it is never the case for QEMU. +In this document, we use "guest" to specify what architecture we are +emulating; "target" always means the TCG target, the machine on which +we are running QEMU. + A TCG "function" corresponds to a QEMU Translated Block (TB). A TCG "temporary" is a variable only live in a basic @@ -379,7 +383,7 @@ double-word product T0. The later is returned in two single-word outputs. Similar to mulu2, except the two inputs T1 and T2 are signed. -********* 64-bit target on 32-bit host support +********* 64-bit guest on 32-bit host support The following opcodes are internal to TCG. Thus they are to be implemented by 32-bit host code generators, but are not to be emitted by guest translators. @@ -521,9 +525,9 @@ register. a better generated code, but it reduces the memory usage of TCG and the speed of the translation. -- Don't hesitate to use helpers for complicated or seldom used target +- Don't hesitate to use helpers for complicated or seldom used guest instructions. There is little performance advantage in using TCG to - implement target instructions taking more than about twenty TCG + implement guest instructions taking more than about twenty TCG instructions. Note that this rule of thumb is more applicable to helpers doing complex logic or arithmetic, where the C compiler has scope to do a good job of optimisation; it is less relevant where @@ -531,9 +535,9 @@ register. inline TCG may still be faster for longer sequences. - The hard limit on the number of TCG instructions you can generate - per target instruction is set by MAX_OP_PER_INSTR in exec-all.h -- + per guest instruction is set by MAX_OP_PER_INSTR in exec-all.h -- you cannot exceed this without risking a buffer overrun. - Use the 'discard' instruction if you know that TCG won't be able to prove that a given global is "dead" at a given program point. The - x86 target uses it to improve the condition codes optimisation. + x86 guest uses it to improve the condition codes optimisation. diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 new file mode 100755 index 0000000000..14a5126635 --- /dev/null +++ b/tests/qemu-iotests/052 @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=stefanha@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + + +size=128M +_make_test_img $size + +echo +echo "== reading whole image ==" +$QEMU_IO -s -c "read 0 $size" $TEST_IMG | _filter_qemu_io + +echo +echo "== writing whole image does not modify image ==" +$QEMU_IO -s -c "write -P 0xa 0 $size" $TEST_IMG | _filter_qemu_io +$QEMU_IO -c "read -P 0 0 $size" $TEST_IMG | _filter_qemu_io + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/052.out b/tests/qemu-iotests/052.out new file mode 100644 index 0000000000..8617aa2a9e --- /dev/null +++ b/tests/qemu-iotests/052.out @@ -0,0 +1,13 @@ +QA output created by 052 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 + +== reading whole image == +read 134217728/134217728 bytes at offset 0 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== writing whole image does not modify image == +wrote 134217728/134217728 bytes at offset 0 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 134217728/134217728 bytes at offset 0 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1d7e4f31a0..73c5966e10 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -57,3 +57,4 @@ 048 img auto quick 049 rw auto 050 rw auto backing quick +052 rw auto backing diff --git a/translate-all.c b/translate-all.c index 1f3237e60e..a98c646d92 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1308,11 +1308,11 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, /* check whether the given addr is in TCG generated code buffer or not */ bool is_tcg_gen_code(uintptr_t tc_ptr) { - /* This can be called during code generation, code_gen_buffer_max_size + /* This can be called during code generation, code_gen_buffer_size is used instead of code_gen_ptr for upper boundary checking */ return (tc_ptr >= (uintptr_t)tcg_ctx.code_gen_buffer && tc_ptr < (uintptr_t)(tcg_ctx.code_gen_buffer + - tcg_ctx.code_gen_buffer_max_size)); + tcg_ctx.code_gen_buffer_size)); } #endif diff --git a/ui/cocoa.m b/ui/cocoa.m index 8e0eaa2601..048cc97347 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -403,6 +403,9 @@ QemuCocoaView *cocoaView; { COCOA_DEBUG("QemuCocoaView: switchSurface\n"); + int w = surface_width(surface); + int h = surface_height(surface); + // update screenBuffer if (dataProviderRef) CGDataProviderRelease(dataProviderRef); @@ -1014,9 +1017,9 @@ static void cocoa_cleanup(void) static const DisplayChangeListenerOps dcl_ops = { .dpy_name = "cocoa", - .dpy_gfx_update = cocoa_update; - .dpy_gfx_switch = cocoa_switch; - .dpy_refresh = cocoa_refresh; + .dpy_gfx_update = cocoa_update, + .dpy_gfx_switch = cocoa_switch, + .dpy_refresh = cocoa_refresh, }; void cocoa_display_init(DisplayState *ds, int full_screen) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 83e4e08e85..b6b78f503a 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -33,10 +33,10 @@ static const int on=1, off=0; -/* used temporarely until all users are converted to QemuOpts */ -static QemuOptsList dummy_opts = { - .name = "dummy", - .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head), +/* used temporarily until all users are converted to QemuOpts */ +QemuOptsList socket_optslist = { + .name = "socket", + .head = QTAILQ_HEAD_INITIALIZER(socket_optslist.head), .desc = { { .name = "path", @@ -156,12 +156,12 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) continue; } - setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); + qemu_setsockopt(slisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); #ifdef IPV6_V6ONLY if (e->ai_family == PF_INET6) { /* listen on both ipv4 and ipv6 */ - setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, - sizeof(off)); + qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off, + sizeof(off)); } #endif @@ -229,7 +229,7 @@ static void wait_for_connect(void *opaque) qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); do { - rc = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); + rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize); } while (rc == -1 && socket_error() == EINTR); /* update rc to contain error */ @@ -456,7 +456,7 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp) error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); goto err; } - setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); + qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); /* bind socket */ if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { @@ -485,7 +485,7 @@ err: } /* compatibility wrapper */ -static InetSocketAddress *inet_parse(const char *str, Error **errp) +InetSocketAddress *inet_parse(const char *str, Error **errp) { InetSocketAddress *addr; const char *optstr, *h; @@ -555,7 +555,7 @@ fail: return NULL; } -static void inet_addr_to_opts(QemuOpts *opts, InetSocketAddress *addr) +static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr) { bool ipv4 = addr->ipv4 || !addr->has_ipv4; bool ipv6 = addr->ipv6 || !addr->has_ipv6; @@ -583,7 +583,7 @@ int inet_listen(const char *str, char *ostr, int olen, addr = inet_parse(str, errp); if (addr != NULL) { - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); inet_addr_to_opts(opts, addr); qapi_free_InetSocketAddress(addr); sock = inet_listen_opts(opts, port_offset, errp); @@ -622,7 +622,7 @@ int inet_connect(const char *str, Error **errp) addr = inet_parse(str, errp); if (addr != NULL) { - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); inet_addr_to_opts(opts, addr); qapi_free_InetSocketAddress(addr); sock = inet_connect_opts(opts, errp, NULL, NULL); @@ -656,7 +656,7 @@ int inet_nonblocking_connect(const char *str, addr = inet_parse(str, errp); if (addr != NULL) { - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); inet_addr_to_opts(opts, addr); qapi_free_InetSocketAddress(addr); sock = inet_connect_opts(opts, errp, callback, opaque); @@ -799,7 +799,7 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp) char *path, *optstr; int sock, len; - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); optstr = strchr(str, ','); if (optstr) { @@ -827,7 +827,7 @@ int unix_connect(const char *path, Error **errp) QemuOpts *opts; int sock; - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); qemu_opt_set(opts, "path", path); sock = unix_connect_opts(opts, errp, NULL, NULL); qemu_opts_del(opts); @@ -844,7 +844,7 @@ int unix_nonblocking_connect(const char *path, g_assert(callback != NULL); - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); qemu_opt_set(opts, "path", path); sock = unix_connect_opts(opts, errp, callback, opaque); qemu_opts_del(opts); @@ -895,7 +895,7 @@ int socket_connect(SocketAddress *addr, Error **errp, QemuOpts *opts; int fd; - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); switch (addr->kind) { case SOCKET_ADDRESS_KIND_INET: inet_addr_to_opts(opts, addr->inet); @@ -926,7 +926,7 @@ int socket_listen(SocketAddress *addr, Error **errp) QemuOpts *opts; int fd; - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); switch (addr->kind) { case SOCKET_ADDRESS_KIND_INET: inet_addr_to_opts(opts, addr->inet); @@ -954,7 +954,7 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) QemuOpts *opts; int fd; - opts = qemu_opts_create_nofail(&dummy_opts); + opts = qemu_opts_create_nofail(&socket_optslist); switch (remote->kind) { case SOCKET_ADDRESS_KIND_INET: qemu_opt_set(opts, "host", remote->inet->host); @@ -234,6 +234,7 @@ int ctrl_grab = 0; unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; int boot_menu; +bool boot_strict; uint8_t *boot_splash_filedata; size_t boot_splash_filedata_size; uint8_t qemu_extra_params_fw[2]; @@ -458,6 +459,9 @@ static QemuOptsList qemu_boot_opts = { }, { .name = "reboot-timeout", .type = QEMU_OPT_STRING, + }, { + .name = "strict", + .type = QEMU_OPT_STRING, }, { /*End of list */ } }, @@ -1267,6 +1271,12 @@ char *get_boot_devices_list(size_t *size) *size = total; + if (boot_strict && *size > 0) { + list[total-1] = '\n'; + list = g_realloc(list, total + 4); + memcpy(&list[total], "HALT", 4); + *size = total + 4; + } return list; } @@ -3131,7 +3141,7 @@ int main(int argc, char **argv, char **envp) static const char * const params[] = { "order", "once", "menu", "splash", "splash-time", - "reboot-timeout", NULL + "reboot-timeout", "strict", NULL }; char buf[sizeof(boot_devices)]; char *standard_boot_devices; @@ -3174,6 +3184,19 @@ int main(int argc, char **argv, char **envp) exit(1); } } + if (get_param_value(buf, sizeof(buf), + "strict", optarg)) { + if (!strcmp(buf, "on")) { + boot_strict = true; + } else if (!strcmp(buf, "off")) { + boot_strict = false; + } else { + fprintf(stderr, + "qemu: invalid option value '%s'\n", + buf); + exit(1); + } + } if (!qemu_opts_parse(qemu_find_opts("boot-opts"), optarg, 0)) { exit(1); |