summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--block/nbd-client.c91
-rw-r--r--block/nbd-client.h10
-rw-r--r--block/nbd.c105
-rw-r--r--blockdev-nbd.c131
-rw-r--r--hmp.c54
-rw-r--r--hw/arm/bcm2835_peripherals.c1
-rw-r--r--hw/arm/bcm2836.c1
-rw-r--r--hw/arm/raspi.c1
-rw-r--r--hw/arm/xilinx_zynq.c17
-rw-r--r--hw/arm/xlnx-ep108.c21
-rw-r--r--hw/arm/xlnx-zynqmp.c8
-rw-r--r--hw/block/nand.c5
-rw-r--r--hw/gpio/pl061.c37
-rw-r--r--hw/input/adb.c18
-rw-r--r--hw/intc/bcm2835_ic.c1
-rw-r--r--hw/intc/bcm2836_control.c1
-rw-r--r--hw/ipmi/ipmi_bmc_sim.c16
-rw-r--r--hw/misc/bcm2835_mbox.c1
-rw-r--r--hw/misc/bcm2835_property.c1
-rw-r--r--hw/misc/macio/cuda.c279
-rw-r--r--hw/nvram/mac_nvram.c6
-rw-r--r--hw/pci-host/uninorth.c4
-rw-r--r--hw/ppc/mac.h2
-rw-r--r--hw/ppc/spapr.c239
-rw-r--r--hw/ppc/spapr_hcall.c62
-rw-r--r--hw/ppc/spapr_rtas.c1
-rw-r--r--hw/scsi/mptconfig.c1
-rw-r--r--hw/scsi/mptsas.c3
-rw-r--r--hw/sd/Makefile.objs2
-rw-r--r--hw/sd/core.c146
-rw-r--r--hw/sd/pxa2xx_mmci.c304
-rw-r--r--hw/sd/sd.c289
-rw-r--r--hw/sd/sdhci.c82
-rw-r--r--hw/timer/arm_timer.c42
-rw-r--r--hw/timer/exynos4210_mct.c12
-rw-r--r--hw/timer/exynos4210_pwm.c12
-rw-r--r--hw/timer/exynos4210_rtc.c12
-rw-r--r--hw/timer/pl031.c11
-rw-r--r--hw/timer/pxa2xx_timer.c36
-rw-r--r--include/block/nbd.h28
-rw-r--r--include/hw/input/adb.h2
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--include/hw/sd/sd.h65
-rw-r--r--include/hw/sd/sdhci.h3
-rw-r--r--include/io/channel-buffer.h2
-rw-r--r--include/io/channel-socket.h11
-rw-r--r--include/io/channel-util.h52
-rw-r--r--include/monitor/monitor.h3
-rw-r--r--include/qemu/compiler.h12
-rw-r--r--include/qemu/osdep.h11
-rw-r--r--include/qom/object_interfaces.h92
-rw-r--r--io/Makefile.objs1
-rw-r--r--io/channel-buffer.c2
-rw-r--r--io/channel-util.c50
-rw-r--r--libdecnumber/decContext.c3
-rw-r--r--libdecnumber/decNumber.c5
-rw-r--r--libdecnumber/dpd/decimal128.c3
-rw-r--r--libdecnumber/dpd/decimal32.c3
-rw-r--r--libdecnumber/dpd/decimal64.c3
-rw-r--r--migration/ram.c4
-rw-r--r--nbd/client.c440
-rw-r--r--nbd/common.c83
-rw-r--r--nbd/nbd-internal.h32
-rw-r--r--nbd/server.c334
-rw-r--r--qapi/block.json4
-rw-r--r--qemu-char.c10
-rw-r--r--qemu-img.c1
-rw-r--r--qemu-io.c1
-rw-r--r--qemu-nbd.c195
-rw-r--r--qemu-nbd.texi14
-rw-r--r--qmp-commands.hx2
-rw-r--r--qmp.c76
-rw-r--r--qom/object_interfaces.c174
-rwxr-xr-xscripts/checkpatch.pl6
-rw-r--r--scripts/feature_to_c.sh2
-rw-r--r--scripts/qapi-commands.py1
-rw-r--r--scripts/qapi-event.py1
-rw-r--r--scripts/qapi-introspect.py3
-rw-r--r--scripts/qapi-types.py3
-rw-r--r--scripts/qapi-visit.py1
-rw-r--r--scripts/tracetool/backend/simple.py3
-rw-r--r--scripts/tracetool/format/events_c.py1
-rw-r--r--scripts/tracetool/format/tcg_helper_c.py1
-rw-r--r--stubs/blockdev-close-all-bdrv-states.c1
-rw-r--r--target-arm/cpu-qom.h2
-rw-r--r--target-arm/cpu.c2
-rw-r--r--target-arm/cpu.h29
-rw-r--r--target-arm/cpu64.c2
-rw-r--r--target-arm/helper.c214
-rw-r--r--target-arm/internals.h26
-rw-r--r--target-arm/op_helper.c51
-rw-r--r--target-arm/translate.c67
-rw-r--r--target-cris/mmu.c4
-rw-r--r--target-i386/Makefile.objs2
-rw-r--r--target-i386/cc_helper.c10
-rw-r--r--target-i386/cpu.c91
-rw-r--r--target-i386/cpu.h21
-rw-r--r--target-i386/fpu_helper.c396
-rw-r--r--target-i386/helper.c14
-rw-r--r--target-i386/helper.h19
-rw-r--r--target-i386/int_helper.c10
-rw-r--r--target-i386/kvm.c34
-rw-r--r--target-i386/mem_helper.c6
-rw-r--r--target-i386/misc_helper.c9
-rw-r--r--target-i386/mpx_helper.c166
-rw-r--r--target-i386/smm_helper.c4
-rw-r--r--target-i386/translate.c1173
-rw-r--r--target-ppc/kvm_ppc.h5
-rw-r--r--target-ppc/mmu-hash64.h4
-rw-r--r--target-ppc/translate.c2
-rw-r--r--tests/Makefile2
-rw-r--r--tests/ac97-test.c3
-rw-r--r--tests/bios-tables-test.c4
-rw-r--r--tests/boot-order-test.c2
-rw-r--r--tests/check-qdict.c1
-rw-r--r--tests/check-qfloat.c1
-rw-r--r--tests/check-qint.c1
-rw-r--r--tests/check-qjson.c1
-rw-r--r--tests/check-qlist.c1
-rw-r--r--tests/check-qom-interface.c1
-rw-r--r--tests/check-qom-proplist.c1
-rw-r--r--tests/check-qstring.c1
-rw-r--r--tests/crypto-tls-x509-helpers.c4
-rw-r--r--tests/device-introspect-test.c2
-rw-r--r--tests/display-vga-test.c3
-rw-r--r--tests/drive_del-test.c2
-rw-r--r--tests/ds1338-test.c1
-rw-r--r--tests/e1000-test.c3
-rw-r--r--tests/eepro100-test.c3
-rw-r--r--tests/endianness-test.c5
-rw-r--r--tests/es1370-test.c3
-rw-r--r--tests/fdc-test.c4
-rw-r--r--tests/fw_cfg-test.c2
-rw-r--r--tests/hd-geo-test.c4
-rw-r--r--tests/i440fx-test.c8
-rw-r--r--tests/i82801b11-test.c3
-rw-r--r--tests/intel-hda-test.c3
-rw-r--r--tests/io-channel-helpers.c1
-rw-r--r--tests/ioh3420-test.c3
-rw-r--r--tests/ipmi-bt-test.c5
-rw-r--r--tests/ipmi-kcs-test.c4
-rw-r--r--tests/ipoctal232-test.c3
-rw-r--r--tests/ivshmem-test.c6
-rw-r--r--tests/libqos/fw_cfg.c1
-rw-r--r--tests/libqos/i2c-imx.c3
-rw-r--r--tests/libqos/i2c-omap.c3
-rw-r--r--tests/libqos/i2c.c1
-rw-r--r--tests/libqos/libqos-pc.c1
-rw-r--r--tests/libqos/libqos.c6
-rw-r--r--tests/libqos/malloc-generic.c1
-rw-r--r--tests/libqos/malloc-pc.c1
-rw-r--r--tests/libqos/malloc.c3
-rw-r--r--tests/libqos/pci-pc.c1
-rw-r--r--tests/libqos/pci.c1
-rw-r--r--tests/libqos/usb.c3
-rw-r--r--tests/libqos/virtio-mmio.c2
-rw-r--r--tests/libqos/virtio-pci.c2
-rw-r--r--tests/libqos/virtio.c1
-rw-r--r--tests/libqtest.c12
-rw-r--r--tests/m48t59-test.c5
-rw-r--r--tests/ne2000-test.c3
-rw-r--r--tests/nvme-test.c3
-rw-r--r--tests/pc-cpu-test.c3
-rw-r--r--tests/pcnet-test.c3
-rw-r--r--tests/pkix_asn1_tab.c1
-rw-r--r--tests/pvpanic-test.c3
-rw-r--r--tests/q35-test.c3
-rw-r--r--tests/qemu-iotests/140.out2
-rw-r--r--tests/qemu-iotests/143.out2
-rw-r--r--tests/qemu-iotests/socket_scm_helper.c8
-rw-r--r--tests/qom-test.c3
-rw-r--r--tests/rcutorture.c5
-rw-r--r--tests/rtc-test.c5
-rw-r--r--tests/rtl8139-test.c3
-rw-r--r--tests/spapr-phb-test.c1
-rw-r--r--tests/tco-test.c4
-rw-r--r--tests/test-aio.c1
-rw-r--r--tests/test-base64.c1
-rw-r--r--tests/test-bitops.c3
-rw-r--r--tests/test-blockjob-txn.c2
-rw-r--r--tests/test-coroutine.c1
-rw-r--r--tests/test-crypto-cipher.c1
-rw-r--r--tests/test-crypto-hash.c1
-rw-r--r--tests/test-crypto-secret.c1
-rw-r--r--tests/test-crypto-tlscredsx509.c4
-rw-r--r--tests/test-crypto-tlssession.c4
-rw-r--r--tests/test-cutils.c3
-rw-r--r--tests/test-hbitmap.c4
-rw-r--r--tests/test-int128.c3
-rw-r--r--tests/test-io-channel-buffer.c1
-rw-r--r--tests/test-io-channel-command.c1
-rw-r--r--tests/test-io-channel-file.c23
-rw-r--r--tests/test-io-channel-socket.c22
-rw-r--r--tests/test-io-channel-tls.c4
-rw-r--r--tests/test-io-task.c1
-rw-r--r--tests/test-iov.c1
-rw-r--r--tests/test-mul64.c3
-rw-r--r--tests/test-netfilter.c1
-rw-r--r--tests/test-opts-visitor.c1
-rw-r--r--tests/test-qdev-global-props.c2
-rw-r--r--tests/test-qemu-opts.c3
-rw-r--r--tests/test-qga.c9
-rw-r--r--tests/test-qmp-commands.c1
-rw-r--r--tests/test-qmp-event.c2
-rw-r--r--tests/test-qmp-input-strict.c2
-rw-r--r--tests/test-qmp-input-visitor.c2
-rw-r--r--tests/test-qmp-output-visitor.c1
-rw-r--r--tests/test-rcu-list.c6
-rw-r--r--tests/test-rfifolock.c1
-rw-r--r--tests/test-string-input-visitor.c2
-rw-r--r--tests/test-string-output-visitor.c1
-rw-r--r--tests/test-thread-pool.c1
-rw-r--r--tests/test-throttle.c1
-rw-r--r--tests/test-timed-average.c2
-rw-r--r--tests/test-visitor-serialization.c3
-rw-r--r--tests/test-vmstate.c1
-rw-r--r--tests/test-write-threshold.c2
-rw-r--r--tests/test-x86-cpuid.c1
-rw-r--r--tests/test-xbzrle.c6
-rw-r--r--tests/tmp105-test.c1
-rw-r--r--tests/tpci200-test.c3
-rw-r--r--tests/vhost-user-bridge.c12
-rw-r--r--tests/vhost-user-test.c1
-rw-r--r--tests/virtio-balloon-test.c3
-rw-r--r--tests/virtio-blk-test.c5
-rw-r--r--tests/virtio-console-test.c3
-rw-r--r--tests/virtio-net-test.c3
-rw-r--r--tests/virtio-rng-test.c3
-rw-r--r--tests/virtio-scsi-test.c4
-rw-r--r--tests/virtio-serial-test.c3
-rw-r--r--tests/vmxnet3-test.c3
-rw-r--r--tests/wdt_ib700-test.c3
-rw-r--r--util/oslib-posix.c9
-rw-r--r--vl.c86
235 files changed, 4777 insertions, 1870 deletions
diff --git a/Makefile b/Makefile
index f9fae3aa16..16db398c6f 100644
--- a/Makefile
+++ b/Makefile
@@ -234,9 +234,9 @@ util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
qemu-img.o: qemu-img-cmds.h
-qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
-qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
-qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
+qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
+qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
+qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 568c56cbb6..6a9b4c73d7 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -28,7 +28,6 @@
#include "qemu/osdep.h"
#include "nbd-client.h"
-#include "qemu/sockets.h"
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
@@ -48,13 +47,21 @@ static void nbd_teardown_connection(BlockDriverState *bs)
{
NbdClientSession *client = nbd_get_client_session(bs);
+ if (!client->ioc) { /* Already closed */
+ return;
+ }
+
/* finish any pending coroutines */
- shutdown(client->sock, 2);
+ qio_channel_shutdown(client->ioc,
+ QIO_CHANNEL_SHUTDOWN_BOTH,
+ NULL);
nbd_recv_coroutines_enter_all(client);
nbd_client_detach_aio_context(bs);
- closesocket(client->sock);
- client->sock = -1;
+ object_unref(OBJECT(client->sioc));
+ client->sioc = NULL;
+ object_unref(OBJECT(client->ioc));
+ client->ioc = NULL;
}
static void nbd_reply_ready(void *opaque)
@@ -64,12 +71,16 @@ static void nbd_reply_ready(void *opaque)
uint64_t i;
int ret;
+ if (!s->ioc) { /* Already closed */
+ return;
+ }
+
if (s->reply.handle == 0) {
/* No reply already in flight. Fetch a header. It is possible
* that another thread has done the same thing in parallel, so
* the socket is not readable anymore.
*/
- ret = nbd_receive_reply(s->sock, &s->reply);
+ ret = nbd_receive_reply(s->ioc, &s->reply);
if (ret == -EAGAIN) {
return;
}
@@ -120,32 +131,35 @@ static int nbd_co_send_request(BlockDriverState *bs,
}
}
+ g_assert(qemu_in_coroutine());
assert(i < MAX_NBD_REQUESTS);
request->handle = INDEX_TO_HANDLE(s, i);
+
+ if (!s->ioc) {
+ qemu_co_mutex_unlock(&s->send_mutex);
+ return -EPIPE;
+ }
+
s->send_coroutine = qemu_coroutine_self();
aio_context = bdrv_get_aio_context(bs);
- aio_set_fd_handler(aio_context, s->sock, false,
+ aio_set_fd_handler(aio_context, s->sioc->fd, false,
nbd_reply_ready, nbd_restart_write, bs);
if (qiov) {
- if (!s->is_unix) {
- socket_set_cork(s->sock, 1);
- }
- rc = nbd_send_request(s->sock, request);
+ qio_channel_set_cork(s->ioc, true);
+ rc = nbd_send_request(s->ioc, request);
if (rc >= 0) {
- ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
- offset, request->len);
+ ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov,
+ offset, request->len, 0);
if (ret != request->len) {
rc = -EIO;
}
}
- if (!s->is_unix) {
- socket_set_cork(s->sock, 0);
- }
+ qio_channel_set_cork(s->ioc, false);
} else {
- rc = nbd_send_request(s->sock, request);
+ rc = nbd_send_request(s->ioc, request);
}
- aio_set_fd_handler(aio_context, s->sock, false,
+ aio_set_fd_handler(aio_context, s->sioc->fd, false,
nbd_reply_ready, NULL, bs);
s->send_coroutine = NULL;
qemu_co_mutex_unlock(&s->send_mutex);
@@ -162,12 +176,13 @@ static void nbd_co_receive_reply(NbdClientSession *s,
* peek at the next reply and avoid yielding if it's ours? */
qemu_coroutine_yield();
*reply = s->reply;
- if (reply->handle != request->handle) {
+ if (reply->handle != request->handle ||
+ !s->ioc) {
reply->error = EIO;
} else {
if (qiov && reply->error == 0) {
- ret = qemu_co_recvv(s->sock, qiov->iov, qiov->niov,
- offset, request->len);
+ ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov,
+ offset, request->len, 1);
if (ret != request->len) {
reply->error = EIO;
}
@@ -350,14 +365,14 @@ int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
void nbd_client_detach_aio_context(BlockDriverState *bs)
{
aio_set_fd_handler(bdrv_get_aio_context(bs),
- nbd_get_client_session(bs)->sock,
+ nbd_get_client_session(bs)->sioc->fd,
false, NULL, NULL, NULL);
}
void nbd_client_attach_aio_context(BlockDriverState *bs,
AioContext *new_context)
{
- aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sock,
+ aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sioc->fd,
false, nbd_reply_ready, NULL, bs);
}
@@ -370,16 +385,20 @@ void nbd_client_close(BlockDriverState *bs)
.len = 0
};
- if (client->sock == -1) {
+ if (client->ioc == NULL) {
return;
}
- nbd_send_request(client->sock, &request);
+ nbd_send_request(client->ioc, &request);
nbd_teardown_connection(bs);
}
-int nbd_client_init(BlockDriverState *bs, int sock, const char *export,
+int nbd_client_init(BlockDriverState *bs,
+ QIOChannelSocket *sioc,
+ const char *export,
+ QCryptoTLSCreds *tlscreds,
+ const char *hostname,
Error **errp)
{
NbdClientSession *client = nbd_get_client_session(bs);
@@ -387,22 +406,32 @@ int nbd_client_init(BlockDriverState *bs, int sock, const char *export,
/* NBD handshake */
logout("session init %s\n", export);
- qemu_set_block(sock);
- ret = nbd_receive_negotiate(sock, export,
- &client->nbdflags, &client->size, errp);
+ qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);
+
+ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
+ &client->nbdflags,
+ tlscreds, hostname,
+ &client->ioc,
+ &client->size, errp);
if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
- closesocket(sock);
return ret;
}
qemu_co_mutex_init(&client->send_mutex);
qemu_co_mutex_init(&client->free_sema);
- client->sock = sock;
+ client->sioc = sioc;
+ object_ref(OBJECT(client->sioc));
+
+ if (!client->ioc) {
+ client->ioc = QIO_CHANNEL(sioc);
+ object_ref(OBJECT(client->ioc));
+ }
/* Now that we're connected, set the socket to be non-blocking and
* kick the reply mechanism. */
- qemu_set_nonblock(sock);
+ qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);
+
nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));
logout("Established connection with NBD server\n");
diff --git a/block/nbd-client.h b/block/nbd-client.h
index e8413408b5..53f116d017 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -4,6 +4,7 @@
#include "qemu-common.h"
#include "block/nbd.h"
#include "block/block_int.h"
+#include "io/channel-socket.h"
/* #define DEBUG_NBD */
@@ -17,7 +18,8 @@
#define MAX_NBD_REQUESTS 16
typedef struct NbdClientSession {
- int sock;
+ QIOChannelSocket *sioc; /* The master data channel */
+ QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
uint32_t nbdflags;
off_t size;
@@ -34,7 +36,11 @@ typedef struct NbdClientSession {
NbdClientSession *nbd_get_client_session(BlockDriverState *bs);
-int nbd_client_init(BlockDriverState *bs, int sock, const char *export_name,
+int nbd_client_init(BlockDriverState *bs,
+ QIOChannelSocket *sock,
+ const char *export_name,
+ QCryptoTLSCreds *tlscreds,
+ const char *hostname,
Error **errp);
void nbd_client_close(BlockDriverState *bs);
diff --git a/block/nbd.c b/block/nbd.c
index 1a90bc7855..db57b4951c 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -31,7 +31,6 @@
#include "qemu/uri.h"
#include "block/block_int.h"
#include "qemu/module.h"
-#include "qemu/sockets.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qint.h"
@@ -238,55 +237,113 @@ NbdClientSession *nbd_get_client_session(BlockDriverState *bs)
return &s->client;
}
-static int nbd_establish_connection(BlockDriverState *bs,
- SocketAddress *saddr,
- Error **errp)
+static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
+ Error **errp)
{
- BDRVNBDState *s = bs->opaque;
- int sock;
+ QIOChannelSocket *sioc;
+ Error *local_err = NULL;
- sock = socket_connect(saddr, errp, NULL, NULL);
+ sioc = qio_channel_socket_new();
- if (sock < 0) {
- logout("Failed to establish connection to NBD server\n");
- return -EIO;
+ qio_channel_socket_connect_sync(sioc,
+ saddr,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return NULL;
}
- if (!s->client.is_unix) {
- socket_set_nodelay(sock);
+ qio_channel_set_delay(QIO_CHANNEL(sioc), false);
+
+ return sioc;
+}
+
+
+static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
+{
+ Object *obj;
+ QCryptoTLSCreds *creds;
+
+ obj = object_resolve_path_component(
+ object_get_objects_root(), id);
+ if (!obj) {
+ error_setg(errp, "No TLS credentials with id '%s'",
+ id);
+ return NULL;
+ }
+ creds = (QCryptoTLSCreds *)
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
+ if (!creds) {
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
+ id);
+ return NULL;
}
- return sock;
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+ error_setg(errp,
+ "Expecting TLS credentials with a client endpoint");
+ return NULL;
+ }
+ object_ref(obj);
+ return creds;
}
+
static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVNBDState *s = bs->opaque;
char *export = NULL;
- int result, sock;
+ QIOChannelSocket *sioc = NULL;
SocketAddress *saddr;
+ const char *tlscredsid;
+ QCryptoTLSCreds *tlscreds = NULL;
+ const char *hostname = NULL;
+ int ret = -EINVAL;
/* Pop the config into our state object. Exit if invalid. */
saddr = nbd_config(s, options, &export, errp);
if (!saddr) {
- return -EINVAL;
+ goto error;
+ }
+
+ tlscredsid = g_strdup(qdict_get_try_str(options, "tls-creds"));
+ if (tlscredsid) {
+ qdict_del(options, "tls-creds");
+ tlscreds = nbd_get_tls_creds(tlscredsid, errp);
+ if (!tlscreds) {
+ goto error;
+ }
+
+ if (saddr->type != SOCKET_ADDRESS_KIND_INET) {
+ error_setg(errp, "TLS only supported over IP sockets");
+ goto error;
+ }
+ hostname = saddr->u.inet->host;
}
/* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour.
*/
- sock = nbd_establish_connection(bs, saddr, errp);
- qapi_free_SocketAddress(saddr);
- if (sock < 0) {
- g_free(export);
- return sock;
+ sioc = nbd_establish_connection(saddr, errp);
+ if (!sioc) {
+ ret = -ECONNREFUSED;
+ goto error;
}
/* NBD handshake */
- result = nbd_client_init(bs, sock, export, errp);
+ ret = nbd_client_init(bs, sioc, export,
+ tlscreds, hostname, errp);
+ error:
+ if (sioc) {
+ object_unref(OBJECT(sioc));
+ }
+ if (tlscreds) {
+ object_unref(OBJECT(tlscreds));
+ }
+ qapi_free_SocketAddress(saddr);
g_free(export);
- return result;
+ return ret;
}
static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
@@ -348,6 +405,7 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
const char *host = qdict_get_try_str(options, "host");
const char *port = qdict_get_try_str(options, "port");
const char *export = qdict_get_try_str(options, "export");
+ const char *tlscreds = qdict_get_try_str(options, "tls-creds");
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
@@ -382,6 +440,9 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
if (export) {
qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(export)));
}
+ if (tlscreds) {
+ qdict_put_obj(opts, "tls-creds", QOBJECT(qstring_from_str(tlscreds)));
+ }
bs->full_open_options = opts;
}
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index efc31a462c..12cae0ea72 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -18,32 +18,128 @@
#include "qmp-commands.h"
#include "trace.h"
#include "block/nbd.h"
-#include "qemu/sockets.h"
+#include "io/channel-socket.h"
-static int server_fd = -1;
+typedef struct NBDServerData {
+ QIOChannelSocket *listen_ioc;
+ int watch;
+ QCryptoTLSCreds *tlscreds;
+} NBDServerData;
-static void nbd_accept(void *opaque)
+static NBDServerData *nbd_server;
+
+
+static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
+ gpointer opaque)
+{
+ QIOChannelSocket *cioc;
+
+ if (!nbd_server) {
+ return FALSE;
+ }
+
+ cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+ NULL);
+ if (!cioc) {
+ return TRUE;
+ }
+
+ nbd_client_new(NULL, cioc,
+ nbd_server->tlscreds, NULL,
+ nbd_client_put);
+ object_unref(OBJECT(cioc));
+ return TRUE;
+}
+
+
+static void nbd_server_free(NBDServerData *server)
+{
+ if (!server) {
+ return;
+ }
+
+ if (server->watch != -1) {
+ g_source_remove(server->watch);
+ }
+ object_unref(OBJECT(server->listen_ioc));
+ if (server->tlscreds) {
+ object_unref(OBJECT(server->tlscreds));
+ }
+
+ g_free(server);
+}
+
+static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
{
- struct sockaddr_in addr;
- socklen_t addr_len = sizeof(addr);
+ Object *obj;
+ QCryptoTLSCreds *creds;
+
+ obj = object_resolve_path_component(
+ object_get_objects_root(), id);
+ if (!obj) {
+ error_setg(errp, "No TLS credentials with id '%s'",
+ id);
+ return NULL;
+ }
+ creds = (QCryptoTLSCreds *)
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
+ if (!creds) {
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
+ id);
+ return NULL;
+ }
- int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
- if (fd >= 0) {
- nbd_client_new(NULL, fd, nbd_client_put);
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ error_setg(errp,
+ "Expecting TLS credentials with a server endpoint");
+ return NULL;
}
+ object_ref(obj);
+ return creds;
}
-void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
+
+void qmp_nbd_server_start(SocketAddress *addr,
+ bool has_tls_creds, const char *tls_creds,
+ Error **errp)
{
- if (server_fd != -1) {
+ if (nbd_server) {
error_setg(errp, "NBD server already running");
return;
}
- server_fd = socket_listen(addr, errp);
- if (server_fd != -1) {
- qemu_set_fd_handler(server_fd, nbd_accept, NULL, NULL);
+ nbd_server = g_new0(NBDServerData, 1);
+ nbd_server->watch = -1;
+ nbd_server->listen_ioc = qio_channel_socket_new();
+ if (qio_channel_socket_listen_sync(
+ nbd_server->listen_ioc, addr, errp) < 0) {
+ goto error;
}
+
+ if (has_tls_creds) {
+ nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
+ if (!nbd_server->tlscreds) {
+ goto error;
+ }
+
+ if (addr->type != SOCKET_ADDRESS_KIND_INET) {
+ error_setg(errp, "TLS is only supported with IPv4/IPv6");
+ goto error;
+ }
+ }
+
+ nbd_server->watch = qio_channel_add_watch(
+ QIO_CHANNEL(nbd_server->listen_ioc),
+ G_IO_IN,
+ nbd_accept,
+ NULL,
+ NULL);
+
+ return;
+
+ error:
+ nbd_server_free(nbd_server);
+ nbd_server = NULL;
}
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
@@ -52,7 +148,7 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
BlockBackend *blk;
NBDExport *exp;
- if (server_fd == -1) {
+ if (!nbd_server) {
error_setg(errp, "NBD server not running");
return;
}
@@ -98,9 +194,6 @@ void qmp_nbd_server_stop(Error **errp)
{
nbd_export_close_all();
- if (server_fd != -1) {
- qemu_set_fd_handler(server_fd, NULL, NULL, NULL);
- close(server_fd);
- server_fd = -1;
- }
+ nbd_server_free(nbd_server);
+ nbd_server = NULL;
}
diff --git a/hmp.c b/hmp.c
index c6419da72f..996cb91027 100644
--- a/hmp.c
+++ b/hmp.c
@@ -30,6 +30,7 @@
#include "qapi/string-output-visitor.h"
#include "qapi/util.h"
#include "qapi-visit.h"
+#include "qom/object_interfaces.h"
#include "ui/console.h"
#include "block/qapi.h"
#include "qemu-io.h"
@@ -1655,58 +1656,27 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
void hmp_object_add(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
- Error *err_end = NULL;
QemuOpts *opts;
- char *type = NULL;
- char *id = NULL;
OptsVisitor *ov;
- QDict *pdict;
- Visitor *v;
+ Object *obj = NULL;
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
if (err) {
- goto out;
+ hmp_handle_error(mon, &err);
+ return;
}
ov = opts_visitor_new(opts);
- pdict = qdict_clone_shallow(qdict);
- v = opts_get_visitor(ov);
-
- visit_start_struct(v, NULL, NULL, 0, &err);
- if (err) {
- goto out_clean;
- }
-
- qdict_del(pdict, "qom-type");
- visit_type_str(v, "qom-type", &type, &err);
- if (err) {
- goto out_end;
- }
+ obj = user_creatable_add(qdict, opts_get_visitor(ov), &err);
+ opts_visitor_cleanup(ov);
+ qemu_opts_del(opts);
- qdict_del(pdict, "id");
- visit_type_str(v, "id", &id, &err);
if (err) {
- goto out_end;
+ hmp_handle_error(mon, &err);
}
-
- object_add(type, id, pdict, v, &err);
-
-out_end:
- visit_end_struct(v, &err_end);
- if (!err && err_end) {
- qmp_object_del(id, NULL);
+ if (obj) {
+ object_unref(obj);
}
- error_propagate(&err, err_end);
-out_clean:
- opts_visitor_cleanup(ov);
-
- QDECREF(pdict);
- qemu_opts_del(opts);
- g_free(id);
- g_free(type);
-
-out:
- hmp_handle_error(mon, &err);
}
void hmp_getfd(Monitor *mon, const QDict *qdict)
@@ -1823,7 +1793,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
goto exit;
}
- qmp_nbd_server_start(addr, &local_err);
+ qmp_nbd_server_start(addr, false, NULL, &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
goto exit;
@@ -1934,7 +1904,7 @@ void hmp_object_del(Monitor *mon, const QDict *qdict)
const char *id = qdict_get_str(qdict, "id");
Error *err = NULL;
- qmp_object_del(id, &err);
+ user_creatable_del(id, &err);
hmp_handle_error(mon, &err);
}
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index e4fb48b803..72467fd907 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -8,6 +8,7 @@
* This code is licensed under the GNU GPLv2 and later.
*/
+#include "qemu/osdep.h"
#include "hw/arm/bcm2835_peripherals.h"
#include "hw/misc/bcm2835_mbox_defs.h"
#include "hw/arm/raspi_platform.h"
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 8a4d13c7d9..15c7622ad1 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -8,6 +8,7 @@
* This code is licensed under the GNU GPLv2 and later.
*/
+#include "qemu/osdep.h"
#include "hw/arm/bcm2836.h"
#include "hw/arm/raspi_platform.h"
#include "hw/sysbus.h"
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 7d3d21ab32..48d014c8d3 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -8,6 +8,7 @@
* This code is licensed under the GNU GPLv2 and later.
*/
+#include "qemu/osdep.h"
#include "hw/arm/bcm2836.h"
#include "qemu/error-report.h"
#include "hw/boards.h"
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 66e7f27ace..a35983a9ec 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -28,6 +28,7 @@
#include "hw/misc/zynq-xadc.h"
#include "hw/ssi/ssi.h"
#include "qemu/error-report.h"
+#include "hw/sd/sd.h"
#define NUM_SPI_FLASHES 4
#define NUM_QSPI_FLASHES 2
@@ -154,8 +155,10 @@ static void zynq_init(MachineState *machine)
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
- DeviceState *dev;
+ DeviceState *dev, *carddev;
SysBusDevice *busdev;
+ DriveInfo *di;
+ BlockBackend *blk;
qemu_irq pic[64];
int n;
@@ -245,11 +248,23 @@ static void zynq_init(MachineState *machine)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]);
+ di = drive_get_next(IF_SD);
+ blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
+
dev = qdev_create(NULL, "generic-sdhci");
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
+ di = drive_get_next(IF_SD);
+ blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
+
dev = qdev_create(NULL, TYPE_ZYNQ_XADC);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c
index 0de132abd2..a1bd283a52 100644
--- a/hw/arm/xlnx-ep108.c
+++ b/hw/arm/xlnx-ep108.c
@@ -59,6 +59,27 @@ static void xlnx_ep108_init(MachineState *machine)
object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
+ /* Create and plug in the SD cards */
+ for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
+ BusState *bus;
+ DriveInfo *di = drive_get_next(IF_SD);
+ BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ DeviceState *carddev;
+ char *bus_name;
+
+ bus_name = g_strdup_printf("sd-bus%d", i);
+ bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name);
+ g_free(bus_name);
+ if (!bus) {
+ error_report("No SD bus found for SD card %d", i);
+ exit(1);
+ }
+ carddev = qdev_create(bus, TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(carddev), true, "realized",
+ &error_fatal);
+ }
+
for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
SSIBus *spi_bus;
DeviceState *flash_dev;
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 1508d0867d..4fbb63550b 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -327,6 +327,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
+ char *bus_name;
+
object_property_set_bool(OBJECT(&s->sdhci[i]), true,
"realized", &err);
if (err) {
@@ -337,6 +339,12 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sdhci_addr[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
gic_spi[sdhci_intr[i]]);
+ /* Alias controller SD bus to the SoC itself */
+ bus_name = g_strdup_printf("sd-bus%d", i);
+ object_property_add_alias(OBJECT(s), bus_name,
+ OBJECT(&s->sdhci[i]), "sd-bus",
+ &error_abort);
+ g_free(bus_name);
}
for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
diff --git a/hw/block/nand.c b/hw/block/nand.c
index 478e1a6b3f..f51e13fcac 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -18,8 +18,9 @@
#ifndef NAND_IO
-# include "hw/hw.h"
-# include "hw/block/flash.h"
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/block/flash.h"
#include "sysemu/block-backend.h"
#include "hw/qdev.h"
#include "qemu/error-report.h"
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index e5a696ef43..5ece8b068e 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -56,7 +56,6 @@ typedef struct PL061State {
uint32_t slr;
uint32_t den;
uint32_t cr;
- uint32_t float_high;
uint32_t amsel;
qemu_irq irq;
qemu_irq out[8];
@@ -65,8 +64,8 @@ typedef struct PL061State {
static const VMStateDescription vmstate_pl061 = {
.name = "pl061",
- .version_id = 3,
- .minimum_version_id = 3,
+ .version_id = 4,
+ .minimum_version_id = 4,
.fields = (VMStateField[]) {
VMSTATE_UINT32(locked, PL061State),
VMSTATE_UINT32(data, PL061State),
@@ -88,7 +87,6 @@ static const VMStateDescription vmstate_pl061 = {
VMSTATE_UINT32(slr, PL061State),
VMSTATE_UINT32(den, PL061State),
VMSTATE_UINT32(cr, PL061State),
- VMSTATE_UINT32(float_high, PL061State),
VMSTATE_UINT32_V(amsel, PL061State, 2),
VMSTATE_END_OF_LIST()
}
@@ -282,10 +280,32 @@ static void pl061_write(void *opaque, hwaddr offset,
pl061_update(s);
}
-static void pl061_reset(PL061State *s)
+static void pl061_reset(DeviceState *dev)
{
- s->locked = 1;
- s->cr = 0xff;
+ PL061State *s = PL061(dev);
+
+ /* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
+ s->data = 0;
+ s->old_out_data = 0;
+ s->old_in_data = 0;
+ s->dir = 0;
+ s->isense = 0;
+ s->ibe = 0;
+ s->iev = 0;
+ s->im = 0;
+ s->istate = 0;
+ s->afsel = 0;
+ s->dr2r = 0xff;
+ s->dr4r = 0;
+ s->dr8r = 0;
+ s->odr = 0;
+ s->pur = 0;
+ s->pdr = 0;
+ s->slr = 0;
+ s->den = 0;
+ s->locked = 1;
+ s->cr = 0xff;
+ s->amsel = 0;
}
static void pl061_set_irq(void * opaque, int irq, int level)
@@ -318,7 +338,7 @@ static int pl061_initfn(SysBusDevice *sbd)
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, pl061_set_irq, 8);
qdev_init_gpio_out(dev, s->out, 8);
- pl061_reset(s);
+
return 0;
}
@@ -343,6 +363,7 @@ static void pl061_class_init(ObjectClass *klass, void *data)
k->init = pl061_initfn;
dc->vmsd = &vmstate_pl061;
+ dc->reset = &pl061_reset;
}
static const TypeInfo pl061_info = {
diff --git a/hw/input/adb.c b/hw/input/adb.c
index c384856c13..f0ad0d4471 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -89,7 +89,7 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
}
/* XXX: move that to cuda ? */
-int adb_poll(ADBBusState *s, uint8_t *obuf)
+int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
{
ADBDevice *d;
int olen, i;
@@ -100,13 +100,15 @@ int adb_poll(ADBBusState *s, uint8_t *obuf)
if (s->poll_index >= s->nb_devices)
s->poll_index = 0;
d = s->devices[s->poll_index];
- buf[0] = ADB_READREG | (d->devaddr << 4);
- olen = adb_request(s, obuf + 1, buf, 1);
- /* if there is data, we poll again the same device */
- if (olen > 0) {
- obuf[0] = buf[0];
- olen++;
- break;
+ if ((1 << d->devaddr) & poll_mask) {
+ buf[0] = ADB_READREG | (d->devaddr << 4);
+ olen = adb_request(s, obuf + 1, buf, 1);
+ /* if there is data, we poll again the same device */
+ if (olen > 0) {
+ obuf[0] = buf[0];
+ olen++;
+ break;
+ }
}
s->poll_index++;
}
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
index 005a72b1e2..80513b28fd 100644
--- a/hw/intc/bcm2835_ic.c
+++ b/hw/intc/bcm2835_ic.c
@@ -12,6 +12,7 @@
* This code is licensed under the GPL.
*/
+#include "qemu/osdep.h"
#include "hw/intc/bcm2835_ic.h"
#define GPU_IRQS 64
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
index ad622aa99f..d0271810cc 100644
--- a/hw/intc/bcm2836_control.c
+++ b/hw/intc/bcm2836_control.c
@@ -13,6 +13,7 @@
* https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
*/
+#include "qemu/osdep.h"
#include "hw/intc/bcm2836_control.h"
#define REG_GPU_ROUTE 0x0c
diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index f8b21761a2..51d234aa1b 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -534,7 +534,7 @@ static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
continue; /* Not a sensor SDR we set from */
}
- if (sdr->sensor_owner_number > MAX_SENSORS) {
+ if (sdr->sensor_owner_number >= MAX_SENSORS) {
continue;
}
sens = s->sensors + sdr->sensor_owner_number;
@@ -1448,7 +1448,7 @@ static void set_sensor_evt_enable(IPMIBmcSim *ibs,
IPMISensor *sens;
IPMI_CHECK_CMD_LEN(4);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
@@ -1500,7 +1500,7 @@ static void get_sensor_evt_enable(IPMIBmcSim *ibs,
IPMISensor *sens;
IPMI_CHECK_CMD_LEN(3);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
@@ -1521,7 +1521,7 @@ static void rearm_sensor_evts(IPMIBmcSim *ibs,
IPMISensor *sens;
IPMI_CHECK_CMD_LEN(4);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
@@ -1543,7 +1543,7 @@ static void get_sensor_evt_status(IPMIBmcSim *ibs,
IPMISensor *sens;
IPMI_CHECK_CMD_LEN(3);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
@@ -1565,7 +1565,7 @@ static void get_sensor_reading(IPMIBmcSim *ibs,
IPMISensor *sens;
IPMI_CHECK_CMD_LEN(3);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
@@ -1588,7 +1588,7 @@ static void set_sensor_type(IPMIBmcSim *ibs,
IPMI_CHECK_CMD_LEN(5);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
@@ -1607,7 +1607,7 @@ static void get_sensor_type(IPMIBmcSim *ibs,
IPMI_CHECK_CMD_LEN(3);
- if ((cmd[2] > MAX_SENSORS) ||
+ if ((cmd[2] >= MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
return;
diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c
index df1d6e6ad6..500baba7c0 100644
--- a/hw/misc/bcm2835_mbox.c
+++ b/hw/misc/bcm2835_mbox.c
@@ -8,6 +8,7 @@
* https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes
*/
+#include "qemu/osdep.h"
#include "hw/misc/bcm2835_mbox.h"
#define MAIL0_PEEK 0x90
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index 45bd6c18ce..581922abd7 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -3,6 +3,7 @@
* This code is licensed under the GNU GPLv2 and later.
*/
+#include "qemu/osdep.h"
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_mbox_defs.h"
#include "sysemu/dma.h"
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index 316c1ac8da..481abdb754 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -106,7 +106,6 @@
#define CUDA_COMBINED_FORMAT_IIC 0x25
#define CUDA_TIMER_FREQ (4700000 / 6)
-#define CUDA_ADB_POLL_FREQ 50
/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
#define RTC_OFFSET 2082844800
@@ -524,7 +523,7 @@ static void cuda_adb_poll(void *opaque)
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
- olen = adb_poll(&s->adb_bus, obuf + 2);
+ olen = adb_poll(&s->adb_bus, obuf + 2, s->adb_poll_mask);
if (olen > 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x40; /* polled data */
@@ -532,87 +531,213 @@ static void cuda_adb_poll(void *opaque)
}
timer_mod(s->adb_poll_timer,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
+ (get_ticks_per_sec() / (1000 / s->autopoll_rate_ms)));
}
-static void cuda_receive_packet(CUDAState *s,
- const uint8_t *data, int len)
+/* description of commands */
+typedef struct CudaCommand {
+ uint8_t command;
+ const char *name;
+ bool (*handler)(CUDAState *s,
+ const uint8_t *in_args, int in_len,
+ uint8_t *out_args, int *out_len);
+} CudaCommand;
+
+static bool cuda_cmd_autopoll(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
{
- uint8_t obuf[16] = { CUDA_PACKET, 0, data[0] };
int autopoll;
+
+ if (in_len != 1) {
+ return false;
+ }
+
+ autopoll = (in_data[0] != 0);
+ if (autopoll != s->autopoll) {
+ s->autopoll = autopoll;
+ if (autopoll) {
+ timer_mod(s->adb_poll_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ (get_ticks_per_sec() / (1000 / s->autopoll_rate_ms)));
+ } else {
+ timer_del(s->adb_poll_timer);
+ }
+ }
+ return true;
+}
+
+static bool cuda_cmd_set_autorate(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ if (in_len != 1) {
+ return false;
+ }
+
+ /* we don't want a period of 0 ms */
+ /* FIXME: check what real hardware does */
+ if (in_data[0] == 0) {
+ return false;
+ }
+
+ s->autopoll_rate_ms = in_data[0];
+ if (s->autopoll) {
+ timer_mod(s->adb_poll_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ (get_ticks_per_sec() / (1000 / s->autopoll_rate_ms)));
+ }
+ return true;
+}
+
+static bool cuda_cmd_set_device_list(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ if (in_len != 2) {
+ return false;
+ }
+
+ s->adb_poll_mask = (((uint16_t)in_data[0]) << 8) | in_data[1];
+ return true;
+}
+
+static bool cuda_cmd_powerdown(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ if (in_len != 0) {
+ return false;
+ }
+
+ qemu_system_shutdown_request();
+ return true;
+}
+
+static bool cuda_cmd_reset_system(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ if (in_len != 0) {
+ return false;
+ }
+
+ qemu_system_reset_request();
+ return true;
+}
+
+static bool cuda_cmd_set_file_server_flag(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ if (in_len != 1) {
+ return false;
+ }
+
+ qemu_log_mask(LOG_UNIMP,
+ "CUDA: unimplemented command FILE_SERVER_FLAG %d\n",
+ in_data[0]);
+ return true;
+}
+
+static bool cuda_cmd_set_power_message(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ if (in_len != 1) {
+ return false;
+ }
+
+ qemu_log_mask(LOG_UNIMP,
+ "CUDA: unimplemented command SET_POWER_MESSAGE %d\n",
+ in_data[0]);
+ return true;
+}
+
+static bool cuda_cmd_get_time(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
uint32_t ti;
- switch(data[0]) {
- case CUDA_AUTOPOLL:
- autopoll = (data[1] != 0);
- if (autopoll != s->autopoll) {
- s->autopoll = autopoll;
- if (autopoll) {
- timer_mod(s->adb_poll_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
+ if (in_len != 0) {
+ return false;
+ }
+
+ ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
+ / get_ticks_per_sec());
+ out_data[0] = ti >> 24;
+ out_data[1] = ti >> 16;
+ out_data[2] = ti >> 8;
+ out_data[3] = ti;
+ *out_len = 4;
+ return true;
+}
+
+static bool cuda_cmd_set_time(CUDAState *s,
+ const uint8_t *in_data, int in_len,
+ uint8_t *out_data, int *out_len)
+{
+ uint32_t ti;
+
+ if (in_len != 4) {
+ return false;
+ }
+
+ ti = (((uint32_t)in_data[1]) << 24) + (((uint32_t)in_data[2]) << 16)
+ + (((uint32_t)in_data[3]) << 8) + in_data[4];
+ s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
+ / get_ticks_per_sec());
+ return true;
+}
+
+static const CudaCommand handlers[] = {
+ { CUDA_AUTOPOLL, "AUTOPOLL", cuda_cmd_autopoll },
+ { CUDA_SET_AUTO_RATE, "SET_AUTO_RATE", cuda_cmd_set_autorate },
+ { CUDA_SET_DEVICE_LIST, "SET_DEVICE_LIST", cuda_cmd_set_device_list },
+ { CUDA_POWERDOWN, "POWERDOWN", cuda_cmd_powerdown },
+ { CUDA_RESET_SYSTEM, "RESET_SYSTEM", cuda_cmd_reset_system },
+ { CUDA_FILE_SERVER_FLAG, "FILE_SERVER_FLAG",
+ cuda_cmd_set_file_server_flag },
+ { CUDA_SET_POWER_MESSAGES, "SET_POWER_MESSAGES",
+ cuda_cmd_set_power_message },
+ { CUDA_GET_TIME, "GET_TIME", cuda_cmd_get_time },
+ { CUDA_SET_TIME, "SET_TIME", cuda_cmd_set_time },
+};
+
+static void cuda_receive_packet(CUDAState *s,
+ const uint8_t *data, int len)
+{
+ uint8_t obuf[16] = { CUDA_PACKET, 0, data[0] };
+ int i, out_len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+ const CudaCommand *desc = &handlers[i];
+ if (desc->command == data[0]) {
+ CUDA_DPRINTF("handling command %s\n", desc->name);
+ out_len = 0;
+ if (desc->handler(s, data + 1, len - 1, obuf + 3, &out_len)) {
+ cuda_send_packet_to_host(s, obuf, 3 + out_len);
} else {
- timer_del(s->adb_poll_timer);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CUDA: %s: wrong parameters %d\n",
+ desc->name, len);
+ obuf[0] = ERROR_PACKET;
+ obuf[1] = 0x5; /* bad parameters */
+ obuf[2] = CUDA_PACKET;
+ obuf[3] = data[0];
+ cuda_send_packet_to_host(s, obuf, 4);
}
+ return;
}
- cuda_send_packet_to_host(s, obuf, 3);
- break;
- case CUDA_GET_6805_ADDR:
- cuda_send_packet_to_host(s, obuf, 3);
- break;
- case CUDA_SET_TIME:
- ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
- s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec());
- cuda_send_packet_to_host(s, obuf, 3);
- break;
- case CUDA_GET_TIME:
- ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec());
- obuf[3] = ti >> 24;
- obuf[4] = ti >> 16;
- obuf[5] = ti >> 8;
- obuf[6] = ti;
- cuda_send_packet_to_host(s, obuf, 7);
- break;
- case CUDA_FILE_SERVER_FLAG:
- case CUDA_SET_DEVICE_LIST:
- case CUDA_SET_AUTO_RATE:
- case CUDA_SET_POWER_MESSAGES:
- cuda_send_packet_to_host(s, obuf, 3);
- break;
- case CUDA_POWERDOWN:
- cuda_send_packet_to_host(s, obuf, 3);
- qemu_system_shutdown_request();
- break;
- case CUDA_RESET_SYSTEM:
- cuda_send_packet_to_host(s, obuf, 3);
- qemu_system_reset_request();
- break;
- case CUDA_COMBINED_FORMAT_IIC:
- obuf[0] = ERROR_PACKET;
- obuf[1] = 0x5;
- obuf[2] = CUDA_PACKET;
- obuf[3] = data[0];
- cuda_send_packet_to_host(s, obuf, 4);
- break;
- case CUDA_GET_SET_IIC:
- if (len == 4) {
- cuda_send_packet_to_host(s, obuf, 3);
- } else {
- obuf[0] = ERROR_PACKET;
- obuf[1] = 0x2;
- obuf[2] = CUDA_PACKET;
- obuf[3] = data[0];
- cuda_send_packet_to_host(s, obuf, 4);
- }
- break;
- default:
- obuf[0] = ERROR_PACKET;
- obuf[1] = 0x2;
- obuf[2] = CUDA_PACKET;
- obuf[3] = data[0];
- cuda_send_packet_to_host(s, obuf, 4);
- break;
}
+
+ qemu_log_mask(LOG_GUEST_ERROR, "CUDA: unknown command 0x%02x\n", data[0]);
+ obuf[0] = ERROR_PACKET;
+ obuf[1] = 0x2; /* unknown command */
+ obuf[2] = CUDA_PACKET;
+ obuf[3] = data[0];
+ cuda_send_packet_to_host(s, obuf, 4);
}
static void cuda_receive_packet_from_host(CUDAState *s,
@@ -710,8 +835,8 @@ static const VMStateDescription vmstate_cuda_timer = {
static const VMStateDescription vmstate_cuda = {
.name = "cuda",
- .version_id = 3,
- .minimum_version_id = 3,
+ .version_id = 4,
+ .minimum_version_id = 4,
.fields = (VMStateField[]) {
VMSTATE_UINT8(a, CUDAState),
VMSTATE_UINT8(b, CUDAState),
@@ -729,6 +854,8 @@ static const VMStateDescription vmstate_cuda = {
VMSTATE_INT32(data_in_index, CUDAState),
VMSTATE_INT32(data_out_index, CUDAState),
VMSTATE_UINT8(autopoll, CUDAState),
+ VMSTATE_UINT8(autopoll_rate_ms, CUDAState),
+ VMSTATE_UINT16(adb_poll_mask, CUDAState),
VMSTATE_BUFFER(data_in, CUDAState),
VMSTATE_BUFFER(data_out, CUDAState),
VMSTATE_UINT32(tick_offset, CUDAState),
@@ -782,6 +909,8 @@ static void cuda_realizefn(DeviceState *dev, Error **errp)
s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s);
+ s->autopoll_rate_ms = 20;
+ s->adb_poll_mask = 0xffff;
}
static void cuda_initfn(Object *obj)
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index 564ef936d1..1671f4686e 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -49,7 +49,8 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr,
addr = (addr >> s->it_shift) & (s->size - 1);
s->data[addr] = value;
- NVR_DPRINTF("writeb addr %04" PHYS_PRIx " val %" PRIx64 "\n", addr, value);
+ NVR_DPRINTF("writeb addr %04" HWADDR_PRIx " val %" PRIx64 "\n",
+ addr, value);
}
static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
@@ -60,7 +61,8 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
addr = (addr >> s->it_shift) & (s->size - 1);
value = s->data[addr];
- NVR_DPRINTF("readb addr %04x val %x\n", (int)addr, value);
+ NVR_DPRINTF("readb addr %04" HWADDR_PRIx " val %" PRIx32 "\n",
+ addr, value);
return value;
}
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
index 40a2e3e6b4..15b1054232 100644
--- a/hw/pci-host/uninorth.c
+++ b/hw/pci-host/uninorth.c
@@ -120,7 +120,7 @@ static void unin_data_write(void *opaque, hwaddr addr,
{
UNINState *s = opaque;
PCIHostState *phb = PCI_HOST_BRIDGE(s);
- UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
+ UNIN_DPRINTF("write addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
addr, len, val);
pci_data_write(phb->bus,
unin_get_config_reg(phb->config_reg, addr),
@@ -137,7 +137,7 @@ static uint64_t unin_data_read(void *opaque, hwaddr addr,
val = pci_data_read(phb->bus,
unin_get_config_reg(phb->config_reg, addr),
len);
- UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
+ UNIN_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
addr, len, val);
return val;
}
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index ecf7792bc9..5764b86c28 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -111,6 +111,8 @@ typedef struct CUDAState {
int data_out_index;
qemu_irq irq;
+ uint16_t adb_poll_mask;
+ uint8_t autopoll_rate_ms;
uint8_t autopoll;
uint8_t data_in[128];
uint8_t data_out[16];
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 5bd8fd3ef8..e214a34257 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1024,83 +1024,93 @@ static void emulate_spapr_hypercall(PowerPCCPU *cpu)
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
-static void spapr_alloc_htab(sPAPRMachineState *spapr)
+/*
+ * Get the fd to access the kernel htab, re-opening it if necessary
+ */
+static int get_htab_fd(sPAPRMachineState *spapr)
{
- long shift;
- int index;
+ if (spapr->htab_fd >= 0) {
+ return spapr->htab_fd;
+ }
- /* allocate hash page table. For now we always make this 16mb,
- * later we should probably make it scale to the size of guest
- * RAM */
+ spapr->htab_fd = kvmppc_get_htab_fd(false);
+ if (spapr->htab_fd < 0) {
+ error_report("Unable to open fd for reading hash table from KVM: %s",
+ strerror(errno));
+ }
- shift = kvmppc_reset_htab(spapr->htab_shift);
- if (shift < 0) {
- /*
- * For HV KVM, host kernel will return -ENOMEM when requested
- * HTAB size can't be allocated.
- */
- error_setg(&error_abort, "Failed to allocate HTAB of requested size, try with smaller maxmem");
- } else if (shift > 0) {
- /*
- * Kernel handles htab, we don't need to allocate one
- *
- * Older kernels can fall back to lower HTAB shift values,
- * but we don't allow booting of such guests.
- */
- if (shift != spapr->htab_shift) {
- error_setg(&error_abort, "Failed to allocate HTAB of requested size, try with smaller maxmem");
- }
+ return spapr->htab_fd;
+}
- spapr->htab_shift = shift;
- kvmppc_kern_htab = true;
- } else {
- /* Allocate htab */
- spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr));
+static void close_htab_fd(sPAPRMachineState *spapr)
+{
+ if (spapr->htab_fd >= 0) {
+ close(spapr->htab_fd);
+ }
+ spapr->htab_fd = -1;
+}
- /* And clear it */
- memset(spapr->htab, 0, HTAB_SIZE(spapr));
+static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
+{
+ int shift;
- for (index = 0; index < HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; index++) {
- DIRTY_HPTE(HPTE(spapr->htab, index));
- }
- }
+ /* We aim for a hash table of size 1/128 the size of RAM (rounded
+ * up). The PAPR recommendation is actually 1/64 of RAM size, but
+ * that's much more than is needed for Linux guests */
+ shift = ctz64(pow2ceil(ramsize)) - 7;
+ shift = MAX(shift, 18); /* Minimum architected size */
+ shift = MIN(shift, 46); /* Maximum architected size */
+ return shift;
}
-/*
- * Clear HTAB entries during reset.
- *
- * If host kernel has allocated HTAB, KVM_PPC_ALLOCATE_HTAB ioctl is
- * used to clear HTAB. Otherwise QEMU-allocated HTAB is cleared manually.
- */
-static void spapr_reset_htab(sPAPRMachineState *spapr)
+static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
+ Error **errp)
{
- long shift;
- int index;
+ long rc;
- shift = kvmppc_reset_htab(spapr->htab_shift);
- if (shift < 0) {
- error_setg(&error_abort, "Failed to reset HTAB");
- } else if (shift > 0) {
- if (shift != spapr->htab_shift) {
- error_setg(&error_abort, "Requested HTAB allocation failed during reset");
- }
+ /* Clean up any HPT info from a previous boot */
+ g_free(spapr->htab);
+ spapr->htab = NULL;
+ spapr->htab_shift = 0;
+ close_htab_fd(spapr);
- /* Tell readers to update their file descriptor */
- if (spapr->htab_fd >= 0) {
- spapr->htab_fd_stale = true;
+ rc = kvmppc_reset_htab(shift);
+ if (rc < 0) {
+ /* kernel-side HPT needed, but couldn't allocate one */
+ error_setg_errno(errp, errno,
+ "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
+ shift);
+ /* This is almost certainly fatal, but if the caller really
+ * wants to carry on with shift == 0, it's welcome to try */
+ } else if (rc > 0) {
+ /* kernel-side HPT allocated */
+ if (rc != shift) {
+ error_setg(errp,
+ "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
+ shift, rc);
}
+
+ spapr->htab_shift = shift;
+ kvmppc_kern_htab = true;
} else {
- memset(spapr->htab, 0, HTAB_SIZE(spapr));
+ /* kernel-side HPT not needed, allocate in userspace instead */
+ size_t size = 1ULL << shift;
+ int i;
- for (index = 0; index < HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; index++) {
- DIRTY_HPTE(HPTE(spapr->htab, index));
+ spapr->htab = qemu_memalign(size, size);
+ if (!spapr->htab) {
+ error_setg_errno(errp, errno,
+ "Could not allocate HPT of order %d", shift);
+ return;
}
- }
- /* Update the RMA size if necessary */
- if (spapr->vrma_adjust) {
- spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
- spapr->htab_shift);
+ memset(spapr->htab, 0, size);
+ spapr->htab_shift = shift;
+ kvmppc_kern_htab = false;
+
+ for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
+ DIRTY_HPTE(HPTE(spapr->htab, i));
+ }
}
}
@@ -1121,39 +1131,26 @@ static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
return 0;
}
-/*
- * A guest reset will cause spapr->htab_fd to become stale if being used.
- * Reopen the file descriptor to make sure the whole HTAB is properly read.
- */
-static int spapr_check_htab_fd(sPAPRMachineState *spapr)
-{
- int rc = 0;
-
- if (spapr->htab_fd_stale) {
- close(spapr->htab_fd);
- spapr->htab_fd = kvmppc_get_htab_fd(false);
- if (spapr->htab_fd < 0) {
- error_report("Unable to open fd for reading hash table from KVM: "
- "%s", strerror(errno));
- rc = -1;
- }
- spapr->htab_fd_stale = false;
- }
-
- return rc;
-}
-
static void ppc_spapr_reset(void)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ MachineState *machine = MACHINE(qdev_get_machine());
+ sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu;
uint32_t rtas_limit;
/* Check for unknown sysbus devices */
foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
- /* Reset the hash table & recalc the RMA */
- spapr_reset_htab(spapr);
+ /* Allocate and/or reset the hash page table */
+ spapr_reallocate_hpt(spapr,
+ spapr_hpt_shift_for_ramsize(machine->maxram_size),
+ &error_fatal);
+
+ /* Update the RMA size if necessary */
+ if (spapr->vrma_adjust) {
+ spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
+ spapr->htab_shift);
+ }
qemu_devices_reset();
@@ -1200,13 +1197,6 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
env->external_htab = (uint8_t *)spapr->htab;
- if (kvm_enabled() && !env->external_htab) {
- /*
- * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
- * functions do the right thing.
- */
- env->external_htab = (void *)1;
- }
env->htab_base = -1;
/*
* htab_mask is the mask used to normalize hash value to PTEG index.
@@ -1313,14 +1303,6 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
spapr->htab_first_pass = true;
} else {
assert(kvm_enabled());
-
- spapr->htab_fd = kvmppc_get_htab_fd(false);
- spapr->htab_fd_stale = false;
- if (spapr->htab_fd < 0) {
- fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n",
- strerror(errno));
- return -1;
- }
}
@@ -1330,6 +1312,7 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
int64_t max_ns)
{
+ bool has_timeout = max_ns != -1;
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
int index = spapr->htab_save_index;
int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
@@ -1363,7 +1346,8 @@ static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
HASH_PTE_SIZE_64 * n_valid);
- if ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
+ if (has_timeout &&
+ (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
break;
}
}
@@ -1460,6 +1444,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
static int htab_save_iterate(QEMUFile *f, void *opaque)
{
sPAPRMachineState *spapr = opaque;
+ int fd;
int rc = 0;
/* Iteration header */
@@ -1468,13 +1453,12 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
if (!spapr->htab) {
assert(kvm_enabled());
- rc = spapr_check_htab_fd(spapr);
- if (rc < 0) {
- return rc;
+ fd = get_htab_fd(spapr);
+ if (fd < 0) {
+ return fd;
}
- rc = kvmppc_save_htab(f, spapr->htab_fd,
- MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
+ rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
if (rc < 0) {
return rc;
}
@@ -1495,6 +1479,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
static int htab_save_complete(QEMUFile *f, void *opaque)
{
sPAPRMachineState *spapr = opaque;
+ int fd;
/* Iteration header */
qemu_put_be32(f, 0);
@@ -1504,18 +1489,20 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
assert(kvm_enabled());
- rc = spapr_check_htab_fd(spapr);
- if (rc < 0) {
- return rc;
+ fd = get_htab_fd(spapr);
+ if (fd < 0) {
+ return fd;
}
- rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1);
+ rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
if (rc < 0) {
return rc;
}
- close(spapr->htab_fd);
- spapr->htab_fd = -1;
+ close_htab_fd(spapr);
} else {
+ if (spapr->htab_first_pass) {
+ htab_save_first_pass(f, spapr, -1);
+ }
htab_save_later_pass(f, spapr, -1);
}
@@ -1541,10 +1528,12 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
section_hdr = qemu_get_be32(f);
if (section_hdr) {
- /* First section, just the hash shift */
- if (spapr->htab_shift != section_hdr) {
- error_report("htab_shift mismatch: source %d target %d",
- section_hdr, spapr->htab_shift);
+ Error *local_err;
+
+ /* First section gives the htab size */
+ spapr_reallocate_hpt(spapr, section_hdr, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
return -EINVAL;
}
return 0;
@@ -1797,18 +1786,6 @@ static void ppc_spapr_init(MachineState *machine)
/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
- /* We aim for a hash table of size 1/128 the size of RAM. The
- * normal rule of thumb is 1/64 the size of RAM, but that's much
- * more than needed for the Linux guests we support. */
- spapr->htab_shift = 18; /* Minimum architected size */
- while (spapr->htab_shift <= 46) {
- if ((1ULL << (spapr->htab_shift + 7)) >= machine->maxram_size) {
- break;
- }
- spapr->htab_shift++;
- }
- spapr_alloc_htab(spapr);
-
/* Set up Interrupt Controller before we create the VCPUs */
spapr->icp = xics_system_init(machine,
DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(),
@@ -2125,6 +2102,9 @@ static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
static void spapr_machine_initfn(Object *obj)
{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ spapr->htab_fd = -1;
object_property_add_str(obj, "kvm-type",
spapr_get_kvm_type, spapr_set_kvm_type, NULL);
object_property_set_description(obj, "kvm-type",
@@ -2411,6 +2391,7 @@ DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
* pseries-2.4
*/
#define SPAPR_COMPAT_2_4 \
+ SPAPR_COMPAT_2_5 \
HW_COMPAT_2_4
static void spapr_machine_2_4_instance_options(MachineState *machine)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 12f8c33db7..6e9b6be58c 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -38,6 +38,12 @@ static void set_spr(CPUState *cs, int spr, target_ulong value,
run_on_cpu(cs, do_spr_sync, &s);
}
+static bool has_spr(PowerPCCPU *cpu, int spr)
+{
+ /* We can test whether the SPR is defined by checking for a valid name */
+ return cpu->env.spr_cb[spr].name != NULL;
+}
+
static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
{
/*
@@ -332,11 +338,52 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
+static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ cpu_synchronize_state(CPU(cpu));
+ cpu->env.spr[SPR_SPRG0] = args[0];
+
+ return H_SUCCESS;
+}
+
static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- /* FIXME: actually implement this */
- return H_HARDWARE;
+ if (!has_spr(cpu, SPR_DABR)) {
+ return H_HARDWARE; /* DABR register not available */
+ }
+ cpu_synchronize_state(CPU(cpu));
+
+ if (has_spr(cpu, SPR_DABRX)) {
+ cpu->env.spr[SPR_DABRX] = 0x3; /* Use Problem and Privileged state */
+ } else if (!(args[0] & 0x4)) { /* Breakpoint Translation set? */
+ return H_RESERVED_DABR;
+ }
+
+ cpu->env.spr[SPR_DABR] = args[0];
+ return H_SUCCESS;
+}
+
+static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong dabrx = args[1];
+
+ if (!has_spr(cpu, SPR_DABR) || !has_spr(cpu, SPR_DABRX)) {
+ return H_HARDWARE;
+ }
+
+ if ((dabrx & ~0xfULL) != 0 || (dabrx & H_DABRX_HYPERVISOR) != 0
+ || (dabrx & (H_DABRX_KERNEL | H_DABRX_USER)) == 0) {
+ return H_PARAMETER;
+ }
+
+ cpu_synchronize_state(CPU(cpu));
+ cpu->env.spr[SPR_DABRX] = dabrx;
+ cpu->env.spr[SPR_DABR] = args[0];
+
+ return H_SUCCESS;
}
#define FLAGS_REGISTER_VPA 0x0000200000000000ULL
@@ -990,13 +1037,16 @@ static void hypercall_register_types(void)
/* hcall-bulk */
spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
- /* hcall-dabr */
- spapr_register_hypercall(H_SET_DABR, h_set_dabr);
-
/* hcall-splpar */
spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
spapr_register_hypercall(H_CEDE, h_cede);
+ /* processor register resource access h-calls */
+ spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0);
+ spapr_register_hypercall(H_SET_DABR, h_set_dabr);
+ spapr_register_hypercall(H_SET_XDABR, h_set_xdabr);
+ spapr_register_hypercall(H_SET_MODE, h_set_mode);
+
/* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
* here between the "CI" and the "CACHE" variants, they will use whatever
* mapping attributes qemu is using. When using KVM, the kernel will
@@ -1013,8 +1063,6 @@ static void hypercall_register_types(void)
/* qemu/KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
- spapr_register_hypercall(H_SET_MODE, h_set_mode);
-
/* ibm,client-architecture-support support */
spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support);
}
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 07ad672e5a..b7c5ebde40 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -113,6 +113,7 @@ static void rtas_power_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return;
}
qemu_system_shutdown_request();
+ cpu_stop_current();
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
diff --git a/hw/scsi/mptconfig.c b/hw/scsi/mptconfig.c
index d04982513a..707185469e 100644
--- a/hw/scsi/mptconfig.c
+++ b/hw/scsi/mptconfig.c
@@ -123,6 +123,7 @@ static size_t vpack(uint8_t **p_data, const char *fmt, va_list ap1)
va_copy(ap2, ap1);
size = vfill(NULL, 0, fmt, ap2);
*p_data = data = g_malloc(size);
+ va_end(ap2);
}
return vfill(data, size, fmt, ap1);
}
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 333cc1fb97..499c1465ae 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -504,6 +504,7 @@ reply_maybe_async:
reply_async->IOCLogInfo = count;
return;
}
+ g_free(reply_async);
reply.TerminationCount = count;
break;
@@ -823,7 +824,7 @@ static uint32_t mptsas_doorbell_read(MPTSASState *s)
{
uint32_t ret;
- ret = (s->who_init << MPI_DOORBELL_WHO_INIT_SHIFT) & MPI_DOORBELL_WHO_INIT_SHIFT;
+ ret = (s->who_init << MPI_DOORBELL_WHO_INIT_SHIFT) & MPI_DOORBELL_WHO_INIT_MASK;
ret |= s->state;
switch (s->doorbell_state) {
case DOORBELL_NONE:
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs
index f1aed83d9d..31c83308f2 100644
--- a/hw/sd/Makefile.objs
+++ b/hw/sd/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-$(CONFIG_PL181) += pl181.o
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
-common-obj-$(CONFIG_SD) += sd.o
+common-obj-$(CONFIG_SD) += sd.o core.o
common-obj-$(CONFIG_SDHCI) += sdhci.o
obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
diff --git a/hw/sd/core.c b/hw/sd/core.c
new file mode 100644
index 0000000000..14c2bdf27b
--- /dev/null
+++ b/hw/sd/core.c
@@ -0,0 +1,146 @@
+/*
+ * SD card bus interface code.
+ *
+ * Copyright (c) 2015 Linaro Limited
+ *
+ * Author:
+ * Peter Maydell <peter.maydell@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-core.h"
+#include "sysemu/block-backend.h"
+#include "hw/sd/sd.h"
+
+static SDState *get_card(SDBus *sdbus)
+{
+ /* We only ever have one child on the bus so just return it */
+ BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
+
+ if (!kid) {
+ return NULL;
+ }
+ return SD_CARD(kid->child);
+}
+
+int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->do_command(card, req, response);
+ }
+
+ return 0;
+}
+
+void sdbus_write_data(SDBus *sdbus, uint8_t value)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ sc->write_data(card, value);
+ }
+}
+
+uint8_t sdbus_read_data(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->read_data(card);
+ }
+
+ return 0;
+}
+
+bool sdbus_data_ready(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->data_ready(card);
+ }
+
+ return false;
+}
+
+bool sdbus_get_inserted(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->get_inserted(card);
+ }
+
+ return false;
+}
+
+bool sdbus_get_readonly(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->get_readonly(card);
+ }
+
+ return false;
+}
+
+void sdbus_set_inserted(SDBus *sdbus, bool inserted)
+{
+ SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
+ BusState *qbus = BUS(sdbus);
+
+ if (sbc->set_inserted) {
+ sbc->set_inserted(qbus->parent, inserted);
+ }
+}
+
+void sdbus_set_readonly(SDBus *sdbus, bool readonly)
+{
+ SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
+ BusState *qbus = BUS(sdbus);
+
+ if (sbc->set_readonly) {
+ sbc->set_readonly(qbus->parent, readonly);
+ }
+}
+
+static const TypeInfo sd_bus_info = {
+ .name = TYPE_SD_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(SDBus),
+ .class_size = sizeof(SDBusClass),
+};
+
+static void sd_bus_register_types(void)
+{
+ type_register_static(&sd_bus_info);
+}
+
+type_init(sd_bus_register_types)
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
index 81da7b7bbd..9c3679b5db 100644
--- a/hw/sd/pxa2xx_mmci.c
+++ b/hw/sd/pxa2xx_mmci.c
@@ -12,17 +12,31 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
+#include "hw/sysbus.h"
#include "hw/arm/pxa.h"
#include "hw/sd/sd.h"
#include "hw/qdev.h"
+#include "hw/qdev-properties.h"
+#include "qemu/error-report.h"
+
+#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
+#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI)
+
+#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
+#define PXA2XX_MMCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_PXA2XX_MMCI_BUS)
struct PXA2xxMMCIState {
+ SysBusDevice parent_obj;
+
MemoryRegion iomem;
qemu_irq irq;
qemu_irq rx_dma;
qemu_irq tx_dma;
+ qemu_irq inserted;
+ qemu_irq readonly;
- SDState *card;
+ BlockBackend *blk;
+ SDBus sdbus;
uint32_t status;
uint32_t clkrt;
@@ -30,25 +44,70 @@ struct PXA2xxMMCIState {
uint32_t cmdat;
uint32_t resp_tout;
uint32_t read_tout;
- int blklen;
- int numblk;
+ int32_t blklen;
+ int32_t numblk;
uint32_t intmask;
uint32_t intreq;
- int cmd;
+ int32_t cmd;
uint32_t arg;
- int active;
- int bytesleft;
+ int32_t active;
+ int32_t bytesleft;
uint8_t tx_fifo[64];
- int tx_start;
- int tx_len;
+ uint32_t tx_start;
+ uint32_t tx_len;
uint8_t rx_fifo[32];
- int rx_start;
- int rx_len;
+ uint32_t rx_start;
+ uint32_t rx_len;
uint16_t resp_fifo[9];
- int resp_len;
+ uint32_t resp_len;
- int cmdreq;
+ int32_t cmdreq;
+};
+
+static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id)
+{
+ PXA2xxMMCIState *s = opaque;
+
+ return s->tx_start < ARRAY_SIZE(s->tx_fifo)
+ && s->rx_start < ARRAY_SIZE(s->rx_fifo)
+ && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
+ && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
+ && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
+}
+
+
+static const VMStateDescription vmstate_pxa2xx_mmci = {
+ .name = "pxa2xx-mmci",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(status, PXA2xxMMCIState),
+ VMSTATE_UINT32(clkrt, PXA2xxMMCIState),
+ VMSTATE_UINT32(spi, PXA2xxMMCIState),
+ VMSTATE_UINT32(cmdat, PXA2xxMMCIState),
+ VMSTATE_UINT32(resp_tout, PXA2xxMMCIState),
+ VMSTATE_UINT32(read_tout, PXA2xxMMCIState),
+ VMSTATE_INT32(blklen, PXA2xxMMCIState),
+ VMSTATE_INT32(numblk, PXA2xxMMCIState),
+ VMSTATE_UINT32(intmask, PXA2xxMMCIState),
+ VMSTATE_UINT32(intreq, PXA2xxMMCIState),
+ VMSTATE_INT32(cmd, PXA2xxMMCIState),
+ VMSTATE_UINT32(arg, PXA2xxMMCIState),
+ VMSTATE_INT32(cmdreq, PXA2xxMMCIState),
+ VMSTATE_INT32(active, PXA2xxMMCIState),
+ VMSTATE_INT32(bytesleft, PXA2xxMMCIState),
+ VMSTATE_UINT32(tx_start, PXA2xxMMCIState),
+ VMSTATE_UINT32(tx_len, PXA2xxMMCIState),
+ VMSTATE_UINT32(rx_start, PXA2xxMMCIState),
+ VMSTATE_UINT32(rx_len, PXA2xxMMCIState),
+ VMSTATE_UINT32(resp_len, PXA2xxMMCIState),
+ VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate),
+ VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64),
+ VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32),
+ VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9),
+ VMSTATE_END_OF_LIST()
+ }
};
#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
@@ -122,7 +181,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
if (s->cmdat & CMDAT_WR_RD) {
while (s->bytesleft && s->tx_len) {
- sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
+ sdbus_write_data(&s->sdbus, s->tx_fifo[s->tx_start++]);
s->tx_start &= 0x1f;
s->tx_len --;
s->bytesleft --;
@@ -132,7 +191,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
} else
while (s->bytesleft && s->rx_len < 32) {
s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
- sd_read_data(s->card);
+ sdbus_read_data(&s->sdbus);
s->bytesleft --;
s->intreq |= INT_RXFIFO_REQ;
}
@@ -166,7 +225,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
request.arg = s->arg;
request.crc = 0; /* FIXME */
- rsplen = sd_do_command(s->card, &request, response);
+ rsplen = sdbus_do_command(&s->sdbus, &request, response);
s->intreq |= INT_END_CMD;
memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
@@ -392,114 +451,147 @@ static const MemoryRegionOps pxa2xx_mmci_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void pxa2xx_mmci_save(QEMUFile *f, void *opaque)
+PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
+ hwaddr base,
+ BlockBackend *blk, qemu_irq irq,
+ qemu_irq rx_dma, qemu_irq tx_dma)
{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- int i;
-
- qemu_put_be32s(f, &s->status);
- qemu_put_be32s(f, &s->clkrt);
- qemu_put_be32s(f, &s->spi);
- qemu_put_be32s(f, &s->cmdat);
- qemu_put_be32s(f, &s->resp_tout);
- qemu_put_be32s(f, &s->read_tout);
- qemu_put_be32(f, s->blklen);
- qemu_put_be32(f, s->numblk);
- qemu_put_be32s(f, &s->intmask);
- qemu_put_be32s(f, &s->intreq);
- qemu_put_be32(f, s->cmd);
- qemu_put_be32s(f, &s->arg);
- qemu_put_be32(f, s->cmdreq);
- qemu_put_be32(f, s->active);
- qemu_put_be32(f, s->bytesleft);
-
- qemu_put_byte(f, s->tx_len);
- for (i = 0; i < s->tx_len; i ++)
- qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
-
- qemu_put_byte(f, s->rx_len);
- for (i = 0; i < s->rx_len; i ++)
- qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
-
- qemu_put_byte(f, s->resp_len);
- for (i = s->resp_len; i < 9; i ++)
- qemu_put_be16s(f, &s->resp_fifo[i]);
+ DeviceState *dev, *carddev;
+ SysBusDevice *sbd;
+ PXA2xxMMCIState *s;
+ Error *err = NULL;
+
+ dev = qdev_create(NULL, TYPE_PXA2XX_MMCI);
+ s = PXA2XX_MMCI(dev);
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(sbd, 0, base);
+ sysbus_connect_irq(sbd, 0, irq);
+ qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
+ qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
+
+ /* Create and plug in the sd card */
+ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &err);
+ if (err) {
+ error_report("failed to init SD card: %s", error_get_pretty(err));
+ return NULL;
+ }
+ object_property_set_bool(OBJECT(carddev), true, "realized", &err);
+ if (err) {
+ error_report("failed to init SD card: %s", error_get_pretty(err));
+ return NULL;
+ }
+
+ return s;
}
-static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
+static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- int i;
-
- qemu_get_be32s(f, &s->status);
- qemu_get_be32s(f, &s->clkrt);
- qemu_get_be32s(f, &s->spi);
- qemu_get_be32s(f, &s->cmdat);
- qemu_get_be32s(f, &s->resp_tout);
- qemu_get_be32s(f, &s->read_tout);
- s->blklen = qemu_get_be32(f);
- s->numblk = qemu_get_be32(f);
- qemu_get_be32s(f, &s->intmask);
- qemu_get_be32s(f, &s->intreq);
- s->cmd = qemu_get_be32(f);
- qemu_get_be32s(f, &s->arg);
- s->cmdreq = qemu_get_be32(f);
- s->active = qemu_get_be32(f);
- s->bytesleft = qemu_get_be32(f);
-
- s->tx_len = qemu_get_byte(f);
- s->tx_start = 0;
- if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0)
- return -EINVAL;
- for (i = 0; i < s->tx_len; i ++)
- s->tx_fifo[i] = qemu_get_byte(f);
+ PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
- s->rx_len = qemu_get_byte(f);
- s->rx_start = 0;
- if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0)
- return -EINVAL;
- for (i = 0; i < s->rx_len; i ++)
- s->rx_fifo[i] = qemu_get_byte(f);
+ qemu_set_irq(s->inserted, inserted);
+}
- s->resp_len = qemu_get_byte(f);
- if (s->resp_len > 9 || s->resp_len < 0)
- return -EINVAL;
- for (i = s->resp_len; i < 9; i ++)
- qemu_get_be16s(f, &s->resp_fifo[i]);
+static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
+{
+ PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
- return 0;
+ qemu_set_irq(s->readonly, readonly);
}
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
- hwaddr base,
- BlockBackend *blk, qemu_irq irq,
- qemu_irq rx_dma, qemu_irq tx_dma)
+void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
+ qemu_irq coverswitch)
{
- PXA2xxMMCIState *s;
+ DeviceState *dev = DEVICE(s);
+
+ s->readonly = readonly;
+ s->inserted = coverswitch;
+
+ pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
+ pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
+}
+
+static void pxa2xx_mmci_reset(DeviceState *d)
+{
+ PXA2xxMMCIState *s = PXA2XX_MMCI(d);
+
+ s->status = 0;
+ s->clkrt = 0;
+ s->spi = 0;
+ s->cmdat = 0;
+ s->resp_tout = 0;
+ s->read_tout = 0;
+ s->blklen = 0;
+ s->numblk = 0;
+ s->intmask = 0;
+ s->intreq = 0;
+ s->cmd = 0;
+ s->arg = 0;
+ s->active = 0;
+ s->bytesleft = 0;
+ s->tx_start = 0;
+ s->tx_len = 0;
+ s->rx_start = 0;
+ s->rx_len = 0;
+ s->resp_len = 0;
+ s->cmdreq = 0;
+ memset(s->tx_fifo, 0, sizeof(s->tx_fifo));
+ memset(s->rx_fifo, 0, sizeof(s->rx_fifo));
+ memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
+}
- s = (PXA2xxMMCIState *) g_malloc0(sizeof(PXA2xxMMCIState));
- s->irq = irq;
- s->rx_dma = rx_dma;
- s->tx_dma = tx_dma;
+static void pxa2xx_mmci_instance_init(Object *obj)
+{
+ PXA2xxMMCIState *s = PXA2XX_MMCI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ DeviceState *dev = DEVICE(obj);
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_mmci_ops, s,
+ memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s,
"pxa2xx-mmci", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+ qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
+ qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
- /* Instantiate the actual storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
+ qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
+ TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
+}
- register_savevm(NULL, "pxa2xx_mmci", 0, 0,
- pxa2xx_mmci_save, pxa2xx_mmci_load, s);
+static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
- return s;
+ dc->vmsd = &vmstate_pxa2xx_mmci;
+ dc->reset = pxa2xx_mmci_reset;
}
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
- qemu_irq coverswitch)
+static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
{
- sd_set_cb(s->card, readonly, coverswitch);
+ SDBusClass *sbc = SD_BUS_CLASS(klass);
+
+ sbc->set_inserted = pxa2xx_mmci_set_inserted;
+ sbc->set_readonly = pxa2xx_mmci_set_readonly;
}
+
+static const TypeInfo pxa2xx_mmci_info = {
+ .name = TYPE_PXA2XX_MMCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxMMCIState),
+ .instance_init = pxa2xx_mmci_instance_init,
+ .class_init = pxa2xx_mmci_class_init,
+};
+
+static const TypeInfo pxa2xx_mmci_bus_info = {
+ .name = TYPE_PXA2XX_MMCI_BUS,
+ .parent = TYPE_SD_BUS,
+ .instance_size = sizeof(SDBus),
+ .class_init = pxa2xx_mmci_bus_class_init,
+};
+
+static void pxa2xx_mmci_register_types(void)
+{
+ type_register_static(&pxa2xx_mmci_info);
+ type_register_static(&pxa2xx_mmci_bus_info);
+}
+
+type_init(pxa2xx_mmci_register_types)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index dd614b0890..edb6b32690 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -30,10 +30,14 @@
*/
#include "qemu/osdep.h"
+#include "hw/qdev.h"
#include "hw/hw.h"
#include "sysemu/block-backend.h"
#include "hw/sd/sd.h"
#include "qemu/bitmap.h"
+#include "hw/qdev-properties.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
//#define DEBUG_SD 1
@@ -44,7 +48,9 @@ do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
#define DPRINTF(fmt, ...) do {} while(0)
#endif
-#define ACMD41_ENQUIRY_MASK 0x00ffffff
+#define ACMD41_ENQUIRY_MASK 0x00ffffff
+#define OCR_POWER_UP 0x80000000
+#define OCR_POWER_DELAY_NS 500000 /* 0.5ms */
typedef enum {
sd_r0 = 0, /* no response */
@@ -78,9 +84,12 @@ enum SDCardStates {
};
struct SDState {
+ DeviceState parent_obj;
+
uint32_t mode; /* current card mode, one of SDCardModes */
int32_t state; /* current card state, one of SDCardStates */
uint32_t ocr;
+ QEMUTimer *ocr_power_timer;
uint8_t scr[8];
uint8_t cid[16];
uint8_t csd[16];
@@ -93,6 +102,7 @@ struct SDState {
int32_t wpgrps_size;
uint64_t size;
uint32_t blk_len;
+ uint32_t multi_blk_cnt;
uint32_t erase_start;
uint32_t erase_end;
uint8_t pwd[16];
@@ -194,8 +204,17 @@ static uint16_t sd_crc16(void *message, size_t width)
static void sd_set_ocr(SDState *sd)
{
- /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */
- sd->ocr = 0x80ffff00;
+ /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up */
+ sd->ocr = 0x00ffff00;
+}
+
+static void sd_ocr_powerup(void *opaque)
+{
+ SDState *sd = opaque;
+
+ /* Set powered up bit in OCR */
+ assert(!(sd->ocr & OCR_POWER_UP));
+ sd->ocr |= OCR_POWER_UP;
}
static void sd_set_scr(SDState *sd)
@@ -390,8 +409,9 @@ static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
}
-static void sd_reset(SDState *sd)
+static void sd_reset(DeviceState *dev)
{
+ SDState *sd = SD_CARD(dev);
uint64_t size;
uint64_t sect;
@@ -424,16 +444,44 @@ static void sd_reset(SDState *sd)
sd->blk_len = 0x200;
sd->pwd_len = 0;
sd->expecting_acmd = false;
+ sd->multi_blk_cnt = 0;
+}
+
+static bool sd_get_inserted(SDState *sd)
+{
+ return blk_is_inserted(sd->blk);
+}
+
+static bool sd_get_readonly(SDState *sd)
+{
+ return sd->wp_switch;
}
static void sd_cardchange(void *opaque, bool load)
{
SDState *sd = opaque;
+ DeviceState *dev = DEVICE(sd);
+ SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev));
+ bool inserted = sd_get_inserted(sd);
+ bool readonly = sd_get_readonly(sd);
- qemu_set_irq(sd->inserted_cb, blk_is_inserted(sd->blk));
- if (blk_is_inserted(sd->blk)) {
- sd_reset(sd);
- qemu_set_irq(sd->readonly_cb, sd->wp_switch);
+ if (inserted) {
+ sd_reset(dev);
+ }
+
+ /* The IRQ notification is for legacy non-QOM SD controller devices;
+ * QOMified controllers use the SDBus APIs.
+ */
+ if (sdbus) {
+ sdbus_set_inserted(sdbus, inserted);
+ if (inserted) {
+ sdbus_set_readonly(sdbus, readonly);
+ }
+ } else {
+ qemu_set_irq(sd->inserted_cb, inserted);
+ if (inserted) {
+ qemu_set_irq(sd->readonly_cb, readonly);
+ }
}
}
@@ -441,10 +489,44 @@ static const BlockDevOps sd_block_ops = {
.change_media_cb = sd_cardchange,
};
+static bool sd_ocr_vmstate_needed(void *opaque)
+{
+ SDState *sd = opaque;
+
+ /* Include the OCR state (and timer) if it is not yet powered up */
+ return !(sd->ocr & OCR_POWER_UP);
+}
+
+static const VMStateDescription sd_ocr_vmstate = {
+ .name = "sd-card/ocr-state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = sd_ocr_vmstate_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ocr, SDState),
+ VMSTATE_TIMER_PTR(ocr_power_timer, SDState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static int sd_vmstate_pre_load(void *opaque)
+{
+ SDState *sd = opaque;
+
+ /* If the OCR state is not included (prior versions, or not
+ * needed), then the OCR must be set as powered up. If the OCR state
+ * is included, this will be replaced by the state restore.
+ */
+ sd_ocr_powerup(sd);
+
+ return 0;
+}
+
static const VMStateDescription sd_vmstate = {
.name = "sd-card",
.version_id = 1,
.minimum_version_id = 1,
+ .pre_load = sd_vmstate_pre_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(mode, SDState),
VMSTATE_INT32(state, SDState),
@@ -456,6 +538,7 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_UINT32(vhs, SDState),
VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
VMSTATE_UINT32(blk_len, SDState),
+ VMSTATE_UINT32(multi_blk_cnt, SDState),
VMSTATE_UINT32(erase_start, SDState),
VMSTATE_UINT32(erase_end, SDState),
VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
@@ -470,37 +553,33 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512),
VMSTATE_BOOL(enable, SDState),
VMSTATE_END_OF_LIST()
- }
+ },
+ .subsections = (const VMStateDescription*[]) {
+ &sd_ocr_vmstate,
+ NULL
+ },
};
-/* We do not model the chip select pin, so allow the board to select
- whether card should be in SSI or MMC/SD mode. It is also up to the
- board to ensure that ssi transfers only occur when the chip select
- is asserted. */
+/* Legacy initialization function for use by non-qdevified callers */
SDState *sd_init(BlockBackend *blk, bool is_spi)
{
- SDState *sd;
+ DeviceState *dev;
+ Error *err = NULL;
- if (blk && blk_is_read_only(blk)) {
- fprintf(stderr, "sd_init: Cannot use read-only drive\n");
+ dev = qdev_create(NULL, TYPE_SD_CARD);
+ qdev_prop_set_drive(dev, "drive", blk, &err);
+ if (err) {
+ error_report("sd_init failed: %s", error_get_pretty(err));
return NULL;
}
-
- sd = (SDState *) g_malloc0(sizeof(SDState));
- sd->buf = blk_blockalign(blk, 512);
- sd->spi = is_spi;
- sd->enable = true;
- sd->blk = blk;
- sd_reset(sd);
- if (sd->blk) {
- /* Attach dev if not already attached. (This call ignores an
- * error return code if sd->blk is already attached.) */
- /* FIXME ignoring blk_attach_dev() failure is dangerously brittle */
- blk_attach_dev(sd->blk, sd);
- blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
+ qdev_prop_set_bit(dev, "spi", is_spi);
+ object_property_set_bool(OBJECT(dev), true, "realized", &err);
+ if (err) {
+ error_report("sd_init failed: %s", error_get_pretty(err));
+ return NULL;
}
- vmstate_register(NULL, -1, &sd_vmstate, sd);
- return sd;
+
+ return SD_CARD(dev);
}
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
@@ -674,6 +753,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
rca = req.arg >> 16;
}
+ /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25
+ * if not, its effects are cancelled */
+ if (sd->multi_blk_cnt != 0 && !(req.cmd == 18 || req.cmd == 25)) {
+ sd->multi_blk_cnt = 0;
+ }
+
DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
switch (req.cmd) {
/* Basic commands (Class 0 and Class 1) */
@@ -684,7 +769,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
default:
sd->state = sd_idle_state;
- sd_reset(sd);
+ sd_reset(DEVICE(sd));
return sd->spi ? sd_r1 : sd_r0;
}
break;
@@ -969,6 +1054,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
break;
+ case 23: /* CMD23: SET_BLOCK_COUNT */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->multi_blk_cnt = req.arg;
+ return sd_r1;
+
+ default:
+ break;
+ }
+ break;
+
/* Block write commands (Class 4) */
case 24: /* CMD24: WRITE_SINGLE_BLOCK */
if (sd->spi)
@@ -1201,16 +1297,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
default:
bad_cmd:
- fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd);
+ qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd);
return sd_illegal;
unimplemented_cmd:
/* Commands that are recognised but not yet implemented in SPI mode. */
- fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd);
+ qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n",
+ req.cmd);
return sd_illegal;
}
- fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd);
+ qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd);
return sd_illegal;
}
@@ -1278,9 +1375,28 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
}
switch (sd->state) {
case sd_idle_state:
+ /* If it's the first ACMD41 since reset, we need to decide
+ * whether to power up. If this is not an enquiry ACMD41,
+ * we immediately report power on and proceed below to the
+ * ready state, but if it is, we set a timer to model a
+ * delay for power up. This works around a bug in EDK2
+ * UEFI, which sends an initial enquiry ACMD41, but
+ * assumes that the card is in ready state as soon as it
+ * sees the power up bit set. */
+ if (!(sd->ocr & OCR_POWER_UP)) {
+ if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) {
+ timer_del(sd->ocr_power_timer);
+ sd_ocr_powerup(sd);
+ } else if (!timer_pending(sd->ocr_power_timer)) {
+ timer_mod_ns(sd->ocr_power_timer,
+ (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
+ + OCR_POWER_DELAY_NS));
+ }
+ }
+
/* We accept any voltage. 10000 V is nothing.
*
- * We don't model init delay so just advance straight to ready state
+ * Once we're powered up, we advance straight to ready state
* unless it's an enquiry ACMD41 (bits 23:0 == 0).
*/
if (req.arg & ACMD41_ENQUIRY_MASK) {
@@ -1323,7 +1439,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
return sd_normal_command(sd, req);
}
- fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd);
+ qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd);
return sd_illegal;
}
@@ -1367,7 +1483,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
if (!cmd_valid_while_locked(sd, req)) {
sd->card_status |= ILLEGAL_COMMAND;
sd->expecting_acmd = false;
- fprintf(stderr, "SD: Card is locked\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "SD: Card is locked\n");
rtype = sd_illegal;
goto send_response;
}
@@ -1525,7 +1641,8 @@ void sd_write_data(SDState *sd, uint8_t value)
return;
if (sd->state != sd_receivingdata_state) {
- fprintf(stderr, "sd_write_data: not in Receiving-Data state\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sd_write_data: not in Receiving-Data state\n");
return;
}
@@ -1569,6 +1686,14 @@ void sd_write_data(SDState *sd, uint8_t value)
sd->csd[14] |= 0x40;
/* Bzzzzzzztt .... Operation complete. */
+ if (sd->multi_blk_cnt != 0) {
+ if (--sd->multi_blk_cnt == 0) {
+ /* Stop! */
+ sd->state = sd_transfer_state;
+ break;
+ }
+ }
+
sd->state = sd_receivingdata_state;
}
break;
@@ -1636,7 +1761,7 @@ void sd_write_data(SDState *sd, uint8_t value)
break;
default:
- fprintf(stderr, "sd_write_data: unknown command\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "sd_write_data: unknown command\n");
break;
}
}
@@ -1651,7 +1776,8 @@ uint8_t sd_read_data(SDState *sd)
return 0x00;
if (sd->state != sd_sendingdata_state) {
- fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sd_read_data: not in Sending-Data state\n");
return 0x00;
}
@@ -1715,6 +1841,15 @@ uint8_t sd_read_data(SDState *sd)
if (sd->data_offset >= io_len) {
sd->data_start += io_len;
sd->data_offset = 0;
+
+ if (sd->multi_blk_cnt != 0) {
+ if (--sd->multi_blk_cnt == 0) {
+ /* Stop! */
+ sd->state = sd_transfer_state;
+ break;
+ }
+ }
+
if (sd->data_start + io_len > sd->size) {
sd->card_status |= ADDRESS_ERROR;
break;
@@ -1753,7 +1888,7 @@ uint8_t sd_read_data(SDState *sd)
break;
default:
- fprintf(stderr, "sd_read_data: unknown command\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "sd_read_data: unknown command\n");
return 0x00;
}
@@ -1769,3 +1904,73 @@ void sd_enable(SDState *sd, bool enable)
{
sd->enable = enable;
}
+
+static void sd_instance_init(Object *obj)
+{
+ SDState *sd = SD_CARD(obj);
+
+ sd->enable = true;
+ sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd);
+}
+
+static void sd_realize(DeviceState *dev, Error **errp)
+{
+ SDState *sd = SD_CARD(dev);
+
+ if (sd->blk && blk_is_read_only(sd->blk)) {
+ error_setg(errp, "Cannot use read-only drive as SD card");
+ return;
+ }
+
+ sd->buf = blk_blockalign(sd->blk, 512);
+
+ if (sd->blk) {
+ blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
+ }
+}
+
+static Property sd_properties[] = {
+ DEFINE_PROP_DRIVE("drive", SDState, blk),
+ /* We do not model the chip select pin, so allow the board to select
+ * whether card should be in SSI or MMC/SD mode. It is also up to the
+ * board to ensure that ssi transfers only occur when the chip select
+ * is asserted. */
+ DEFINE_PROP_BOOL("spi", SDState, spi, false),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void sd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SDCardClass *sc = SD_CARD_CLASS(klass);
+
+ dc->realize = sd_realize;
+ dc->props = sd_properties;
+ dc->vmsd = &sd_vmstate;
+ dc->reset = sd_reset;
+ dc->bus_type = TYPE_SD_BUS;
+
+ sc->do_command = sd_do_command;
+ sc->write_data = sd_write_data;
+ sc->read_data = sd_read_data;
+ sc->data_ready = sd_data_ready;
+ sc->enable = sd_enable;
+ sc->get_inserted = sd_get_inserted;
+ sc->get_readonly = sd_get_readonly;
+}
+
+static const TypeInfo sd_info = {
+ .name = TYPE_SD_CARD,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SDState),
+ .class_size = sizeof(SDCardClass),
+ .class_init = sd_class_init,
+ .instance_init = sd_instance_init,
+};
+
+static void sd_register_types(void)
+{
+ type_register_static(&sd_info);
+}
+
+type_init(sd_register_types)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 30e3bf4f3c..73e7c87fbf 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -55,6 +55,9 @@
} \
} while (0)
+#define TYPE_SDHCI_BUS "sdhci-bus"
+#define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS)
+
/* Default SD/MMC host controller features information, which will be
* presented in CAPABILITIES register of generic SD host controller at reset.
* If not stated otherwise:
@@ -145,9 +148,9 @@ static void sdhci_raise_insertion_irq(void *opaque)
}
}
-static void sdhci_insert_eject_cb(void *opaque, int irq, int level)
+static void sdhci_set_inserted(DeviceState *dev, bool level)
{
- SDHCIState *s = (SDHCIState *)opaque;
+ SDHCIState *s = (SDHCIState *)dev;
DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject");
if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
@@ -172,9 +175,9 @@ static void sdhci_insert_eject_cb(void *opaque, int irq, int level)
}
}
-static void sdhci_card_readonly_cb(void *opaque, int irq, int level)
+static void sdhci_set_readonly(DeviceState *dev, bool level)
{
- SDHCIState *s = (SDHCIState *)opaque;
+ SDHCIState *s = (SDHCIState *)dev;
if (level) {
s->prnsts &= ~SDHC_WRITE_PROTECT;
@@ -186,6 +189,8 @@ static void sdhci_card_readonly_cb(void *opaque, int irq, int level)
static void sdhci_reset(SDHCIState *s)
{
+ DeviceState *dev = DEVICE(s);
+
timer_del(s->insert_timer);
timer_del(s->transfer_timer);
/* Set all registers to 0. Capabilities registers are not cleared
@@ -194,8 +199,11 @@ static void sdhci_reset(SDHCIState *s)
memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
if (!s->noeject_quirk) {
- sd_set_cb(s->card, s->ro_cb, s->eject_cb);
+ /* Reset other state based on current card insertion/readonly status */
+ sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
+ sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
}
+
s->data_count = 0;
s->stopped_state = sdhc_not_stopped;
}
@@ -213,7 +221,7 @@ static void sdhci_send_command(SDHCIState *s)
request.cmd = s->cmdreg >> 8;
request.arg = s->argument;
DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg);
- rlen = sd_do_command(s->card, &request, response);
+ rlen = sdbus_do_command(&s->sdbus, &request, response);
if (s->cmdreg & SDHC_CMD_RESPONSE) {
if (rlen == 4) {
@@ -269,7 +277,7 @@ static void sdhci_end_transfer(SDHCIState *s)
request.cmd = 0x0C;
request.arg = 0;
DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg);
- sd_do_command(s->card, &request, response);
+ sdbus_do_command(&s->sdbus, &request, response);
/* Auto CMD12 response goes to the upper Response register */
s->rspreg[3] = (response[0] << 24) | (response[1] << 16) |
(response[2] << 8) | response[3];
@@ -301,7 +309,7 @@ static void sdhci_read_block_from_card(SDHCIState *s)
}
for (index = 0; index < (s->blksize & 0x0fff); index++) {
- s->fifo_buffer[index] = sd_read_data(s->card);
+ s->fifo_buffer[index] = sdbus_read_data(&s->sdbus);
}
/* New data now available for READ through Buffer Port Register */
@@ -394,7 +402,7 @@ static void sdhci_write_block_to_card(SDHCIState *s)
}
for (index = 0; index < (s->blksize & 0x0fff); index++) {
- sd_write_data(s->card, s->fifo_buffer[index]);
+ sdbus_write_data(&s->sdbus, s->fifo_buffer[index]);
}
/* Next data can be written through BUFFER DATORT register */
@@ -476,7 +484,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
while (s->blkcnt) {
if (s->data_count == 0) {
for (n = 0; n < block_size; n++) {
- s->fifo_buffer[n] = sd_read_data(s->card);
+ s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
}
}
begin = s->data_count;
@@ -517,7 +525,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
s->sdmasysad += s->data_count - begin;
if (s->data_count == block_size) {
for (n = 0; n < block_size; n++) {
- sd_write_data(s->card, s->fifo_buffer[n]);
+ sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
}
s->data_count = 0;
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
@@ -549,7 +557,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
if (s->trnmod & SDHC_TRNS_READ) {
for (n = 0; n < datacnt; n++) {
- s->fifo_buffer[n] = sd_read_data(s->card);
+ s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
}
dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer,
datacnt);
@@ -557,7 +565,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer,
datacnt);
for (n = 0; n < datacnt; n++) {
- sd_write_data(s->card, s->fifo_buffer[n]);
+ sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
}
}
@@ -661,7 +669,7 @@ static void sdhci_do_adma(SDHCIState *s)
while (length) {
if (s->data_count == 0) {
for (n = 0; n < block_size; n++) {
- s->fifo_buffer[n] = sd_read_data(s->card);
+ s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
}
}
begin = s->data_count;
@@ -702,7 +710,7 @@ static void sdhci_do_adma(SDHCIState *s)
dscr.addr += s->data_count - begin;
if (s->data_count == block_size) {
for (n = 0; n < block_size; n++) {
- sd_write_data(s->card, s->fifo_buffer[n]);
+ sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
}
s->data_count = 0;
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
@@ -816,7 +824,7 @@ static void sdhci_data_transfer(void *opaque)
break;
}
} else {
- if ((s->trnmod & SDHC_TRNS_READ) && sd_data_ready(s->card)) {
+ if ((s->trnmod & SDHC_TRNS_READ) && sdbus_data_ready(&s->sdbus)) {
s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
SDHC_DAT_LINE_ACTIVE;
sdhci_read_block_from_card(s);
@@ -1153,15 +1161,10 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
}
}
-static void sdhci_initfn(SDHCIState *s, BlockBackend *blk)
+static void sdhci_initfn(SDHCIState *s)
{
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
- s->eject_cb = qemu_allocate_irq(sdhci_insert_eject_cb, s, 0);
- s->ro_cb = qemu_allocate_irq(sdhci_card_readonly_cb, s, 0);
- sd_set_cb(s->card, s->ro_cb, s->eject_cb);
+ qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
+ TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s);
s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
@@ -1220,12 +1223,6 @@ const VMStateDescription sdhci_vmstate = {
/* Capabilities registers provide information on supported features of this
* specific host controller implementation */
static Property sdhci_pci_properties[] = {
- /*
- * We currently fuse controller and card into a single device
- * model, but we intend to separate them. For that purpose, the
- * properties that belong to the card are marked as experimental.
- */
- DEFINE_PROP_DRIVE("x-drive", SDHCIState, blk),
DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
SDHC_CAPAB_REG_DEFAULT),
DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
@@ -1237,7 +1234,7 @@ static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
SDHCIState *s = PCI_SDHCI(dev);
dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
- sdhci_initfn(s, s->blk);
+ sdhci_initfn(s);
s->buf_maxsz = sdhci_get_fifolen(s);
s->fifo_buffer = g_malloc0(s->buf_maxsz);
s->irq = pci_allocate_irq(dev);
@@ -1285,11 +1282,8 @@ static Property sdhci_sysbus_properties[] = {
static void sdhci_sysbus_init(Object *obj)
{
SDHCIState *s = SYSBUS_SDHCI(obj);
- DriveInfo *di;
- /* FIXME use a qdev drive property instead of drive_get_next() */
- di = drive_get_next(IF_SD);
- sdhci_initfn(s, di ? blk_by_legacy_dinfo(di) : NULL);
+ sdhci_initfn(s);
}
static void sdhci_sysbus_finalize(Object *obj)
@@ -1318,8 +1312,6 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
dc->vmsd = &sdhci_vmstate;
dc->props = sdhci_sysbus_properties;
dc->realize = sdhci_sysbus_realize;
- /* Reason: instance_init() method uses drive_get_next() */
- dc->cannot_instantiate_with_device_add_yet = true;
}
static const TypeInfo sdhci_sysbus_info = {
@@ -1331,10 +1323,26 @@ static const TypeInfo sdhci_sysbus_info = {
.class_init = sdhci_sysbus_class_init,
};
+static void sdhci_bus_class_init(ObjectClass *klass, void *data)
+{
+ SDBusClass *sbc = SD_BUS_CLASS(klass);
+
+ sbc->set_inserted = sdhci_set_inserted;
+ sbc->set_readonly = sdhci_set_readonly;
+}
+
+static const TypeInfo sdhci_bus_info = {
+ .name = TYPE_SDHCI_BUS,
+ .parent = TYPE_SD_BUS,
+ .instance_size = sizeof(SDBus),
+ .class_init = sdhci_bus_class_init,
+};
+
static void sdhci_register_types(void)
{
type_register_static(&sdhci_pci_info);
type_register_static(&sdhci_sysbus_info);
+ type_register_static(&sdhci_bus_info);
}
type_init(sdhci_register_types)
diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
index ba390ad50b..f1ede5f53b 100644
--- a/hw/timer/arm_timer.c
+++ b/hw/timer/arm_timer.c
@@ -277,21 +277,25 @@ static const VMStateDescription vmstate_sp804 = {
}
};
-static int sp804_init(SysBusDevice *sbd)
+static void sp804_init(Object *obj)
{
- DeviceState *dev = DEVICE(sbd);
- SP804State *s = SP804(dev);
+ SP804State *s = SP804(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
sysbus_init_irq(sbd, &s->irq);
+ memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
+ "sp804", 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void sp804_realize(DeviceState *dev, Error **errp)
+{
+ SP804State *s = SP804(dev);
+
s->timer[0] = arm_timer_init(s->freq0);
s->timer[1] = arm_timer_init(s->freq1);
s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
- memory_region_init_io(&s->iomem, OBJECT(s), &sp804_ops, s,
- "sp804", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- vmstate_register(dev, -1, &vmstate_sp804, s);
- return 0;
}
/* Integrator/CP timer module. */
@@ -344,9 +348,10 @@ static const MemoryRegionOps icp_pit_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int icp_pit_init(SysBusDevice *dev)
+static void icp_pit_init(Object *obj)
{
- icp_pit_state *s = INTEGRATOR_PIT(dev);
+ icp_pit_state *s = INTEGRATOR_PIT(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
/* Timer 0 runs at the system clock speed (40MHz). */
s->timer[0] = arm_timer_init(40000000);
@@ -358,26 +363,18 @@ static int icp_pit_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->timer[1]->irq);
sysbus_init_irq(dev, &s->timer[2]->irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &icp_pit_ops, s,
+ memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
"icp_pit", 0x1000);
sysbus_init_mmio(dev, &s->iomem);
/* This device has no state to save/restore. The component timers will
save themselves. */
- return 0;
-}
-
-static void icp_pit_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = icp_pit_init;
}
static const TypeInfo icp_pit_info = {
.name = TYPE_INTEGRATOR_PIT,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(icp_pit_state),
- .class_init = icp_pit_class_init,
+ .instance_init = icp_pit_init,
};
static Property sp804_properties[] = {
@@ -388,17 +385,18 @@ static Property sp804_properties[] = {
static void sp804_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *k = DEVICE_CLASS(klass);
- sdc->init = sp804_init;
+ k->realize = sp804_realize;
k->props = sp804_properties;
+ k->vmsd = &vmstate_sp804;
}
static const TypeInfo sp804_info = {
.name = TYPE_SP804,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SP804State),
+ .instance_init = sp804_init,
.class_init = sp804_class_init,
};
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
index 73e547c91f..ae69345f0d 100644
--- a/hw/timer/exynos4210_mct.c
+++ b/hw/timer/exynos4210_mct.c
@@ -1422,10 +1422,11 @@ static const MemoryRegionOps exynos4210_mct_ops = {
};
/* MCT init */
-static int exynos4210_mct_init(SysBusDevice *dev)
+static void exynos4210_mct_init(Object *obj)
{
int i;
- Exynos4210MCTState *s = EXYNOS4210_MCT(dev);
+ Exynos4210MCTState *s = EXYNOS4210_MCT(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
QEMUBH *bh[2];
/* Global timer */
@@ -1450,19 +1451,15 @@ static int exynos4210_mct_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->l_timer[i].irq);
}
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_mct_ops, s,
+ memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s,
"exynos4210-mct", MCT_SFR_SIZE);
sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
}
static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = exynos4210_mct_init;
dc->reset = exynos4210_mct_reset;
dc->vmsd = &vmstate_exynos4210_mct_state;
}
@@ -1471,6 +1468,7 @@ static const TypeInfo exynos4210_mct_info = {
.name = TYPE_EXYNOS4210_MCT,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210MCTState),
+ .instance_init = exynos4210_mct_init,
.class_init = exynos4210_mct_class_init,
};
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
index 38f941f441..0e9e2e9bf5 100644
--- a/hw/timer/exynos4210_pwm.c
+++ b/hw/timer/exynos4210_pwm.c
@@ -380,9 +380,10 @@ static const MemoryRegionOps exynos4210_pwm_ops = {
/*
* PWM timer initialization
*/
-static int exynos4210_pwm_init(SysBusDevice *dev)
+static void exynos4210_pwm_init(Object *obj)
{
- Exynos4210PWMState *s = EXYNOS4210_PWM(dev);
+ Exynos4210PWMState *s = EXYNOS4210_PWM(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
int i;
QEMUBH *bh;
@@ -394,19 +395,15 @@ static int exynos4210_pwm_init(SysBusDevice *dev)
s->timer[i].parent = s;
}
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_pwm_ops, s,
+ memory_region_init_io(&s->iomem, obj, &exynos4210_pwm_ops, s,
"exynos4210-pwm", EXYNOS4210_PWM_REG_MEM_SIZE);
sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
}
static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = exynos4210_pwm_init;
dc->reset = exynos4210_pwm_reset;
dc->vmsd = &vmstate_exynos4210_pwm_state;
}
@@ -415,6 +412,7 @@ static const TypeInfo exynos4210_pwm_info = {
.name = TYPE_EXYNOS4210_PWM,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210PWMState),
+ .instance_init = exynos4210_pwm_init,
.class_init = exynos4210_pwm_class_init,
};
diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c
index 33413039aa..f21fb54f5c 100644
--- a/hw/timer/exynos4210_rtc.c
+++ b/hw/timer/exynos4210_rtc.c
@@ -547,9 +547,10 @@ static const MemoryRegionOps exynos4210_rtc_ops = {
/*
* RTC timer initialization
*/
-static int exynos4210_rtc_init(SysBusDevice *dev)
+static void exynos4210_rtc_init(Object *obj)
{
- Exynos4210RTCState *s = EXYNOS4210_RTC(dev);
+ Exynos4210RTCState *s = EXYNOS4210_RTC(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
QEMUBH *bh;
bh = qemu_bh_new(exynos4210_rtc_tick, s);
@@ -564,19 +565,15 @@ static int exynos4210_rtc_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->alm_irq);
sysbus_init_irq(dev, &s->tick_irq);
- memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_rtc_ops, s,
+ memory_region_init_io(&s->iomem, obj, &exynos4210_rtc_ops, s,
"exynos4210-rtc", EXYNOS4210_RTC_REG_MEM_SIZE);
sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
}
static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = exynos4210_rtc_init;
dc->reset = exynos4210_rtc_reset;
dc->vmsd = &vmstate_exynos4210_rtc_state;
}
@@ -585,6 +582,7 @@ static const TypeInfo exynos4210_rtc_info = {
.name = TYPE_EXYNOS4210_RTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210RTCState),
+ .instance_init = exynos4210_rtc_init,
.class_init = exynos4210_rtc_class_init,
};
diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c
index d99d18ce51..3ccb2cb460 100644
--- a/hw/timer/pl031.c
+++ b/hw/timer/pl031.c
@@ -192,12 +192,13 @@ static const MemoryRegionOps pl031_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int pl031_init(SysBusDevice *dev)
+static void pl031_init(Object *obj)
{
- PL031State *s = PL031(dev);
+ PL031State *s = PL031(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
struct tm tm;
- memory_region_init_io(&s->iomem, OBJECT(s), &pl031_ops, s, "pl031", 0x1000);
+ memory_region_init_io(&s->iomem, obj, &pl031_ops, s, "pl031", 0x1000);
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
@@ -206,7 +207,6 @@ static int pl031_init(SysBusDevice *dev)
qemu_clock_get_ns(rtc_clock) / get_ticks_per_sec();
s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s);
- return 0;
}
static void pl031_pre_save(void *opaque)
@@ -249,9 +249,7 @@ static const VMStateDescription vmstate_pl031 = {
static void pl031_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = pl031_init;
dc->vmsd = &vmstate_pl031;
}
@@ -259,6 +257,7 @@ static const TypeInfo pl031_info = {
.name = TYPE_PL031,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PL031State),
+ .instance_init = pl031_init,
.class_init = pl031_class_init,
};
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
index 0daa69c6b9..33449e66b5 100644
--- a/hw/timer/pxa2xx_timer.c
+++ b/hw/timer/pxa2xx_timer.c
@@ -433,10 +433,10 @@ static int pxa25x_timer_post_load(void *opaque, int version_id)
return 0;
}
-static int pxa2xx_timer_init(SysBusDevice *dev)
+static void pxa2xx_timer_init(Object *obj)
{
- PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
- int i;
+ PXA2xxTimerInfo *s = PXA2XX_TIMER(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
s->irq_enabled = 0;
s->oldclock = 0;
@@ -444,16 +444,28 @@ static int pxa2xx_timer_init(SysBusDevice *dev)
s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
s->reset3 = 0;
+ memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s,
+ "pxa2xx-timer", 0x00001000);
+ sysbus_init_mmio(dev, &s->iomem);
+}
+
+static void pxa2xx_timer_realize(DeviceState *dev, Error **errp)
+{
+ PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ int i;
+
for (i = 0; i < 4; i ++) {
s->timer[i].value = 0;
- sysbus_init_irq(dev, &s->timer[i].irq);
+ sysbus_init_irq(sbd, &s->timer[i].irq);
s->timer[i].info = s;
s->timer[i].num = i;
s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- pxa2xx_timer_tick, &s->timer[i]);
+ pxa2xx_timer_tick, &s->timer[i]);
}
+
if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
- sysbus_init_irq(dev, &s->irq4);
+ sysbus_init_irq(sbd, &s->irq4);
for (i = 0; i < 8; i ++) {
s->tm4[i].tm.value = 0;
@@ -462,15 +474,9 @@ static int pxa2xx_timer_init(SysBusDevice *dev)
s->tm4[i].freq = 0;
s->tm4[i].control = 0x0;
s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- pxa2xx_timer_tick4, &s->tm4[i]);
+ pxa2xx_timer_tick4, &s->tm4[i]);
}
}
-
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_timer_ops, s,
- "pxa2xx-timer", 0x00001000);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
}
static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
@@ -573,9 +579,8 @@ static const TypeInfo pxa27x_timer_dev_info = {
static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc);
- sdc->init = pxa2xx_timer_init;
+ dc->realize = pxa2xx_timer_realize;
dc->vmsd = &vmstate_pxa2xx_timer_regs;
}
@@ -583,6 +588,7 @@ static const TypeInfo pxa2xx_timer_type_info = {
.name = TYPE_PXA2XX_TIMER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(PXA2xxTimerInfo),
+ .instance_init = pxa2xx_timer_init,
.abstract = true,
.class_init = pxa2xx_timer_class_init,
};
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 7eccb41da8..b197adca1c 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -23,6 +23,8 @@
#include "qemu-common.h"
#include "qemu/option.h"
+#include "io/channel-socket.h"
+#include "crypto/tlscreds.h"
struct nbd_request {
uint32_t magic;
@@ -55,7 +57,10 @@ struct nbd_reply {
#define NBD_REP_ACK (1) /* Data sending finished. */
#define NBD_REP_SERVER (2) /* Export description. */
#define NBD_REP_ERR_UNSUP ((UINT32_C(1) << 31) | 1) /* Unknown option. */
+#define NBD_REP_ERR_POLICY ((UINT32_C(1) << 31) | 2) /* Server denied */
#define NBD_REP_ERR_INVALID ((UINT32_C(1) << 31) | 3) /* Invalid length. */
+#define NBD_REP_ERR_TLS_REQD ((UINT32_C(1) << 31) | 5) /* TLS required */
+
#define NBD_CMD_MASK_COMMAND 0x0000ffff
#define NBD_CMD_FLAG_FUA (1 << 16)
@@ -73,12 +78,19 @@ enum {
/* Maximum size of a single READ/WRITE data buffer */
#define NBD_MAX_BUFFER_SIZE (32 * 1024 * 1024)
-ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
-int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
+ssize_t nbd_wr_syncv(QIOChannel *ioc,
+ struct iovec *iov,
+ size_t niov,
+ size_t offset,
+ size_t length,
+ bool do_read);
+int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint32_t *flags,
+ QCryptoTLSCreds *tlscreds, const char *hostname,
+ QIOChannel **outioc,
off_t *size, Error **errp);
-int nbd_init(int fd, int csock, uint32_t flags, off_t size);
-ssize_t nbd_send_request(int csock, struct nbd_request *request);
-ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
+int nbd_init(int fd, QIOChannelSocket *sioc, uint32_t flags, off_t size);
+ssize_t nbd_send_request(QIOChannel *ioc, struct nbd_request *request);
+ssize_t nbd_receive_reply(QIOChannel *ioc, struct nbd_reply *reply);
int nbd_client(int fd);
int nbd_disconnect(int fd);
@@ -98,7 +110,11 @@ NBDExport *nbd_export_find(const char *name);
void nbd_export_set_name(NBDExport *exp, const char *name);
void nbd_export_close_all(void);
-void nbd_client_new(NBDExport *exp, int csock, void (*close_fn)(NBDClient *));
+void nbd_client_new(NBDExport *exp,
+ QIOChannelSocket *sioc,
+ QCryptoTLSCreds *tlscreds,
+ const char *tlsaclname,
+ void (*close)(NBDClient *));
void nbd_client_get(NBDClient *client);
void nbd_client_put(NBDClient *client);
diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h
index bdfccd4041..db51d03804 100644
--- a/include/hw/input/adb.h
+++ b/include/hw/input/adb.h
@@ -79,7 +79,7 @@ struct ADBBusState {
int adb_request(ADBBusState *s, uint8_t *buf_out,
const uint8_t *buf, int len);
-int adb_poll(ADBBusState *s, uint8_t *buf_out);
+int adb_poll(ADBBusState *s, uint8_t *buf_out, uint16_t poll_mask);
#define TYPE_ADB_KEYBOARD "adb-keyboard"
#define TYPE_ADB_MOUSE "adb-mouse"
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 1f9e722545..098d85d1a1 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -72,7 +72,6 @@ struct sPAPRMachineState {
int htab_save_index;
bool htab_first_pass;
int htab_fd;
- bool htab_fd_stale;
/* RTAS state */
QTAILQ_HEAD(, sPAPRConfigureConnectorState) ccs_list;
diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
index 79adb5bb48..d5d273a449 100644
--- a/include/hw/sd/sd.h
+++ b/include/hw/sd/sd.h
@@ -67,7 +67,51 @@ typedef struct {
} SDRequest;
typedef struct SDState SDState;
+typedef struct SDBus SDBus;
+#define TYPE_SD_CARD "sd-card"
+#define SD_CARD(obj) OBJECT_CHECK(SDState, (obj), TYPE_SD_CARD)
+#define SD_CARD_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SDCardClass, (klass), TYPE_SD_CARD)
+#define SD_CARD_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SDCardClass, (obj), TYPE_SD_CARD)
+
+typedef struct {
+ /*< private >*/
+ DeviceClass parent_class;
+ /*< public >*/
+
+ int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
+ void (*write_data)(SDState *sd, uint8_t value);
+ uint8_t (*read_data)(SDState *sd);
+ bool (*data_ready)(SDState *sd);
+ void (*enable)(SDState *sd, bool enable);
+ bool (*get_inserted)(SDState *sd);
+ bool (*get_readonly)(SDState *sd);
+} SDCardClass;
+
+#define TYPE_SD_BUS "sd-bus"
+#define SD_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SD_BUS)
+#define SD_BUS_CLASS(klass) OBJECT_CLASS_CHECK(SDBusClass, (klass), TYPE_SD_BUS)
+#define SD_BUS_GET_CLASS(obj) OBJECT_GET_CLASS(SDBusClass, (obj), TYPE_SD_BUS)
+
+struct SDBus {
+ BusState qbus;
+};
+
+typedef struct {
+ /*< private >*/
+ BusClass parent_class;
+ /*< public >*/
+
+ /* These methods are called by the SD device to notify the controller
+ * when the card insertion or readonly status changes
+ */
+ void (*set_inserted)(DeviceState *dev, bool inserted);
+ void (*set_readonly)(DeviceState *dev, bool readonly);
+} SDBusClass;
+
+/* Legacy functions to be used only by non-qdevified callers */
SDState *sd_init(BlockBackend *bs, bool is_spi);
int sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response);
@@ -75,6 +119,27 @@ void sd_write_data(SDState *sd, uint8_t value);
uint8_t sd_read_data(SDState *sd);
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
bool sd_data_ready(SDState *sd);
+/* sd_enable should not be used -- it is only used on the nseries boards,
+ * where it is part of a broken implementation of the MMC card slot switch
+ * (there should be two card slots which are multiplexed to a single MMC
+ * controller, but instead we model it with one card and controller and
+ * disable the card when the second slot is selected, so it looks like the
+ * second slot is always empty).
+ */
void sd_enable(SDState *sd, bool enable);
+/* Functions to be used by qdevified callers (working via
+ * an SDBus rather than directly with SDState)
+ */
+int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
+void sdbus_write_data(SDBus *sd, uint8_t value);
+uint8_t sdbus_read_data(SDBus *sd);
+bool sdbus_data_ready(SDBus *sd);
+bool sdbus_get_inserted(SDBus *sd);
+bool sdbus_get_readonly(SDBus *sd);
+
+/* Functions to be used by SD devices to report back to qdevified controllers */
+void sdbus_set_inserted(SDBus *sd, bool inserted);
+void sdbus_set_readonly(SDBus *sd, bool inserted);
+
#endif /* __hw_sd_h */
diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h
index ffd1f80891..607a83e855 100644
--- a/include/hw/sd/sdhci.h
+++ b/include/hw/sd/sdhci.h
@@ -37,9 +37,8 @@ typedef struct SDHCIState {
PCIDevice pcidev;
SysBusDevice busdev;
};
- SDState *card;
+ SDBus sdbus;
MemoryRegion iomem;
- BlockBackend *blk;
QEMUTimer *insert_timer; /* timer for 'changing' sd card. */
QEMUTimer *transfer_timer;
diff --git a/include/io/channel-buffer.h b/include/io/channel-buffer.h
index 91a52b3373..65c498b2c2 100644
--- a/include/io/channel-buffer.h
+++ b/include/io/channel-buffer.h
@@ -42,7 +42,7 @@ struct QIOChannelBuffer {
size_t capacity; /* Total allocated memory */
size_t usage; /* Current size of data */
size_t offset; /* Offset for future I/O ops */
- char *data;
+ uint8_t *data;
};
diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h
index 810537ef6f..70d06b40d9 100644
--- a/include/io/channel-socket.h
+++ b/include/io/channel-socket.h
@@ -105,7 +105,9 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
* Attempt to connect to the address @addr. This method
* will run in the background so the caller will regain
* execution control immediately. The function @callback
- * will be invoked on completion or failure.
+ * will be invoked on completion or failure. The @addr
+ * parameter will be copied, so may be freed as soon
+ * as this function returns without waiting for completion.
*/
void qio_channel_socket_connect_async(QIOChannelSocket *ioc,
SocketAddress *addr,
@@ -140,7 +142,9 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
* Attempt to listen to the address @addr. This method
* will run in the background so the caller will regain
* execution control immediately. The function @callback
- * will be invoked on completion or failure.
+ * will be invoked on completion or failure. The @addr
+ * parameter will be copied, so may be freed as soon
+ * as this function returns without waiting for completion.
*/
void qio_channel_socket_listen_async(QIOChannelSocket *ioc,
SocketAddress *addr,
@@ -181,6 +185,9 @@ int qio_channel_socket_dgram_sync(QIOChannelSocket *ioc,
* This method will run in the background so the caller
* will regain execution control immediately. The function
* @callback will be invoked on completion or failure.
+ * The @localAddr and @remoteAddr parameters will be copied,
+ * so may be freed as soon as this function returns without
+ * waiting for completion.
*/
void qio_channel_socket_dgram_async(QIOChannelSocket *ioc,
SocketAddress *localAddr,
diff --git a/include/io/channel-util.h b/include/io/channel-util.h
new file mode 100644
index 0000000000..c93af82884
--- /dev/null
+++ b/include/io/channel-util.h
@@ -0,0 +1,52 @@
+/*
+ * QEMU I/O channels utility APIs
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * 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/>.
+ *
+ */
+
+#ifndef QIO_CHANNEL_UTIL_H__
+#define QIO_CHANNEL_UTIL_H__
+
+#include "io/channel.h"
+
+/*
+ * This module provides helper functions that are useful when dealing
+ * with QIOChannel objects
+ */
+
+
+/**
+ * qio_channel_new_fd:
+ * @fd: the file descriptor
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Create a channel for performing I/O on the file
+ * descriptor @fd. The particular subclass of QIOChannel
+ * that is returned will depend on what underlying object
+ * the file descriptor is associated with. It may be either
+ * a QIOChannelSocket or a QIOChannelFile instance. Upon
+ * success, the returned QIOChannel instance will own
+ * the @fd file descriptor, and take responsibility for
+ * closing it when no longer required. On failure, the
+ * caller is responsible for closing @fd.
+ *
+ * Returns: the channel object, or NULL on error
+ */
+QIOChannel *qio_channel_new_fd(int fd,
+ Error **errp);
+
+#endif /* QIO_CHANNEL_UTIL_H__ */
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 91b95ae90a..aa0f37320c 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -43,9 +43,6 @@ void monitor_read_command(Monitor *mon, int show_prompt);
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void *opaque);
-void object_add(const char *type, const char *id, const QDict *qdict,
- Visitor *v, Error **errp);
-
AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
bool has_opaque, const char *opaque,
Error **errp);
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index d22eb01be4..c5fbe28b02 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -77,18 +77,6 @@
#define typeof_field(type, field) typeof(((type *)0)->field)
#define type_check(t1,t2) ((t1*)0 - (t2*)0)
-#ifndef always_inline
-#if !((__GNUC__ < 3) || defined(__APPLE__))
-#ifdef __OPTIMIZE__
-#undef inline
-#define inline __attribute__ (( always_inline )) __inline__
-#endif
-#endif
-#else
-#undef inline
-#define inline always_inline
-#endif
-
#define QEMU_BUILD_BUG_ON(x) \
typedef char glue(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused));
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 59a7f8deca..cc055c909e 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -27,6 +27,17 @@
#include "config-host.h"
#include "qemu/compiler.h"
+
+/* The following block of code temporarily renames the daemon() function so the
+ * compiler does not see the warning associated with it in stdlib.h on OSX
+ */
+#ifdef __APPLE__
+#define daemon qemu_fake_daemon_function
+#include <stdlib.h>
+#undef daemon
+extern int daemon(int, int);
+#endif
+
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
index 283ae0db4d..d579746db6 100644
--- a/include/qom/object_interfaces.h
+++ b/include/qom/object_interfaces.h
@@ -2,6 +2,8 @@
#define OBJECT_INTERFACES_H
#include "qom/object.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/visitor.h"
#define TYPE_USER_CREATABLE "user-creatable"
@@ -72,4 +74,94 @@ void user_creatable_complete(Object *obj, Error **errp);
* from implements USER_CREATABLE interface.
*/
bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp);
+
+/**
+ * user_creatable_add:
+ * @qdict: the object definition
+ * @v: the visitor
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Create an instance of the user creatable object whose type
+ * is defined in @qdict by the 'qom-type' field, placing it
+ * in the object composition tree with name provided by the
+ * 'id' field. The remaining fields in @qdict are used to
+ * initialize the object properties.
+ *
+ * Returns: the newly created object or NULL on error
+ */
+Object *user_creatable_add(const QDict *qdict,
+ Visitor *v, Error **errp);
+
+/**
+ * user_creatable_add_type:
+ * @type: the object type name
+ * @id: the unique ID for the object
+ * @qdict: the object properties
+ * @v: the visitor
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Create an instance of the user creatable object @type, placing
+ * it in the object composition tree with name @id, initializing
+ * it with properties from @qdict
+ *
+ * Returns: the newly created object or NULL on error
+ */
+Object *user_creatable_add_type(const char *type, const char *id,
+ const QDict *qdict,
+ Visitor *v, Error **errp);
+
+/**
+ * user_creatable_add_opts:
+ * @opts: the object definition
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Create an instance of the user creatable object whose type
+ * is defined in @opts by the 'qom-type' option, placing it
+ * in the object composition tree with name provided by the
+ * 'id' field. The remaining options in @opts are used to
+ * initialize the object properties.
+ *
+ * Returns: the newly created object or NULL on error
+ */
+Object *user_creatable_add_opts(QemuOpts *opts, Error **errp);
+
+
+/**
+ * user_creatable_add_opts_predicate:
+ * @type: the QOM type to be added
+ *
+ * A callback function to determine whether an object
+ * of type @type should be created. Instances of this
+ * callback should be passed to user_creatable_add_opts_foreach
+ */
+typedef bool (*user_creatable_add_opts_predicate)(const char *type);
+
+/**
+ * user_creatable_add_opts_foreach:
+ * @opaque: a user_creatable_add_opts_predicate callback or NULL
+ * @opts: options to create
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * An iterator callback to be used in conjunction with
+ * the qemu_opts_foreach() method for creating a list of
+ * objects from a set of QemuOpts
+ *
+ * The @opaque parameter can be passed a user_creatable_add_opts_predicate
+ * callback to filter which types of object are created during iteration.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int user_creatable_add_opts_foreach(void *opaque,
+ QemuOpts *opts, Error **errp);
+
+/**
+ * user_creatable_del:
+ * @id: the unique ID for the object
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Delete an instance of the user creatable object identified
+ * by @id.
+ */
+void user_creatable_del(const char *id, Error **errp);
+
#endif
diff --git a/io/Makefile.objs b/io/Makefile.objs
index 0e3de31a5a..9d8337d89a 100644
--- a/io/Makefile.objs
+++ b/io/Makefile.objs
@@ -6,4 +6,5 @@ io-obj-y += channel-socket.o
io-obj-y += channel-tls.o
io-obj-y += channel-watch.o
io-obj-y += channel-websock.o
+io-obj-y += channel-util.o
io-obj-y += task.o
diff --git a/io/channel-buffer.c b/io/channel-buffer.c
index 0f7c5671fe..3e5117bf28 100644
--- a/io/channel-buffer.c
+++ b/io/channel-buffer.c
@@ -32,7 +32,7 @@ qio_channel_buffer_new(size_t capacity)
ioc = QIO_CHANNEL_BUFFER(object_new(TYPE_QIO_CHANNEL_BUFFER));
if (capacity) {
- ioc->data = g_new0(char, capacity);
+ ioc->data = g_new0(uint8_t, capacity);
ioc->capacity = capacity;
}
diff --git a/io/channel-util.c b/io/channel-util.c
new file mode 100644
index 0000000000..f96907cb5c
--- /dev/null
+++ b/io/channel-util.c
@@ -0,0 +1,50 @@
+/*
+ * QEMU I/O channels utility APIs
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * 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 "io/channel-util.h"
+#include "io/channel-file.h"
+#include "io/channel-socket.h"
+
+
+static bool fd_is_socket(int fd)
+{
+ int optval;
+ socklen_t optlen;
+ optlen = sizeof(optval);
+ return qemu_getsockopt(fd,
+ SOL_SOCKET,
+ SO_TYPE,
+ (char *)&optval,
+ &optlen) == 0;
+}
+
+
+QIOChannel *qio_channel_new_fd(int fd,
+ Error **errp)
+{
+ QIOChannel *ioc;
+
+ if (fd_is_socket(fd)) {
+ ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
+ } else {
+ ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
+ }
+ return ioc;
+}
diff --git a/libdecnumber/decContext.c b/libdecnumber/decContext.c
index 68e6f60e96..7d97a65ac5 100644
--- a/libdecnumber/decContext.c
+++ b/libdecnumber/decContext.c
@@ -35,8 +35,7 @@
/* context structures. */
/* ------------------------------------------------------------------ */
-#include <string.h> /* for strcmp */
-#include <stdio.h> /* for printf if DECCHECK */
+#include "qemu/osdep.h"
#include "libdecnumber/dconfig.h"
#include "libdecnumber/decContext.h"
#include "libdecnumber/decNumberLocal.h"
diff --git a/libdecnumber/decNumber.c b/libdecnumber/decNumber.c
index ca1412f30b..c9e7807f87 100644
--- a/libdecnumber/decNumber.c
+++ b/libdecnumber/decNumber.c
@@ -166,10 +166,7 @@
/* ** -- raise to the power */
/* ------------------------------------------------------------------ */
-#include <stdlib.h> /* for malloc, free, etc. */
-#include <stdio.h> /* for printf [if needed] */
-#include <string.h> /* for strcpy */
-#include <ctype.h> /* for lower */
+#include "qemu/osdep.h"
#include "libdecnumber/dconfig.h"
#include "libdecnumber/decNumber.h"
#include "libdecnumber/decNumberLocal.h"
diff --git a/libdecnumber/dpd/decimal128.c b/libdecnumber/dpd/decimal128.c
index 7551b7caaf..ca4764e547 100644
--- a/libdecnumber/dpd/decimal128.c
+++ b/libdecnumber/dpd/decimal128.c
@@ -39,8 +39,7 @@
/* */
/* Error handling is the same as decNumber (qv.). */
/* ------------------------------------------------------------------ */
-#include <string.h> /* [for memset/memcpy] */
-#include <stdio.h> /* [for printf] */
+#include "qemu/osdep.h"
#include "libdecnumber/dconfig.h"
#define DECNUMDIGITS 34 /* make decNumbers with space for 34 */
diff --git a/libdecnumber/dpd/decimal32.c b/libdecnumber/dpd/decimal32.c
index 095ab75654..53f29789d7 100644
--- a/libdecnumber/dpd/decimal32.c
+++ b/libdecnumber/dpd/decimal32.c
@@ -39,8 +39,7 @@
/* */
/* Error handling is the same as decNumber (qv.). */
/* ------------------------------------------------------------------ */
-#include <string.h> /* [for memset/memcpy] */
-#include <stdio.h> /* [for printf] */
+#include "qemu/osdep.h"
#include "libdecnumber/dconfig.h"
#define DECNUMDIGITS 7 /* make decNumbers with space for 7 */
diff --git a/libdecnumber/dpd/decimal64.c b/libdecnumber/dpd/decimal64.c
index 8256084e90..4816176410 100644
--- a/libdecnumber/dpd/decimal64.c
+++ b/libdecnumber/dpd/decimal64.c
@@ -39,8 +39,7 @@
/* */
/* Error handling is the same as decNumber (qv.). */
/* ------------------------------------------------------------------ */
-#include <string.h> /* [for memset/memcpy] */
-#include <stdio.h> /* [for printf] */
+#include "qemu/osdep.h"
#include "libdecnumber/dconfig.h"
#define DECNUMDIGITS 16 /* make decNumbers with space for 16 */
diff --git a/migration/ram.c b/migration/ram.c
index 96c749face..704f6a95bf 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1920,6 +1920,9 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
acct_clear();
}
+ /* For memory_global_dirty_log_start below. */
+ qemu_mutex_lock_iothread();
+
qemu_mutex_lock_ramlist();
rcu_read_lock();
bytes_transferred = 0;
@@ -1944,6 +1947,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
memory_global_dirty_log_start();
migration_bitmap_sync();
qemu_mutex_unlock_ramlist();
+ qemu_mutex_unlock_iothread();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
diff --git a/nbd/client.c b/nbd/client.c
index f07cb4822d..9e5b651082 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -71,19 +71,307 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
*/
-int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
+
+static int nbd_handle_reply_err(uint32_t opt, uint32_t type, Error **errp)
+{
+ if (!(type & (1 << 31))) {
+ return 0;
+ }
+
+ switch (type) {
+ case NBD_REP_ERR_UNSUP:
+ error_setg(errp, "Unsupported option type %x", opt);
+ break;
+
+ case NBD_REP_ERR_POLICY:
+ error_setg(errp, "Denied by server for option %x", opt);
+ break;
+
+ case NBD_REP_ERR_INVALID:
+ error_setg(errp, "Invalid data length for option %x", opt);
+ break;
+
+ case NBD_REP_ERR_TLS_REQD:
+ error_setg(errp, "TLS negotiation required before option %x", opt);
+ break;
+
+ default:
+ error_setg(errp, "Unknown error code when asking for option %x", opt);
+ break;
+ }
+
+ return -1;
+}
+
+static int nbd_receive_list(QIOChannel *ioc, char **name, Error **errp)
+{
+ uint64_t magic;
+ uint32_t opt;
+ uint32_t type;
+ uint32_t len;
+ uint32_t namelen;
+
+ *name = NULL;
+ if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
+ error_setg(errp, "failed to read list option magic");
+ return -1;
+ }
+ magic = be64_to_cpu(magic);
+ if (magic != NBD_REP_MAGIC) {
+ error_setg(errp, "Unexpected option list magic");
+ return -1;
+ }
+ if (read_sync(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
+ error_setg(errp, "failed to read list option");
+ return -1;
+ }
+ opt = be32_to_cpu(opt);
+ if (opt != NBD_OPT_LIST) {
+ error_setg(errp, "Unexpected option type %x expected %x",
+ opt, NBD_OPT_LIST);
+ return -1;
+ }
+
+ if (read_sync(ioc, &type, sizeof(type)) != sizeof(type)) {
+ error_setg(errp, "failed to read list option type");
+ return -1;
+ }
+ type = be32_to_cpu(type);
+ if (type == NBD_REP_ERR_UNSUP) {
+ return 0;
+ }
+ if (nbd_handle_reply_err(opt, type, errp) < 0) {
+ return -1;
+ }
+
+ if (read_sync(ioc, &len, sizeof(len)) != sizeof(len)) {
+ error_setg(errp, "failed to read option length");
+ return -1;
+ }
+ len = be32_to_cpu(len);
+
+ if (type == NBD_REP_ACK) {
+ if (len != 0) {
+ error_setg(errp, "length too long for option end");
+ return -1;
+ }
+ } else if (type == NBD_REP_SERVER) {
+ if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
+ error_setg(errp, "failed to read option name length");
+ return -1;
+ }
+ namelen = be32_to_cpu(namelen);
+ if (len != (namelen + sizeof(namelen))) {
+ error_setg(errp, "incorrect option mame length");
+ return -1;
+ }
+ if (namelen > 255) {
+ error_setg(errp, "export name length too long %d", namelen);
+ return -1;
+ }
+
+ *name = g_new0(char, namelen + 1);
+ if (read_sync(ioc, *name, namelen) != namelen) {
+ error_setg(errp, "failed to read export name");
+ g_free(*name);
+ *name = NULL;
+ return -1;
+ }
+ (*name)[namelen] = '\0';
+ } else {
+ error_setg(errp, "Unexpected reply type %x expected %x",
+ type, NBD_REP_SERVER);
+ return -1;
+ }
+ return 1;
+}
+
+
+static int nbd_receive_query_exports(QIOChannel *ioc,
+ const char *wantname,
+ Error **errp)
+{
+ uint64_t magic = cpu_to_be64(NBD_OPTS_MAGIC);
+ uint32_t opt = cpu_to_be32(NBD_OPT_LIST);
+ uint32_t length = 0;
+ bool foundExport = false;
+
+ TRACE("Querying export list");
+ if (write_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
+ error_setg(errp, "Failed to send list option magic");
+ return -1;
+ }
+
+ if (write_sync(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
+ error_setg(errp, "Failed to send list option number");
+ return -1;
+ }
+
+ if (write_sync(ioc, &length, sizeof(length)) != sizeof(length)) {
+ error_setg(errp, "Failed to send list option length");
+ return -1;
+ }
+
+ TRACE("Reading available export names");
+ while (1) {
+ char *name = NULL;
+ int ret = nbd_receive_list(ioc, &name, errp);
+
+ if (ret < 0) {
+ g_free(name);
+ name = NULL;
+ return -1;
+ }
+ if (ret == 0) {
+ /* Server doesn't support export listing, so
+ * we will just assume an export with our
+ * wanted name exists */
+ foundExport = true;
+ break;
+ }
+ if (name == NULL) {
+ TRACE("End of export name list");
+ break;
+ }
+ if (g_str_equal(name, wantname)) {
+ foundExport = true;
+ TRACE("Found desired export name '%s'", name);
+ } else {
+ TRACE("Ignored export name '%s'", name);
+ }
+ g_free(name);
+ }
+
+ if (!foundExport) {
+ error_setg(errp, "No export with name '%s' available", wantname);
+ return -1;
+ }
+
+ return 0;
+}
+
+static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
+ QCryptoTLSCreds *tlscreds,
+ const char *hostname, Error **errp)
+{
+ uint64_t magic = cpu_to_be64(NBD_OPTS_MAGIC);
+ uint32_t opt = cpu_to_be32(NBD_OPT_STARTTLS);
+ uint32_t length = 0;
+ uint32_t type;
+ QIOChannelTLS *tioc;
+ struct NBDTLSHandshakeData data = { 0 };
+
+ TRACE("Requesting TLS from server");
+ if (write_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
+ error_setg(errp, "Failed to send option magic");
+ return NULL;
+ }
+
+ if (write_sync(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
+ error_setg(errp, "Failed to send option number");
+ return NULL;
+ }
+
+ if (write_sync(ioc, &length, sizeof(length)) != sizeof(length)) {
+ error_setg(errp, "Failed to send option length");
+ return NULL;
+ }
+
+ TRACE("Getting TLS reply from server1");
+ if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
+ error_setg(errp, "failed to read option magic");
+ return NULL;
+ }
+ magic = be64_to_cpu(magic);
+ if (magic != NBD_REP_MAGIC) {
+ error_setg(errp, "Unexpected option magic");
+ return NULL;
+ }
+ TRACE("Getting TLS reply from server2");
+ if (read_sync(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
+ error_setg(errp, "failed to read option");
+ return NULL;
+ }
+ opt = be32_to_cpu(opt);
+ if (opt != NBD_OPT_STARTTLS) {
+ error_setg(errp, "Unexpected option type %x expected %x",
+ opt, NBD_OPT_STARTTLS);
+ return NULL;
+ }
+
+ TRACE("Getting TLS reply from server");
+ if (read_sync(ioc, &type, sizeof(type)) != sizeof(type)) {
+ error_setg(errp, "failed to read option type");
+ return NULL;
+ }
+ type = be32_to_cpu(type);
+ if (type != NBD_REP_ACK) {
+ error_setg(errp, "Server rejected request to start TLS %x",
+ type);
+ return NULL;
+ }
+
+ TRACE("Getting TLS reply from server");
+ if (read_sync(ioc, &length, sizeof(length)) != sizeof(length)) {
+ error_setg(errp, "failed to read option length");
+ return NULL;
+ }
+ length = be32_to_cpu(length);
+ if (length != 0) {
+ error_setg(errp, "Start TLS reponse was not zero %x",
+ length);
+ return NULL;
+ }
+
+ TRACE("TLS request approved, setting up TLS");
+ tioc = qio_channel_tls_new_client(ioc, tlscreds, hostname, errp);
+ if (!tioc) {
+ return NULL;
+ }
+ data.loop = g_main_loop_new(g_main_context_default(), FALSE);
+ TRACE("Starting TLS hanshake");
+ qio_channel_tls_handshake(tioc,
+ nbd_tls_handshake,
+ &data,
+ NULL);
+
+ if (!data.complete) {
+ g_main_loop_run(data.loop);
+ }
+ g_main_loop_unref(data.loop);
+ if (data.error) {
+ error_propagate(errp, data.error);
+ object_unref(OBJECT(tioc));
+ return NULL;
+ }
+
+ return QIO_CHANNEL(tioc);
+}
+
+
+int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint32_t *flags,
+ QCryptoTLSCreds *tlscreds, const char *hostname,
+ QIOChannel **outioc,
off_t *size, Error **errp)
{
char buf[256];
uint64_t magic, s;
- uint16_t tmp;
int rc;
- TRACE("Receiving negotiation.");
+ TRACE("Receiving negotiation tlscreds=%p hostname=%s.",
+ tlscreds, hostname ? hostname : "<null>");
rc = -EINVAL;
- if (read_sync(csock, buf, 8) != 8) {
+ if (outioc) {
+ *outioc = NULL;
+ }
+ if (tlscreds && !outioc) {
+ error_setg(errp, "Output I/O channel required for TLS");
+ goto fail;
+ }
+
+ if (read_sync(ioc, buf, 8) != 8) {
error_setg(errp, "Failed to read data");
goto fail;
}
@@ -109,93 +397,133 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
goto fail;
}
- if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
error_setg(errp, "Failed to read magic");
goto fail;
}
magic = be64_to_cpu(magic);
TRACE("Magic is 0x%" PRIx64, magic);
- if (name) {
- uint32_t reserved = 0;
+ if (magic == NBD_OPTS_MAGIC) {
+ uint32_t clientflags = 0;
uint32_t opt;
uint32_t namesize;
+ uint16_t globalflags;
+ uint16_t exportflags;
+ bool fixedNewStyle = false;
- TRACE("Checking magic (opts_magic)");
- if (magic != NBD_OPTS_MAGIC) {
- if (magic == NBD_CLIENT_MAGIC) {
- error_setg(errp, "Server does not support export names");
- } else {
- error_setg(errp, "Bad magic received");
- }
- goto fail;
- }
- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (read_sync(ioc, &globalflags, sizeof(globalflags)) !=
+ sizeof(globalflags)) {
error_setg(errp, "Failed to read server flags");
goto fail;
}
- *flags = be16_to_cpu(tmp) << 16;
- /* reserved for future use */
- if (write_sync(csock, &reserved, sizeof(reserved)) !=
- sizeof(reserved)) {
- error_setg(errp, "Failed to read reserved field");
+ globalflags = be16_to_cpu(globalflags);
+ *flags = globalflags << 16;
+ TRACE("Global flags are %x", globalflags);
+ if (globalflags & NBD_FLAG_FIXED_NEWSTYLE) {
+ fixedNewStyle = true;
+ TRACE("Server supports fixed new style");
+ clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
+ }
+ /* client requested flags */
+ clientflags = cpu_to_be32(clientflags);
+ if (write_sync(ioc, &clientflags, sizeof(clientflags)) !=
+ sizeof(clientflags)) {
+ error_setg(errp, "Failed to send clientflags field");
goto fail;
}
+ if (tlscreds) {
+ if (fixedNewStyle) {
+ *outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp);
+ if (!*outioc) {
+ goto fail;
+ }
+ ioc = *outioc;
+ } else {
+ error_setg(errp, "Server does not support STARTTLS");
+ goto fail;
+ }
+ }
+ if (!name) {
+ TRACE("Using default NBD export name \"\"");
+ name = "";
+ }
+ if (fixedNewStyle) {
+ /* Check our desired export is present in the
+ * server export list. Since NBD_OPT_EXPORT_NAME
+ * cannot return an error message, running this
+ * query gives us good error reporting if the
+ * server required TLS
+ */
+ if (nbd_receive_query_exports(ioc, name, errp) < 0) {
+ goto fail;
+ }
+ }
/* write the export name */
magic = cpu_to_be64(magic);
- if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (write_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
error_setg(errp, "Failed to send export name magic");
goto fail;
}
opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
- if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+ if (write_sync(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
error_setg(errp, "Failed to send export name option number");
goto fail;
}
namesize = cpu_to_be32(strlen(name));
- if (write_sync(csock, &namesize, sizeof(namesize)) !=
+ if (write_sync(ioc, &namesize, sizeof(namesize)) !=
sizeof(namesize)) {
error_setg(errp, "Failed to send export name length");
goto fail;
}
- if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
+ if (write_sync(ioc, (char *)name, strlen(name)) != strlen(name)) {
error_setg(errp, "Failed to send export name");
goto fail;
}
- } else {
- TRACE("Checking magic (cli_magic)");
- if (magic != NBD_CLIENT_MAGIC) {
- if (magic == NBD_OPTS_MAGIC) {
- error_setg(errp, "Server requires an export name");
- } else {
- error_setg(errp, "Bad magic received");
- }
+ if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
+ error_setg(errp, "Failed to read export length");
goto fail;
}
- }
-
- if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
- error_setg(errp, "Failed to read export length");
- goto fail;
- }
- *size = be64_to_cpu(s);
- TRACE("Size is %" PRIu64, *size);
+ *size = be64_to_cpu(s);
+ TRACE("Size is %" PRIu64, *size);
- if (!name) {
- if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
+ if (read_sync(ioc, &exportflags, sizeof(exportflags)) !=
+ sizeof(exportflags)) {
error_setg(errp, "Failed to read export flags");
goto fail;
}
- *flags = be32_to_cpup(flags);
- } else {
- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ exportflags = be16_to_cpu(exportflags);
+ *flags |= exportflags;
+ TRACE("Export flags are %x", exportflags);
+ } else if (magic == NBD_CLIENT_MAGIC) {
+ if (name) {
+ error_setg(errp, "Server does not support export names");
+ goto fail;
+ }
+ if (tlscreds) {
+ error_setg(errp, "Server does not support STARTTLS");
+ goto fail;
+ }
+
+ if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
+ error_setg(errp, "Failed to read export length");
+ goto fail;
+ }
+ *size = be64_to_cpu(s);
+ TRACE("Size is %" PRIu64, *size);
+
+ if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) {
error_setg(errp, "Failed to read export flags");
goto fail;
}
- *flags |= be16_to_cpu(tmp);
+ *flags = be32_to_cpup(flags);
+ } else {
+ error_setg(errp, "Bad magic received");
+ goto fail;
}
- if (read_sync(csock, &buf, 124) != 124) {
+
+ if (read_sync(ioc, &buf, 124) != 124) {
error_setg(errp, "Failed to read reserved block");
goto fail;
}
@@ -206,11 +534,11 @@ fail:
}
#ifdef __linux__
-int nbd_init(int fd, int csock, uint32_t flags, off_t size)
+int nbd_init(int fd, QIOChannelSocket *sioc, uint32_t flags, off_t size)
{
TRACE("Setting NBD socket");
- if (ioctl(fd, NBD_SET_SOCK, csock) < 0) {
+ if (ioctl(fd, NBD_SET_SOCK, sioc->fd) < 0) {
int serrno = errno;
LOG("Failed to set NBD socket");
return -serrno;
@@ -283,7 +611,7 @@ int nbd_client(int fd)
return ret;
}
#else
-int nbd_init(int fd, int csock, uint32_t flags, off_t size)
+int nbd_init(int fd, QIOChannelSocket *ioc, uint32_t flags, off_t size)
{
return -ENOTSUP;
}
@@ -294,7 +622,7 @@ int nbd_client(int fd)
}
#endif
-ssize_t nbd_send_request(int csock, struct nbd_request *request)
+ssize_t nbd_send_request(QIOChannel *ioc, struct nbd_request *request)
{
uint8_t buf[NBD_REQUEST_SIZE];
ssize_t ret;
@@ -309,7 +637,7 @@ ssize_t nbd_send_request(int csock, struct nbd_request *request)
"{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
request->from, request->len, request->handle, request->type);
- ret = write_sync(csock, buf, sizeof(buf));
+ ret = write_sync(ioc, buf, sizeof(buf));
if (ret < 0) {
return ret;
}
@@ -321,13 +649,13 @@ ssize_t nbd_send_request(int csock, struct nbd_request *request)
return 0;
}
-ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
+ssize_t nbd_receive_reply(QIOChannel *ioc, struct nbd_reply *reply)
{
uint8_t buf[NBD_REPLY_SIZE];
uint32_t magic;
ssize_t ret;
- ret = read_sync(csock, buf, sizeof(buf));
+ ret = read_sync(ioc, buf, sizeof(buf));
if (ret < 0) {
return ret;
}
diff --git a/nbd/common.c b/nbd/common.c
index 178d4a7ff2..bde673a04a 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -19,47 +19,74 @@
#include "qemu/osdep.h"
#include "nbd-internal.h"
-ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
+ssize_t nbd_wr_syncv(QIOChannel *ioc,
+ struct iovec *iov,
+ size_t niov,
+ size_t offset,
+ size_t length,
+ bool do_read)
{
- size_t offset = 0;
- int err;
+ ssize_t done = 0;
+ Error *local_err = NULL;
+ struct iovec *local_iov = g_new(struct iovec, niov);
+ struct iovec *local_iov_head = local_iov;
+ unsigned int nlocal_iov = niov;
- if (qemu_in_coroutine()) {
- if (do_read) {
- return qemu_co_recv(fd, buffer, size);
- } else {
- return qemu_co_send(fd, buffer, size);
- }
- }
+ nlocal_iov = iov_copy(local_iov, nlocal_iov,
+ iov, niov,
+ offset, length);
- while (offset < size) {
+ while (nlocal_iov > 0) {
ssize_t len;
-
if (do_read) {
- len = qemu_recv(fd, buffer + offset, size - offset, 0);
+ len = qio_channel_readv(ioc, local_iov, nlocal_iov, &local_err);
} else {
- len = send(fd, buffer + offset, size - offset, 0);
+ len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err);
}
-
- if (len < 0) {
- err = socket_error();
-
- /* recoverable error */
- if (err == EINTR || (offset > 0 && (err == EAGAIN || err == EWOULDBLOCK))) {
- continue;
+ if (len == QIO_CHANNEL_ERR_BLOCK) {
+ if (qemu_in_coroutine()) {
+ /* XXX figure out if we can create a variant on
+ * qio_channel_yield() that works with AIO contexts
+ * and consider using that in this branch */
+ qemu_coroutine_yield();
+ } else {
+ qio_channel_wait(ioc,
+ do_read ? G_IO_IN : G_IO_OUT);
}
-
- /* unrecoverable error */
- return -err;
+ continue;
+ }
+ if (len < 0) {
+ TRACE("I/O error: %s", error_get_pretty(local_err));
+ error_free(local_err);
+ /* XXX handle Error objects */
+ done = -EIO;
+ goto cleanup;
}
- /* eof */
- if (len == 0) {
+ if (do_read && len == 0) {
break;
}
- offset += len;
+ iov_discard_front(&local_iov, &nlocal_iov, len);
+ done += len;
}
- return offset;
+ cleanup:
+ g_free(local_iov_head);
+ return done;
+}
+
+
+void nbd_tls_handshake(Object *src,
+ Error *err,
+ void *opaque)
+{
+ struct NBDTLSHandshakeData *data = opaque;
+
+ if (err) {
+ TRACE("TLS failed %s", error_get_pretty(err));
+ data->error = error_copy(err);
+ }
+ data->complete = true;
+ g_main_loop_quit(data->loop);
}
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index c0a657575b..db6ab65ced 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -11,8 +11,10 @@
#define NBD_INTERNAL_H
#include "block/nbd.h"
#include "sysemu/block-backend.h"
+#include "io/channel-tls.h"
#include "qemu/coroutine.h"
+#include "qemu/iov.h"
#include <errno.h>
#include <string.h>
@@ -29,7 +31,6 @@
#include <linux/fs.h>
#endif
-#include "qemu/sockets.h"
#include "qemu/queue.h"
#include "qemu/main-loop.h"
@@ -78,6 +79,8 @@
#define NBD_OPT_EXPORT_NAME (1)
#define NBD_OPT_ABORT (2)
#define NBD_OPT_LIST (3)
+#define NBD_OPT_PEEK_EXPORT (4)
+#define NBD_OPT_STARTTLS (5)
/* NBD errors are based on errno numbers, so there is a 1:1 mapping,
* but only a limited set of errno values is specified in the protocol.
@@ -90,24 +93,33 @@
#define NBD_EINVAL 22
#define NBD_ENOSPC 28
-static inline ssize_t read_sync(int fd, void *buffer, size_t size)
+static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
{
+ struct iovec iov = { .iov_base = buffer, .iov_len = size };
/* Sockets are kept in blocking mode in the negotiation phase. After
* that, a non-readable socket simply means that another thread stole
* our request/reply. Synchronization is done with recv_coroutine, so
* that this is coroutine-safe.
*/
- return nbd_wr_sync(fd, buffer, size, true);
+ return nbd_wr_syncv(ioc, &iov, 1, 0, size, true);
}
-static inline ssize_t write_sync(int fd, void *buffer, size_t size)
+static inline ssize_t write_sync(QIOChannel *ioc, void *buffer, size_t size)
{
- int ret;
- do {
- /* For writes, we do expect the socket to be writable. */
- ret = nbd_wr_sync(fd, buffer, size, false);
- } while (ret == -EAGAIN);
- return ret;
+ struct iovec iov = { .iov_base = buffer, .iov_len = size };
+
+ return nbd_wr_syncv(ioc, &iov, 1, 0, size, false);
}
+struct NBDTLSHandshakeData {
+ GMainLoop *loop;
+ bool complete;
+ Error *error;
+};
+
+
+void nbd_tls_handshake(Object *src,
+ Error *err,
+ void *opaque);
+
#endif
diff --git a/nbd/server.c b/nbd/server.c
index dc1d66fa47..d4225cdb55 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -76,7 +76,10 @@ struct NBDClient {
void (*close)(NBDClient *client);
NBDExport *exp;
- int sock;
+ QCryptoTLSCreds *tlscreds;
+ char *tlsaclname;
+ QIOChannelSocket *sioc; /* The underlying data channel */
+ QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
Coroutine *recv_coroutine;
@@ -96,45 +99,56 @@ static void nbd_set_handlers(NBDClient *client);
static void nbd_unset_handlers(NBDClient *client);
static void nbd_update_can_read(NBDClient *client);
-static void nbd_negotiate_continue(void *opaque)
+static gboolean nbd_negotiate_continue(QIOChannel *ioc,
+ GIOCondition condition,
+ void *opaque)
{
qemu_coroutine_enter(opaque, NULL);
+ return TRUE;
}
-static ssize_t nbd_negotiate_read(int fd, void *buffer, size_t size)
+static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
{
ssize_t ret;
+ guint watch;
assert(qemu_in_coroutine());
/* Negotiation are always in main loop. */
- qemu_set_fd_handler(fd, nbd_negotiate_continue, NULL,
- qemu_coroutine_self());
- ret = read_sync(fd, buffer, size);
- qemu_set_fd_handler(fd, NULL, NULL, NULL);
+ watch = qio_channel_add_watch(ioc,
+ G_IO_IN,
+ nbd_negotiate_continue,
+ qemu_coroutine_self(),
+ NULL);
+ ret = read_sync(ioc, buffer, size);
+ g_source_remove(watch);
return ret;
}
-static ssize_t nbd_negotiate_write(int fd, void *buffer, size_t size)
+static ssize_t nbd_negotiate_write(QIOChannel *ioc, void *buffer, size_t size)
{
ssize_t ret;
+ guint watch;
assert(qemu_in_coroutine());
/* Negotiation are always in main loop. */
- qemu_set_fd_handler(fd, NULL, nbd_negotiate_continue,
- qemu_coroutine_self());
- ret = write_sync(fd, buffer, size);
- qemu_set_fd_handler(fd, NULL, NULL, NULL);
+ watch = qio_channel_add_watch(ioc,
+ G_IO_OUT,
+ nbd_negotiate_continue,
+ qemu_coroutine_self(),
+ NULL);
+ ret = write_sync(ioc, buffer, size);
+ g_source_remove(watch);
return ret;
}
-static ssize_t nbd_negotiate_drop_sync(int fd, size_t size)
+static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
{
ssize_t ret, dropped = size;
uint8_t *buffer = g_malloc(MIN(65536, size));
while (size > 0) {
- ret = nbd_negotiate_read(fd, buffer, MIN(65536, size));
+ ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size));
if (ret < 0) {
g_free(buffer);
return ret;
@@ -175,66 +189,69 @@ static ssize_t nbd_negotiate_drop_sync(int fd, size_t size)
*/
-static int nbd_negotiate_send_rep(int csock, uint32_t type, uint32_t opt)
+static int nbd_negotiate_send_rep(QIOChannel *ioc, uint32_t type, uint32_t opt)
{
uint64_t magic;
uint32_t len;
+ TRACE("Reply opt=%x type=%x", type, opt);
+
magic = cpu_to_be64(NBD_REP_MAGIC);
- if (nbd_negotiate_write(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("write failed (rep magic)");
return -EINVAL;
}
opt = cpu_to_be32(opt);
- if (nbd_negotiate_write(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+ if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
LOG("write failed (rep opt)");
return -EINVAL;
}
type = cpu_to_be32(type);
- if (nbd_negotiate_write(csock, &type, sizeof(type)) != sizeof(type)) {
+ if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) {
LOG("write failed (rep type)");
return -EINVAL;
}
len = cpu_to_be32(0);
- if (nbd_negotiate_write(csock, &len, sizeof(len)) != sizeof(len)) {
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
LOG("write failed (rep data length)");
return -EINVAL;
}
return 0;
}
-static int nbd_negotiate_send_rep_list(int csock, NBDExport *exp)
+static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
{
uint64_t magic, name_len;
uint32_t opt, type, len;
+ TRACE("Advertizing export name '%s'", exp->name ? exp->name : "");
name_len = strlen(exp->name);
magic = cpu_to_be64(NBD_REP_MAGIC);
- if (nbd_negotiate_write(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("write failed (magic)");
return -EINVAL;
}
opt = cpu_to_be32(NBD_OPT_LIST);
- if (nbd_negotiate_write(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+ if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
LOG("write failed (opt)");
return -EINVAL;
}
type = cpu_to_be32(NBD_REP_SERVER);
- if (nbd_negotiate_write(csock, &type, sizeof(type)) != sizeof(type)) {
+ if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) {
LOG("write failed (reply type)");
return -EINVAL;
}
len = cpu_to_be32(name_len + sizeof(len));
- if (nbd_negotiate_write(csock, &len, sizeof(len)) != sizeof(len)) {
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
LOG("write failed (length)");
return -EINVAL;
}
len = cpu_to_be32(name_len);
- if (nbd_negotiate_write(csock, &len, sizeof(len)) != sizeof(len)) {
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
LOG("write failed (length)");
return -EINVAL;
}
- if (nbd_negotiate_write(csock, exp->name, name_len) != name_len) {
+ if (nbd_negotiate_write(ioc, exp->name, name_len) != name_len) {
LOG("write failed (buffer)");
return -EINVAL;
}
@@ -243,30 +260,29 @@ static int nbd_negotiate_send_rep_list(int csock, NBDExport *exp)
static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length)
{
- int csock;
NBDExport *exp;
- csock = client->sock;
if (length) {
- if (nbd_negotiate_drop_sync(csock, length) != length) {
+ if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
return -EIO;
}
- return nbd_negotiate_send_rep(csock, NBD_REP_ERR_INVALID, NBD_OPT_LIST);
+ return nbd_negotiate_send_rep(client->ioc,
+ NBD_REP_ERR_INVALID, NBD_OPT_LIST);
}
/* For each export, send a NBD_REP_SERVER reply. */
QTAILQ_FOREACH(exp, &exports, next) {
- if (nbd_negotiate_send_rep_list(csock, exp)) {
+ if (nbd_negotiate_send_rep_list(client->ioc, exp)) {
return -EINVAL;
}
}
/* Finish with a NBD_REP_ACK. */
- return nbd_negotiate_send_rep(csock, NBD_REP_ACK, NBD_OPT_LIST);
+ return nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, NBD_OPT_LIST);
}
static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
{
- int rc = -EINVAL, csock = client->sock;
+ int rc = -EINVAL;
char name[256];
/* Client sends:
@@ -277,12 +293,14 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
LOG("Bad length received");
goto fail;
}
- if (nbd_negotiate_read(csock, name, length) != length) {
+ if (nbd_negotiate_read(client->ioc, name, length) != length) {
LOG("read failed");
goto fail;
}
name[length] = '\0';
+ TRACE("Client requested export '%s'", name);
+
client->exp = nbd_export_find(name);
if (!client->exp) {
LOG("export not found");
@@ -296,10 +314,59 @@ fail:
return rc;
}
+
+static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
+ uint32_t length)
+{
+ QIOChannel *ioc;
+ QIOChannelTLS *tioc;
+ struct NBDTLSHandshakeData data = { 0 };
+
+ TRACE("Setting up TLS");
+ ioc = client->ioc;
+ if (length) {
+ if (nbd_negotiate_drop_sync(ioc, length) != length) {
+ return NULL;
+ }
+ nbd_negotiate_send_rep(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS);
+ return NULL;
+ }
+
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, NBD_OPT_STARTTLS);
+
+ tioc = qio_channel_tls_new_server(ioc,
+ client->tlscreds,
+ client->tlsaclname,
+ NULL);
+ if (!tioc) {
+ return NULL;
+ }
+
+ TRACE("Starting TLS handshake");
+ data.loop = g_main_loop_new(g_main_context_default(), FALSE);
+ qio_channel_tls_handshake(tioc,
+ nbd_tls_handshake,
+ &data,
+ NULL);
+
+ if (!data.complete) {
+ g_main_loop_run(data.loop);
+ }
+ g_main_loop_unref(data.loop);
+ if (data.error) {
+ object_unref(OBJECT(tioc));
+ error_free(data.error);
+ return NULL;
+ }
+
+ return QIO_CHANNEL(tioc);
+}
+
+
static int nbd_negotiate_options(NBDClient *client)
{
- int csock = client->sock;
uint32_t flags;
+ bool fixedNewstyle = false;
/* Client sends:
[ 0 .. 3] client flags
@@ -315,23 +382,30 @@ static int nbd_negotiate_options(NBDClient *client)
... Rest of request
*/
- if (nbd_negotiate_read(csock, &flags, sizeof(flags)) != sizeof(flags)) {
+ if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) !=
+ sizeof(flags)) {
LOG("read failed");
return -EIO;
}
TRACE("Checking client flags");
be32_to_cpus(&flags);
- if (flags != 0 && flags != NBD_FLAG_C_FIXED_NEWSTYLE) {
- LOG("Bad client flags received");
+ if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
+ TRACE("Support supports fixed newstyle handshake");
+ fixedNewstyle = true;
+ flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
+ }
+ if (flags != 0) {
+ TRACE("Unknown client flags 0x%x received", flags);
return -EIO;
}
while (1) {
int ret;
- uint32_t tmp, length;
+ uint32_t clientflags, length;
uint64_t magic;
- if (nbd_negotiate_read(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
+ sizeof(magic)) {
LOG("read failed");
return -EINVAL;
}
@@ -341,38 +415,89 @@ static int nbd_negotiate_options(NBDClient *client)
return -EINVAL;
}
- if (nbd_negotiate_read(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (nbd_negotiate_read(client->ioc, &clientflags,
+ sizeof(clientflags)) != sizeof(clientflags)) {
LOG("read failed");
return -EINVAL;
}
+ clientflags = be32_to_cpu(clientflags);
- if (nbd_negotiate_read(csock, &length,
- sizeof(length)) != sizeof(length)) {
+ if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
+ sizeof(length)) {
LOG("read failed");
return -EINVAL;
}
length = be32_to_cpu(length);
- TRACE("Checking option");
- switch (be32_to_cpu(tmp)) {
- case NBD_OPT_LIST:
- ret = nbd_negotiate_handle_list(client, length);
- if (ret < 0) {
- return ret;
+ TRACE("Checking option 0x%x", clientflags);
+ if (client->tlscreds &&
+ client->ioc == (QIOChannel *)client->sioc) {
+ QIOChannel *tioc;
+ if (!fixedNewstyle) {
+ TRACE("Unsupported option 0x%x", clientflags);
+ return -EINVAL;
+ }
+ switch (clientflags) {
+ case NBD_OPT_STARTTLS:
+ tioc = nbd_negotiate_handle_starttls(client, length);
+ if (!tioc) {
+ return -EIO;
+ }
+ object_unref(OBJECT(client->ioc));
+ client->ioc = QIO_CHANNEL(tioc);
+ break;
+
+ default:
+ TRACE("Option 0x%x not permitted before TLS", clientflags);
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_TLS_REQD,
+ clientflags);
+ return -EINVAL;
+ }
+ } else if (fixedNewstyle) {
+ switch (clientflags) {
+ case NBD_OPT_LIST:
+ ret = nbd_negotiate_handle_list(client, length);
+ if (ret < 0) {
+ return ret;
+ }
+ break;
+
+ case NBD_OPT_ABORT:
+ return -EINVAL;
+
+ case NBD_OPT_EXPORT_NAME:
+ return nbd_negotiate_handle_export_name(client, length);
+
+ case NBD_OPT_STARTTLS:
+ if (client->tlscreds) {
+ TRACE("TLS already enabled");
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_INVALID,
+ clientflags);
+ } else {
+ TRACE("TLS not configured");
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_POLICY,
+ clientflags);
+ }
+ return -EINVAL;
+ default:
+ TRACE("Unsupported option 0x%x", clientflags);
+ nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP,
+ clientflags);
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * If broken new-style we should drop the connection
+ * for anything except NBD_OPT_EXPORT_NAME
+ */
+ switch (clientflags) {
+ case NBD_OPT_EXPORT_NAME:
+ return nbd_negotiate_handle_export_name(client, length);
+
+ default:
+ TRACE("Unsupported option 0x%x", clientflags);
+ return -EINVAL;
}
- break;
-
- case NBD_OPT_ABORT:
- return -EINVAL;
-
- case NBD_OPT_EXPORT_NAME:
- return nbd_negotiate_handle_export_name(client, length);
-
- default:
- tmp = be32_to_cpu(tmp);
- LOG("Unsupported option 0x%x", tmp);
- nbd_negotiate_send_rep(client->sock, NBD_REP_ERR_UNSUP, tmp);
- return -EINVAL;
}
}
}
@@ -385,13 +510,13 @@ typedef struct {
static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
{
NBDClient *client = data->client;
- int csock = client->sock;
char buf[8 + 8 + 8 + 128];
int rc;
const int myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM |
NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA);
+ bool oldStyle;
- /* Negotiation header without options:
+ /* Old style negotiation header without options
[ 0 .. 7] passwd ("NBDMAGIC")
[ 8 .. 15] magic (NBD_CLIENT_MAGIC)
[16 .. 23] size
@@ -399,23 +524,25 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
[26 .. 27] export flags
[28 .. 151] reserved (0)
- Negotiation header with options, part 1:
+ New style negotiation header with options
[ 0 .. 7] passwd ("NBDMAGIC")
[ 8 .. 15] magic (NBD_OPTS_MAGIC)
[16 .. 17] server flags (0)
-
- part 2 (after options are sent):
+ ....options sent....
[18 .. 25] size
[26 .. 27] export flags
[28 .. 151] reserved (0)
*/
+ qio_channel_set_blocking(client->ioc, false, NULL);
rc = -EINVAL;
TRACE("Beginning negotiation.");
memset(buf, 0, sizeof(buf));
memcpy(buf, "NBDMAGIC", 8);
- if (client->exp) {
+
+ oldStyle = client->exp != NULL && !client->tlscreds;
+ if (oldStyle) {
assert ((client->exp->nbdflags & ~65535) == 0);
stq_be_p(buf + 8, NBD_CLIENT_MAGIC);
stq_be_p(buf + 16, client->exp->size);
@@ -425,13 +552,17 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
stw_be_p(buf + 16, NBD_FLAG_FIXED_NEWSTYLE);
}
- if (client->exp) {
- if (nbd_negotiate_write(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ if (oldStyle) {
+ if (client->tlscreds) {
+ TRACE("TLS cannot be enabled with oldstyle protocol");
+ goto fail;
+ }
+ if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) {
LOG("write failed");
goto fail;
}
} else {
- if (nbd_negotiate_write(csock, buf, 18) != 18) {
+ if (nbd_negotiate_write(client->ioc, buf, 18) != 18) {
LOG("write failed");
goto fail;
}
@@ -444,8 +575,8 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
assert ((client->exp->nbdflags & ~65535) == 0);
stq_be_p(buf + 18, client->exp->size);
stw_be_p(buf + 26, client->exp->nbdflags | myflags);
- if (nbd_negotiate_write(csock, buf + 18,
- sizeof(buf) - 18) != sizeof(buf) - 18) {
+ if (nbd_negotiate_write(client->ioc, buf + 18, sizeof(buf) - 18) !=
+ sizeof(buf) - 18) {
LOG("write failed");
goto fail;
}
@@ -475,13 +606,13 @@ int nbd_disconnect(int fd)
}
#endif
-static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
+static ssize_t nbd_receive_request(QIOChannel *ioc, struct nbd_request *request)
{
uint8_t buf[NBD_REQUEST_SIZE];
uint32_t magic;
ssize_t ret;
- ret = read_sync(csock, buf, sizeof(buf));
+ ret = read_sync(ioc, buf, sizeof(buf));
if (ret < 0) {
return ret;
}
@@ -516,7 +647,7 @@ static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
return 0;
}
-static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
+static ssize_t nbd_send_reply(QIOChannel *ioc, struct nbd_reply *reply)
{
uint8_t buf[NBD_REPLY_SIZE];
ssize_t ret;
@@ -534,7 +665,7 @@ static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
TRACE("Sending response to client");
- ret = write_sync(csock, buf, sizeof(buf));
+ ret = write_sync(ioc, buf, sizeof(buf));
if (ret < 0) {
return ret;
}
@@ -562,8 +693,12 @@ void nbd_client_put(NBDClient *client)
assert(client->closing);
nbd_unset_handlers(client);
- close(client->sock);
- client->sock = -1;
+ object_unref(OBJECT(client->sioc));
+ object_unref(OBJECT(client->ioc));
+ if (client->tlscreds) {
+ object_unref(OBJECT(client->tlscreds));
+ }
+ g_free(client->tlsaclname);
if (client->exp) {
QTAILQ_REMOVE(&client->exp->clients, client, next);
nbd_export_put(client->exp);
@@ -583,7 +718,8 @@ static void client_close(NBDClient *client)
/* Force requests to finish. They will drop their own references,
* then we'll close the socket and free the NBDClient.
*/
- shutdown(client->sock, 2);
+ qio_channel_shutdown(client->ioc, QIO_CHANNEL_SHUTDOWN_BOTH,
+ NULL);
/* Also tell the client, so that they release their reference. */
if (client->close) {
@@ -789,25 +925,25 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
int len)
{
NBDClient *client = req->client;
- int csock = client->sock;
ssize_t rc, ret;
+ g_assert(qemu_in_coroutine());
qemu_co_mutex_lock(&client->send_lock);
client->send_coroutine = qemu_coroutine_self();
nbd_set_handlers(client);
if (!len) {
- rc = nbd_send_reply(csock, reply);
+ rc = nbd_send_reply(client->ioc, reply);
} else {
- socket_set_cork(csock, 1);
- rc = nbd_send_reply(csock, reply);
+ qio_channel_set_cork(client->ioc, true);
+ rc = nbd_send_reply(client->ioc, reply);
if (rc >= 0) {
- ret = qemu_co_send(csock, req->data, len);
+ ret = write_sync(client->ioc, req->data, len);
if (ret != len) {
rc = -EIO;
}
}
- socket_set_cork(csock, 0);
+ qio_channel_set_cork(client->ioc, false);
}
client->send_coroutine = NULL;
@@ -819,14 +955,14 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
{
NBDClient *client = req->client;
- int csock = client->sock;
uint32_t command;
ssize_t rc;
+ g_assert(qemu_in_coroutine());
client->recv_coroutine = qemu_coroutine_self();
nbd_update_can_read(client);
- rc = nbd_receive_request(csock, request);
+ rc = nbd_receive_request(client->ioc, request);
if (rc < 0) {
if (rc != -EAGAIN) {
rc = -EIO;
@@ -861,7 +997,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
if (command == NBD_CMD_WRITE) {
TRACE("Reading %u byte(s)", request->len);
- if (qemu_co_recv(csock, req->data, request->len) != request->len) {
+ if (read_sync(client->ioc, req->data, request->len) != request->len) {
LOG("reading from socket failed");
rc = -EIO;
goto out;
@@ -1056,7 +1192,7 @@ static void nbd_restart_write(void *opaque)
static void nbd_set_handlers(NBDClient *client)
{
if (client->exp && client->exp->ctx) {
- aio_set_fd_handler(client->exp->ctx, client->sock,
+ aio_set_fd_handler(client->exp->ctx, client->sioc->fd,
true,
client->can_read ? nbd_read : NULL,
client->send_coroutine ? nbd_restart_write : NULL,
@@ -1067,7 +1203,7 @@ static void nbd_set_handlers(NBDClient *client)
static void nbd_unset_handlers(NBDClient *client)
{
if (client->exp && client->exp->ctx) {
- aio_set_fd_handler(client->exp->ctx, client->sock,
+ aio_set_fd_handler(client->exp->ctx, client->sioc->fd,
true, NULL, NULL, NULL);
}
}
@@ -1109,7 +1245,11 @@ out:
g_free(data);
}
-void nbd_client_new(NBDExport *exp, int csock, void (*close_fn)(NBDClient *))
+void nbd_client_new(NBDExport *exp,
+ QIOChannelSocket *sioc,
+ QCryptoTLSCreds *tlscreds,
+ const char *tlsaclname,
+ void (*close_fn)(NBDClient *))
{
NBDClient *client;
NBDClientNewData *data = g_new(NBDClientNewData, 1);
@@ -1117,7 +1257,15 @@ void nbd_client_new(NBDExport *exp, int csock, void (*close_fn)(NBDClient *))
client = g_malloc0(sizeof(NBDClient));
client->refcount = 1;
client->exp = exp;
- client->sock = csock;
+ client->tlscreds = tlscreds;
+ if (tlscreds) {
+ object_ref(OBJECT(client->tlscreds));
+ }
+ client->tlsaclname = g_strdup(tlsaclname);
+ client->sioc = sioc;
+ object_ref(OBJECT(client->sioc));
+ client->ioc = QIO_CHANNEL(sioc);
+ object_ref(OBJECT(client->ioc));
client->can_read = true;
client->close = close_fn;
diff --git a/qapi/block.json b/qapi/block.json
index ed61f82359..58e6b301bf 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -146,13 +146,15 @@
# QEMU instance could refer to them as "nbd:HOST:PORT:exportname=NAME".
#
# @addr: Address on which to listen.
+# @tls-creds: (optional) ID of the TLS credentials object. Since 2.6
#
# Returns: error if the server is already running.
#
# Since: 1.3.0
##
{ 'command': 'nbd-server-start',
- 'data': { 'addr': 'SocketAddress' } }
+ 'data': { 'addr': 'SocketAddress',
+ '*tls-creds': 'str'} }
##
# @nbd-server-add:
diff --git a/qemu-char.c b/qemu-char.c
index 1b7d5dac76..ad11b75e3d 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -896,13 +896,13 @@ static int io_channel_send_full(QIOChannel *ioc,
ioc, &iov, 1,
fds, nfds, NULL);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
- errno = EAGAIN;
- return -1;
- } else if (ret < 0) {
if (offset) {
return offset;
}
+ errno = EAGAIN;
+ return -1;
+ } else if (ret < 0) {
errno = EINVAL;
return -1;
}
@@ -1171,7 +1171,6 @@ typedef struct {
int connected;
guint timer_tag;
guint open_tag;
- int slave_fd;
} PtyCharDriver;
static void pty_chr_update_read_handler_locked(CharDriverState *chr);
@@ -1348,7 +1347,6 @@ static void pty_chr_close(struct CharDriverState *chr)
qemu_mutex_lock(&chr->chr_write_lock);
pty_chr_state(chr, 0);
- close(s->slave_fd);
object_unref(OBJECT(s->ioc));
if (s->timer_tag) {
g_source_remove(s->timer_tag);
@@ -1376,6 +1374,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
return NULL;
}
+ close(slave_fd);
qemu_set_nonblock(master_fd);
chr = qemu_chr_alloc(common, errp);
@@ -1400,7 +1399,6 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
chr->explicit_be_open = true;
s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
- s->slave_fd = slave_fd;
s->timer_tag = 0;
return chr;
diff --git a/qemu-img.c b/qemu-img.c
index 163d8c1664..7030107da2 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3104,6 +3104,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
+ module_call_init(MODULE_INIT_QOM);
bdrv_init();
if (argc < 2) {
error_exit("Not enough arguments");
diff --git a/qemu-io.c b/qemu-io.c
index 83c48f4149..6c0c028f98 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -394,6 +394,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
qemu_init_exec_dir(argv[0]);
+ module_call_init(MODULE_INIT_QOM);
bdrv_init();
while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d374015125..933ca4a368 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -22,17 +22,17 @@
#include "block/block_int.h"
#include "block/nbd.h"
#include "qemu/main-loop.h"
-#include "qemu/sockets.h"
#include "qemu/error-report.h"
+#include "qemu/config-file.h"
#include "block/snapshot.h"
#include "qapi/util.h"
#include "qapi/qmp/qstring.h"
+#include "qom/object_interfaces.h"
+#include "io/channel-socket.h"
#include <getopt.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
+#include <sys/types.h>
+#include <signal.h>
#include <libgen.h>
#include <pthread.h>
@@ -41,8 +41,11 @@
#define QEMU_NBD_OPT_AIO 2
#define QEMU_NBD_OPT_DISCARD 3
#define QEMU_NBD_OPT_DETECT_ZEROES 4
+#define QEMU_NBD_OPT_OBJECT 5
+#define QEMU_NBD_OPT_TLSCREDS 6
static NBDExport *exp;
+static bool newproto;
static int verbose;
static char *srcpath;
static SocketAddress *saddr;
@@ -50,7 +53,9 @@ static int persistent = 0;
static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
static int shared = 1;
static int nb_fds;
-static int server_fd;
+static QIOChannelSocket *server_ioc;
+static int server_watch = -1;
+static QCryptoTLSCreds *tlscreds;
static void usage(const char *name)
{
@@ -74,6 +79,9 @@ static void usage(const char *name)
" -o, --offset=OFFSET offset into the image\n"
" -P, --partition=NUM only expose partition NUM\n"
"\n"
+"General purpose options:\n"
+" --object type,id=ID,... define an object such as 'secret' for providing\n"
+" passwords and/or encryption keys\n"
#ifdef __linux__
"Kernel NBD client support:\n"
" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
@@ -230,19 +238,22 @@ static void *nbd_client_thread(void *arg)
char *device = arg;
off_t size;
uint32_t nbdflags;
- int fd, sock;
+ QIOChannelSocket *sioc;
+ int fd;
int ret;
pthread_t show_parts_thread;
Error *local_error = NULL;
-
- sock = socket_connect(saddr, &local_error, NULL, NULL);
- if (sock < 0) {
+ sioc = qio_channel_socket_new();
+ if (qio_channel_socket_connect_sync(sioc,
+ saddr,
+ &local_error) < 0) {
error_report_err(local_error);
goto out;
}
- ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
+ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, &nbdflags,
+ NULL, NULL, NULL,
&size, &local_error);
if (ret < 0) {
if (local_error) {
@@ -258,7 +269,7 @@ static void *nbd_client_thread(void *arg)
goto out_socket;
}
- ret = nbd_init(fd, sock, nbdflags, size);
+ ret = nbd_init(fd, sioc, nbdflags, size);
if (ret < 0) {
goto out_fd;
}
@@ -279,13 +290,14 @@ static void *nbd_client_thread(void *arg)
goto out_fd;
}
close(fd);
+ object_unref(OBJECT(sioc));
kill(getpid(), SIGTERM);
return (void *) EXIT_SUCCESS;
out_fd:
close(fd);
out_socket:
- closesocket(sock);
+ object_unref(OBJECT(sioc));
out:
kill(getpid(), SIGTERM);
return (void *) EXIT_FAILURE;
@@ -302,7 +314,7 @@ static void nbd_export_closed(NBDExport *exp)
state = TERMINATED;
}
-static void nbd_update_server_fd_handler(int fd);
+static void nbd_update_server_watch(void);
static void nbd_client_closed(NBDClient *client)
{
@@ -310,37 +322,48 @@ static void nbd_client_closed(NBDClient *client)
if (nb_fds == 0 && !persistent && state == RUNNING) {
state = TERMINATE;
}
- nbd_update_server_fd_handler(server_fd);
+ nbd_update_server_watch();
nbd_client_put(client);
}
-static void nbd_accept(void *opaque)
+static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
{
- struct sockaddr_in addr;
- socklen_t addr_len = sizeof(addr);
+ QIOChannelSocket *cioc;
- int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
- if (fd < 0) {
- perror("accept");
- return;
+ cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+ NULL);
+ if (!cioc) {
+ return TRUE;
}
if (state >= TERMINATE) {
- close(fd);
- return;
+ object_unref(OBJECT(cioc));
+ return TRUE;
}
nb_fds++;
- nbd_update_server_fd_handler(server_fd);
- nbd_client_new(exp, fd, nbd_client_closed);
+ nbd_update_server_watch();
+ nbd_client_new(newproto ? NULL : exp, cioc,
+ tlscreds, NULL, nbd_client_closed);
+ object_unref(OBJECT(cioc));
+
+ return TRUE;
}
-static void nbd_update_server_fd_handler(int fd)
+static void nbd_update_server_watch(void)
{
if (nbd_can_accept()) {
- qemu_set_fd_handler(fd, nbd_accept, NULL, (void *)(uintptr_t)fd);
+ if (server_watch == -1) {
+ server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
+ G_IO_IN,
+ nbd_accept,
+ NULL, NULL);
+ }
} else {
- qemu_set_fd_handler(fd, NULL, NULL, NULL);
+ if (server_watch != -1) {
+ g_source_remove(server_watch);
+ server_watch = -1;
+ }
}
}
@@ -371,6 +394,47 @@ static SocketAddress *nbd_build_socket_address(const char *sockpath,
}
+static QemuOptsList qemu_object_opts = {
+ .name = "object",
+ .implied_opt_name = "qom-type",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
+ .desc = {
+ { }
+ },
+};
+
+
+
+static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
+{
+ Object *obj;
+ QCryptoTLSCreds *creds;
+
+ obj = object_resolve_path_component(
+ object_get_objects_root(), id);
+ if (!obj) {
+ error_setg(errp, "No TLS credentials with id '%s'",
+ id);
+ return NULL;
+ }
+ creds = (QCryptoTLSCreds *)
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
+ if (!creds) {
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
+ id);
+ return NULL;
+ }
+
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ error_setg(errp,
+ "Expecting TLS credentials with a server endpoint");
+ return NULL;
+ }
+ object_ref(obj);
+ return creds;
+}
+
+
int main(int argc, char **argv)
{
BlockBackend *blk;
@@ -385,7 +449,7 @@ int main(int argc, char **argv)
off_t fd_size;
QemuOpts *sn_opts = NULL;
const char *sn_id_or_name = NULL;
- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:";
+ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:";
struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -408,6 +472,9 @@ int main(int argc, char **argv)
{ "format", 1, NULL, 'f' },
{ "persistent", 0, NULL, 't' },
{ "verbose", 0, NULL, 'v' },
+ { "object", 1, NULL, QEMU_NBD_OPT_OBJECT },
+ { "export-name", 1, NULL, 'x' },
+ { "tls-creds", 1, NULL, QEMU_NBD_OPT_TLSCREDS },
{ NULL, 0, NULL, 0 }
};
int ch;
@@ -416,7 +483,6 @@ int main(int argc, char **argv)
int flags = BDRV_O_RDWR;
int partition = -1;
int ret = 0;
- int fd;
bool seen_cache = false;
bool seen_discard = false;
bool seen_aio = false;
@@ -425,6 +491,8 @@ int main(int argc, char **argv)
Error *local_err = NULL;
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
QDict *options = NULL;
+ const char *export_name = NULL;
+ const char *tlscredsid = NULL;
/* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -433,6 +501,8 @@ int main(int argc, char **argv)
memset(&sa_sigterm, 0, sizeof(sa_sigterm));
sa_sigterm.sa_handler = termsig_handler;
sigaction(SIGTERM, &sa_sigterm, NULL);
+ module_call_init(MODULE_INIT_QOM);
+ qemu_add_opts(&qemu_object_opts);
qemu_init_exec_dir(argv[0]);
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
@@ -574,6 +644,9 @@ int main(int argc, char **argv)
case 't':
persistent = 1;
break;
+ case 'x':
+ export_name = optarg;
+ break;
case 'v':
verbose = 1;
break;
@@ -588,6 +661,17 @@ int main(int argc, char **argv)
case '?':
error_report("Try `%s --help' for more information.", argv[0]);
exit(EXIT_FAILURE);
+ case QEMU_NBD_OPT_OBJECT: {
+ QemuOpts *opts;
+ opts = qemu_opts_parse_noisily(&qemu_object_opts,
+ optarg, true);
+ if (!opts) {
+ exit(EXIT_FAILURE);
+ }
+ } break;
+ case QEMU_NBD_OPT_TLSCREDS:
+ tlscredsid = optarg;
+ break;
}
}
@@ -597,16 +681,45 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
+ if (qemu_opts_foreach(&qemu_object_opts,
+ user_creatable_add_opts_foreach,
+ NULL, &local_err)) {
+ error_report_err(local_err);
+ exit(EXIT_FAILURE);
+ }
+
+ if (tlscredsid) {
+ if (sockpath) {
+ error_report("TLS is only supported with IPv4/IPv6");
+ exit(EXIT_FAILURE);
+ }
+ if (device) {
+ error_report("TLS is not supported with a host device");
+ exit(EXIT_FAILURE);
+ }
+ if (!export_name) {
+ /* Set the default NBD protocol export name, since
+ * we *must* use new style protocol for TLS */
+ export_name = "";
+ }
+ tlscreds = nbd_get_tls_creds(tlscredsid, &local_err);
+ if (local_err) {
+ error_report("Failed to get TLS creds %s",
+ error_get_pretty(local_err));
+ exit(EXIT_FAILURE);
+ }
+ }
+
if (disconnect) {
- fd = open(argv[optind], O_RDWR);
- if (fd < 0) {
+ int nbdfd = open(argv[optind], O_RDWR);
+ if (nbdfd < 0) {
error_report("Cannot open %s: %s", argv[optind],
strerror(errno));
exit(EXIT_FAILURE);
}
- nbd_disconnect(fd);
+ nbd_disconnect(nbdfd);
- close(fd);
+ close(nbdfd);
printf("%s disconnected\n", argv[optind]);
@@ -738,9 +851,14 @@ int main(int argc, char **argv)
error_report_err(local_err);
exit(EXIT_FAILURE);
}
+ if (export_name) {
+ nbd_export_set_name(exp, export_name);
+ newproto = true;
+ }
- fd = socket_listen(saddr, &local_err);
- if (fd < 0) {
+ server_ioc = qio_channel_socket_new();
+ if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
+ object_unref(OBJECT(server_ioc));
error_report_err(local_err);
return 1;
}
@@ -758,8 +876,7 @@ int main(int argc, char **argv)
memset(&client_thread, 0, sizeof(client_thread));
}
- server_fd = fd;
- nbd_update_server_fd_handler(fd);
+ nbd_update_server_watch();
/* now when the initialization is (almost) complete, chdir("/")
* to free any busy filesystems */
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 0027841ecb..227a73ca36 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -18,6 +18,13 @@ Export a QEMU disk image using the NBD protocol.
@var{dev} is an NBD device.
@table @option
+@item --object type,id=@var{id},...props...
+Define a new instance of the @var{type} object class identified by @var{id}.
+See the @code{qemu(1)} manual page for full details of the properties
+supported. The common object types that it makes sense to define are the
+@code{secret} object, which is used to supply passwords and/or encryption
+keys, and the @code{tls-creds} object, which is used to supply TLS
+credentials for the qemu-nbd server.
@item -p, --port=@var{port}
The TCP port to listen on (default @samp{10809})
@item -o, --offset=@var{offset}
@@ -67,6 +74,13 @@ Disconnect the device @var{dev}
Allow up to @var{num} clients to share the device (default @samp{1})
@item -t, --persistent
Don't exit on the last connection
+@item -x NAME, --export-name=NAME
+Set the NBD volume export name. This switches the server to use
+the new style NBD protocol negotiation
+@item --tls-creds=ID
+Enable mandatory TLS encryption for the server by setting the ID
+of the TLS credentials object previously created with the --object
+option.
@item -v, --verbose
Display extra debugging information
@item -h, --help
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 020e5ee96c..9fb0d788bc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3825,7 +3825,7 @@ EQMP
{
.name = "nbd-server-start",
- .args_type = "addr:q",
+ .args_type = "addr:q,tls-creds:s?",
.mhandler.cmd_new = qmp_marshal_nbd_server_start,
},
{
diff --git a/qmp.c b/qmp.c
index 6ae723022e..9a93d5e246 100644
--- a/qmp.c
+++ b/qmp.c
@@ -633,65 +633,13 @@ void qmp_add_client(const char *protocol, const char *fdname,
close(fd);
}
-void object_add(const char *type, const char *id, const QDict *qdict,
- Visitor *v, Error **errp)
-{
- Object *obj;
- ObjectClass *klass;
- const QDictEntry *e;
- Error *local_err = NULL;
-
- klass = object_class_by_name(type);
- if (!klass) {
- error_setg(errp, "invalid object type: %s", type);
- return;
- }
-
- if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
- error_setg(errp, "object type '%s' isn't supported by object-add",
- type);
- return;
- }
-
- if (object_class_is_abstract(klass)) {
- error_setg(errp, "object type '%s' is abstract", type);
- return;
- }
-
- obj = object_new(type);
- if (qdict) {
- for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
- object_property_set(obj, v, e->key, &local_err);
- if (local_err) {
- goto out;
- }
- }
- }
-
- object_property_add_child(object_get_objects_root(),
- id, obj, &local_err);
- if (local_err) {
- goto out;
- }
-
- user_creatable_complete(obj, &local_err);
- if (local_err) {
- object_property_del(object_get_objects_root(),
- id, &error_abort);
- goto out;
- }
-out:
- if (local_err) {
- error_propagate(errp, local_err);
- }
- object_unref(obj);
-}
void qmp_object_add(const char *type, const char *id,
bool has_props, QObject *props, Error **errp)
{
const QDict *pdict = NULL;
QmpInputVisitor *qiv;
+ Object *obj;
if (props) {
pdict = qobject_to_qdict(props);
@@ -702,27 +650,17 @@ void qmp_object_add(const char *type, const char *id,
}
qiv = qmp_input_visitor_new(props);
- object_add(type, id, pdict, qmp_input_get_visitor(qiv), errp);
+ obj = user_creatable_add_type(type, id, pdict,
+ qmp_input_get_visitor(qiv), errp);
qmp_input_visitor_cleanup(qiv);
+ if (obj) {
+ object_unref(obj);
+ }
}
void qmp_object_del(const char *id, Error **errp)
{
- Object *container;
- Object *obj;
-
- container = object_get_objects_root();
- obj = object_resolve_path_component(container, id);
- if (!obj) {
- error_setg(errp, "object id not found");
- return;
- }
-
- if (!user_creatable_can_be_deleted(USER_CREATABLE(obj), errp)) {
- error_setg(errp, "%s is in use, can not be deleted", id);
- return;
- }
- object_unparent(obj);
+ user_creatable_del(id, errp);
}
MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index f1218f0cc1..c2f6e2998e 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -1,6 +1,9 @@
#include "qemu/osdep.h"
#include "qom/object_interfaces.h"
#include "qemu/module.h"
+#include "qapi-visit.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/opts-visitor.h"
void user_creatable_complete(Object *obj, Error **errp)
{
@@ -31,6 +34,177 @@ bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp)
}
}
+
+Object *user_creatable_add(const QDict *qdict,
+ Visitor *v, Error **errp)
+{
+ char *type = NULL;
+ char *id = NULL;
+ Object *obj = NULL;
+ Error *local_err = NULL, *end_err = NULL;
+ QDict *pdict;
+
+ pdict = qdict_clone_shallow(qdict);
+
+ visit_start_struct(v, NULL, NULL, 0, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ qdict_del(pdict, "qom-type");
+ visit_type_str(v, "qom-type", &type, &local_err);
+ if (local_err) {
+ goto out_visit;
+ }
+
+ qdict_del(pdict, "id");
+ visit_type_str(v, "id", &id, &local_err);
+ if (local_err) {
+ goto out_visit;
+ }
+
+ obj = user_creatable_add_type(type, id, pdict, v, &local_err);
+ if (local_err) {
+ goto out_visit;
+ }
+
+ out_visit:
+ visit_end_struct(v, &end_err);
+ if (end_err) {
+ error_propagate(&local_err, end_err);
+ if (obj) {
+ user_creatable_del(id, NULL);
+ }
+ goto out;
+ }
+
+out:
+ QDECREF(pdict);
+ g_free(id);
+ g_free(type);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ object_unref(obj);
+ return NULL;
+ }
+ return obj;
+}
+
+
+Object *user_creatable_add_type(const char *type, const char *id,
+ const QDict *qdict,
+ Visitor *v, Error **errp)
+{
+ Object *obj;
+ ObjectClass *klass;
+ const QDictEntry *e;
+ Error *local_err = NULL;
+
+ klass = object_class_by_name(type);
+ if (!klass) {
+ error_setg(errp, "invalid object type: %s", type);
+ return NULL;
+ }
+
+ if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
+ error_setg(errp, "object type '%s' isn't supported by object-add",
+ type);
+ return NULL;
+ }
+
+ if (object_class_is_abstract(klass)) {
+ error_setg(errp, "object type '%s' is abstract", type);
+ return NULL;
+ }
+
+ obj = object_new(type);
+ if (qdict) {
+ for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
+ object_property_set(obj, v, e->key, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ }
+ }
+
+ object_property_add_child(object_get_objects_root(),
+ id, obj, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ user_creatable_complete(obj, &local_err);
+ if (local_err) {
+ object_property_del(object_get_objects_root(),
+ id, &error_abort);
+ goto out;
+ }
+out:
+ if (local_err) {
+ error_propagate(errp, local_err);
+ object_unref(obj);
+ return NULL;
+ }
+ return obj;
+}
+
+
+Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
+{
+ OptsVisitor *ov;
+ QDict *pdict;
+ Object *obj = NULL;
+
+ ov = opts_visitor_new(opts);
+ pdict = qemu_opts_to_qdict(opts, NULL);
+
+ obj = user_creatable_add(pdict, opts_get_visitor(ov), errp);
+ opts_visitor_cleanup(ov);
+ QDECREF(pdict);
+ return obj;
+}
+
+
+int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
+{
+ bool (*type_predicate)(const char *) = opaque;
+ Object *obj = NULL;
+ const char *type;
+
+ type = qemu_opt_get(opts, "qom-type");
+ if (type && type_predicate &&
+ !type_predicate(type)) {
+ return 0;
+ }
+
+ obj = user_creatable_add_opts(opts, errp);
+ if (!obj) {
+ return -1;
+ }
+ object_unref(obj);
+ return 0;
+}
+
+
+void user_creatable_del(const char *id, Error **errp)
+{
+ Object *container;
+ Object *obj;
+
+ container = object_get_objects_root();
+ obj = object_resolve_path_component(container, id);
+ if (!obj) {
+ error_setg(errp, "object '%s' not found", id);
+ return;
+ }
+
+ if (!user_creatable_can_be_deleted(USER_CREATABLE(obj), errp)) {
+ error_setg(errp, "object '%s' is in use, can not be deleted", id);
+ return;
+ }
+ object_unparent(obj);
+}
+
static void register_types(void)
{
static const TypeInfo uc_interface_info = {
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 257126f91b..c26f76ed09 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1715,11 +1715,15 @@ sub process {
# 1. with a type on the left -- int [] a;
# 2. at the beginning of a line for slice initialisers -- [0...10] = 5,
# 3. inside a curly brace -- = { [0...10] = 5 }
+# 4. after a comma -- [1] = 5, [2] = 6
+# 5. in a macro definition -- #define abc(x) [x] = y
while ($line =~ /(.*?\s)\[/g) {
my ($where, $prefix) = ($-[1], $1);
if ($prefix !~ /$Type\s+$/ &&
($where != 0 || $prefix !~ /^.\s+$/) &&
- $prefix !~ /{\s+$/) {
+ $prefix !~ /{\s+$/ &&
+ $prefix !~ /\#\s*define[^(]*\([^)]*\)\s+$/ &&
+ $prefix !~ /,\s+$/) {
ERROR("space prohibited before open square bracket '['\n" . $herecurr);
}
}
diff --git a/scripts/feature_to_c.sh b/scripts/feature_to_c.sh
index 888548e58b..fb1f3363f7 100644
--- a/scripts/feature_to_c.sh
+++ b/scripts/feature_to_c.sh
@@ -36,7 +36,7 @@ for input; do
arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
${AWK:-awk} 'BEGIN { n = 0
- printf "#include \"config.h\"\n"
+ printf "#include \"qemu/osdep.h\"\n"
printf "#include \"qemu-common.h\"\n"
printf "#include \"exec/gdbstub.h\"\n"
print "static const char '$arrayname'[] = {"
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 91c5a4e8cd..f831621843 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -297,6 +297,7 @@ h_comment = '''
c_comment, h_comment)
fdef.write(mcgen('''
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/module.h"
#include "qapi/qmp/types.h"
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 07bcb73d3d..544ae1218d 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -159,6 +159,7 @@ h_comment = '''
c_comment, h_comment)
fdef.write(mcgen('''
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
#include "%(prefix)sqapi-visit.h"
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 64f2cd0631..e0f926be04 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -1,7 +1,7 @@
#
# QAPI introspection generator
#
-# Copyright (C) 2015 Red Hat, Inc.
+# Copyright (C) 2015-2016 Red Hat, Inc.
#
# Authors:
# Markus Armbruster <armbru@redhat.com>
@@ -204,6 +204,7 @@ h_comment = '''
c_comment, h_comment)
fdef.write(mcgen('''
+#include "qemu/osdep.h"
#include "%(prefix)sqmp-introspect.h"
''',
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index d3f631a2f4..7b0dca8c72 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -279,6 +279,7 @@ h_comment = '''
c_comment, h_comment)
fdef.write(mcgen('''
+#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"
@@ -287,8 +288,6 @@ fdef.write(mcgen('''
# To avoid circular headers, use only typedefs.h here, not qobject.h
fdecl.write(mcgen('''
-#include <stdbool.h>
-#include <stdint.h>
#include "qemu/typedefs.h"
'''))
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 0fdcebcca8..0cc9b08b14 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -435,6 +435,7 @@ h_comment = '''
c_comment, h_comment)
fdef.write(mcgen('''
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "%(prefix)sqapi-visit.h"
''',
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
index e8c2cd57e9..3246c20015 100644
--- a/scripts/tracetool/backend/simple.py
+++ b/scripts/tracetool/backend/simple.py
@@ -42,7 +42,8 @@ def generate_h(event):
def generate_c_begin(events):
- out('#include "trace.h"',
+ out('#include "qemu/osdep.h"',
+ '#include "trace.h"',
'#include "trace/control.h"',
'#include "trace/simple.h"',
'')
diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py
index 2717ea3a0b..1cc6a49a71 100644
--- a/scripts/tracetool/format/events_c.py
+++ b/scripts/tracetool/format/events_c.py
@@ -19,6 +19,7 @@ from tracetool import out
def generate(events, backend):
out('/* This file is autogenerated by tracetool, do not edit. */',
'',
+ '#include "qemu/osdep.h"',
'#include "trace.h"',
'#include "trace/generated-events.h"',
'#include "trace/control.h"',
diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py
index 96655a0590..afd6e98537 100644
--- a/scripts/tracetool/format/tcg_helper_c.py
+++ b/scripts/tracetool/format/tcg_helper_c.py
@@ -23,6 +23,7 @@ def generate(events, backend):
out('/* This file is autogenerated by tracetool, do not edit. */',
'',
+ '#include "qemu/osdep.h"',
'#include "qemu-common.h"',
'#include "trace.h"',
'#include "exec/helper-proto.h"',
diff --git a/stubs/blockdev-close-all-bdrv-states.c b/stubs/blockdev-close-all-bdrv-states.c
index 12d2442362..f1f1d9cdca 100644
--- a/stubs/blockdev-close-all-bdrv-states.c
+++ b/stubs/blockdev-close-all-bdrv-states.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include "block/block_int.h"
void blockdev_close_all_bdrv_states(void)
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 07c0a71942..1cc4502fc4 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -148,6 +148,8 @@ typedef struct ARMCPU {
uint32_t id_pfr0;
uint32_t id_pfr1;
uint32_t id_dfr0;
+ uint32_t pmceid0;
+ uint32_t pmceid1;
uint32_t id_afr0;
uint32_t id_mmfr0;
uint32_t id_mmfr1;
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index f2393cd9f2..e95b0307a6 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -1156,6 +1156,8 @@ static void cortex_a15_initfn(Object *obj)
cpu->id_pfr0 = 0x00001131;
cpu->id_pfr1 = 0x00011011;
cpu->id_dfr0 = 0x02010555;
+ cpu->pmceid0 = 0x0000000;
+ cpu->pmceid1 = 0x00000000;
cpu->id_afr0 = 0x00000000;
cpu->id_mmfr0 = 0x10201105;
cpu->id_mmfr1 = 0x20000000;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 5137632ccc..16238216f4 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -595,6 +595,18 @@ void pmccntr_sync(CPUARMState *env);
#define CPTR_TTA (1U << 20)
#define CPTR_TFP (1U << 10)
+#define MDCR_EPMAD (1U << 21)
+#define MDCR_EDAD (1U << 20)
+#define MDCR_SPME (1U << 17)
+#define MDCR_SDD (1U << 16)
+#define MDCR_TDRA (1U << 11)
+#define MDCR_TDOSA (1U << 10)
+#define MDCR_TDA (1U << 9)
+#define MDCR_TDE (1U << 8)
+#define MDCR_HPME (1U << 7)
+#define MDCR_TPM (1U << 6)
+#define MDCR_TPMCR (1U << 5)
+
#define CPSR_M (0x1fU)
#define CPSR_T (1U << 5)
#define CPSR_F (1U << 6)
@@ -1255,6 +1267,18 @@ static inline bool cptype_valid(int cptype)
#define PL1_RW (PL1_R | PL1_W)
#define PL0_RW (PL0_R | PL0_W)
+/* Return the highest implemented Exception Level */
+static inline int arm_highest_el(CPUARMState *env)
+{
+ if (arm_feature(env, ARM_FEATURE_EL3)) {
+ return 3;
+ }
+ if (arm_feature(env, ARM_FEATURE_EL2)) {
+ return 2;
+ }
+ return 1;
+}
+
/* Return the current Exception Level (as per ARMv8; note that this differs
* from the ARMv7 Privilege Level).
*/
@@ -1310,6 +1334,11 @@ typedef enum CPAccessResult {
/* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */
CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5,
CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6,
+ /* Access fails and results in an exception syndrome for an FP access,
+ * trapped directly to EL2 or EL3
+ */
+ CP_ACCESS_TRAP_FP_EL2 = 7,
+ CP_ACCESS_TRAP_FP_EL3 = 8,
} CPAccessResult;
/* Access functions for coprocessor registers. These cannot fail and
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index c5bc19a405..fa5eda2cd1 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -135,6 +135,8 @@ static void aarch64_a57_initfn(Object *obj)
cpu->id_isar5 = 0x00011121;
cpu->id_aa64pfr0 = 0x00002222;
cpu->id_aa64dfr0 = 0x10305106;
+ cpu->pmceid0 = 0x00000000;
+ cpu->pmceid1 = 0x00000000;
cpu->id_aa64isar0 = 0x00011120;
cpu->id_aa64mmfr0 = 0x00001124;
cpu->dbgdidr = 0x3516d000;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2f9db72806..5a0447b93a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -385,6 +385,60 @@ static CPAccessResult access_trap_aa32s_el1(CPUARMState *env,
return CP_ACCESS_TRAP_UNCATEGORIZED;
}
+/* Check for traps to "powerdown debug" registers, which are controlled
+ * by MDCR.TDOSA
+ */
+static CPAccessResult access_tdosa(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ int el = arm_current_el(env);
+
+ if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDOSA)
+ && !arm_is_secure_below_el3(env)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDOSA)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+/* Check for traps to "debug ROM" registers, which are controlled
+ * by MDCR_EL2.TDRA for EL2 but by the more general MDCR_EL3.TDA for EL3.
+ */
+static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ int el = arm_current_el(env);
+
+ if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDRA)
+ && !arm_is_secure_below_el3(env)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+/* Check for traps to general debug registers, which are controlled
+ * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3.
+ */
+static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ int el = arm_current_el(env);
+
+ if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDA)
+ && !arm_is_secure_below_el3(env)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@@ -1003,6 +1057,13 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.accessfn = pmreg_access,
.writefn = pmovsr_write,
.raw_writefn = raw_write },
+ { .name = "PMOVSCLR_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 3,
+ .access = PL0_RW, .accessfn = pmreg_access,
+ .type = ARM_CP_ALIAS,
+ .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr),
+ .writefn = pmovsr_write,
+ .raw_writefn = raw_write },
/* Unimplemented so WI. */
{ .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4,
.access = PL0_W, .accessfn = pmreg_access, .type = ARM_CP_NOP },
@@ -1044,6 +1105,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr),
.resetvalue = 0,
.writefn = pmuserenr_write, .raw_writefn = raw_write },
+ { .name = "PMUSERENR_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 14, .opc2 = 0,
+ .access = PL0_R | PL1_RW, .type = ARM_CP_ALIAS,
+ .fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr),
+ .resetvalue = 0,
+ .writefn = pmuserenr_write, .raw_writefn = raw_write },
{ .name = "PMINTENSET", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 1,
.access = PL1_RW,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
@@ -1053,6 +1120,11 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.access = PL1_RW, .type = ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
.writefn = pmintenclr_write, },
+ { .name = "PMINTENCLR_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 2,
+ .access = PL1_RW, .type = ARM_CP_ALIAS,
+ .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
+ .writefn = pmintenclr_write },
{ .name = "VBAR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .writefn = vbar_write,
@@ -1218,10 +1290,33 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
- /* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
- if (arm_current_el(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
- return CP_ACCESS_TRAP;
+ /* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero.
+ * Writable only at the highest implemented exception level.
+ */
+ int el = arm_current_el(env);
+
+ switch (el) {
+ case 0:
+ if (!extract32(env->cp15.c14_cntkctl, 0, 2)) {
+ return CP_ACCESS_TRAP;
+ }
+ break;
+ case 1:
+ if (!isread && ri->state == ARM_CP_STATE_AA32 &&
+ arm_is_secure_below_el3(env)) {
+ /* Accesses from 32-bit Secure EL1 UNDEF (*not* trap to EL3!) */
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
+ }
+ break;
+ case 2:
+ case 3:
+ break;
+ }
+
+ if (!isread && el < arm_highest_el(env)) {
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
}
+
return CP_ACCESS_OK;
}
@@ -2934,10 +3029,10 @@ static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) {
- return CP_ACCESS_TRAP_EL2;
+ return CP_ACCESS_TRAP_FP_EL2;
}
if (env->cp15.cptr_el[3] & CPTR_TFP) {
- return CP_ACCESS_TRAP_EL3;
+ return CP_ACCESS_TRAP_FP_EL3;
}
return CP_ACCESS_OK;
}
@@ -3325,7 +3420,8 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
- .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ .access = PL2_RW, .accessfn = access_tda,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
.access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
@@ -3732,16 +3828,19 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
* accessor.
*/
{ .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+ .access = PL0_R, .accessfn = access_tdra,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+ .access = PL1_R, .accessfn = access_tdra,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
+ .access = PL0_R, .accessfn = access_tdra,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
/* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
{ .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
- .access = PL1_RW,
+ .access = PL1_RW, .accessfn = access_tda,
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
.resetvalue = 0 },
/* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
@@ -3750,26 +3849,30 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
{ .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
.type = ARM_CP_ALIAS,
- .access = PL1_R,
+ .access = PL1_R, .accessfn = access_tda,
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
{ .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
.access = PL1_W, .type = ARM_CP_NO_RAW,
+ .accessfn = access_tdosa,
.writefn = oslar_write },
{ .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4,
.access = PL1_R, .resetvalue = 10,
+ .accessfn = access_tdosa,
.fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) },
/* Dummy OSDLR_EL1: 32-bit Linux will read this */
{ .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4,
- .access = PL1_RW, .type = ARM_CP_NOP },
+ .access = PL1_RW, .accessfn = access_tdosa,
+ .type = ARM_CP_NOP },
/* Dummy DBGVCR: Linux wants to clear this on startup, but we don't
* implement vector catch debug events yet.
*/
{ .name = "DBGVCR",
.cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_NOP },
+ .access = PL1_RW, .accessfn = access_tda,
+ .type = ARM_CP_NOP },
REGINFO_SENTINEL
};
@@ -4034,7 +4137,8 @@ static void define_debug_regs(ARMCPU *cpu)
int wrps, brps, ctx_cmps;
ARMCPRegInfo dbgdidr = {
.name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
+ .access = PL0_R, .accessfn = access_tda,
+ .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
};
/* Note that all these register fields hold "number of Xs minus 1". */
@@ -4065,13 +4169,13 @@ static void define_debug_regs(ARMCPU *cpu)
ARMCPRegInfo dbgregs[] = {
{ .name = "DBGBVR", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
- .access = PL1_RW,
+ .access = PL1_RW, .accessfn = access_tda,
.fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
.writefn = dbgbvr_write, .raw_writefn = raw_write
},
{ .name = "DBGBCR", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
- .access = PL1_RW,
+ .access = PL1_RW, .accessfn = access_tda,
.fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
.writefn = dbgbcr_write, .raw_writefn = raw_write
},
@@ -4084,13 +4188,13 @@ static void define_debug_regs(ARMCPU *cpu)
ARMCPRegInfo dbgregs[] = {
{ .name = "DBGWVR", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
- .access = PL1_RW,
+ .access = PL1_RW, .accessfn = access_tda,
.fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
.writefn = dbgwvr_write, .raw_writefn = raw_write
},
{ .name = "DBGWCR", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
- .access = PL1_RW,
+ .access = PL1_RW, .accessfn = access_tda,
.fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
.writefn = dbgwcr_write, .raw_writefn = raw_write
},
@@ -4294,6 +4398,22 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
.access = PL1_R, .type = ARM_CP_CONST,
.resetvalue = cpu->mvfr2 },
+ { .name = "PMCEID0", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 6,
+ .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
+ .resetvalue = cpu->pmceid0 },
+ { .name = "PMCEID0_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 6,
+ .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
+ .resetvalue = cpu->pmceid0 },
+ { .name = "PMCEID1", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 7,
+ .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
+ .resetvalue = cpu->pmceid1 },
+ { .name = "PMCEID1_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7,
+ .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
+ .resetvalue = cpu->pmceid1 },
REGINFO_SENTINEL
};
/* RVBAR_EL1 is only implemented if EL1 is the highest EL */
@@ -5279,21 +5399,6 @@ void switch_mode(CPUARMState *env, int mode)
}
}
-void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
-{
- ARMCPU *cpu = arm_env_get_cpu(env);
-
- cpu_abort(CPU(cpu), "banked r13 write\n");
-}
-
-uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
-{
- ARMCPU *cpu = arm_env_get_cpu(env);
-
- cpu_abort(CPU(cpu), "banked r13 read\n");
- return 0;
-}
-
uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
uint32_t cur_el, bool secure)
{
@@ -5307,31 +5412,6 @@ void aarch64_sync_64_to_32(CPUARMState *env)
#else
-/* Map CPU modes onto saved register banks. */
-int bank_number(int mode)
-{
- switch (mode) {
- case ARM_CPU_MODE_USR:
- case ARM_CPU_MODE_SYS:
- return BANK_USRSYS;
- case ARM_CPU_MODE_SVC:
- return BANK_SVC;
- case ARM_CPU_MODE_ABT:
- return BANK_ABT;
- case ARM_CPU_MODE_UND:
- return BANK_UND;
- case ARM_CPU_MODE_IRQ:
- return BANK_IRQ;
- case ARM_CPU_MODE_FIQ:
- return BANK_FIQ;
- case ARM_CPU_MODE_HYP:
- return BANK_HYP;
- case ARM_CPU_MODE_MON:
- return BANK_MON;
- }
- g_assert_not_reached();
-}
-
void switch_mode(CPUARMState *env, int mode)
{
int old_mode;
@@ -7676,24 +7756,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
return phys_addr;
}
-void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
-{
- if ((env->uncached_cpsr & CPSR_M) == mode) {
- env->regs[13] = val;
- } else {
- env->banked_r13[bank_number(mode)] = val;
- }
-}
-
-uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
-{
- if ((env->uncached_cpsr & CPSR_M) == mode) {
- return env->regs[13];
- } else {
- return env->banked_r13[bank_number(mode)];
- }
-}
-
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
{
ARMCPU *cpu = arm_env_get_cpu(env);
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 70bec4a4d2..2e70272be2 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -109,7 +109,31 @@ static inline unsigned int aarch64_banked_spsr_index(unsigned int el)
return map[el];
}
-int bank_number(int mode);
+/* Map CPU modes onto saved register banks. */
+static inline int bank_number(int mode)
+{
+ switch (mode) {
+ case ARM_CPU_MODE_USR:
+ case ARM_CPU_MODE_SYS:
+ return BANK_USRSYS;
+ case ARM_CPU_MODE_SVC:
+ return BANK_SVC;
+ case ARM_CPU_MODE_ABT:
+ return BANK_ABT;
+ case ARM_CPU_MODE_UND:
+ return BANK_UND;
+ case ARM_CPU_MODE_IRQ:
+ return BANK_IRQ;
+ case ARM_CPU_MODE_FIQ:
+ return BANK_FIQ;
+ case ARM_CPU_MODE_HYP:
+ return BANK_HYP;
+ case ARM_CPU_MODE_MON:
+ return BANK_MON;
+ }
+ g_assert_not_reached();
+}
+
void switch_mode(CPUARMState *, int);
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
void arm_translate_init(void);
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index bd48549826..538887ce0c 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -457,6 +457,32 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
}
}
+void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
+{
+ if ((env->uncached_cpsr & CPSR_M) == mode) {
+ env->regs[13] = val;
+ } else {
+ env->banked_r13[bank_number(mode)] = val;
+ }
+}
+
+uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
+{
+ if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_SYS) {
+ /* SRS instruction is UNPREDICTABLE from System mode; we UNDEF.
+ * Other UNPREDICTABLE and UNDEF cases were caught at translate time.
+ */
+ raise_exception(env, EXCP_UDEF, syn_uncategorized(),
+ exception_target_el(env));
+ }
+
+ if ((env->uncached_cpsr & CPSR_M) == mode) {
+ return env->regs[13];
+ } else {
+ return env->banked_r13[bank_number(mode)];
+ }
+}
+
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
uint32_t isread)
{
@@ -500,6 +526,19 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
target_el = 3;
syndrome = syn_uncategorized();
break;
+ case CP_ACCESS_TRAP_FP_EL2:
+ target_el = 2;
+ /* Since we are an implementation that takes exceptions on a trapped
+ * conditional insn only if the insn has passed its condition code
+ * check, we take the IMPDEF choice to always report CV=1 COND=0xe
+ * (which is also the required value for AArch64 traps).
+ */
+ syndrome = syn_fp_access_trap(1, 0xe, false);
+ break;
+ case CP_ACCESS_TRAP_FP_EL3:
+ target_el = 3;
+ syndrome = syn_fp_access_trap(1, 0xe, false);
+ break;
default:
g_assert_not_reached();
}
@@ -614,12 +653,14 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
int cur_el = arm_current_el(env);
bool secure = arm_is_secure(env);
bool smd = env->cp15.scr_el3 & SCR_SMD;
- /* On ARMv8 AArch32, SMD only applies to NS state.
- * On ARMv7 SMD only applies to NS state and only if EL2 is available.
- * For ARMv7 non EL2, we force SMD to zero so we don't need to re-check
- * the EL2 condition here.
+ /* On ARMv8 with EL3 AArch64, SMD applies to both S and NS state.
+ * On ARMv8 with EL3 AArch32, or ARMv7 with the Virtualization
+ * extensions, SMD only applies to NS state.
+ * On ARMv7 without the Virtualization extensions, the SMD bit
+ * doesn't exist, but we forbid the guest to set it to 1 in scr_write(),
+ * so we need not special case this here.
*/
- bool undef = is_a64(env) ? smd : (!secure && smd);
+ bool undef = arm_feature(env, ARM_FEATURE_AARCH64) ? smd : smd && !secure;
if (arm_is_psci_call(cpu, EXCP_SMC)) {
/* If PSCI is enabled and this looks like a valid PSCI call then
diff --git a/target-arm/translate.c b/target-arm/translate.c
index cf3dc33774..e69145d401 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7578,8 +7578,67 @@ static void gen_srs(DisasContext *s,
uint32_t mode, uint32_t amode, bool writeback)
{
int32_t offset;
- TCGv_i32 addr = tcg_temp_new_i32();
- TCGv_i32 tmp = tcg_const_i32(mode);
+ TCGv_i32 addr, tmp;
+ bool undef = false;
+
+ /* SRS is:
+ * - trapped to EL3 if EL3 is AArch64 and we are at Secure EL1
+ * - UNDEFINED in Hyp mode
+ * - UNPREDICTABLE in User or System mode
+ * - UNPREDICTABLE if the specified mode is:
+ * -- not implemented
+ * -- not a valid mode number
+ * -- a mode that's at a higher exception level
+ * -- Monitor, if we are Non-secure
+ * For the UNPREDICTABLE cases we choose to UNDEF.
+ */
+ if (s->current_el == 1 && !s->ns) {
+ gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), 3);
+ return;
+ }
+
+ if (s->current_el == 0 || s->current_el == 2) {
+ undef = true;
+ }
+
+ switch (mode) {
+ case ARM_CPU_MODE_USR:
+ case ARM_CPU_MODE_FIQ:
+ case ARM_CPU_MODE_IRQ:
+ case ARM_CPU_MODE_SVC:
+ case ARM_CPU_MODE_ABT:
+ case ARM_CPU_MODE_UND:
+ case ARM_CPU_MODE_SYS:
+ break;
+ case ARM_CPU_MODE_HYP:
+ if (s->current_el == 1 || !arm_dc_feature(s, ARM_FEATURE_EL2)) {
+ undef = true;
+ }
+ break;
+ case ARM_CPU_MODE_MON:
+ /* No need to check specifically for "are we non-secure" because
+ * we've already made EL0 UNDEF and handled the trap for S-EL1;
+ * so if this isn't EL3 then we must be non-secure.
+ */
+ if (s->current_el != 3) {
+ undef = true;
+ }
+ break;
+ default:
+ undef = true;
+ }
+
+ if (undef) {
+ gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
+ default_exception_el(s));
+ return;
+ }
+
+ addr = tcg_temp_new_i32();
+ tmp = tcg_const_i32(mode);
+ /* get_r13_banked() will raise an exception if called from System mode */
+ gen_set_condexec(s);
+ gen_set_pc_im(s, s->pc - 4);
gen_helper_get_r13_banked(addr, cpu_env, tmp);
tcg_temp_free_i32(tmp);
switch (amode) {
@@ -7629,6 +7688,7 @@ static void gen_srs(DisasContext *s,
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
+ s->is_jmp = DISAS_UPDATE;
}
static void disas_arm_insn(DisasContext *s, unsigned int insn)
@@ -7739,9 +7799,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
} else if ((insn & 0x0e5fffe0) == 0x084d0500) {
/* srs */
- if (IS_USER(s)) {
- goto illegal_op;
- }
ARCH(6);
gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
return;
diff --git a/target-cris/mmu.c b/target-cris/mmu.c
index 1c95a415f2..4278d2dce4 100644
--- a/target-cris/mmu.c
+++ b/target-cris/mmu.c
@@ -18,8 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef CONFIG_USER_ONLY
-
+#include "qemu/osdep.h"
#include "cpu.h"
#include "mmu.h"
@@ -360,4 +359,3 @@ int cris_mmu_translate(struct cris_mmu_result *res,
env->pregs[PR_SRS] = old_srs;
return miss;
}
-#endif
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 2255f46a9e..b223d7932b 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -1,6 +1,6 @@
obj-y += translate.o helper.o cpu.o bpt_helper.o
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
-obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
+obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o mpx_helper.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
index 99a3b5496b..83af223c9f 100644
--- a/target-i386/cc_helper.c
+++ b/target-i386/cc_helper.c
@@ -383,13 +383,3 @@ void helper_sti_vm(CPUX86State *env)
}
}
#endif
-
-void helper_set_inhibit_irq(CPUX86State *env)
-{
- env->hflags |= HF_INHIBIT_IRQ_MASK;
-}
-
-void helper_reset_inhibit_irq(CPUX86State *env)
-{
- env->hflags &= ~HF_INHIBIT_IRQ_MASK;
-}
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 3fa14bf171..0af43a3ae1 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -331,14 +331,14 @@ static const char *cpuid_6_feature_name[] = {
#define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | \
CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | \
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
+ CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \
CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR)
/* missing:
CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX,
CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA,
CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA,
- CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_XSAVE,
- CPUID_EXT_OSXSAVE, CPUID_EXT_AVX, CPUID_EXT_F16C,
- CPUID_EXT_RDRAND */
+ CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AVX,
+ CPUID_EXT_F16C, CPUID_EXT_RDRAND */
#ifdef TARGET_X86_64
#define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM)
@@ -358,15 +358,17 @@ static const char *cpuid_6_feature_name[] = {
#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \
CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \
- CPUID_7_0_EBX_CLWB)
+ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE)
/* missing:
- CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
+ CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
CPUID_7_0_EBX_RDSEED */
#define TCG_7_0_ECX_FEATURES 0
#define TCG_APM_FEATURES 0
#define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
-
+#define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1)
+ /* missing:
+ CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
typedef struct FeatureWordInfo {
const char **feat_names;
@@ -440,7 +442,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.cpuid_eax = 0xd,
.cpuid_needs_ecx = true, .cpuid_ecx = 1,
.cpuid_reg = R_EAX,
- .tcg_features = 0,
+ .tcg_features = TCG_XSAVE_FEATURES,
},
[FEAT_6_EAX] = {
.feat_names = cpuid_6_feature_name,
@@ -470,12 +472,7 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
};
#undef REGISTER
-typedef struct ExtSaveArea {
- uint32_t feature, bits;
- uint32_t offset, size;
-} ExtSaveArea;
-
-static const ExtSaveArea ext_save_areas[] = {
+const ExtSaveArea x86_ext_save_areas[] = {
[2] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
.offset = 0x240, .size = 0x100 },
[3] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
@@ -2323,10 +2320,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ebx = (cpu->apic_id << 24) |
8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
*ecx = env->features[FEAT_1_ECX];
+ if ((*ecx & CPUID_EXT_XSAVE) && (env->cr[4] & CR4_OSXSAVE_MASK)) {
+ *ecx |= CPUID_EXT_OSXSAVE;
+ }
*edx = env->features[FEAT_1_EDX];
if (cs->nr_cores * cs->nr_threads > 1) {
*ebx |= (cs->nr_cores * cs->nr_threads) << 16;
- *edx |= 1 << 28; /* HTT bit */
+ *edx |= CPUID_HT;
}
break;
case 2:
@@ -2450,7 +2450,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 0xD: {
KVMState *s = cs->kvm_state;
- uint64_t kvm_mask;
+ uint64_t ena_mask;
int i;
/* Processor Extended State */
@@ -2458,35 +2458,39 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ebx = 0;
*ecx = 0;
*edx = 0;
- if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) || !kvm_enabled()) {
+ if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
break;
}
- kvm_mask =
- kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX) |
- ((uint64_t)kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX) << 32);
+ if (kvm_enabled()) {
+ ena_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX);
+ ena_mask <<= 32;
+ ena_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX);
+ } else {
+ ena_mask = -1;
+ }
if (count == 0) {
*ecx = 0x240;
- for (i = 2; i < ARRAY_SIZE(ext_save_areas); i++) {
- const ExtSaveArea *esa = &ext_save_areas[i];
- if ((env->features[esa->feature] & esa->bits) == esa->bits &&
- (kvm_mask & (1 << i)) != 0) {
+ for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
+ const ExtSaveArea *esa = &x86_ext_save_areas[i];
+ if ((env->features[esa->feature] & esa->bits) == esa->bits
+ && ((ena_mask >> i) & 1) != 0) {
if (i < 32) {
- *eax |= 1 << i;
+ *eax |= 1u << i;
} else {
- *edx |= 1 << (i - 32);
+ *edx |= 1u << (i - 32);
}
*ecx = MAX(*ecx, esa->offset + esa->size);
}
}
- *eax |= kvm_mask & (XSTATE_FP | XSTATE_SSE);
+ *eax |= ena_mask & (XSTATE_FP | XSTATE_SSE);
*ebx = *ecx;
} else if (count == 1) {
*eax = env->features[FEAT_XSAVE];
- } else if (count < ARRAY_SIZE(ext_save_areas)) {
- const ExtSaveArea *esa = &ext_save_areas[count];
- if ((env->features[esa->feature] & esa->bits) == esa->bits &&
- (kvm_mask & (1 << count)) != 0) {
+ } else if (count < ARRAY_SIZE(x86_ext_save_areas)) {
+ const ExtSaveArea *esa = &x86_ext_save_areas[count];
+ if ((env->features[esa->feature] & esa->bits) == esa->bits
+ && ((ena_mask >> count) & 1) != 0) {
*eax = esa->size;
*ebx = esa->offset;
}
@@ -2639,6 +2643,8 @@ static void x86_cpu_reset(CPUState *s)
X86CPU *cpu = X86_CPU(s);
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
CPUX86State *env = &cpu->env;
+ target_ulong cr4;
+ uint64_t xcr0;
int i;
xcc->parent_reset(s);
@@ -2698,7 +2704,8 @@ static void x86_cpu_reset(CPUState *s)
cpu_set_fpuc(env, 0x37f);
env->mxcsr = 0x1f80;
- env->xstate_bv = XSTATE_FP | XSTATE_SSE;
+ /* All units are in INIT state. */
+ env->xstate_bv = 0;
env->pat = 0x0007040600070406ULL;
env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
@@ -2709,7 +2716,27 @@ static void x86_cpu_reset(CPUState *s)
cpu_breakpoint_remove_all(s, BP_CPU);
cpu_watchpoint_remove_all(s, BP_CPU);
- env->xcr0 = 1;
+ cr4 = 0;
+ xcr0 = XSTATE_FP;
+
+#ifdef CONFIG_USER_ONLY
+ /* Enable all the features for user-mode. */
+ if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+ xcr0 |= XSTATE_SSE;
+ }
+ if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) {
+ xcr0 |= XSTATE_BNDREGS | XSTATE_BNDCSR;
+ }
+ if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
+ cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK;
+ }
+ if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_FSGSBASE) {
+ cr4 |= CR4_FSGSBASE_MASK;
+ }
+#endif
+
+ env->xcr0 = xcr0;
+ cpu_x86_update_cr4(env, cr4);
/*
* SDM 11.11.5 requires:
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index a990ea7fef..94cb4db27d 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -156,6 +156,8 @@
#define HF_OSFXSR_SHIFT 22 /* CR4.OSFXSR */
#define HF_SMAP_SHIFT 23 /* CR4.SMAP */
#define HF_IOBPT_SHIFT 24 /* an io breakpoint enabled */
+#define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */
+#define HF_MPX_IU_SHIFT 26 /* BND registers in-use */
#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
@@ -180,6 +182,8 @@
#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT)
#define HF_IOBPT_MASK (1 << HF_IOBPT_SHIFT)
+#define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT)
+#define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT)
/* hflags2 */
@@ -188,12 +192,14 @@
#define HF2_NMI_SHIFT 2 /* CPU serving NMI */
#define HF2_VINTR_SHIFT 3 /* value of V_INTR_MASKING bit */
#define HF2_SMM_INSIDE_NMI_SHIFT 4 /* CPU serving SMI nested inside NMI */
+#define HF2_MPX_PR_SHIFT 5 /* BNDCFGx.BNDPRESERVE */
#define HF2_GIF_MASK (1 << HF2_GIF_SHIFT)
#define HF2_HIF_MASK (1 << HF2_HIF_SHIFT)
#define HF2_NMI_MASK (1 << HF2_NMI_SHIFT)
#define HF2_VINTR_MASK (1 << HF2_VINTR_SHIFT)
#define HF2_SMM_INSIDE_NMI_MASK (1 << HF2_SMM_INSIDE_NMI_SHIFT)
+#define HF2_MPX_PR_MASK (1 << HF2_MPX_PR_SHIFT)
#define CR0_PE_SHIFT 0
#define CR0_MP_SHIFT 1
@@ -753,6 +759,10 @@ typedef struct BNDCSReg {
uint64_t sts;
} BNDCSReg;
+#define BNDCFG_ENABLE 1ULL
+#define BNDCFG_BNDPRESERVE 2ULL
+#define BNDCFG_BDIR_MASK TARGET_PAGE_MASK
+
#ifdef HOST_WORDS_BIGENDIAN
#define ZMM_B(n) _b_ZMMReg[63 - (n)]
#define ZMM_W(n) _w_ZMMReg[31 - (n)]
@@ -1121,7 +1131,14 @@ void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32);
int cpu_x86_signal_handler(int host_signum, void *pinfo,
void *puc);
-/* cpuid.c */
+/* cpu.c */
+typedef struct ExtSaveArea {
+ uint32_t feature, bits;
+ uint32_t offset, size;
+} ExtSaveArea;
+
+extern const ExtSaveArea x86_ext_save_areas[];
+
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
@@ -1342,6 +1359,8 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
*/
void x86_cpu_change_kvm_default(const char *prop, const char *value);
+/* mpx_helper.c */
+void cpu_sync_bndcs_hflags(CPUX86State *env);
/* Return name of 32-bit register, from a R_* constant */
const char *get_register_name_32(unsigned int reg);
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 2d54b47ac6..9dfbc4c7a6 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1115,89 +1115,174 @@ void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
}
#endif
-static void do_fxsave(CPUX86State *env, target_ulong ptr, int data64,
- uintptr_t retaddr)
+static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
- int fpus, fptag, i, nb_xmm_regs;
- floatx80 tmp;
+ int fpus, fptag, i;
target_ulong addr;
- /* The operand must be 16 byte aligned */
- if (ptr & 0xf) {
- raise_exception_ra(env, EXCP0D_GPF, retaddr);
- }
-
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
fptag = 0;
for (i = 0; i < 8; i++) {
fptag |= (env->fptags[i] << i);
}
- cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
- cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
- cpu_stw_data_ra(env, ptr + 4, fptag ^ 0xff, retaddr);
-#ifdef TARGET_X86_64
- if (data64) {
- cpu_stq_data_ra(env, ptr + 0x08, 0, retaddr); /* rip */
- cpu_stq_data_ra(env, ptr + 0x10, 0, retaddr); /* rdp */
- } else
-#endif
- {
- cpu_stl_data_ra(env, ptr + 0x08, 0, retaddr); /* eip */
- cpu_stl_data_ra(env, ptr + 0x0c, 0, retaddr); /* sel */
- cpu_stl_data_ra(env, ptr + 0x10, 0, retaddr); /* dp */
- cpu_stl_data_ra(env, ptr + 0x14, 0, retaddr); /* sel */
- }
+ cpu_stw_data_ra(env, ptr, env->fpuc, ra);
+ cpu_stw_data_ra(env, ptr + 2, fpus, ra);
+ cpu_stw_data_ra(env, ptr + 4, fptag ^ 0xff, ra);
+
+ /* In 32-bit mode this is eip, sel, dp, sel.
+ In 64-bit mode this is rip, rdp.
+ But in either case we don't write actual data, just zeros. */
+ cpu_stq_data_ra(env, ptr + 0x08, 0, ra); /* eip+sel; rip */
+ cpu_stq_data_ra(env, ptr + 0x10, 0, ra); /* edp+sel; rdp */
addr = ptr + 0x20;
for (i = 0; i < 8; i++) {
- tmp = ST(i);
- helper_fstt(env, tmp, addr, retaddr);
+ floatx80 tmp = ST(i);
+ helper_fstt(env, tmp, addr, ra);
+ addr += 16;
+ }
+}
+
+static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+{
+ cpu_stl_data_ra(env, ptr + 0x18, env->mxcsr, ra); /* mxcsr */
+ cpu_stl_data_ra(env, ptr + 0x1c, 0x0000ffff, ra); /* mxcsr_mask */
+}
+
+static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+{
+ int i, nb_xmm_regs;
+ target_ulong addr;
+
+ if (env->hflags & HF_CS64_MASK) {
+ nb_xmm_regs = 16;
+ } else {
+ nb_xmm_regs = 8;
+ }
+
+ addr = ptr + 0xa0;
+ for (i = 0; i < nb_xmm_regs; i++) {
+ cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), ra);
+ cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), ra);
addr += 16;
}
+}
+
+static void do_xsave_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra)
+{
+ int i;
+
+ for (i = 0; i < 4; i++, addr += 16) {
+ cpu_stq_data_ra(env, addr, env->bnd_regs[i].lb, ra);
+ cpu_stq_data_ra(env, addr + 8, env->bnd_regs[i].ub, ra);
+ }
+}
+
+static void do_xsave_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra)
+{
+ cpu_stq_data_ra(env, addr, env->bndcs_regs.cfgu, ra);
+ cpu_stq_data_ra(env, addr + 8, env->bndcs_regs.sts, ra);
+}
+
+void helper_fxsave(CPUX86State *env, target_ulong ptr)
+{
+ uintptr_t ra = GETPC();
+
+ /* The operand must be 16 byte aligned */
+ if (ptr & 0xf) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ do_xsave_fpu(env, ptr, ra);
if (env->cr[4] & CR4_OSFXSR_MASK) {
- /* XXX: finish it */
- cpu_stl_data_ra(env, ptr + 0x18, env->mxcsr, retaddr); /* mxcsr */
- cpu_stl_data_ra(env, ptr + 0x1c, 0x0000ffff, retaddr); /* mxcsr_mask */
- if (env->hflags & HF_CS64_MASK) {
- nb_xmm_regs = 16;
- } else {
- nb_xmm_regs = 8;
- }
- addr = ptr + 0xa0;
+ do_xsave_mxcsr(env, ptr, ra);
/* Fast FXSAVE leaves out the XMM registers */
if (!(env->efer & MSR_EFER_FFXSR)
|| (env->hflags & HF_CPL_MASK)
|| !(env->hflags & HF_LMA_MASK)) {
- for (i = 0; i < nb_xmm_regs; i++) {
- cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), retaddr);
- cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), retaddr);
- addr += 16;
- }
+ do_xsave_sse(env, ptr, ra);
}
}
}
-void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)
+static uint64_t get_xinuse(CPUX86State *env)
{
- do_fxsave(env, ptr, data64, GETPC());
+ uint64_t inuse = -1;
+
+ /* For the most part, we don't track XINUSE. We could calculate it
+ here for all components, but it's probably less work to simply
+ indicate in use. That said, the state of BNDREGS is important
+ enough to track in HFLAGS, so we might as well use that here. */
+ if ((env->hflags & HF_MPX_IU_MASK) == 0) {
+ inuse &= ~XSTATE_BNDREGS;
+ }
+ return inuse;
}
-static void do_fxrstor(CPUX86State *env, target_ulong ptr, int data64,
- uintptr_t retaddr)
+static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
+ uint64_t inuse, uint64_t opt, uintptr_t ra)
{
- int i, fpus, fptag, nb_xmm_regs;
- floatx80 tmp;
- target_ulong addr;
+ uint64_t old_bv, new_bv;
- /* The operand must be 16 byte aligned */
- if (ptr & 0xf) {
- raise_exception_ra(env, EXCP0D_GPF, retaddr);
+ /* The OS must have enabled XSAVE. */
+ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
+ raise_exception_ra(env, EXCP06_ILLOP, ra);
+ }
+
+ /* The operand must be 64 byte aligned. */
+ if (ptr & 63) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ /* Never save anything not enabled by XCR0. */
+ rfbm &= env->xcr0;
+ opt &= rfbm;
+
+ if (opt & XSTATE_FP) {
+ do_xsave_fpu(env, ptr, ra);
+ }
+ if (rfbm & XSTATE_SSE) {
+ /* Note that saving MXCSR is not suppressed by XSAVEOPT. */
+ do_xsave_mxcsr(env, ptr, ra);
+ }
+ if (opt & XSTATE_SSE) {
+ do_xsave_sse(env, ptr, ra);
+ }
+ if (opt & XSTATE_BNDREGS) {
+ target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset;
+ do_xsave_bndregs(env, ptr + off, ra);
}
+ if (opt & XSTATE_BNDCSR) {
+ target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset;
+ do_xsave_bndcsr(env, ptr + off, ra);
+ }
+
+ /* Update the XSTATE_BV field. */
+ old_bv = cpu_ldq_data_ra(env, ptr + 512, ra);
+ new_bv = (old_bv & ~rfbm) | (inuse & rfbm);
+ cpu_stq_data_ra(env, ptr + 512, new_bv, ra);
+}
+
+void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+{
+ do_xsave(env, ptr, rfbm, get_xinuse(env), -1, GETPC());
+}
- cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
- fpus = cpu_lduw_data_ra(env, ptr + 2, retaddr);
- fptag = cpu_lduw_data_ra(env, ptr + 4, retaddr);
+void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+{
+ uint64_t inuse = get_xinuse(env);
+ do_xsave(env, ptr, rfbm, inuse, inuse, GETPC());
+}
+
+static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+{
+ int i, fpus, fptag;
+ target_ulong addr;
+
+ cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, ra));
+ fpus = cpu_lduw_data_ra(env, ptr + 2, ra);
+ fptag = cpu_lduw_data_ra(env, ptr + 4, ra);
env->fpstt = (fpus >> 11) & 7;
env->fpus = fpus & ~0x3800;
fptag ^= 0xff;
@@ -1207,37 +1292,206 @@ static void do_fxrstor(CPUX86State *env, target_ulong ptr, int data64,
addr = ptr + 0x20;
for (i = 0; i < 8; i++) {
- tmp = helper_fldt(env, addr, retaddr);
+ floatx80 tmp = helper_fldt(env, addr, ra);
ST(i) = tmp;
addr += 16;
}
+}
+
+static void do_xrstor_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+{
+ cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + 0x18, ra));
+}
+
+static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+{
+ int i, nb_xmm_regs;
+ target_ulong addr;
+
+ if (env->hflags & HF_CS64_MASK) {
+ nb_xmm_regs = 16;
+ } else {
+ nb_xmm_regs = 8;
+ }
+
+ addr = ptr + 0xa0;
+ for (i = 0; i < nb_xmm_regs; i++) {
+ env->xmm_regs[i].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, ra);
+ env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, ra);
+ addr += 16;
+ }
+}
+
+static void do_xrstor_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra)
+{
+ int i;
+
+ for (i = 0; i < 4; i++, addr += 16) {
+ env->bnd_regs[i].lb = cpu_ldq_data_ra(env, addr, ra);
+ env->bnd_regs[i].ub = cpu_ldq_data_ra(env, addr + 8, ra);
+ }
+}
+
+static void do_xrstor_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra)
+{
+ /* FIXME: Extend highest implemented bit of linear address. */
+ env->bndcs_regs.cfgu = cpu_ldq_data_ra(env, addr, ra);
+ env->bndcs_regs.sts = cpu_ldq_data_ra(env, addr + 8, ra);
+}
+
+void helper_fxrstor(CPUX86State *env, target_ulong ptr)
+{
+ uintptr_t ra = GETPC();
+
+ /* The operand must be 16 byte aligned */
+ if (ptr & 0xf) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ do_xrstor_fpu(env, ptr, ra);
if (env->cr[4] & CR4_OSFXSR_MASK) {
- /* XXX: finish it */
- cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + 0x18, retaddr));
- /* cpu_ldl_data_ra(env, ptr + 0x1c, retaddr); */
- if (env->hflags & HF_CS64_MASK) {
- nb_xmm_regs = 16;
- } else {
- nb_xmm_regs = 8;
- }
- addr = ptr + 0xa0;
- /* Fast FXRESTORE leaves out the XMM registers */
+ do_xrstor_mxcsr(env, ptr, ra);
+ /* Fast FXRSTOR leaves out the XMM registers */
if (!(env->efer & MSR_EFER_FFXSR)
|| (env->hflags & HF_CPL_MASK)
|| !(env->hflags & HF_LMA_MASK)) {
- for (i = 0; i < nb_xmm_regs; i++) {
- env->xmm_regs[i].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, retaddr);
- env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, retaddr);
- addr += 16;
- }
+ do_xrstor_sse(env, ptr, ra);
}
}
}
-void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
+void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
{
- do_fxrstor(env, ptr, data64, GETPC());
+ uintptr_t ra = GETPC();
+ uint64_t xstate_bv, xcomp_bv0, xcomp_bv1;
+
+ rfbm &= env->xcr0;
+
+ /* The OS must have enabled XSAVE. */
+ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
+ raise_exception_ra(env, EXCP06_ILLOP, ra);
+ }
+
+ /* The operand must be 64 byte aligned. */
+ if (ptr & 63) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ xstate_bv = cpu_ldq_data_ra(env, ptr + 512, ra);
+
+ if ((int64_t)xstate_bv < 0) {
+ /* FIXME: Compact form. */
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ /* Standard form. */
+
+ /* The XSTATE field must not set bits not present in XCR0. */
+ if (xstate_bv & ~env->xcr0) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ /* The XCOMP field must be zero. */
+ xcomp_bv0 = cpu_ldq_data_ra(env, ptr + 520, ra);
+ xcomp_bv1 = cpu_ldq_data_ra(env, ptr + 528, ra);
+ if (xcomp_bv0 || xcomp_bv1) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ if (rfbm & XSTATE_FP) {
+ if (xstate_bv & XSTATE_FP) {
+ do_xrstor_fpu(env, ptr, ra);
+ } else {
+ helper_fninit(env);
+ memset(env->fpregs, 0, sizeof(env->fpregs));
+ }
+ }
+ if (rfbm & XSTATE_SSE) {
+ /* Note that the standard form of XRSTOR loads MXCSR from memory
+ whether or not the XSTATE_BV bit is set. */
+ do_xrstor_mxcsr(env, ptr, ra);
+ if (xstate_bv & XSTATE_SSE) {
+ do_xrstor_sse(env, ptr, ra);
+ } else {
+ /* ??? When AVX is implemented, we may have to be more
+ selective in the clearing. */
+ memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
+ }
+ }
+ if (rfbm & XSTATE_BNDREGS) {
+ if (xstate_bv & XSTATE_BNDREGS) {
+ target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset;
+ do_xrstor_bndregs(env, ptr + off, ra);
+ env->hflags |= HF_MPX_IU_MASK;
+ } else {
+ memset(env->bnd_regs, 0, sizeof(env->bnd_regs));
+ env->hflags &= ~HF_MPX_IU_MASK;
+ }
+ }
+ if (rfbm & XSTATE_BNDCSR) {
+ if (xstate_bv & XSTATE_BNDCSR) {
+ target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset;
+ do_xrstor_bndcsr(env, ptr + off, ra);
+ } else {
+ memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
+ }
+ cpu_sync_bndcs_hflags(env);
+ }
+}
+
+uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
+{
+ /* The OS must have enabled XSAVE. */
+ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
+ raise_exception_ra(env, EXCP06_ILLOP, GETPC());
+ }
+
+ switch (ecx) {
+ case 0:
+ return env->xcr0;
+ case 1:
+ if (env->features[FEAT_XSAVE] & CPUID_XSAVE_XGETBV1) {
+ return env->xcr0 & get_xinuse(env);
+ }
+ break;
+ }
+ raise_exception_ra(env, EXCP0D_GPF, GETPC());
+}
+
+void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
+{
+ uint32_t dummy, ena_lo, ena_hi;
+ uint64_t ena;
+
+ /* The OS must have enabled XSAVE. */
+ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
+ raise_exception_ra(env, EXCP06_ILLOP, GETPC());
+ }
+
+ /* Only XCR0 is defined at present; the FPU may not be disabled. */
+ if (ecx != 0 || (mask & XSTATE_FP) == 0) {
+ goto do_gpf;
+ }
+
+ /* Disallow enabling unimplemented features. */
+ cpu_x86_cpuid(env, 0x0d, 0, &ena_lo, &dummy, &dummy, &ena_hi);
+ ena = ((uint64_t)ena_hi << 32) | ena_lo;
+ if (mask & ~ena) {
+ goto do_gpf;
+ }
+
+ /* Disallow enabling only half of MPX. */
+ if ((mask ^ (mask * (XSTATE_BNDCSR / XSTATE_BNDREGS))) & XSTATE_BNDCSR) {
+ goto do_gpf;
+ }
+
+ env->xcr0 = mask;
+ cpu_sync_bndcs_hflags(env);
+ return;
+
+ do_gpf:
+ raise_exception_ra(env, EXCP0D_GPF, GETPC());
}
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 3802ed9359..3f60ec6122 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -647,6 +647,7 @@ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
{
X86CPU *cpu = x86_env_get_cpu(env);
+ uint32_t hflags;
#if defined(DEBUG_MMU)
printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
@@ -656,24 +657,29 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
CR4_SMEP_MASK | CR4_SMAP_MASK)) {
tlb_flush(CPU(cpu), 1);
}
+
+ /* Clear bits we're going to recompute. */
+ hflags = env->hflags & ~(HF_OSFXSR_MASK | HF_SMAP_MASK);
+
/* SSE handling */
if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
new_cr4 &= ~CR4_OSFXSR_MASK;
}
- env->hflags &= ~HF_OSFXSR_MASK;
if (new_cr4 & CR4_OSFXSR_MASK) {
- env->hflags |= HF_OSFXSR_MASK;
+ hflags |= HF_OSFXSR_MASK;
}
if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) {
new_cr4 &= ~CR4_SMAP_MASK;
}
- env->hflags &= ~HF_SMAP_MASK;
if (new_cr4 & CR4_SMAP_MASK) {
- env->hflags |= HF_SMAP_MASK;
+ hflags |= HF_SMAP_MASK;
}
env->cr[4] = new_cr4;
+ env->hflags = hflags;
+
+ cpu_sync_bndcs_hflags(env);
}
#if defined(CONFIG_USER_ONLY)
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 3a25c3b392..e33451aea9 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -15,6 +15,14 @@ DEF_HELPER_2(idivl_EAX, void, env, tl)
DEF_HELPER_2(divq_EAX, void, env, tl)
DEF_HELPER_2(idivq_EAX, void, env, tl)
#endif
+DEF_HELPER_FLAGS_2(cr4_testbit, TCG_CALL_NO_WG, void, env, i32)
+
+DEF_HELPER_FLAGS_2(bndck, TCG_CALL_NO_WG, void, env, i32)
+DEF_HELPER_FLAGS_3(bndldx32, TCG_CALL_NO_WG, i64, env, tl, tl)
+DEF_HELPER_FLAGS_3(bndldx64, TCG_CALL_NO_WG, i64, env, tl, tl)
+DEF_HELPER_FLAGS_5(bndstx32, TCG_CALL_NO_WG, void, env, tl, tl, i64, i64)
+DEF_HELPER_FLAGS_5(bndstx64, TCG_CALL_NO_WG, void, env, tl, tl, i64, i64)
+DEF_HELPER_1(bnd_jmp, void, env)
DEF_HELPER_2(aam, void, env, int)
DEF_HELPER_2(aad, void, env, int)
@@ -62,8 +70,6 @@ DEF_HELPER_1(cli, void, env)
DEF_HELPER_1(sti, void, env)
DEF_HELPER_1(clac, void, env)
DEF_HELPER_1(stac, void, env)
-DEF_HELPER_1(set_inhibit_irq, void, env)
-DEF_HELPER_1(reset_inhibit_irq, void, env)
DEF_HELPER_3(boundw, void, env, tl, int)
DEF_HELPER_3(boundl, void, env, tl, int)
DEF_HELPER_1(rsm, void, env)
@@ -185,8 +191,13 @@ DEF_HELPER_3(fstenv, void, env, tl, int)
DEF_HELPER_3(fldenv, void, env, tl, int)
DEF_HELPER_3(fsave, void, env, tl, int)
DEF_HELPER_3(frstor, void, env, tl, int)
-DEF_HELPER_3(fxsave, void, env, tl, int)
-DEF_HELPER_3(fxrstor, void, env, tl, int)
+DEF_HELPER_FLAGS_2(fxsave, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(fxrstor, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_3(xsave, TCG_CALL_NO_WG, void, env, tl, i64)
+DEF_HELPER_FLAGS_3(xsaveopt, TCG_CALL_NO_WG, void, env, tl, i64)
+DEF_HELPER_FLAGS_3(xrstor, TCG_CALL_NO_WG, void, env, tl, i64)
+DEF_HELPER_FLAGS_2(xgetbv, TCG_CALL_NO_WG, i64, env, i32)
+DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64)
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c
index 9d0d21e786..cf5bbb0481 100644
--- a/target-i386/int_helper.c
+++ b/target-i386/int_helper.c
@@ -470,3 +470,13 @@ target_ulong helper_pext(target_ulong src, target_ulong mask)
#include "shift_helper_template.h"
#undef SHIFT
#endif
+
+/* Test that BIT is enabled in CR4. If not, raise an illegal opcode
+ exception. This reduces the requirements for rare CR4 bits being
+ mapped into HFLAGS. */
+void helper_cr4_testbit(CPUX86State *env, uint32_t bit)
+{
+ if (unlikely((env->cr[4] & bit) == 0)) {
+ raise_exception_ra(env, EXCP06_ILLOP, GETPC());
+ }
+}
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 94024bc1b1..7974acb399 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1855,13 +1855,16 @@ static int kvm_get_sregs(X86CPU *cpu)
HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
- hflags = (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+ hflags = env->hflags & HFLAG_COPY_MASK;
+ hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
- hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
- (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
+
+ if (env->cr[4] & CR4_OSFXSR_MASK) {
+ hflags |= HF_OSFXSR_MASK;
+ }
if (env->efer & MSR_EFER_LMA) {
hflags |= HF_LMA_MASK;
@@ -1882,7 +1885,7 @@ static int kvm_get_sregs(X86CPU *cpu)
env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT;
}
}
- env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+ env->hflags = hflags;
return 0;
}
@@ -2585,41 +2588,44 @@ int kvm_arch_get_registers(CPUState *cs)
ret = kvm_getput_regs(cpu, 0);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_xsave(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_xcrs(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_sregs(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_msrs(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_mp_state(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_apic(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_vcpu_events(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
ret = kvm_get_debugregs(cpu);
if (ret < 0) {
- return ret;
+ goto out;
}
- return 0;
+ ret = 0;
+ out:
+ cpu_sync_bndcs_hflags(&cpu->env);
+ return ret;
}
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c
index 7de775259d..85e75161bc 100644
--- a/target-i386/mem_helper.c
+++ b/target-i386/mem_helper.c
@@ -112,6 +112,9 @@ void helper_boundw(CPUX86State *env, target_ulong a0, int v)
high = cpu_ldsw_data_ra(env, a0 + 2, GETPC());
v = (int16_t)v;
if (v < low || v > high) {
+ if (env->hflags & HF_MPX_EN_MASK) {
+ env->bndcs_regs.sts = 0;
+ }
raise_exception_ra(env, EXCP05_BOUND, GETPC());
}
}
@@ -123,6 +126,9 @@ void helper_boundl(CPUX86State *env, target_ulong a0, int v)
low = cpu_ldl_data_ra(env, a0, GETPC());
high = cpu_ldl_data_ra(env, a0 + 4, GETPC());
if (v < low || v > high) {
+ if (env->hflags & HF_MPX_EN_MASK) {
+ env->bndcs_regs.sts = 0;
+ }
raise_exception_ra(env, EXCP05_BOUND, GETPC());
}
}
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 460257f6bc..5fbab8fd0c 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -361,6 +361,12 @@ void helper_wrmsr(CPUX86State *env)
case MSR_IA32_MISC_ENABLE:
env->msr_ia32_misc_enable = val;
break;
+ case MSR_IA32_BNDCFGS:
+ /* FIXME: #GP if reserved bits are set. */
+ /* FIXME: Extend highest implemented bit of linear address. */
+ env->msr_bndcfgs = val;
+ cpu_sync_bndcs_hflags(env);
+ break;
default:
if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
&& (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
@@ -506,6 +512,9 @@ void helper_rdmsr(CPUX86State *env)
case MSR_IA32_MISC_ENABLE:
val = env->msr_ia32_misc_enable;
break;
+ case MSR_IA32_BNDCFGS:
+ val = env->msr_bndcfgs;
+ break;
default:
if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
&& (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
diff --git a/target-i386/mpx_helper.c b/target-i386/mpx_helper.c
new file mode 100644
index 0000000000..1bf717af05
--- /dev/null
+++ b/target-i386/mpx_helper.c
@@ -0,0 +1,166 @@
+/*
+ * x86 MPX helpers
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * 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 "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
+
+
+void cpu_sync_bndcs_hflags(CPUX86State *env)
+{
+ uint32_t hflags = env->hflags;
+ uint32_t hflags2 = env->hflags2;
+ uint32_t bndcsr;
+
+ if ((hflags & HF_CPL_MASK) == 3) {
+ bndcsr = env->bndcs_regs.cfgu;
+ } else {
+ bndcsr = env->msr_bndcfgs;
+ }
+
+ if ((env->cr[4] & CR4_OSXSAVE_MASK)
+ && (env->xcr0 & XSTATE_BNDCSR)
+ && (bndcsr & BNDCFG_ENABLE)) {
+ hflags |= HF_MPX_EN_MASK;
+ } else {
+ hflags &= ~HF_MPX_EN_MASK;
+ }
+
+ if (bndcsr & BNDCFG_BNDPRESERVE) {
+ hflags2 |= HF2_MPX_PR_MASK;
+ } else {
+ hflags2 &= ~HF2_MPX_PR_MASK;
+ }
+
+ env->hflags = hflags;
+ env->hflags2 = hflags2;
+}
+
+void helper_bndck(CPUX86State *env, uint32_t fail)
+{
+ if (unlikely(fail)) {
+ env->bndcs_regs.sts = 1;
+ raise_exception_ra(env, EXCP05_BOUND, GETPC());
+ }
+}
+
+static uint64_t lookup_bte64(CPUX86State *env, uint64_t base, uintptr_t ra)
+{
+ uint64_t bndcsr, bde, bt;
+
+ if ((env->hflags & HF_CPL_MASK) == 3) {
+ bndcsr = env->bndcs_regs.cfgu;
+ } else {
+ bndcsr = env->msr_bndcfgs;
+ }
+
+ bde = (extract64(base, 20, 28) << 3) + (extract64(bndcsr, 20, 44) << 12);
+ bt = cpu_ldq_data_ra(env, bde, ra);
+ if ((bt & 1) == 0) {
+ env->bndcs_regs.sts = bde | 2;
+ raise_exception_ra(env, EXCP05_BOUND, ra);
+ }
+
+ return (extract64(base, 3, 17) << 5) + (bt & ~7);
+}
+
+static uint32_t lookup_bte32(CPUX86State *env, uint32_t base, uintptr_t ra)
+{
+ uint32_t bndcsr, bde, bt;
+
+ if ((env->hflags & HF_CPL_MASK) == 3) {
+ bndcsr = env->bndcs_regs.cfgu;
+ } else {
+ bndcsr = env->msr_bndcfgs;
+ }
+
+ bde = (extract32(base, 12, 20) << 2) + (bndcsr & TARGET_PAGE_MASK);
+ bt = cpu_ldl_data_ra(env, bde, ra);
+ if ((bt & 1) == 0) {
+ env->bndcs_regs.sts = bde | 2;
+ raise_exception_ra(env, EXCP05_BOUND, ra);
+ }
+
+ return (extract32(base, 2, 10) << 4) + (bt & ~3);
+}
+
+uint64_t helper_bndldx64(CPUX86State *env, target_ulong base, target_ulong ptr)
+{
+ uintptr_t ra = GETPC();
+ uint64_t bte, lb, ub, pt;
+
+ bte = lookup_bte64(env, base, ra);
+ lb = cpu_ldq_data_ra(env, bte, ra);
+ ub = cpu_ldq_data_ra(env, bte + 8, ra);
+ pt = cpu_ldq_data_ra(env, bte + 16, ra);
+
+ if (pt != ptr) {
+ lb = ub = 0;
+ }
+ env->mmx_t0.MMX_Q(0) = ub;
+ return lb;
+}
+
+uint64_t helper_bndldx32(CPUX86State *env, target_ulong base, target_ulong ptr)
+{
+ uintptr_t ra = GETPC();
+ uint32_t bte, lb, ub, pt;
+
+ bte = lookup_bte32(env, base, ra);
+ lb = cpu_ldl_data_ra(env, bte, ra);
+ ub = cpu_ldl_data_ra(env, bte + 4, ra);
+ pt = cpu_ldl_data_ra(env, bte + 8, ra);
+
+ if (pt != ptr) {
+ lb = ub = 0;
+ }
+ return ((uint64_t)ub << 32) | lb;
+}
+
+void helper_bndstx64(CPUX86State *env, target_ulong base, target_ulong ptr,
+ uint64_t lb, uint64_t ub)
+{
+ uintptr_t ra = GETPC();
+ uint64_t bte;
+
+ bte = lookup_bte64(env, base, ra);
+ cpu_stq_data_ra(env, bte, lb, ra);
+ cpu_stq_data_ra(env, bte + 8, ub, ra);
+ cpu_stq_data_ra(env, bte + 16, ptr, ra);
+}
+
+void helper_bndstx32(CPUX86State *env, target_ulong base, target_ulong ptr,
+ uint64_t lb, uint64_t ub)
+{
+ uintptr_t ra = GETPC();
+ uint32_t bte;
+
+ bte = lookup_bte32(env, base, ra);
+ cpu_stl_data_ra(env, bte, lb, ra);
+ cpu_stl_data_ra(env, bte + 4, ub, ra);
+ cpu_stl_data_ra(env, bte + 8, ptr, ra);
+}
+
+void helper_bnd_jmp(CPUX86State *env)
+{
+ if (!(env->hflags2 & HF2_MPX_PR_MASK)) {
+ memset(env->bnd_regs, 0, sizeof(env->bnd_regs));
+ env->hflags &= ~HF_MPX_IU_MASK;
+ }
+}
diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c
index e7bb5be521..4dd6a2c544 100644
--- a/target-i386/smm_helper.c
+++ b/target-i386/smm_helper.c
@@ -99,6 +99,10 @@ void do_smm_enter(X86CPU *cpu)
x86_stl_phys(cs, sm_state + 0x7e94, env->tr.limit);
x86_stw_phys(cs, sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
+ /* ??? Vol 1, 16.5.6 Intel MPX and SMM says that IA32_BNDCFGS
+ is saved at offset 7ED0. Vol 3, 34.4.1.1, Table 32-2, has
+ 7EA0-7ED7 as "reserved". What's this, and what's really
+ supposed to happen? */
x86_stq_phys(cs, sm_state + 0x7ed0, env->efer);
x86_stq_phys(cs, sm_state + 0x7ff8, env->regs[R_EAX]);
diff --git a/target-i386/translate.c b/target-i386/translate.c
index c8e2799269..9171929fc7 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -56,6 +56,12 @@
# define clztl clz32
#endif
+/* For a switch indexed by MODRM, match all memory operands for a given OP. */
+#define CASE_MEM_OP(OP) \
+ case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \
+ case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \
+ case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7
+
//#define MACRO_TEST 1
/* global register indexes */
@@ -65,6 +71,8 @@ static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2, cpu_cc_srcT;
static TCGv_i32 cpu_cc_op;
static TCGv cpu_regs[CPU_NB_REGS];
static TCGv cpu_seg_base[6];
+static TCGv_i64 cpu_bndl[4];
+static TCGv_i64 cpu_bndu[4];
/* local temps */
static TCGv cpu_T0, cpu_T1;
/* local register indexes (only used inside old micro ops) */
@@ -121,6 +129,7 @@ typedef struct DisasContext {
int cpuid_ext2_features;
int cpuid_ext3_features;
int cpuid_7_0_ebx_features;
+ int cpuid_xsave_features;
} DisasContext;
static void gen_eob(DisasContext *s);
@@ -1800,37 +1809,52 @@ static void gen_shifti(DisasContext *s1, int op, TCGMemOp ot, int d, int c)
}
}
-static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
+/* Decompose an address. */
+
+typedef struct AddressParts {
+ int def_seg;
+ int base;
+ int index;
+ int scale;
+ target_long disp;
+} AddressParts;
+
+static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s,
+ int modrm)
{
+ int def_seg, base, index, scale, mod, rm;
target_long disp;
- int havesib, base, index, scale;
- int mod, rm, code, def_seg, ovr_seg;
- TCGv sum;
+ bool havesib;
def_seg = R_DS;
- ovr_seg = s->override;
+ index = -1;
+ scale = 0;
+ disp = 0;
+
mod = (modrm >> 6) & 3;
rm = modrm & 7;
+ base = rm | REX_B(s);
+
+ if (mod == 3) {
+ /* Normally filtered out earlier, but including this path
+ simplifies multi-byte nop, as well as bndcl, bndcu, bndcn. */
+ goto done;
+ }
switch (s->aflag) {
case MO_64:
case MO_32:
havesib = 0;
- base = rm;
- index = -1;
- scale = 0;
-
- if (base == 4) {
- havesib = 1;
- code = cpu_ldub_code(env, s->pc++);
+ if (rm == 4) {
+ int code = cpu_ldub_code(env, s->pc++);
scale = (code >> 6) & 3;
index = ((code >> 3) & 7) | REX_X(s);
if (index == 4) {
index = -1; /* no index */
}
- base = (code & 7);
+ base = (code & 7) | REX_B(s);
+ havesib = 1;
}
- base |= REX_B(s);
switch (mod) {
case 0:
@@ -1839,10 +1863,9 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
disp = (int32_t)cpu_ldl_code(env, s->pc);
s->pc += 4;
if (CODE64(s) && !havesib) {
+ base = -2;
disp += s->pc + s->rip_offset;
}
- } else {
- disp = 0;
}
break;
case 1:
@@ -1859,46 +1882,19 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
if (base == R_ESP && s->popl_esp_hack) {
disp += s->popl_esp_hack;
}
-
- /* Compute the address, with a minimum number of TCG ops. */
- TCGV_UNUSED(sum);
- if (index >= 0) {
- if (scale == 0) {
- sum = cpu_regs[index];
- } else {
- tcg_gen_shli_tl(cpu_A0, cpu_regs[index], scale);
- sum = cpu_A0;
- }
- if (base >= 0) {
- tcg_gen_add_tl(cpu_A0, sum, cpu_regs[base]);
- sum = cpu_A0;
- }
- } else if (base >= 0) {
- sum = cpu_regs[base];
- }
- if (TCGV_IS_UNUSED(sum)) {
- tcg_gen_movi_tl(cpu_A0, disp);
- sum = cpu_A0;
- } else if (disp != 0) {
- tcg_gen_addi_tl(cpu_A0, sum, disp);
- sum = cpu_A0;
- }
-
if (base == R_EBP || base == R_ESP) {
def_seg = R_SS;
}
break;
case MO_16:
- sum = cpu_A0;
if (mod == 0) {
if (rm == 6) {
+ base = -1;
disp = cpu_lduw_code(env, s->pc);
s->pc += 2;
- tcg_gen_movi_tl(cpu_A0, disp);
break;
}
- disp = 0;
} else if (mod == 1) {
disp = (int8_t)cpu_ldub_code(env, s->pc++);
} else {
@@ -1908,102 +1904,104 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
switch (rm) {
case 0:
- tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBX], cpu_regs[R_ESI]);
+ base = R_EBX;
+ index = R_ESI;
break;
case 1:
- tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBX], cpu_regs[R_EDI]);
+ base = R_EBX;
+ index = R_EDI;
break;
case 2:
- tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBP], cpu_regs[R_ESI]);
+ base = R_EBP;
+ index = R_ESI;
def_seg = R_SS;
break;
case 3:
- tcg_gen_add_tl(cpu_A0, cpu_regs[R_EBP], cpu_regs[R_EDI]);
+ base = R_EBP;
+ index = R_EDI;
def_seg = R_SS;
break;
case 4:
- sum = cpu_regs[R_ESI];
+ base = R_ESI;
break;
case 5:
- sum = cpu_regs[R_EDI];
+ base = R_EDI;
break;
case 6:
- sum = cpu_regs[R_EBP];
+ base = R_EBP;
def_seg = R_SS;
break;
default:
case 7:
- sum = cpu_regs[R_EBX];
+ base = R_EBX;
break;
}
- if (disp != 0) {
- tcg_gen_addi_tl(cpu_A0, sum, disp);
- sum = cpu_A0;
- }
break;
default:
tcg_abort();
}
- gen_lea_v_seg(s, s->aflag, sum, def_seg, ovr_seg);
+ done:
+ return (AddressParts){ def_seg, base, index, scale, disp };
}
-static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
+/* Compute the address, with a minimum number of TCG ops. */
+static TCGv gen_lea_modrm_1(AddressParts a)
{
- int mod, rm, base, code;
+ TCGv ea;
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- return;
- rm = modrm & 7;
+ TCGV_UNUSED(ea);
+ if (a.index >= 0) {
+ if (a.scale == 0) {
+ ea = cpu_regs[a.index];
+ } else {
+ tcg_gen_shli_tl(cpu_A0, cpu_regs[a.index], a.scale);
+ ea = cpu_A0;
+ }
+ if (a.base >= 0) {
+ tcg_gen_add_tl(cpu_A0, ea, cpu_regs[a.base]);
+ ea = cpu_A0;
+ }
+ } else if (a.base >= 0) {
+ ea = cpu_regs[a.base];
+ }
+ if (TCGV_IS_UNUSED(ea)) {
+ tcg_gen_movi_tl(cpu_A0, a.disp);
+ ea = cpu_A0;
+ } else if (a.disp != 0) {
+ tcg_gen_addi_tl(cpu_A0, ea, a.disp);
+ ea = cpu_A0;
+ }
- switch (s->aflag) {
- case MO_64:
- case MO_32:
- base = rm;
+ return ea;
+}
- if (base == 4) {
- code = cpu_ldub_code(env, s->pc++);
- base = (code & 7);
- }
+static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
+{
+ AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ TCGv ea = gen_lea_modrm_1(a);
+ gen_lea_v_seg(s, s->aflag, ea, a.def_seg, s->override);
+}
- switch (mod) {
- case 0:
- if (base == 5) {
- s->pc += 4;
- }
- break;
- case 1:
- s->pc++;
- break;
- default:
- case 2:
- s->pc += 4;
- break;
- }
- break;
+static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
+{
+ (void)gen_lea_modrm_0(env, s, modrm);
+}
- case MO_16:
- switch (mod) {
- case 0:
- if (rm == 6) {
- s->pc += 2;
- }
- break;
- case 1:
- s->pc++;
- break;
- default:
- case 2:
- s->pc += 2;
- break;
- }
- break;
+/* Used for BNDCL, BNDCU, BNDCN. */
+static void gen_bndck(CPUX86State *env, DisasContext *s, int modrm,
+ TCGCond cond, TCGv_i64 bndv)
+{
+ TCGv ea = gen_lea_modrm_1(gen_lea_modrm_0(env, s, modrm));
- default:
- tcg_abort();
+ tcg_gen_extu_tl_i64(cpu_tmp1_i64, ea);
+ if (!CODE64(s)) {
+ tcg_gen_ext32u_i64(cpu_tmp1_i64, cpu_tmp1_i64);
}
+ tcg_gen_setcond_i64(cond, cpu_tmp1_i64, cpu_tmp1_i64, bndv);
+ tcg_gen_extrl_i64_i32(cpu_tmp2_i32, cpu_tmp1_i64);
+ gen_helper_bndck(cpu_env, cpu_tmp2_i32);
}
/* used for LEA and MOV AX, mem */
@@ -2384,14 +2382,49 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
s->is_jmp = DISAS_TB_JUMP;
}
+static void gen_set_hflag(DisasContext *s, uint32_t mask)
+{
+ if ((s->flags & mask) == 0) {
+ TCGv_i32 t = tcg_temp_new_i32();
+ tcg_gen_ld_i32(t, cpu_env, offsetof(CPUX86State, hflags));
+ tcg_gen_ori_i32(t, t, mask);
+ tcg_gen_st_i32(t, cpu_env, offsetof(CPUX86State, hflags));
+ tcg_temp_free_i32(t);
+ s->flags |= mask;
+ }
+}
+
+static void gen_reset_hflag(DisasContext *s, uint32_t mask)
+{
+ if (s->flags & mask) {
+ TCGv_i32 t = tcg_temp_new_i32();
+ tcg_gen_ld_i32(t, cpu_env, offsetof(CPUX86State, hflags));
+ tcg_gen_andi_i32(t, t, ~mask);
+ tcg_gen_st_i32(t, cpu_env, offsetof(CPUX86State, hflags));
+ tcg_temp_free_i32(t);
+ s->flags &= ~mask;
+ }
+}
+
+/* Clear BND registers during legacy branches. */
+static void gen_bnd_jmp(DisasContext *s)
+{
+ /* Do nothing if BND prefix present, MPX is disabled, or if the
+ BNDREGs are known to be in INIT state already. The helper
+ itself will check BNDPRESERVE at runtime. */
+ if ((s->prefix & PREFIX_REPNZ) == 0
+ && (s->flags & HF_MPX_EN_MASK) == 0
+ && (s->flags & HF_MPX_IU_MASK) == 0) {
+ gen_helper_bnd_jmp(cpu_env);
+ }
+}
+
/* generate a generic end of block. Trace exception is also generated
if needed */
static void gen_eob(DisasContext *s)
{
gen_update_cc_op(s);
- if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
- gen_helper_reset_inhibit_irq(cpu_env);
- }
+ gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
if (s->tb->flags & HF_RF_MASK) {
gen_helper_reset_rf(cpu_env);
}
@@ -4775,6 +4808,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_movi_tl(cpu_T1, next_eip);
gen_push_v(s, cpu_T1);
gen_op_jmp_v(cpu_T0);
+ gen_bnd_jmp(s);
gen_eob(s);
break;
case 3: /* lcall Ev */
@@ -4800,6 +4834,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_ext16u_tl(cpu_T0, cpu_T0);
}
gen_op_jmp_v(cpu_T0);
+ gen_bnd_jmp(s);
gen_eob(s);
break;
case 5: /* ljmp Ev */
@@ -5140,8 +5175,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
/* if reg == SS, inhibit interrupts/trace. */
/* If several instructions disable interrupts, only the
_first_ does it */
- if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_helper_set_inhibit_irq(cpu_env);
+ gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
s->tf = 0;
}
if (s->is_jmp) {
@@ -5208,8 +5242,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
/* if reg == SS, inhibit interrupts/trace */
/* If several instructions disable interrupts, only the
_first_ does it */
- if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_helper_set_inhibit_irq(cpu_env);
+ gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
s->tf = 0;
}
if (s->is_jmp) {
@@ -5275,19 +5308,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
case 0x8d: /* lea */
- ot = dflag;
modrm = cpu_ldub_code(env, s->pc++);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
reg = ((modrm >> 3) & 7) | rex_r;
- /* we must ensure that no segment is added */
- s->override = -1;
- val = s->addseg;
- s->addseg = 0;
- gen_lea_modrm(env, s, modrm);
- s->addseg = val;
- gen_op_mov_reg_v(ot, reg, cpu_A0);
+ {
+ AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ TCGv ea = gen_lea_modrm_1(a);
+ gen_op_mov_reg_v(dflag, reg, ea);
+ }
break;
case 0xa0: /* mov EAX, Ov */
@@ -6186,6 +6216,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_stack_update(s, val + (1 << ot));
/* Note that gen_pop_T0 uses a zero-extending load. */
gen_op_jmp_v(cpu_T0);
+ gen_bnd_jmp(s);
gen_eob(s);
break;
case 0xc3: /* ret */
@@ -6193,6 +6224,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_pop_update(s, ot);
/* Note that gen_pop_T0 uses a zero-extending load. */
gen_op_jmp_v(cpu_T0);
+ gen_bnd_jmp(s);
gen_eob(s);
break;
case 0xca: /* lret im */
@@ -6259,6 +6291,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
tcg_gen_movi_tl(cpu_T0, next_eip);
gen_push_v(s, cpu_T0);
+ gen_bnd_jmp(s);
gen_jmp(s, tval);
}
break;
@@ -6288,6 +6321,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} else if (!CODE64(s)) {
tval &= 0xffffffff;
}
+ gen_bnd_jmp(s);
gen_jmp(s, tval);
break;
case 0xea: /* ljmp im */
@@ -6327,6 +6361,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (dflag == MO_16) {
tval &= 0xffff;
}
+ gen_bnd_jmp(s);
gen_jcc(s, b, tval, next_eip);
break;
@@ -6745,8 +6780,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
/* interruptions are enabled only the first insn after sti */
/* If several instructions disable interrupts, only the
_first_ does it */
- if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_helper_set_inhibit_irq(cpu_env);
+ gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
/* give a chance to handle pending irqs */
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
@@ -7000,15 +7034,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
goto illegal_op;
}
break;
+
case 0x101:
modrm = cpu_ldub_code(env, s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- rm = modrm & 7;
- switch(op) {
- case 0: /* sgdt */
- if (mod == 3)
- goto illegal_op;
+ switch (modrm) {
+ CASE_MEM_OP(0): /* sgdt */
gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
gen_lea_modrm(env, s, modrm);
tcg_gen_ld32u_tl(cpu_T0,
@@ -7021,178 +7051,230 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
break;
- case 1:
- if (mod == 3) {
- switch (rm) {
- case 0: /* monitor */
- if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
- s->cpl != 0)
- goto illegal_op;
- gen_update_cc_op(s);
- gen_jmp_im(pc_start - s->cs_base);
- tcg_gen_mov_tl(cpu_A0, cpu_regs[R_EAX]);
- gen_extu(s->aflag, cpu_A0);
- gen_add_A0_ds_seg(s);
- gen_helper_monitor(cpu_env, cpu_A0);
- break;
- case 1: /* mwait */
- if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
- s->cpl != 0)
- goto illegal_op;
- gen_update_cc_op(s);
- gen_jmp_im(pc_start - s->cs_base);
- gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
- gen_eob(s);
- break;
- case 2: /* clac */
- if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) ||
- s->cpl != 0) {
- goto illegal_op;
- }
- gen_helper_clac(cpu_env);
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- break;
- case 3: /* stac */
- if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) ||
- s->cpl != 0) {
- goto illegal_op;
- }
- gen_helper_stac(cpu_env);
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- break;
- default:
- goto illegal_op;
- }
- } else { /* sidt */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
- gen_lea_modrm(env, s, modrm);
- tcg_gen_ld32u_tl(cpu_T0,
- cpu_env, offsetof(CPUX86State, idt.limit));
- gen_op_st_v(s, MO_16, cpu_T0, cpu_A0);
- gen_add_A0_im(s, 2);
- tcg_gen_ld_tl(cpu_T0,
- cpu_env, offsetof(CPUX86State, idt.base));
- if (dflag == MO_16) {
- tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
- }
- gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+
+ case 0xc8: /* monitor */
+ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+ goto illegal_op;
}
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ tcg_gen_mov_tl(cpu_A0, cpu_regs[R_EAX]);
+ gen_extu(s->aflag, cpu_A0);
+ gen_add_A0_ds_seg(s);
+ gen_helper_monitor(cpu_env, cpu_A0);
break;
- case 2: /* lgdt */
- case 3: /* lidt */
- if (mod == 3) {
- gen_update_cc_op(s);
- gen_jmp_im(pc_start - s->cs_base);
- switch(rm) {
- case 0: /* VMRUN */
- if (!(s->flags & HF_SVME_MASK) || !s->pe)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- break;
- } else {
- gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
- tcg_const_i32(s->pc - pc_start));
- tcg_gen_exit_tb(0);
- s->is_jmp = DISAS_TB_JUMP;
- }
- break;
- case 1: /* VMMCALL */
- if (!(s->flags & HF_SVME_MASK))
- goto illegal_op;
- gen_helper_vmmcall(cpu_env);
- break;
- case 2: /* VMLOAD */
- if (!(s->flags & HF_SVME_MASK) || !s->pe)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- break;
- } else {
- gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag - 1));
- }
- break;
- case 3: /* VMSAVE */
- if (!(s->flags & HF_SVME_MASK) || !s->pe)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- break;
- } else {
- gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag - 1));
- }
- break;
- case 4: /* STGI */
- if ((!(s->flags & HF_SVME_MASK) &&
- !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
- !s->pe)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- break;
- } else {
- gen_helper_stgi(cpu_env);
- }
- break;
- case 5: /* CLGI */
- if (!(s->flags & HF_SVME_MASK) || !s->pe)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- break;
- } else {
- gen_helper_clgi(cpu_env);
- }
- break;
- case 6: /* SKINIT */
- if ((!(s->flags & HF_SVME_MASK) &&
- !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
- !s->pe)
- goto illegal_op;
- gen_helper_skinit(cpu_env);
- break;
- case 7: /* INVLPGA */
- if (!(s->flags & HF_SVME_MASK) || !s->pe)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- break;
- } else {
- gen_helper_invlpga(cpu_env,
- tcg_const_i32(s->aflag - 1));
- }
- break;
- default:
- goto illegal_op;
- }
- } else if (s->cpl != 0) {
+
+ case 0xc9: /* mwait */
+ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+ goto illegal_op;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
+ gen_eob(s);
+ break;
+
+ case 0xca: /* clac */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
+ || s->cpl != 0) {
+ goto illegal_op;
+ }
+ gen_helper_clac(cpu_env);
+ gen_jmp_im(s->pc - s->cs_base);
+ gen_eob(s);
+ break;
+
+ case 0xcb: /* stac */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
+ || s->cpl != 0) {
+ goto illegal_op;
+ }
+ gen_helper_stac(cpu_env);
+ gen_jmp_im(s->pc - s->cs_base);
+ gen_eob(s);
+ break;
+
+ CASE_MEM_OP(1): /* sidt */
+ gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
+ gen_lea_modrm(env, s, modrm);
+ tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.limit));
+ gen_op_st_v(s, MO_16, cpu_T0, cpu_A0);
+ gen_add_A0_im(s, 2);
+ tcg_gen_ld_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.base));
+ if (dflag == MO_16) {
+ tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
+ }
+ gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+ break;
+
+ case 0xd0: /* xgetbv */
+ if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+ || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+ | PREFIX_REPZ | PREFIX_REPNZ))) {
+ goto illegal_op;
+ }
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_ECX]);
+ gen_helper_xgetbv(cpu_tmp1_i64, cpu_env, cpu_tmp2_i32);
+ tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], cpu_tmp1_i64);
+ break;
+
+ case 0xd1: /* xsetbv */
+ if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+ || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+ | PREFIX_REPZ | PREFIX_REPNZ))) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_svm_check_intercept(s, pc_start,
- op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE);
- gen_lea_modrm(env, s, modrm);
- gen_op_ld_v(s, MO_16, cpu_T1, cpu_A0);
- gen_add_A0_im(s, 2);
- gen_op_ld_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
- if (dflag == MO_16) {
- tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
- }
- if (op == 2) {
- tcg_gen_st_tl(cpu_T0, cpu_env,
- offsetof(CPUX86State, gdt.base));
- tcg_gen_st32_tl(cpu_T1, cpu_env,
- offsetof(CPUX86State, gdt.limit));
- } else {
- tcg_gen_st_tl(cpu_T0, cpu_env,
- offsetof(CPUX86State, idt.base));
- tcg_gen_st32_tl(cpu_T1, cpu_env,
- offsetof(CPUX86State, idt.limit));
- }
+ break;
+ }
+ tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+ cpu_regs[R_EDX]);
+ tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_ECX]);
+ gen_helper_xsetbv(cpu_env, cpu_tmp2_i32, cpu_tmp1_i64);
+ /* End TB because translation flags may change. */
+ gen_jmp_im(s->pc - pc_start);
+ gen_eob(s);
+ break;
+
+ case 0xd8: /* VMRUN */
+ if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
+ tcg_const_i32(s->pc - pc_start));
+ tcg_gen_exit_tb(0);
+ s->is_jmp = DISAS_TB_JUMP;
+ break;
+
+ case 0xd9: /* VMMCALL */
+ if (!(s->flags & HF_SVME_MASK)) {
+ goto illegal_op;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_vmmcall(cpu_env);
+ break;
+
+ case 0xda: /* VMLOAD */
+ if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag - 1));
+ break;
+
+ case 0xdb: /* VMSAVE */
+ if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
}
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag - 1));
break;
- case 4: /* smsw */
+
+ case 0xdc: /* STGI */
+ if ((!(s->flags & HF_SVME_MASK)
+ && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+ || !s->pe) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_stgi(cpu_env);
+ break;
+
+ case 0xdd: /* CLGI */
+ if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_clgi(cpu_env);
+ break;
+
+ case 0xde: /* SKINIT */
+ if ((!(s->flags & HF_SVME_MASK)
+ && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+ || !s->pe) {
+ goto illegal_op;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_skinit(cpu_env);
+ break;
+
+ case 0xdf: /* INVLPGA */
+ if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ goto illegal_op;
+ }
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1));
+ break;
+
+ CASE_MEM_OP(2): /* lgdt */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_WRITE);
+ gen_lea_modrm(env, s, modrm);
+ gen_op_ld_v(s, MO_16, cpu_T1, cpu_A0);
+ gen_add_A0_im(s, 2);
+ gen_op_ld_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+ if (dflag == MO_16) {
+ tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
+ }
+ tcg_gen_st_tl(cpu_T0, cpu_env, offsetof(CPUX86State, gdt.base));
+ tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, gdt.limit));
+ break;
+
+ CASE_MEM_OP(3): /* lidt */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_WRITE);
+ gen_lea_modrm(env, s, modrm);
+ gen_op_ld_v(s, MO_16, cpu_T1, cpu_A0);
+ gen_add_A0_im(s, 2);
+ gen_op_ld_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+ if (dflag == MO_16) {
+ tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
+ }
+ tcg_gen_st_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.base));
+ tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, idt.limit));
+ break;
+
+ CASE_MEM_OP(4): /* smsw */
gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0);
#if defined TARGET_X86_64 && defined HOST_WORDS_BIGENDIAN
tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, cr[0]) + 4);
@@ -7201,70 +7283,70 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
#endif
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 1);
break;
- case 6: /* lmsw */
+
+ CASE_MEM_OP(6): /* lmsw */
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
- gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
- gen_helper_lmsw(cpu_env, cpu_T0);
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
+ break;
}
+ gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
+ gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
+ gen_helper_lmsw(cpu_env, cpu_T0);
+ gen_jmp_im(s->pc - s->cs_base);
+ gen_eob(s);
break;
- case 7:
- if (mod != 3) { /* invlpg */
+
+ CASE_MEM_OP(7): /* invlpg */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ break;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_lea_modrm(env, s, modrm);
+ gen_helper_invlpg(cpu_env, cpu_A0);
+ gen_jmp_im(s->pc - s->cs_base);
+ gen_eob(s);
+ break;
+
+ case 0xf8: /* swapgs */
+#ifdef TARGET_X86_64
+ if (CODE64(s)) {
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- gen_update_cc_op(s);
- gen_jmp_im(pc_start - s->cs_base);
- gen_lea_modrm(env, s, modrm);
- gen_helper_invlpg(cpu_env, cpu_A0);
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
+ tcg_gen_mov_tl(cpu_T0, cpu_seg_base[R_GS]);
+ tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env,
+ offsetof(CPUX86State, kernelgsbase));
+ tcg_gen_st_tl(cpu_T0, cpu_env,
+ offsetof(CPUX86State, kernelgsbase));
}
- } else {
- switch (rm) {
- case 0: /* swapgs */
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- tcg_gen_mov_tl(cpu_T0, cpu_seg_base[R_GS]);
- tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env,
- offsetof(CPUX86State, kernelgsbase));
- tcg_gen_st_tl(cpu_T0, cpu_env,
- offsetof(CPUX86State, kernelgsbase));
- }
- break;
- }
+ break;
+ }
#endif
- goto illegal_op;
- case 1: /* rdtscp */
- if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP))
- goto illegal_op;
- gen_update_cc_op(s);
- gen_jmp_im(pc_start - s->cs_base);
- if (s->tb->cflags & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_rdtscp(cpu_env);
- if (s->tb->cflags & CF_USE_ICOUNT) {
- gen_io_end();
- gen_jmp(s, s->pc - s->cs_base);
- }
- break;
- default:
- goto illegal_op;
- }
+ goto illegal_op;
+
+ case 0xf9: /* rdtscp */
+ if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP)) {
+ goto illegal_op;
+ }
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ if (s->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_rdtscp(cpu_env);
+ if (s->tb->cflags & CF_USE_ICOUNT) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
}
break;
+
default:
goto illegal_op;
}
break;
+
case 0x108: /* invd */
case 0x109: /* wbinvd */
if (s->cpl != 0) {
@@ -7393,7 +7475,199 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
}
break;
- case 0x119 ... 0x11f: /* nop (multi byte) */
+ case 0x11a:
+ modrm = cpu_ldub_code(env, s->pc++);
+ if (s->flags & HF_MPX_EN_MASK) {
+ mod = (modrm >> 6) & 3;
+ reg = ((modrm >> 3) & 7) | rex_r;
+ if (prefixes & PREFIX_REPZ) {
+ /* bndcl */
+ if (reg >= 4
+ || (prefixes & PREFIX_LOCK)
+ || s->aflag == MO_16) {
+ goto illegal_op;
+ }
+ gen_bndck(env, s, modrm, TCG_COND_LTU, cpu_bndl[reg]);
+ } else if (prefixes & PREFIX_REPNZ) {
+ /* bndcu */
+ if (reg >= 4
+ || (prefixes & PREFIX_LOCK)
+ || s->aflag == MO_16) {
+ goto illegal_op;
+ }
+ TCGv_i64 notu = tcg_temp_new_i64();
+ tcg_gen_not_i64(notu, cpu_bndu[reg]);
+ gen_bndck(env, s, modrm, TCG_COND_GTU, notu);
+ tcg_temp_free_i64(notu);
+ } else if (prefixes & PREFIX_DATA) {
+ /* bndmov -- from reg/mem */
+ if (reg >= 4 || s->aflag == MO_16) {
+ goto illegal_op;
+ }
+ if (mod == 3) {
+ int reg2 = (modrm & 7) | REX_B(s);
+ if (reg2 >= 4 || (prefixes & PREFIX_LOCK)) {
+ goto illegal_op;
+ }
+ if (s->flags & HF_MPX_IU_MASK) {
+ tcg_gen_mov_i64(cpu_bndl[reg], cpu_bndl[reg2]);
+ tcg_gen_mov_i64(cpu_bndu[reg], cpu_bndu[reg2]);
+ }
+ } else {
+ gen_lea_modrm(env, s, modrm);
+ if (CODE64(s)) {
+ tcg_gen_qemu_ld_i64(cpu_bndl[reg], cpu_A0,
+ s->mem_index, MO_LEQ);
+ tcg_gen_addi_tl(cpu_A0, cpu_A0, 8);
+ tcg_gen_qemu_ld_i64(cpu_bndu[reg], cpu_A0,
+ s->mem_index, MO_LEQ);
+ } else {
+ tcg_gen_qemu_ld_i64(cpu_bndl[reg], cpu_A0,
+ s->mem_index, MO_LEUL);
+ tcg_gen_addi_tl(cpu_A0, cpu_A0, 4);
+ tcg_gen_qemu_ld_i64(cpu_bndu[reg], cpu_A0,
+ s->mem_index, MO_LEUL);
+ }
+ /* bnd registers are now in-use */
+ gen_set_hflag(s, HF_MPX_IU_MASK);
+ }
+ } else if (mod != 3) {
+ /* bndldx */
+ AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ if (reg >= 4
+ || (prefixes & PREFIX_LOCK)
+ || s->aflag == MO_16
+ || a.base < -1) {
+ goto illegal_op;
+ }
+ if (a.base >= 0) {
+ tcg_gen_addi_tl(cpu_A0, cpu_regs[a.base], a.disp);
+ } else {
+ tcg_gen_movi_tl(cpu_A0, 0);
+ }
+ gen_lea_v_seg(s, s->aflag, cpu_A0, a.def_seg, s->override);
+ if (a.index >= 0) {
+ tcg_gen_mov_tl(cpu_T0, cpu_regs[a.index]);
+ } else {
+ tcg_gen_movi_tl(cpu_T0, 0);
+ }
+ if (CODE64(s)) {
+ gen_helper_bndldx64(cpu_bndl[reg], cpu_env, cpu_A0, cpu_T0);
+ tcg_gen_ld_i64(cpu_bndu[reg], cpu_env,
+ offsetof(CPUX86State, mmx_t0.MMX_Q(0)));
+ } else {
+ gen_helper_bndldx32(cpu_bndu[reg], cpu_env, cpu_A0, cpu_T0);
+ tcg_gen_ext32u_i64(cpu_bndl[reg], cpu_bndu[reg]);
+ tcg_gen_shri_i64(cpu_bndu[reg], cpu_bndu[reg], 32);
+ }
+ gen_set_hflag(s, HF_MPX_IU_MASK);
+ }
+ }
+ gen_nop_modrm(env, s, modrm);
+ break;
+ case 0x11b:
+ modrm = cpu_ldub_code(env, s->pc++);
+ if (s->flags & HF_MPX_EN_MASK) {
+ mod = (modrm >> 6) & 3;
+ reg = ((modrm >> 3) & 7) | rex_r;
+ if (mod != 3 && (prefixes & PREFIX_REPZ)) {
+ /* bndmk */
+ if (reg >= 4
+ || (prefixes & PREFIX_LOCK)
+ || s->aflag == MO_16) {
+ goto illegal_op;
+ }
+ AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ if (a.base >= 0) {
+ tcg_gen_extu_tl_i64(cpu_bndl[reg], cpu_regs[a.base]);
+ if (!CODE64(s)) {
+ tcg_gen_ext32u_i64(cpu_bndl[reg], cpu_bndl[reg]);
+ }
+ } else if (a.base == -1) {
+ /* no base register has lower bound of 0 */
+ tcg_gen_movi_i64(cpu_bndl[reg], 0);
+ } else {
+ /* rip-relative generates #ud */
+ goto illegal_op;
+ }
+ tcg_gen_not_tl(cpu_A0, gen_lea_modrm_1(a));
+ if (!CODE64(s)) {
+ tcg_gen_ext32u_tl(cpu_A0, cpu_A0);
+ }
+ tcg_gen_extu_tl_i64(cpu_bndu[reg], cpu_A0);
+ /* bnd registers are now in-use */
+ gen_set_hflag(s, HF_MPX_IU_MASK);
+ break;
+ } else if (prefixes & PREFIX_REPNZ) {
+ /* bndcn */
+ if (reg >= 4
+ || (prefixes & PREFIX_LOCK)
+ || s->aflag == MO_16) {
+ goto illegal_op;
+ }
+ gen_bndck(env, s, modrm, TCG_COND_GTU, cpu_bndu[reg]);
+ } else if (prefixes & PREFIX_DATA) {
+ /* bndmov -- to reg/mem */
+ if (reg >= 4 || s->aflag == MO_16) {
+ goto illegal_op;
+ }
+ if (mod == 3) {
+ int reg2 = (modrm & 7) | REX_B(s);
+ if (reg2 >= 4 || (prefixes & PREFIX_LOCK)) {
+ goto illegal_op;
+ }
+ if (s->flags & HF_MPX_IU_MASK) {
+ tcg_gen_mov_i64(cpu_bndl[reg2], cpu_bndl[reg]);
+ tcg_gen_mov_i64(cpu_bndu[reg2], cpu_bndu[reg]);
+ }
+ } else {
+ gen_lea_modrm(env, s, modrm);
+ if (CODE64(s)) {
+ tcg_gen_qemu_st_i64(cpu_bndl[reg], cpu_A0,
+ s->mem_index, MO_LEQ);
+ tcg_gen_addi_tl(cpu_A0, cpu_A0, 8);
+ tcg_gen_qemu_st_i64(cpu_bndu[reg], cpu_A0,
+ s->mem_index, MO_LEQ);
+ } else {
+ tcg_gen_qemu_st_i64(cpu_bndl[reg], cpu_A0,
+ s->mem_index, MO_LEUL);
+ tcg_gen_addi_tl(cpu_A0, cpu_A0, 4);
+ tcg_gen_qemu_st_i64(cpu_bndu[reg], cpu_A0,
+ s->mem_index, MO_LEUL);
+ }
+ }
+ } else if (mod != 3) {
+ /* bndstx */
+ AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ if (reg >= 4
+ || (prefixes & PREFIX_LOCK)
+ || s->aflag == MO_16
+ || a.base < -1) {
+ goto illegal_op;
+ }
+ if (a.base >= 0) {
+ tcg_gen_addi_tl(cpu_A0, cpu_regs[a.base], a.disp);
+ } else {
+ tcg_gen_movi_tl(cpu_A0, 0);
+ }
+ gen_lea_v_seg(s, s->aflag, cpu_A0, a.def_seg, s->override);
+ if (a.index >= 0) {
+ tcg_gen_mov_tl(cpu_T0, cpu_regs[a.index]);
+ } else {
+ tcg_gen_movi_tl(cpu_T0, 0);
+ }
+ if (CODE64(s)) {
+ gen_helper_bndstx64(cpu_env, cpu_A0, cpu_T0,
+ cpu_bndl[reg], cpu_bndu[reg]);
+ } else {
+ gen_helper_bndstx32(cpu_env, cpu_A0, cpu_T0,
+ cpu_bndl[reg], cpu_bndu[reg]);
+ }
+ }
+ }
+ gen_nop_modrm(env, s, modrm);
+ break;
+ case 0x119: case 0x11c ... 0x11f: /* nop (multi byte) */
modrm = cpu_ldub_code(env, s->pc++);
gen_nop_modrm(env, s, modrm);
break;
@@ -7503,96 +7777,189 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break;
case 0x1ae:
modrm = cpu_ldub_code(env, s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- switch(op) {
- case 0: /* fxsave */
- if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
- (s->prefix & PREFIX_LOCK))
+ switch (modrm) {
+ CASE_MEM_OP(0): /* fxsave */
+ if (!(s->cpuid_features & CPUID_FXSR)
+ || (prefixes & PREFIX_LOCK)) {
goto illegal_op;
+ }
if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
break;
}
gen_lea_modrm(env, s, modrm);
- gen_helper_fxsave(cpu_env, cpu_A0, tcg_const_i32(dflag == MO_64));
+ gen_helper_fxsave(cpu_env, cpu_A0);
break;
- case 1: /* fxrstor */
- if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
- (s->prefix & PREFIX_LOCK))
+
+ CASE_MEM_OP(1): /* fxrstor */
+ if (!(s->cpuid_features & CPUID_FXSR)
+ || (prefixes & PREFIX_LOCK)) {
goto illegal_op;
+ }
if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
break;
}
gen_lea_modrm(env, s, modrm);
- gen_helper_fxrstor(cpu_env, cpu_A0, tcg_const_i32(dflag == MO_64));
+ gen_helper_fxrstor(cpu_env, cpu_A0);
break;
- case 2: /* ldmxcsr */
- case 3: /* stmxcsr */
+
+ CASE_MEM_OP(2): /* ldmxcsr */
+ if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) {
+ goto illegal_op;
+ }
if (s->flags & HF_TS_MASK) {
gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
break;
}
- if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) ||
- mod == 3)
+ gen_lea_modrm(env, s, modrm);
+ tcg_gen_qemu_ld_i32(cpu_tmp2_i32, cpu_A0, s->mem_index, MO_LEUL);
+ gen_helper_ldmxcsr(cpu_env, cpu_tmp2_i32);
+ break;
+
+ CASE_MEM_OP(3): /* stmxcsr */
+ if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) {
goto illegal_op;
+ }
+ if (s->flags & HF_TS_MASK) {
+ gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+ break;
+ }
gen_lea_modrm(env, s, modrm);
- if (op == 2) {
- tcg_gen_qemu_ld_i32(cpu_tmp2_i32, cpu_A0,
- s->mem_index, MO_LEUL);
- gen_helper_ldmxcsr(cpu_env, cpu_tmp2_i32);
- } else {
- tcg_gen_ld32u_tl(cpu_T0,
- cpu_env, offsetof(CPUX86State, mxcsr));
- gen_op_st_v(s, MO_32, cpu_T0, cpu_A0);
+ tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, mxcsr));
+ gen_op_st_v(s, MO_32, cpu_T0, cpu_A0);
+ break;
+
+ CASE_MEM_OP(4): /* xsave */
+ if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+ || (prefixes & (PREFIX_LOCK | PREFIX_DATA
+ | PREFIX_REPZ | PREFIX_REPNZ))) {
+ goto illegal_op;
}
+ gen_lea_modrm(env, s, modrm);
+ tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+ cpu_regs[R_EDX]);
+ gen_helper_xsave(cpu_env, cpu_A0, cpu_tmp1_i64);
break;
- case 5: /* lfence */
- if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
+
+ CASE_MEM_OP(5): /* xrstor */
+ if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+ || (prefixes & (PREFIX_LOCK | PREFIX_DATA
+ | PREFIX_REPZ | PREFIX_REPNZ))) {
goto illegal_op;
+ }
+ gen_lea_modrm(env, s, modrm);
+ tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+ cpu_regs[R_EDX]);
+ gen_helper_xrstor(cpu_env, cpu_A0, cpu_tmp1_i64);
+ /* XRSTOR is how MPX is enabled, which changes how
+ we translate. Thus we need to end the TB. */
+ gen_update_cc_op(s);
+ gen_jmp_im(s->pc - s->cs_base);
+ gen_eob(s);
break;
- case 6: /* mfence/clwb */
- if (s->prefix & PREFIX_DATA) {
+
+ CASE_MEM_OP(6): /* xsaveopt / clwb */
+ if (prefixes & PREFIX_LOCK) {
+ goto illegal_op;
+ }
+ if (prefixes & PREFIX_DATA) {
/* clwb */
- if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLWB))
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLWB)) {
goto illegal_op;
+ }
gen_nop_modrm(env, s, modrm);
} else {
- /* mfence */
- if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
+ /* xsaveopt */
+ if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+ || (s->cpuid_xsave_features & CPUID_XSAVE_XSAVEOPT) == 0
+ || (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))) {
goto illegal_op;
+ }
+ gen_lea_modrm(env, s, modrm);
+ tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+ cpu_regs[R_EDX]);
+ gen_helper_xsaveopt(cpu_env, cpu_A0, cpu_tmp1_i64);
}
break;
- case 7: /* sfence / clflush / clflushopt / pcommit */
- if ((modrm & 0xc7) == 0xc0) {
- if (s->prefix & PREFIX_DATA) {
- /* pcommit */
- if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_PCOMMIT))
- goto illegal_op;
- } else {
- /* sfence */
- /* XXX: also check for cpuid_ext2_features & CPUID_EXT2_EMMX */
- if (!(s->cpuid_features & CPUID_SSE))
- goto illegal_op;
+
+ CASE_MEM_OP(7): /* clflush / clflushopt */
+ if (prefixes & PREFIX_LOCK) {
+ goto illegal_op;
+ }
+ if (prefixes & PREFIX_DATA) {
+ /* clflushopt */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLFLUSHOPT)) {
+ goto illegal_op;
}
} else {
- if (s->prefix & PREFIX_DATA) {
- /* clflushopt */
- if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLFLUSHOPT))
- goto illegal_op;
+ /* clflush */
+ if ((s->prefix & (PREFIX_REPZ | PREFIX_REPNZ))
+ || !(s->cpuid_features & CPUID_CLFLUSH)) {
+ goto illegal_op;
+ }
+ }
+ gen_nop_modrm(env, s, modrm);
+ break;
+
+ case 0xc0 ... 0xc7: /* rdfsbase (f3 0f ae /0) */
+ case 0xc8 ... 0xc8: /* rdgsbase (f3 0f ae /1) */
+ case 0xd0 ... 0xd7: /* wrfsbase (f3 0f ae /2) */
+ case 0xd8 ... 0xd8: /* wrgsbase (f3 0f ae /3) */
+ if (CODE64(s)
+ && (prefixes & PREFIX_REPZ)
+ && !(prefixes & PREFIX_LOCK)
+ && (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_FSGSBASE)) {
+ TCGv base, treg, src, dst;
+
+ /* Preserve hflags bits by testing CR4 at runtime. */
+ tcg_gen_movi_i32(cpu_tmp2_i32, CR4_FSGSBASE_MASK);
+ gen_helper_cr4_testbit(cpu_env, cpu_tmp2_i32);
+
+ base = cpu_seg_base[modrm & 8 ? R_GS : R_FS];
+ treg = cpu_regs[(modrm & 7) | REX_B(s)];
+
+ if (modrm & 0x10) {
+ /* wr*base */
+ dst = base, src = treg;
} else {
- /* clflush */
- if (!(s->cpuid_features & CPUID_CLFLUSH))
- goto illegal_op;
+ /* rd*base */
+ dst = treg, src = base;
}
- gen_lea_modrm(env, s, modrm);
+
+ if (s->dflag == MO_32) {
+ tcg_gen_ext32u_tl(dst, src);
+ } else {
+ tcg_gen_mov_tl(dst, src);
+ }
+ break;
+ }
+ goto illegal_op;
+
+ case 0xf8: /* sfence / pcommit */
+ if (prefixes & PREFIX_DATA) {
+ /* pcommit */
+ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_PCOMMIT)
+ || (prefixes & PREFIX_LOCK)) {
+ goto illegal_op;
+ }
+ break;
+ }
+ /* fallthru */
+ case 0xf9 ... 0xff: /* sfence */
+ case 0xe8 ... 0xef: /* lfence */
+ case 0xf0 ... 0xf7: /* mfence */
+ if (!(s->cpuid_features & CPUID_SSE2)
+ || (prefixes & PREFIX_LOCK)) {
+ goto illegal_op;
}
break;
+
default:
goto illegal_op;
}
break;
+
case 0x10d: /* 3DNow! prefetch(w) */
modrm = cpu_ldub_code(env, s->pc++);
mod = (modrm >> 6) & 3;
@@ -7699,6 +8066,12 @@ void tcg_x86_init(void)
[R_GS] = "gs_base",
[R_SS] = "ss_base",
};
+ static const char bnd_regl_names[4][8] = {
+ "bnd0_lb", "bnd1_lb", "bnd2_lb", "bnd3_lb"
+ };
+ static const char bnd_regu_names[4][8] = {
+ "bnd0_ub", "bnd1_ub", "bnd2_ub", "bnd3_ub"
+ };
int i;
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
@@ -7724,6 +8097,17 @@ void tcg_x86_init(void)
seg_base_names[i]);
}
+ for (i = 0; i < 4; ++i) {
+ cpu_bndl[i]
+ = tcg_global_mem_new_i64(cpu_env,
+ offsetof(CPUX86State, bnd_regs[i].lb),
+ bnd_regl_names[i]);
+ cpu_bndu[i]
+ = tcg_global_mem_new_i64(cpu_env,
+ offsetof(CPUX86State, bnd_regs[i].ub),
+ bnd_regu_names[i]);
+ }
+
helper_lock_init();
}
@@ -7770,6 +8154,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
dc->cpuid_ext2_features = env->features[FEAT_8000_0001_EDX];
dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
+ dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
#ifdef TARGET_X86_64
dc->lma = (flags >> HF_LMA_SHIFT) & 1;
dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 62406ce4e1..aaa828c055 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -184,11 +184,6 @@ static inline uint64_t kvmppc_rma_size(uint64_t current_size,
return ram_size;
}
-static inline int kvmppc_update_sdr1(CPUPPCState *env)
-{
- return 0;
-}
-
#endif /* !CONFIG_USER_ONLY */
static inline bool kvmppc_has_cap_epr(void)
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index ab0f86b222..e7d9925411 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -102,7 +102,7 @@ static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
uint64_t addr;
addr = token + (index * HASH_PTE_SIZE_64);
- if (env->external_htab) {
+ if (kvmppc_kern_htab || env->external_htab) {
return ldq_p((const void *)(uintptr_t)addr);
} else {
return ldq_phys(CPU(cpu)->as, addr);
@@ -116,7 +116,7 @@ static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
uint64_t addr;
addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
- if (env->external_htab) {
+ if (kvmppc_kern_htab || env->external_htab) {
return ldq_p((const void *)(uintptr_t)addr);
} else {
return ldq_phys(CPU(cpu)->as, addr);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index ffef754fe0..ecc85f0e6d 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -11352,7 +11352,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
case POWERPC_MMU_64B:
case POWERPC_MMU_2_03:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06a:
case POWERPC_MMU_2_07:
+ case POWERPC_MMU_2_07a:
#endif
cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " DAR " TARGET_FMT_lx
" DSISR " TARGET_FMT_lx "\n", env->spr[SPR_SDR1],
diff --git a/tests/Makefile b/tests/Makefile
index fc042f7309..839d357d46 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -391,8 +391,8 @@ test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
tests/test-qapi-event.o tests/test-qmp-introspect.o \
$(test-qom-obj-y)
test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
-test-block-obj-y = $(block-obj-y) $(test-crypto-obj-y)
test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
+test-block-obj-y = $(block-obj-y) $(test-io-obj-y)
tests/check-qint$(EXESUF): tests/check-qint.o $(test-util-obj-y)
tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
diff --git a/tests/ac97-test.c b/tests/ac97-test.c
index af30ea1dd6..75cab8f98f 100644
--- a/tests/ac97-test.c
+++ b/tests/ac97-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 3488058a18..0a80ddf04b 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -10,13 +10,11 @@
* See the COPYING file in the top-level directory.
*/
-#include <string.h>
-#include <stdio.h>
+#include "qemu/osdep.h"
#include <glib.h>
#include <glib/gstdio.h>
#include "qemu-common.h"
#include "libqtest.h"
-#include "qemu/compiler.h"
#include "hw/acpi/acpi-defs.h"
#include "hw/smbios/smbios.h"
#include "qemu/bitmap.h"
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
index 360a6911eb..210964a00c 100644
--- a/tests/boot-order-test.c
+++ b/tests/boot-order-test.c
@@ -10,7 +10,7 @@
* See the COPYING file in the top-level directory.
*/
-#include <string.h>
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqos/fw_cfg.h"
#include "libqtest.h"
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index a136f2addf..a43056c5de 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -9,6 +9,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qapi/qmp/qint.h"
diff --git a/tests/check-qfloat.c b/tests/check-qfloat.c
index 6404ac8df6..3102608f55 100644
--- a/tests/check-qfloat.c
+++ b/tests/check-qfloat.c
@@ -10,6 +10,7 @@
* See the COPYING.LIB file in the top-level directory.
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qapi/qmp/qfloat.h"
diff --git a/tests/check-qint.c b/tests/check-qint.c
index 86868844ab..c86f7dfa38 100644
--- a/tests/check-qint.c
+++ b/tests/check-qint.c
@@ -9,6 +9,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qapi/qmp/qint.h"
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 61e9bfbabf..99de6f5252 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -10,6 +10,7 @@
* See the COPYING.LIB file in the top-level directory.
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qapi/qmp/qstring.h"
diff --git a/tests/check-qlist.c b/tests/check-qlist.c
index b9c05d43fd..f231d5fa97 100644
--- a/tests/check-qlist.c
+++ b/tests/check-qlist.c
@@ -9,6 +9,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qapi/qmp/qint.h"
diff --git a/tests/check-qom-interface.c b/tests/check-qom-interface.c
index f06380ef14..09354deb70 100644
--- a/tests/check-qom-interface.c
+++ b/tests/check-qom-interface.c
@@ -9,6 +9,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qom/object.h"
diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c
index 448d270b68..a2bb556906 100644
--- a/tests/check-qom-proplist.c
+++ b/tests/check-qom-proplist.c
@@ -18,6 +18,7 @@
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qom/object.h"
diff --git a/tests/check-qstring.c b/tests/check-qstring.c
index 95dc9e3e7b..9877b42c89 100644
--- a/tests/check-qstring.c
+++ b/tests/check-qstring.c
@@ -9,6 +9,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qapi/qmp/qstring.h"
diff --git a/tests/crypto-tls-x509-helpers.c b/tests/crypto-tls-x509-helpers.c
index 47b4c7ba53..64073d3bd3 100644
--- a/tests/crypto-tls-x509-helpers.c
+++ b/tests/crypto-tls-x509-helpers.c
@@ -18,10 +18,8 @@
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
-#include <stdlib.h>
-#include <fcntl.h>
+#include "qemu/osdep.h"
-#include "config-host.h"
#include "crypto-tls-x509-helpers.h"
#include "qemu/sockets.h"
diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c
index 11d5fea3e2..4477926014 100644
--- a/tests/device-introspect-test.c
+++ b/tests/device-introspect-test.c
@@ -17,8 +17,8 @@
* bugs around here.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdarg.h>
#include "qemu-common.h"
#include "qapi/qmp/qstring.h"
#include "libqtest.h"
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
index 7694344eaf..5706d338a1 100644
--- a/tests/display-vga-test.c
+++ b/tests/display-vga-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
static void pci_cirrus(void)
{
diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c
index 33909469f1..fe03236f3a 100644
--- a/tests/drive_del-test.c
+++ b/tests/drive_del-test.c
@@ -10,8 +10,8 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
static void drive_add(void)
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
index 7d513d8972..2792415841 100644
--- a/tests/ds1338-test.c
+++ b/tests/ds1338-test.c
@@ -17,6 +17,7 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include "libqtest.h"
#include "libqos/i2c.h"
diff --git a/tests/e1000-test.c b/tests/e1000-test.c
index 7ca6d7e72e..a42b3810c1 100644
--- a/tests/e1000-test.c
+++ b/tests/e1000-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void test_device(gconstpointer data)
diff --git a/tests/eepro100-test.c b/tests/eepro100-test.c
index 8bfaccdcbb..e17eed0b7a 100644
--- a/tests/eepro100-test.c
+++ b/tests/eepro100-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
static void test_device(gconstpointer data)
{
diff --git a/tests/endianness-test.c b/tests/endianness-test.c
index 2054338e18..cc5bccd88e 100644
--- a/tests/endianness-test.c
+++ b/tests/endianness-test.c
@@ -11,11 +11,8 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "libqtest.h"
#include "qemu/bswap.h"
diff --git a/tests/es1370-test.c b/tests/es1370-test.c
index cc23fb5c67..824dc31c64 100644
--- a/tests/es1370-test.c
+++ b/tests/es1370-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index dbabf50a9a..53df1d0d88 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -22,9 +22,7 @@
* THE SOFTWARE.
*/
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
+#include "qemu/osdep.h"
#include <glib.h>
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
index b7d4007e32..398643aada 100644
--- a/tests/fw_cfg-test.c
+++ b/tests/fw_cfg-test.c
@@ -10,7 +10,7 @@
* See the COPYING file in the top-level directory.
*/
-#include <string.h>
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
index 13b763d6a7..c8e669ac26 100644
--- a/tests/hd-geo-test.c
+++ b/tests/hd-geo-test.c
@@ -15,10 +15,8 @@
* Improvements welcome.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "qemu-common.h"
#include "libqtest.h"
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
index 7fa170990f..05029e90b2 100644
--- a/tests/i440fx-test.c
+++ b/tests/i440fx-test.c
@@ -12,13 +12,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
#include <sys/mman.h>
-#include <stdlib.h>
#include "libqtest.h"
#include "libqos/pci.h"
@@ -27,8 +23,6 @@
#define BROKEN 1
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
-
typedef struct TestData
{
int num_cpus;
diff --git a/tests/i82801b11-test.c b/tests/i82801b11-test.c
index 78d9ce0e6b..c3b5ebbca1 100644
--- a/tests/i82801b11-test.c
+++ b/tests/i82801b11-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c
index d89b407dcc..1be6add9b5 100644
--- a/tests/intel-hda-test.c
+++ b/tests/intel-hda-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
#define HDA_ID "hda0"
#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \
diff --git a/tests/io-channel-helpers.c b/tests/io-channel-helpers.c
index 78d36dd703..844066904b 100644
--- a/tests/io-channel-helpers.c
+++ b/tests/io-channel-helpers.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include "io-channel-helpers.h"
struct QIOChannelTest {
diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c
index c991a5f873..93eb2f7506 100644
--- a/tests/ioh3420-test.c
+++ b/tests/ioh3420-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/ipmi-bt-test.c b/tests/ipmi-bt-test.c
index 5b7eb73949..812907fb7b 100644
--- a/tests/ipmi-bt-test.c
+++ b/tests/ipmi-bt-test.c
@@ -22,10 +22,7 @@
* THE SOFTWARE.
*/
-#include <sys/types.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
+#include "qemu/osdep.h"
#include <sys/socket.h>
#include <netinet/in.h>
diff --git a/tests/ipmi-kcs-test.c b/tests/ipmi-kcs-test.c
index 564c470f55..42c4b974c5 100644
--- a/tests/ipmi-kcs-test.c
+++ b/tests/ipmi-kcs-test.c
@@ -22,9 +22,7 @@
* THE SOFTWARE.
*/
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
+#include "qemu/osdep.h"
#include <glib.h>
diff --git a/tests/ipoctal232-test.c b/tests/ipoctal232-test.c
index 3ac1714b48..846aaf5711 100644
--- a/tests/ipoctal232-test.c
+++ b/tests/ipoctal232-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index 705fece717..e184c67a1d 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -8,17 +8,13 @@
* See the COPYING file in the top-level directory.
*/
-#include <errno.h>
-#include <fcntl.h>
+#include "qemu/osdep.h"
#include <glib.h>
#include <glib/gstdio.h>
-#include <string.h>
#include <sys/mman.h>
-#include <unistd.h>
#include "contrib/ivshmem-server/ivshmem-server.h"
#include "libqos/pci-pc.h"
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "qemu-common.h"
#define TMPSHMSIZE (1 << 20)
diff --git a/tests/libqos/fw_cfg.c b/tests/libqos/fw_cfg.c
index ef00fedf1a..76894d5759 100644
--- a/tests/libqos/fw_cfg.c
+++ b/tests/libqos/fw_cfg.c
@@ -12,6 +12,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqos/fw_cfg.h"
#include "libqtest.h"
diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c
index b5cef66b94..51c3468f97 100644
--- a/tests/libqos/i2c-imx.c
+++ b/tests/libqos/i2c-imx.c
@@ -17,12 +17,11 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include "libqos/i2c.h"
#include <glib.h>
-#include <string.h>
-#include "qemu/osdep.h"
#include "libqtest.h"
#include "hw/i2c/imx_i2c.h"
diff --git a/tests/libqos/i2c-omap.c b/tests/libqos/i2c-omap.c
index 3d4d45d848..2028f2f146 100644
--- a/tests/libqos/i2c-omap.c
+++ b/tests/libqos/i2c-omap.c
@@ -6,12 +6,11 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/i2c.h"
#include <glib.h>
-#include <string.h>
-#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "libqtest.h"
diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c
index da7592f713..23bc2a3eb2 100644
--- a/tests/libqos/i2c.c
+++ b/tests/libqos/i2c.c
@@ -6,6 +6,7 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/i2c.h"
#include "libqtest.h"
diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
index 1403699377..72b5e3ba09 100644
--- a/tests/libqos/libqos-pc.c
+++ b/tests/libqos/libqos-pc.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include "libqos/libqos-pc.h"
#include "libqos/malloc-pc.h"
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index 2d1a802dbe..79b0b29b4d 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -1,9 +1,5 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "qemu/osdep.h"
#include <glib.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <sys/wait.h>
#include "libqtest.h"
diff --git a/tests/libqos/malloc-generic.c b/tests/libqos/malloc-generic.c
index d30a2f4240..6000df2b82 100644
--- a/tests/libqos/malloc-generic.c
+++ b/tests/libqos/malloc-generic.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqos/malloc-generic.h"
#include "libqos/malloc.h"
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index 6e253b6877..74f76c59db 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/malloc-pc.h"
#include "libqos/fw_cfg.h"
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index 19d05cafa6..c0df52f338 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -10,10 +10,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/malloc.h"
#include "qemu-common.h"
-#include <stdio.h>
-#include <inttypes.h>
#include <glib.h>
typedef QTAILQ_HEAD(MemList, MemBlock) MemList;
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 6dba0db00a..08167c09fe 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqtest.h"
#include "libqos/pci-pc.h"
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index 80b1a2117d..0e104e14ed 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/pci.h"
#include "hw/pci/pci_regs.h"
diff --git a/tests/libqos/usb.c b/tests/libqos/usb.c
index 41d89b8487..87efb90782 100644
--- a/tests/libqos/usb.c
+++ b/tests/libqos/usb.c
@@ -11,10 +11,9 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "hw/usb/uhci-regs.h"
#include "libqos/usb.h"
diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
index b3e62e77d8..a4382f3660 100644
--- a/tests/libqos/virtio-mmio.c
+++ b/tests/libqos/virtio-mmio.c
@@ -7,8 +7,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
#include "libqtest.h"
#include "libqos/virtio.h"
#include "libqos/virtio-mmio.h"
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index f9fb924b8e..fde2ff0bcb 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -7,8 +7,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
#include "libqtest.h"
#include "libqos/virtio.h"
#include "libqos/virtio-pci.h"
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 3205b88d90..613decea5a 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
#include "libqos/virtio.h"
diff --git a/tests/libqtest.c b/tests/libqtest.c
index fa314e1ee7..b12a9e4ca9 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -14,22 +14,14 @@
* See the COPYING file in the top-level directory.
*
*/
+#include "qemu/osdep.h"
#include "libqtest.h"
#include <glib.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "qemu/compiler.h"
-#include "qemu/osdep.h"
+
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/json-streamer.h"
#include "qapi/qmp/qjson.h"
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
index 71b4f28052..a751fd350e 100644
--- a/tests/m48t59-test.c
+++ b/tests/m48t59-test.c
@@ -12,11 +12,8 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "libqtest.h"
diff --git a/tests/ne2000-test.c b/tests/ne2000-test.c
index 61a678ad30..3727875f2e 100644
--- a/tests/ne2000-test.c
+++ b/tests/ne2000-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void pci_nop(void)
diff --git a/tests/nvme-test.c b/tests/nvme-test.c
index ff38b5e48f..ec06893eee 100644
--- a/tests/nvme-test.c
+++ b/tests/nvme-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/pc-cpu-test.c b/tests/pc-cpu-test.c
index 3505c7c43f..6b34ca588b 100644
--- a/tests/pc-cpu-test.c
+++ b/tests/pc-cpu-test.c
@@ -7,12 +7,11 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "qemu-common.h"
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "qapi/qmp/types.h"
struct PCTestData {
diff --git a/tests/pcnet-test.c b/tests/pcnet-test.c
index 84af4f327a..2ddf4965c6 100644
--- a/tests/pcnet-test.c
+++ b/tests/pcnet-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void pci_nop(void)
diff --git a/tests/pkix_asn1_tab.c b/tests/pkix_asn1_tab.c
index 5b4e6b9e2d..903bc02518 100644
--- a/tests/pkix_asn1_tab.c
+++ b/tests/pkix_asn1_tab.c
@@ -3,6 +3,7 @@
* and is under copyright of various GNUTLS contributors.
*/
+#include "qemu/osdep.h"
#include <libtasn1.h>
const ASN1_ARRAY_TYPE pkix_asn1_tab[] = {
diff --git a/tests/pvpanic-test.c b/tests/pvpanic-test.c
index a7ad6b3064..d435833f79 100644
--- a/tests/pvpanic-test.c
+++ b/tests/pvpanic-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
static void test_panic(void)
{
diff --git a/tests/q35-test.c b/tests/q35-test.c
index 812abe5480..a105f10782 100644
--- a/tests/q35-test.c
+++ b/tests/q35-test.c
@@ -9,12 +9,11 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
-#include "qemu/osdep.h"
#include "hw/pci-host/q35.h"
static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled)
diff --git a/tests/qemu-iotests/140.out b/tests/qemu-iotests/140.out
index fdedeb3973..72f1b4cf1c 100644
--- a/tests/qemu-iotests/140.out
+++ b/tests/qemu-iotests/140.out
@@ -9,7 +9,7 @@ read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "drv", "tray-open": true}}
{"return": {}}
-can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: Failed to read export length
+can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: No export with name 'drv' available
no file open, try 'help open'
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out
index dad20240a4..d24ad20db3 100644
--- a/tests/qemu-iotests/143.out
+++ b/tests/qemu-iotests/143.out
@@ -1,7 +1,7 @@
QA output created by 143
{"return": {}}
{"return": {}}
-can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: Failed to read export length
+can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: No export with name 'no_such_export' available
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
*** done
diff --git a/tests/qemu-iotests/socket_scm_helper.c b/tests/qemu-iotests/socket_scm_helper.c
index 81959835eb..80cadf43bc 100644
--- a/tests/qemu-iotests/socket_scm_helper.c
+++ b/tests/qemu-iotests/socket_scm_helper.c
@@ -10,15 +10,9 @@
* See the COPYING.LIB file in the top-level directory.
*/
-#include <stdio.h>
-#include <errno.h>
+#include "qemu/osdep.h"
#include <sys/socket.h>
#include <sys/un.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
/* #define SOCKET_SCM_DEBUG */
diff --git a/tests/qom-test.c b/tests/qom-test.c
index 3e5e8730e7..3c6cfca788 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -7,12 +7,11 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "qemu-common.h"
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "qapi/qmp/types.h"
static const char *blacklist_x86[] = {
diff --git a/tests/rcutorture.c b/tests/rcutorture.c
index d6b304d000..244f0f28b2 100644
--- a/tests/rcutorture.c
+++ b/tests/rcutorture.c
@@ -60,13 +60,10 @@
* Test variables.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
#include "qemu/atomic.h"
#include "qemu/rcu.h"
-#include "qemu/compiler.h"
#include "qemu/thread.h"
long long n_reads = 0LL;
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 4243624de6..fa7029aa8a 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -11,11 +11,8 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "libqtest.h"
#include "hw/timer/mc146818rtc_regs.h"
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
index ba62851cae..54e5aa7d0e 100644
--- a/tests/rtl8139-test.c
+++ b/tests/rtl8139-test.c
@@ -7,11 +7,10 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
#include "libqos/pci-pc.h"
-#include "qemu/osdep.h"
#include "qemu/timer.h"
#include "qemu-common.h"
diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c
index b629de475a..f53911d9f7 100644
--- a/tests/spapr-phb-test.c
+++ b/tests/spapr-phb-test.c
@@ -7,6 +7,7 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
diff --git a/tests/tco-test.c b/tests/tco-test.c
index 419f7cf46c..ac11175e90 100644
--- a/tests/tco-test.c
+++ b/tests/tco-test.c
@@ -6,10 +6,8 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
#include "libqtest.h"
#include "libqos/pci.h"
diff --git a/tests/test-aio.c b/tests/test-aio.c
index 6ccea98977..a109bd0c42 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -10,6 +10,7 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "block/aio.h"
#include "qemu/timer.h"
diff --git a/tests/test-base64.c b/tests/test-base64.c
index a0ca2d8de8..ae0c107c7d 100644
--- a/tests/test-base64.c
+++ b/tests/test-base64.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu/base64.h"
diff --git a/tests/test-bitops.c b/tests/test-bitops.c
index 47b5d3ed9a..5050950607 100644
--- a/tests/test-bitops.c
+++ b/tests/test-bitops.c
@@ -6,9 +6,8 @@
*
*/
-#include <glib.h>
-#include <stdint.h>
#include "qemu/osdep.h"
+#include <glib.h>
#include "qemu/bitops.h"
typedef struct {
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
index 34747e924d..c866da66c8 100644
--- a/tests/test-blockjob-txn.c
+++ b/tests/test-blockjob-txn.c
@@ -10,8 +10,8 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "block/blockjob.h"
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index f5951cb1f1..dd4ced946c 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -11,6 +11,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu/coroutine.h"
#include "qemu/coroutine_int.h"
diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
index c687307bcd..9f912eccb5 100644
--- a/tests/test-crypto-cipher.c
+++ b/tests/test-crypto-cipher.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "crypto/init.h"
diff --git a/tests/test-crypto-hash.c b/tests/test-crypto-hash.c
index 3ec31dde7b..735d6d7e0b 100644
--- a/tests/test-crypto-hash.c
+++ b/tests/test-crypto-hash.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "crypto/init.h"
diff --git a/tests/test-crypto-secret.c b/tests/test-crypto-secret.c
index a49c8e31e8..2bbc4d9e3c 100644
--- a/tests/test-crypto-secret.c
+++ b/tests/test-crypto-secret.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "crypto/init.h"
diff --git a/tests/test-crypto-tlscredsx509.c b/tests/test-crypto-tlscredsx509.c
index c70aa5563a..7ca387db65 100644
--- a/tests/test-crypto-tlscredsx509.c
+++ b/tests/test-crypto-tlscredsx509.c
@@ -18,10 +18,8 @@
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
-#include <stdlib.h>
-#include <fcntl.h>
+#include "qemu/osdep.h"
-#include "config-host.h"
#include "crypto-tls-x509-helpers.h"
#include "crypto/tlscredsx509.h"
diff --git a/tests/test-crypto-tlssession.c b/tests/test-crypto-tlssession.c
index 4524128fca..036a86b0c3 100644
--- a/tests/test-crypto-tlssession.c
+++ b/tests/test-crypto-tlssession.c
@@ -18,10 +18,8 @@
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
-#include <stdlib.h>
-#include <fcntl.h>
+#include "qemu/osdep.h"
-#include "config-host.h"
#include "crypto-tls-x509-helpers.h"
#include "crypto/tlscredsx509.h"
#include "crypto/tlssession.h"
diff --git a/tests/test-cutils.c b/tests/test-cutils.c
index a3de6ab870..398700df45 100644
--- a/tests/test-cutils.c
+++ b/tests/test-cutils.c
@@ -25,9 +25,8 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <errno.h>
-#include <string.h>
#include "qemu-common.h"
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
index abcea0cda6..abe1427917 100644
--- a/tests/test-hbitmap.c
+++ b/tests/test-hbitmap.c
@@ -9,10 +9,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/types.h>
#include "qemu/hbitmap.h"
#define LOG_BITS_PER_LONG (BITS_PER_LONG == 32 ? 5 : 6)
diff --git a/tests/test-int128.c b/tests/test-int128.c
index 0772ef7538..cacf6beac8 100644
--- a/tests/test-int128.c
+++ b/tests/test-int128.c
@@ -6,10 +6,9 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
#include "qemu/int128.h"
-#include "qemu/osdep.h"
/* clang doesn't support __noclone__ but it does have a mechanism for
* telling us this. We assume that if we don't have __has_attribute()
diff --git a/tests/test-io-channel-buffer.c b/tests/test-io-channel-buffer.c
index 6637501b41..64722a214b 100644
--- a/tests/test-io-channel-buffer.c
+++ b/tests/test-io-channel-buffer.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include "io/channel-buffer.h"
#include "io-channel-helpers.h"
diff --git a/tests/test-io-channel-command.c b/tests/test-io-channel-command.c
index 03cac36a3f..885543760a 100644
--- a/tests/test-io-channel-command.c
+++ b/tests/test-io-channel-command.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include "io/channel-command.h"
#include "io-channel-helpers.h"
diff --git a/tests/test-io-channel-file.c b/tests/test-io-channel-file.c
index f276a32de0..1e7f3c7f12 100644
--- a/tests/test-io-channel-file.c
+++ b/tests/test-io-channel-file.c
@@ -18,7 +18,9 @@
*
*/
+#include "qemu/osdep.h"
#include "io/channel-file.h"
+#include "io/channel-util.h"
#include "io-channel-helpers.h"
@@ -49,6 +51,26 @@ static void test_io_channel_file(void)
}
+static void test_io_channel_fd(void)
+{
+ QIOChannel *ioc;
+ int fd = -1;
+
+#define TEST_FILE "tests/test-io-channel-file.txt"
+ fd = open(TEST_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ g_assert_cmpint(fd, >, -1);
+
+ ioc = qio_channel_new_fd(fd, &error_abort);
+
+ g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
+ ==,
+ TYPE_QIO_CHANNEL_FILE);
+
+ unlink(TEST_FILE);
+ object_unref(OBJECT(ioc));
+}
+
+
#ifndef _WIN32
static void test_io_channel_pipe(bool async)
{
@@ -92,6 +114,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
g_test_add_func("/io/channel/file", test_io_channel_file);
+ g_test_add_func("/io/channel/file/fd", test_io_channel_fd);
#ifndef _WIN32
g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync);
g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async);
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index 1a36a3c696..069736373c 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -18,7 +18,9 @@
*
*/
+#include "qemu/osdep.h"
#include "io/channel-socket.h"
+#include "io/channel-util.h"
#include "io-channel-helpers.h"
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
@@ -473,6 +475,24 @@ static void test_io_channel_unix_fd_pass(void)
#endif /* _WIN32 */
+static void test_io_channel_ipv4_fd(void)
+{
+ QIOChannel *ioc;
+ int fd = -1;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ g_assert_cmpint(fd, >, -1);
+
+ ioc = qio_channel_new_fd(fd, &error_abort);
+
+ g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
+ ==,
+ TYPE_QIO_CHANNEL_SOCKET);
+
+ object_unref(OBJECT(ioc));
+}
+
+
int main(int argc, char **argv)
{
bool has_ipv4, has_ipv6;
@@ -495,6 +515,8 @@ int main(int argc, char **argv)
test_io_channel_ipv4_sync);
g_test_add_func("/io/channel/socket/ipv4-async",
test_io_channel_ipv4_async);
+ g_test_add_func("/io/channel/socket/ipv4-fd",
+ test_io_channel_ipv4_fd);
}
if (has_ipv6) {
g_test_add_func("/io/channel/socket/ipv6-sync",
diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
index 3c11a5097c..3c361a7bef 100644
--- a/tests/test-io-channel-tls.c
+++ b/tests/test-io-channel-tls.c
@@ -21,10 +21,8 @@
*/
-#include <stdlib.h>
-#include <fcntl.h>
+#include "qemu/osdep.h"
-#include "config-host.h"
#include "crypto-tls-x509-helpers.h"
#include "io/channel-tls.h"
#include "io/channel-socket.h"
diff --git a/tests/test-io-task.c b/tests/test-io-task.c
index 3344382c7f..ae46c56a47 100644
--- a/tests/test-io-task.c
+++ b/tests/test-io-task.c
@@ -18,6 +18,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "io/task.h"
diff --git a/tests/test-iov.c b/tests/test-iov.c
index 46e4dddc55..3f25268dd4 100644
--- a/tests/test-iov.c
+++ b/tests/test-iov.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
#include "qemu/iov.h"
diff --git a/tests/test-mul64.c b/tests/test-mul64.c
index a0a17f7775..1282ec5a22 100644
--- a/tests/test-mul64.c
+++ b/tests/test-mul64.c
@@ -6,10 +6,9 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdint.h>
#include "qemu/host-utils.h"
-#include "qemu/osdep.h"
typedef struct {
diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c
index 303deb7e09..7d105c3232 100644
--- a/tests/test-netfilter.c
+++ b/tests/test-netfilter.c
@@ -8,6 +8,7 @@
* later. See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
diff --git a/tests/test-opts-visitor.c b/tests/test-opts-visitor.c
index 9600b97012..b7acf7d294 100644
--- a/tests/test-opts-visitor.c
+++ b/tests/test-opts-visitor.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu/config-file.h" /* qemu_add_opts() */
diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c
index 07c182338b..f0cc31e113 100644
--- a/tests/test-qdev-global-props.c
+++ b/tests/test-qdev-global-props.c
@@ -22,8 +22,8 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdint.h>
#include "hw/qdev.h"
#include "qom/object.h"
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index 0c1136d1b2..848374e2bd 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -7,12 +7,11 @@
* See the COPYING.LIB file in the top-level directory.
*/
-#include "qapi/error.h"
+#include "qemu/osdep.h"
#include "qapi/qmp/qstring.h"
#include "qemu/config-file.h"
#include <glib.h>
-#include <string.h>
static QemuOptsList opts_list_01 = {
.name = "opts_list_01",
diff --git a/tests/test-qga.c b/tests/test-qga.c
index e6a84d17f0..0973b487d2 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -1,18 +1,11 @@
+#include "qemu/osdep.h"
#include <locale.h>
#include <glib.h>
#include <glib/gstdio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <unistd.h>
-#include <inttypes.h>
#include "libqtest.h"
-#include "config-host.h"
#include "qga/guest-agent-core.h"
typedef struct {
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 4d267b6a83..d6171f2d44 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
#include "qapi/qmp/types.h"
diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index 035c65cfdf..a296fdbac2 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -11,8 +11,8 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdarg.h>
#include "qemu-common.h"
#include "test-qapi-types.h"
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
index 775ad39d93..6a33aa41e5 100644
--- a/tests/test-qmp-input-strict.c
+++ b/tests/test-qmp-input-strict.c
@@ -11,8 +11,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdarg.h>
#include "qemu-common.h"
#include "qapi/qmp-input-visitor.h"
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index f6bd408db3..c72cdad563 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -10,8 +10,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdarg.h>
#include "qemu-common.h"
#include "qapi/qmp-input-visitor.h"
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 26dc752b81..965f298e11 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
diff --git a/tests/test-rcu-list.c b/tests/test-rcu-list.c
index daa8bf41db..79d3750144 100644
--- a/tests/test-rcu-list.c
+++ b/tests/test-rcu-list.c
@@ -20,14 +20,10 @@
* Copyright (c) 2013 Mike D. Day, IBM Corporation.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
#include "qemu/atomic.h"
#include "qemu/rcu.h"
-#include "qemu/compiler.h"
-#include "qemu/osdep.h"
#include "qemu/thread.h"
#include "qemu/rcu_queue.h"
diff --git a/tests/test-rfifolock.c b/tests/test-rfifolock.c
index 0572ebb42a..9a3cb243ba 100644
--- a/tests/test-rfifolock.c
+++ b/tests/test-rfifolock.c
@@ -10,6 +10,7 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
#include "qemu/rfifolock.h"
diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c
index d99498d098..4b48ec25d3 100644
--- a/tests/test-string-input-visitor.c
+++ b/tests/test-string-input-visitor.c
@@ -10,8 +10,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdarg.h>
#include "qemu-common.h"
#include "qapi/string-input-visitor.h"
diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c
index 4f4450fe70..0beccf98c7 100644
--- a/tests/test-string-output-visitor.c
+++ b/tests/test-string-output-visitor.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c
index ccdee39993..40600b40bb 100644
--- a/tests/test-thread-pool.c
+++ b/tests/test-thread-pool.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
#include "block/aio.h"
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
index a95039fdbf..858f1aa43f 100644
--- a/tests/test-throttle.c
+++ b/tests/test-throttle.c
@@ -12,6 +12,7 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include <math.h>
#include "block/aio.h"
diff --git a/tests/test-timed-average.c b/tests/test-timed-average.c
index a049799b80..1cc4ab3027 100644
--- a/tests/test-timed-average.c
+++ b/tests/test-timed-average.c
@@ -10,8 +10,8 @@
* See the COPYING.LIB file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <unistd.h>
#include "qemu/timed-average.h"
diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index f74a6df97b..ef4dac5e01 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -11,9 +11,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdlib.h>
-#include <stdint.h>
#include <float.h>
#include "qemu-common.h"
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index 4d13bd09b3..713d4443b2 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "qemu-common.h"
diff --git a/tests/test-write-threshold.c b/tests/test-write-threshold.c
index faffa7b855..fdbc8020fd 100644
--- a/tests/test-write-threshold.c
+++ b/tests/test-write-threshold.c
@@ -6,8 +6,8 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdint.h>
#include "block/block_int.h"
#include "block/write-threshold.h"
diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c
index 6cd20d4a23..8eb0bc6ad5 100644
--- a/tests/test-x86-cpuid.c
+++ b/tests/test-x86-cpuid.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "hw/i386/topology.h"
diff --git a/tests/test-xbzrle.c b/tests/test-xbzrle.c
index 1cd8cb7d78..abd309d418 100644
--- a/tests/test-xbzrle.c
+++ b/tests/test-xbzrle.c
@@ -10,11 +10,7 @@
* See the COPYING file in the top-level directory.
*
*/
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "include/migration/migration.h"
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
index 99db538191..235cae0137 100644
--- a/tests/tmp105-test.c
+++ b/tests/tmp105-test.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
diff --git a/tests/tpci200-test.c b/tests/tpci200-test.c
index 9ae01277ee..cb2b00ca8b 100644
--- a/tests/tpci200-test.c
+++ b/tests/tpci200-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c
index f5030b247b..f2b6c67e5b 100644
--- a/tests/vhost-user-bridge.c
+++ b/tests/vhost-user-bridge.c
@@ -29,23 +29,13 @@
#define _FILE_OFFSET_BITS 64
-#include <stddef.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
+#include "qemu/osdep.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/unistd.h>
#include <sys/mman.h>
#include <sys/eventfd.h>
#include <arpa/inet.h>
-#include <ctype.h>
#include <netdb.h>
#include <qemu/osdep.h>
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index e30b7f4abc..69615968ce 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -8,6 +8,7 @@
*
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
diff --git a/tests/virtio-balloon-test.c b/tests/virtio-balloon-test.c
index becebb51a7..b010ce98e8 100644
--- a/tests/virtio-balloon-test.c
+++ b/tests/virtio-balloon-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void pci_nop(void)
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 4078321a20..3a66630d79 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -8,11 +8,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
#include "libqtest.h"
#include "libqos/virtio.h"
#include "libqos/virtio-pci.h"
diff --git a/tests/virtio-console-test.c b/tests/virtio-console-test.c
index 6be96e8c64..0b9c2a55ef 100644
--- a/tests/virtio-console-test.c
+++ b/tests/virtio-console-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void console_pci_nop(void)
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index 982d77a14b..04cfcd594e 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -7,12 +7,11 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
#include "qemu-common.h"
#include "qemu/sockets.h"
-#include "qemu/osdep.h"
#include "qemu/iov.h"
#include "libqos/pci-pc.h"
#include "libqos/virtio.h"
diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c
index 41c1cdb1aa..771dbd73af 100644
--- a/tests/virtio-rng-test.c
+++ b/tests/virtio-rng-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "libqos/pci.h"
#define PCI_SLOT_HP 0x06
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 66d8491e9d..d78747a466 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -8,11 +8,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
-#include <stdio.h>
#include "block/scsi.h"
#include "libqos/virtio.h"
#include "libqos/virtio-pci.h"
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
index bf030a6162..480d4abb2d 100644
--- a/tests/virtio-serial-test.c
+++ b/tests/virtio-serial-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void pci_nop(void)
diff --git a/tests/vmxnet3-test.c b/tests/vmxnet3-test.c
index a2ebed39cc..6ef0e2f043 100644
--- a/tests/vmxnet3-test.c
+++ b/tests/vmxnet3-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
/* Tests only initialization so far. TODO: Replace with functional tests */
static void nop(void)
diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c
index 82ca597252..efe3370453 100644
--- a/tests/wdt_ib700-test.c
+++ b/tests/wdt_ib700-test.c
@@ -7,10 +7,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "qemu/timer.h"
static void qmp_check_no_event(void)
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index d844387b79..7615be4e7a 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -26,15 +26,6 @@
* THE SOFTWARE.
*/
-/* The following block of code temporarily renames the daemon() function so the
- compiler does not see the warning associated with it in stdlib.h on OSX */
-#ifdef __APPLE__
-#define daemon qemu_fake_daemon_function
-#include <stdlib.h>
-#undef daemon
-extern int daemon(int, int);
-#endif
-
#if defined(__linux__) && (defined(__x86_64__) || defined(__arm__))
/* Use 2 MiB alignment so transparent hugepages can be used by KVM.
Valgrind does not support alignments larger than 1 MiB,
diff --git a/vl.c b/vl.c
index 175ebccb81..18e6086ffe 100644
--- a/vl.c
+++ b/vl.c
@@ -579,6 +579,7 @@ static const RunStateTransition runstate_transitions_def[] = {
/* from -> to */
{ RUN_STATE_DEBUG, RUN_STATE_RUNNING },
{ RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_DEBUG, RUN_STATE_PRELAUNCH },
{ RUN_STATE_INMIGRATE, RUN_STATE_INTERNAL_ERROR },
{ RUN_STATE_INMIGRATE, RUN_STATE_IO_ERROR },
@@ -589,18 +590,24 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_INMIGRATE, RUN_STATE_WATCHDOG },
{ RUN_STATE_INMIGRATE, RUN_STATE_GUEST_PANICKED },
{ RUN_STATE_INMIGRATE, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
+ { RUN_STATE_INMIGRATE, RUN_STATE_POSTMIGRATE },
{ RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
{ RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PRELAUNCH },
{ RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
{ RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_IO_ERROR, RUN_STATE_PRELAUNCH },
{ RUN_STATE_PAUSED, RUN_STATE_RUNNING },
{ RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH },
{ RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
{ RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_POSTMIGRATE, RUN_STATE_PRELAUNCH },
{ RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
{ RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE },
@@ -608,8 +615,10 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
{ RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
+ { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PRELAUNCH },
{ RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
+ { RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH },
{ RUN_STATE_RUNNING, RUN_STATE_DEBUG },
{ RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR },
@@ -626,17 +635,21 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
{ RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_SHUTDOWN, RUN_STATE_PRELAUNCH },
{ RUN_STATE_DEBUG, RUN_STATE_SUSPENDED },
{ RUN_STATE_RUNNING, RUN_STATE_SUSPENDED },
{ RUN_STATE_SUSPENDED, RUN_STATE_RUNNING },
{ RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_SUSPENDED, RUN_STATE_PRELAUNCH },
{ RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
{ RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_WATCHDOG, RUN_STATE_PRELAUNCH },
{ RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING },
{ RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE },
+ { RUN_STATE_GUEST_PANICKED, RUN_STATE_PRELAUNCH },
{ RUN_STATE__MAX, RUN_STATE__MAX },
};
@@ -1881,8 +1894,9 @@ static bool main_loop_should_exit(void)
cpu_synchronize_all_states();
qemu_system_reset(VMRESET_REPORT);
resume_all_vcpus();
- if (runstate_needs_reset()) {
- runstate_set(RUN_STATE_PAUSED);
+ if (!runstate_check(RUN_STATE_RUNNING) &&
+ !runstate_check(RUN_STATE_INMIGRATE)) {
+ runstate_set(RUN_STATE_PRELAUNCH);
}
}
if (qemu_wakeup_requested()) {
@@ -2816,64 +2830,6 @@ static bool object_create_delayed(const char *type)
}
-static int object_create(void *opaque, QemuOpts *opts, Error **errp)
-{
- Error *err = NULL;
- Error *err_end = NULL;
- char *type = NULL;
- char *id = NULL;
- OptsVisitor *ov;
- QDict *pdict;
- bool (*type_predicate)(const char *) = opaque;
- Visitor *v;
-
- ov = opts_visitor_new(opts);
- pdict = qemu_opts_to_qdict(opts, NULL);
- v = opts_get_visitor(ov);
-
- visit_start_struct(v, NULL, NULL, 0, &err);
- if (err) {
- goto out;
- }
-
- qdict_del(pdict, "qom-type");
- visit_type_str(v, "qom-type", &type, &err);
- if (err) {
- goto out;
- }
- if (!type_predicate(type)) {
- visit_end_struct(v, NULL);
- goto out;
- }
-
- qdict_del(pdict, "id");
- visit_type_str(v, "id", &id, &err);
- if (err) {
- goto out_end;
- }
-
- object_add(type, id, pdict, v, &err);
-
-out_end:
- visit_end_struct(v, &err_end);
- if (!err && err_end) {
- qmp_object_del(id, NULL);
- }
- error_propagate(&err, err_end);
-
-out:
- opts_visitor_cleanup(ov);
-
- QDECREF(pdict);
- g_free(id);
- g_free(type);
- if (err) {
- error_report_err(err);
- return -1;
- }
- return 0;
-}
-
static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size,
MachineClass *mc)
{
@@ -4299,8 +4255,9 @@ int main(int argc, char **argv, char **envp)
socket_init();
if (qemu_opts_foreach(qemu_find_opts("object"),
- object_create,
- object_create_initial, NULL)) {
+ user_creatable_add_opts_foreach,
+ object_create_initial, &err)) {
+ error_report_err(err);
exit(1);
}
@@ -4417,8 +4374,9 @@ int main(int argc, char **argv, char **envp)
}
if (qemu_opts_foreach(qemu_find_opts("object"),
- object_create,
- object_create_delayed, NULL)) {
+ user_creatable_add_opts_foreach,
+ object_create_delayed, &err)) {
+ error_report_err(err);
exit(1);
}