aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/audio.c28
-rw-r--r--audio/trace-events5
-rwxr-xr-xconfigure2
-rw-r--r--crypto/Makefile.objs1
-rw-r--r--crypto/tlscredspsk.c308
-rw-r--r--crypto/tlssession.c56
-rw-r--r--crypto/trace-events3
-rw-r--r--hw/audio/hda-codec.c5
-rw-r--r--hw/display/cirrus_vga.c9
-rw-r--r--hw/display/qxl.c3
-rw-r--r--hw/display/vga-isa-mm.c3
-rw-r--r--hw/display/vga-isa.c3
-rw-r--r--hw/display/vga-pci.c5
-rw-r--r--hw/display/vga.c4
-rw-r--r--hw/display/vga_int.h3
-rw-r--r--hw/display/virtio-gpu.c64
-rw-r--r--hw/display/virtio-vga.c2
-rw-r--r--hw/display/vmware_vga.c4
-rw-r--r--hw/usb/hcd-ehci.c3
-rw-r--r--hw/usb/hcd-xhci.c7
-rw-r--r--include/crypto/tlscredspsk.h106
-rw-r--r--include/hw/compat.h16
-rw-r--r--linux-user/openrisc/signal.c217
-rw-r--r--linux-user/openrisc/target_signal.h2
-rw-r--r--linux-user/openrisc/target_syscall.h28
-rw-r--r--linux-user/signal.c2
-rw-r--r--linux-user/strace.list6
-rw-r--r--linux-user/syscall.c4
-rw-r--r--qemu-doc.texi37
-rw-r--r--qemu-options.hx24
-rw-r--r--qga/commands-posix.c362
-rw-r--r--qga/commands-win32.c14
-rw-r--r--qga/installer/qemu-ga.wxs2
-rw-r--r--qga/qapi-schema.json11
-rwxr-xr-xscripts/qemu-binfmt-conf.sh74
-rw-r--r--target/openrisc/Makefile.objs5
-rw-r--r--target/openrisc/cpu.c17
-rw-r--r--target/openrisc/cpu.h61
-rw-r--r--target/openrisc/disas.c170
-rw-r--r--target/openrisc/helper.h4
-rw-r--r--target/openrisc/interrupt.c55
-rw-r--r--target/openrisc/interrupt_helper.c35
-rw-r--r--target/openrisc/machine.c44
-rw-r--r--target/openrisc/mmu.c279
-rw-r--r--target/openrisc/mmu_helper.c40
-rw-r--r--target/openrisc/sys_helper.c84
-rw-r--r--target/openrisc/translate.c303
-rw-r--r--tests/Makefile.include4
-rw-r--r--tests/crypto-tls-psk-helpers.c50
-rw-r--r--tests/crypto-tls-psk-helpers.h29
-rw-r--r--tests/test-crypto-tlssession.c179
-rw-r--r--tests/test-qga.c54
52 files changed, 1877 insertions, 959 deletions
diff --git a/audio/audio.c b/audio/audio.c
index d6e91901aa..1ace47f510 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -29,6 +29,7 @@
#include "sysemu/sysemu.h"
#include "qemu/cutils.h"
#include "sysemu/replay.h"
+#include "trace.h"
#define AUDIO_CAP "audio"
#include "audio_int.h"
@@ -1129,6 +1130,10 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
/*
* Timer
*/
+
+static bool audio_timer_running;
+static uint64_t audio_timer_last;
+
static int audio_is_timer_needed (void)
{
HWVoiceIn *hwi = NULL;
@@ -1148,14 +1153,31 @@ static void audio_reset_timer (AudioState *s)
if (audio_is_timer_needed ()) {
timer_mod_anticipate_ns(s->ts,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks);
- }
- else {
- timer_del (s->ts);
+ if (!audio_timer_running) {
+ audio_timer_running = true;
+ audio_timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ trace_audio_timer_start(conf.period.ticks / SCALE_MS);
+ }
+ } else {
+ timer_del(s->ts);
+ if (audio_timer_running) {
+ audio_timer_running = false;
+ trace_audio_timer_stop();
+ }
}
}
static void audio_timer (void *opaque)
{
+ int64_t now, diff;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ diff = now - audio_timer_last;
+ if (diff > conf.period.ticks * 3 / 2) {
+ trace_audio_timer_delayed(diff / SCALE_MS);
+ }
+ audio_timer_last = now;
+
audio_run ("timer");
audio_reset_timer (opaque);
}
diff --git a/audio/trace-events b/audio/trace-events
index d37639e611..c986469319 100644
--- a/audio/trace-events
+++ b/audio/trace-events
@@ -15,3 +15,8 @@ alsa_no_frames(int state) "No frames available and ALSA state is %d"
# audio/ossaudio.c
oss_version(int version) "OSS version = 0x%x"
oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d"
+
+# audio/audio.c
+audio_timer_start(int interval) "interval %d ms"
+audio_timer_stop(void) ""
+audio_timer_delayed(int interval) "interval %d ms"
diff --git a/configure b/configure
index dcb605d7a2..b99ebdde24 100755
--- a/configure
+++ b/configure
@@ -3883,7 +3883,7 @@ libs_softmmu="$libs_softmmu $fdt_libs"
# opengl probe (for sdl2, gtk, milkymist-tmu2)
if test "$opengl" != "no" ; then
- opengl_pkgs="epoxy libdrm gbm"
+ opengl_pkgs="epoxy gbm"
if $pkg_config $opengl_pkgs; then
opengl_cflags="$($pkg_config --cflags $opengl_pkgs)"
opengl_libs="$($pkg_config --libs $opengl_pkgs)"
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 2b99e08062..756bab111b 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -15,6 +15,7 @@ crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o
crypto-obj-$(CONFIG_AF_ALG) += hash-afalg.o
crypto-obj-y += tlscreds.o
crypto-obj-y += tlscredsanon.o
+crypto-obj-y += tlscredspsk.o
crypto-obj-y += tlscredsx509.o
crypto-obj-y += tlssession.o
crypto-obj-y += secret.o
diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c
new file mode 100644
index 0000000000..7be7c8efdd
--- /dev/null
+++ b/crypto/tlscredspsk.c
@@ -0,0 +1,308 @@
+/*
+ * QEMU crypto TLS Pre-Shared Keys (PSK) support
+ *
+ * Copyright (c) 2018 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 "qemu/osdep.h"
+#include "crypto/tlscredspsk.h"
+#include "tlscredspriv.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "trace.h"
+
+
+#ifdef CONFIG_GNUTLS
+
+static int
+lookup_key(const char *pskfile, const char *username, gnutls_datum_t *key,
+ Error **errp)
+{
+ const size_t ulen = strlen(username);
+ GError *gerr = NULL;
+ char *content = NULL;
+ char **lines = NULL;
+ size_t clen = 0, i;
+ int ret = -1;
+
+ if (!g_file_get_contents(pskfile, &content, &clen, &gerr)) {
+ error_setg(errp, "Cannot read PSK file %s: %s",
+ pskfile, gerr->message);
+ g_error_free(gerr);
+ return -1;
+ }
+
+ lines = g_strsplit(content, "\n", -1);
+ for (i = 0; lines[i] != NULL; ++i) {
+ if (strncmp(lines[i], username, ulen) == 0 && lines[i][ulen] == ':') {
+ key->data = (unsigned char *) g_strdup(&lines[i][ulen + 1]);
+ key->size = strlen(lines[i]) - ulen - 1;
+ ret = 0;
+ goto out;
+ }
+ }
+ error_setg(errp, "Username %s not found in PSK file %s",
+ username, pskfile);
+
+ out:
+ free(content);
+ g_strfreev(lines);
+ return ret;
+}
+
+static int
+qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
+ Error **errp)
+{
+ char *pskfile = NULL, *dhparams = NULL;
+ const char *username;
+ int ret;
+ int rv = -1;
+ gnutls_datum_t key = { .data = NULL };
+
+ trace_qcrypto_tls_creds_psk_load(creds,
+ creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
+
+ if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ if (creds->username) {
+ error_setg(errp, "username should not be set when endpoint=server");
+ goto cleanup;
+ }
+
+ if (qcrypto_tls_creds_get_path(&creds->parent_obj,
+ QCRYPTO_TLS_CREDS_DH_PARAMS,
+ false, &dhparams, errp) < 0 ||
+ qcrypto_tls_creds_get_path(&creds->parent_obj,
+ QCRYPTO_TLS_CREDS_PSKFILE,
+ true, &pskfile, errp) < 0) {
+ goto cleanup;
+ }
+
+ ret = gnutls_psk_allocate_server_credentials(&creds->data.server);
+ if (ret < 0) {
+ error_setg(errp, "Cannot allocate credentials: %s",
+ gnutls_strerror(ret));
+ goto cleanup;
+ }
+
+ if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
+ &creds->parent_obj.dh_params,
+ errp) < 0) {
+ goto cleanup;
+ }
+
+ gnutls_psk_set_server_credentials_file(creds->data.server, pskfile);
+ gnutls_psk_set_server_dh_params(creds->data.server,
+ creds->parent_obj.dh_params);
+ } else {
+ if (qcrypto_tls_creds_get_path(&creds->parent_obj,
+ QCRYPTO_TLS_CREDS_PSKFILE,
+ true, &pskfile, errp) < 0) {
+ goto cleanup;
+ }
+
+ if (creds->username) {
+ username = creds->username;
+ } else {
+ username = "qemu";
+ }
+ if (lookup_key(pskfile, username, &key, errp) != 0) {
+ goto cleanup;
+ }
+
+ ret = gnutls_psk_allocate_client_credentials(&creds->data.client);
+ if (ret < 0) {
+ error_setg(errp, "Cannot allocate credentials: %s",
+ gnutls_strerror(ret));
+ goto cleanup;
+ }
+
+ gnutls_psk_set_client_credentials(creds->data.client,
+ username, &key, GNUTLS_PSK_KEY_HEX);
+ }
+
+ rv = 0;
+ cleanup:
+ g_free(key.data);
+ g_free(pskfile);
+ g_free(dhparams);
+ return rv;
+}
+
+
+static void
+qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds)
+{
+ if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+ if (creds->data.client) {
+ gnutls_psk_free_client_credentials(creds->data.client);
+ creds->data.client = NULL;
+ }
+ } else {
+ if (creds->data.server) {
+ gnutls_psk_free_server_credentials(creds->data.server);
+ creds->data.server = NULL;
+ }
+ }
+ if (creds->parent_obj.dh_params) {
+ gnutls_dh_params_deinit(creds->parent_obj.dh_params);
+ creds->parent_obj.dh_params = NULL;
+ }
+}
+
+#else /* ! CONFIG_GNUTLS */
+
+
+static void
+qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED,
+ Error **errp)
+{
+ error_setg(errp, "TLS credentials support requires GNUTLS");
+}
+
+
+static void
+qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED)
+{
+ /* nada */
+}
+
+
+#endif /* ! CONFIG_GNUTLS */
+
+
+static void
+qcrypto_tls_creds_psk_prop_set_loaded(Object *obj,
+ bool value,
+ Error **errp)
+{
+ QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
+
+ if (value) {
+ qcrypto_tls_creds_psk_load(creds, errp);
+ } else {
+ qcrypto_tls_creds_psk_unload(creds);
+ }
+}
+
+
+#ifdef CONFIG_GNUTLS
+
+
+static bool
+qcrypto_tls_creds_psk_prop_get_loaded(Object *obj,
+ Error **errp G_GNUC_UNUSED)
+{
+ QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
+
+ if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ return creds->data.server != NULL;
+ } else {
+ return creds->data.client != NULL;
+ }
+}
+
+
+#else /* ! CONFIG_GNUTLS */
+
+
+static bool
+qcrypto_tls_creds_psk_prop_get_loaded(Object *obj G_GNUC_UNUSED,
+ Error **errp G_GNUC_UNUSED)
+{
+ return false;
+}
+
+
+#endif /* ! CONFIG_GNUTLS */
+
+
+static void
+qcrypto_tls_creds_psk_complete(UserCreatable *uc, Error **errp)
+{
+ object_property_set_bool(OBJECT(uc), true, "loaded", errp);
+}
+
+
+static void
+qcrypto_tls_creds_psk_finalize(Object *obj)
+{
+ QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
+
+ qcrypto_tls_creds_psk_unload(creds);
+}
+
+static void
+qcrypto_tls_creds_psk_prop_set_username(Object *obj,
+ const char *value,
+ Error **errp G_GNUC_UNUSED)
+{
+ QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
+
+ creds->username = g_strdup(value);
+}
+
+
+static char *
+qcrypto_tls_creds_psk_prop_get_username(Object *obj,
+ Error **errp G_GNUC_UNUSED)
+{
+ QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
+
+ return g_strdup(creds->username);
+}
+
+static void
+qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+
+ ucc->complete = qcrypto_tls_creds_psk_complete;
+
+ object_class_property_add_bool(oc, "loaded",
+ qcrypto_tls_creds_psk_prop_get_loaded,
+ qcrypto_tls_creds_psk_prop_set_loaded,
+ NULL);
+ object_class_property_add_str(oc, "username",
+ qcrypto_tls_creds_psk_prop_get_username,
+ qcrypto_tls_creds_psk_prop_set_username,
+ NULL);
+}
+
+
+static const TypeInfo qcrypto_tls_creds_psk_info = {
+ .parent = TYPE_QCRYPTO_TLS_CREDS,
+ .name = TYPE_QCRYPTO_TLS_CREDS_PSK,
+ .instance_size = sizeof(QCryptoTLSCredsPSK),
+ .instance_finalize = qcrypto_tls_creds_psk_finalize,
+ .class_size = sizeof(QCryptoTLSCredsPSKClass),
+ .class_init = qcrypto_tls_creds_psk_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { }
+ }
+};
+
+
+static void
+qcrypto_tls_creds_psk_register_types(void)
+{
+ type_register_static(&qcrypto_tls_creds_psk_info);
+}
+
+
+type_init(qcrypto_tls_creds_psk_register_types);
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index 96a02deb69..66a6fbe19c 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "crypto/tlssession.h"
#include "crypto/tlscredsanon.h"
+#include "crypto/tlscredspsk.h"
#include "crypto/tlscredsx509.h"
#include "qapi/error.h"
#include "qemu/acl.h"
@@ -88,6 +89,14 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
return session->readFunc(buf, len, session->opaque);
}
+#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
+
+#if GNUTLS_VERSION_MAJOR >= 3
+#define TLS_ECDHE_PSK "+ECDHE-PSK:"
+#else
+#define TLS_ECDHE_PSK ""
+#endif
+#define TLS_PRIORITY_ADDITIONAL_PSK TLS_ECDHE_PSK "+DHE-PSK:+PSK"
QCryptoTLSSession *
qcrypto_tls_session_new(QCryptoTLSCreds *creds,
@@ -135,9 +144,12 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
char *prio;
if (creds->priority != NULL) {
- prio = g_strdup_printf("%s:+ANON-DH", creds->priority);
+ prio = g_strdup_printf("%s:%s",
+ creds->priority,
+ TLS_PRIORITY_ADDITIONAL_ANON);
} else {
- prio = g_strdup(CONFIG_TLS_PRIORITY ":+ANON-DH");
+ prio = g_strdup(CONFIG_TLS_PRIORITY ":"
+ TLS_PRIORITY_ADDITIONAL_ANON);
}
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
@@ -163,6 +175,42 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
goto error;
}
} else if (object_dynamic_cast(OBJECT(creds),
+ TYPE_QCRYPTO_TLS_CREDS_PSK)) {
+ QCryptoTLSCredsPSK *pcreds = QCRYPTO_TLS_CREDS_PSK(creds);
+ char *prio;
+
+ if (creds->priority != NULL) {
+ prio = g_strdup_printf("%s:%s",
+ creds->priority,
+ TLS_PRIORITY_ADDITIONAL_PSK);
+ } else {
+ prio = g_strdup(CONFIG_TLS_PRIORITY ":"
+ TLS_PRIORITY_ADDITIONAL_PSK);
+ }
+
+ ret = gnutls_priority_set_direct(session->handle, prio, NULL);
+ if (ret < 0) {
+ error_setg(errp, "Unable to set TLS session priority %s: %s",
+ prio, gnutls_strerror(ret));
+ g_free(prio);
+ goto error;
+ }
+ g_free(prio);
+ if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ ret = gnutls_credentials_set(session->handle,
+ GNUTLS_CRD_PSK,
+ pcreds->data.server);
+ } else {
+ ret = gnutls_credentials_set(session->handle,
+ GNUTLS_CRD_PSK,
+ pcreds->data.client);
+ }
+ if (ret < 0) {
+ error_setg(errp, "Cannot set session credentials: %s",
+ gnutls_strerror(ret));
+ goto error;
+ }
+ } else if (object_dynamic_cast(OBJECT(creds),
TYPE_QCRYPTO_TLS_CREDS_X509)) {
QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
const char *prio = creds->priority;
@@ -354,6 +402,10 @@ qcrypto_tls_session_check_credentials(QCryptoTLSSession *session,
trace_qcrypto_tls_session_check_creds(session, "nop");
return 0;
} else if (object_dynamic_cast(OBJECT(session->creds),
+ TYPE_QCRYPTO_TLS_CREDS_PSK)) {
+ trace_qcrypto_tls_session_check_creds(session, "nop");
+ return 0;
+ } else if (object_dynamic_cast(OBJECT(session->creds),
TYPE_QCRYPTO_TLS_CREDS_X509)) {
if (session->creds->verifyPeer) {
int ret = qcrypto_tls_session_check_certificate(session,
diff --git a/crypto/trace-events b/crypto/trace-events
index e589990359..597389b73c 100644
--- a/crypto/trace-events
+++ b/crypto/trace-events
@@ -7,6 +7,9 @@ qcrypto_tls_creds_get_path(void *creds, const char *filename, const char *path)
# crypto/tlscredsanon.c
qcrypto_tls_creds_anon_load(void *creds, const char *dir) "TLS creds anon load creds=%p dir=%s"
+# crypto/tlscredspsk.c
+qcrypto_tls_creds_psk_load(void *creds, const char *dir) "TLS creds psk load creds=%p dir=%s"
+
# crypto/tlscredsx509.c
qcrypto_tls_creds_x509_load(void *creds, const char *dir) "TLS creds x509 load creds=%p dir=%s"
qcrypto_tls_creds_x509_check_basic_constraints(void *creds, const char *file, int status) "TLS creds x509 check basic constraints creds=%p file=%s status=%d"
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 31c66d4255..2b58c3505b 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -189,7 +189,7 @@ struct HDAAudioState {
static inline int64_t hda_bytes_per_second(HDAAudioStream *st)
{
- return 2 * st->as.nchannels * st->as.freq;
+ return 2LL * st->as.nchannels * st->as.freq;
}
static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos)
@@ -203,6 +203,9 @@ static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos)
if (target_pos < -limit) {
corr = -HDA_TIMER_TICKS;
}
+ if (target_pos < -(2 * limit)) {
+ corr = -(4 * HDA_TIMER_TICKS);
+ }
if (corr == 0) {
return;
}
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 5e44f00f3f..7583b18c29 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -3048,7 +3048,8 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
s->vram_size_mb);
return;
}
- vga_common_init(s, OBJECT(dev), true);
+ s->global_vmstate = true;
+ vga_common_init(s, OBJECT(dev));
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
@@ -3062,7 +3063,7 @@ static Property isa_cirrus_vga_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
cirrus_vga.vga.vram_size_mb, 4),
DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState,
- cirrus_vga.enable_blitter, true),
+ cirrus_vga.enable_blitter, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -3105,7 +3106,7 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp)
return;
}
/* setup VGA */
- vga_common_init(&s->vga, OBJECT(dev), true);
+ vga_common_init(&s->vga, OBJECT(dev));
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
@@ -3134,6 +3135,8 @@ static Property pci_vga_cirrus_properties[] = {
cirrus_vga.vga.vram_size_mb, 4),
DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState,
cirrus_vga.enable_blitter, true),
+ DEFINE_PROP_BOOL("global-vmstate", struct PCICirrusVGAState,
+ cirrus_vga.vga.global_vmstate, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index b09a03997a..830c392c53 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2168,7 +2168,7 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp)
qxl_init_ramsize(qxl);
vga->vbe_size = qxl->vgamem_size;
vga->vram_size_mb = qxl->vga.vram_size / MiB;
- vga_common_init(vga, OBJECT(dev), true);
+ vga_common_init(vga, OBJECT(dev));
vga_init(vga, OBJECT(dev),
pci_address_space(dev), pci_address_space_io(dev), false);
portio_list_init(&qxl->vga_port_list, OBJECT(dev), qxl_vga_portio_list,
@@ -2408,6 +2408,7 @@ static Property qxl_properties[] = {
#endif
DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0),
DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0),
+ DEFINE_PROP_BOOL("global-vmstate", PCIQXLDevice, vga.global_vmstate, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index bd58141117..232216cad0 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -132,7 +132,8 @@ int isa_vga_mm_init(hwaddr vram_base,
s = g_malloc0(sizeof(*s));
s->vga.vram_size_mb = VGA_RAM_SIZE / MiB;
- vga_common_init(&s->vga, NULL, true);
+ s->vga.global_vmstate = true;
+ vga_common_init(&s->vga, NULL);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index 469834add5..fa44242e0d 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -58,7 +58,8 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
MemoryRegion *vga_io_memory;
const MemoryRegionPortio *vga_ports, *vbe_ports;
- vga_common_init(s, OBJECT(dev), true);
+ s->global_vmstate = true;
+ vga_common_init(s, OBJECT(dev));
s->legacy_address_space = isa_address_space(isadev);
vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
isa_register_portio_list(isadev, &d->portio_vga,
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 1ea559762a..e9e62eac70 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -222,7 +222,7 @@ static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
bool qext = false;
/* vga + console init */
- vga_common_init(s, OBJECT(dev), true);
+ vga_common_init(s, OBJECT(dev));
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
@@ -265,7 +265,7 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
bool qext = false;
/* vga + console init */
- vga_common_init(s, OBJECT(dev), false);
+ vga_common_init(s, OBJECT(dev));
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
/* mmio bar */
@@ -308,6 +308,7 @@ static Property vga_pci_properties[] = {
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
DEFINE_PROP_BIT("qemu-extended-regs",
PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_QEXT, true),
+ DEFINE_PROP_BOOL("global-vmstate", PCIVGAState, vga.global_vmstate, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/display/vga.c b/hw/display/vga.c
index d7599182a8..802cfd47db 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -2164,7 +2164,7 @@ static inline uint32_t uint_clamp(uint32_t val, uint32_t vmin, uint32_t vmax)
return val;
}
-void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
+void vga_common_init(VGACommonState *s, Object *obj)
{
int i, j, v, b;
@@ -2203,7 +2203,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
s->is_vbe_vmstate = 1;
memory_region_init_ram_nomigrate(&s->vram, obj, "vga.vram", s->vram_size,
&error_fatal);
- vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
+ vmstate_register_ram(&s->vram, s->global_vmstate ? NULL : DEVICE(obj));
xen_register_framebuffer(&s->vram);
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
s->get_bpp = vga_get_bpp;
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index f8fcf62a56..339661bc01 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -133,6 +133,7 @@ typedef struct VGACommonState {
bool full_update_gfx;
bool big_endian_fb;
bool default_endian_fb;
+ bool global_vmstate;
/* hardware mouse cursor support */
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
uint32_t hw_cursor_x;
@@ -157,7 +158,7 @@ static inline int c6_to_8(int v)
return (v << 2) | (b << 1) | b;
}
-void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate);
+void vga_common_init(VGACommonState *s, Object *obj);
void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
MemoryRegion *address_space_io, bool init_vga_ports);
MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 71a00718e6..ec366f4c35 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -400,9 +400,47 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
g->hostmem += res->hostmem;
}
+static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
+{
+ struct virtio_gpu_scanout *scanout = &g->scanout[scanout_id];
+ struct virtio_gpu_simple_resource *res;
+ DisplaySurface *ds = NULL;
+
+ if (scanout->resource_id == 0) {
+ return;
+ }
+
+ res = virtio_gpu_find_resource(g, scanout->resource_id);
+ if (res) {
+ res->scanout_bitmask &= ~(1 << scanout_id);
+ }
+
+ if (scanout_id == 0) {
+ /* primary head */
+ ds = qemu_create_message_surface(scanout->width ?: 640,
+ scanout->height ?: 480,
+ "Guest disabled display.");
+ }
+ dpy_gfx_replace_surface(scanout->con, ds);
+ scanout->resource_id = 0;
+ scanout->ds = NULL;
+ scanout->width = 0;
+ scanout->height = 0;
+}
+
static void virtio_gpu_resource_destroy(VirtIOGPU *g,
struct virtio_gpu_simple_resource *res)
{
+ int i;
+
+ if (res->scanout_bitmask) {
+ for (i = 0; i < g->conf.max_outputs; i++) {
+ if (res->scanout_bitmask & (1 << i)) {
+ virtio_gpu_disable_scanout(g, i);
+ }
+ }
+ }
+
pixman_image_unref(res->image);
virtio_gpu_cleanup_mapping(res);
QTAILQ_REMOVE(&g->reslist, res, next);
@@ -563,7 +601,7 @@ static void virtio_unref_resource(pixman_image_t *image, void *data)
static void virtio_gpu_set_scanout(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
- struct virtio_gpu_simple_resource *res;
+ struct virtio_gpu_simple_resource *res, *ores;
struct virtio_gpu_scanout *scanout;
pixman_format_code_t format;
uint32_t offset;
@@ -584,24 +622,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
g->enable = 1;
if (ss.resource_id == 0) {
- scanout = &g->scanout[ss.scanout_id];
- if (scanout->resource_id) {
- res = virtio_gpu_find_resource(g, scanout->resource_id);
- if (res) {
- res->scanout_bitmask &= ~(1 << ss.scanout_id);
- }
- }
- if (ss.scanout_id == 0) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: illegal scanout id specified %d",
- __func__, ss.scanout_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
- return;
- }
- dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
- scanout->ds = NULL;
- scanout->width = 0;
- scanout->height = 0;
+ virtio_gpu_disable_scanout(g, ss.scanout_id);
return;
}
@@ -654,6 +675,11 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
}
+ ores = virtio_gpu_find_resource(g, scanout->resource_id);
+ if (ores) {
+ ores->scanout_bitmask &= ~(1 << ss.scanout_id);
+ }
+
res->scanout_bitmask |= (1 << ss.scanout_id);
scanout->resource_id = ss.resource_id;
scanout->x = ss.r.x;
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 97db6c3372..8d3d9e14a7 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -106,7 +106,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
/* init vga compat bits */
vga->vram_size_mb = 8;
- vga_common_init(vga, OBJECT(vpci_dev), false);
+ vga_common_init(vga, OBJECT(vpci_dev));
vga_init(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev),
pci_address_space_io(&vpci_dev->pci_dev), true);
pci_register_bar(&vpci_dev->pci_dev, 0,
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 08deb08783..0bbb78b9a6 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1242,7 +1242,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
&error_fatal);
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
- vga_common_init(&s->vga, OBJECT(dev), true);
+ vga_common_init(&s->vga, OBJECT(dev));
vga_init(&s->vga, OBJECT(dev), address_space, io, true);
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
s->new_depth = 32;
@@ -1322,6 +1322,8 @@ static void pci_vmsvga_realize(PCIDevice *dev, Error **errp)
static Property vga_vmware_properties[] = {
DEFINE_PROP_UINT32("vgamem_mb", struct pci_vmsvga_state_s,
chip.vga.vram_size_mb, 16),
+ DEFINE_PROP_BOOL("global-vmstate", struct pci_vmsvga_state_s,
+ chip.vga.global_vmstate, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 0134232627..e5acfc5ba5 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1672,7 +1672,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
ehci_set_state(ehci, async, EST_HORIZONTALQH);
} else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
- (NLPTR_TBIT(q->qh.current_qtd) == 0)) {
+ (NLPTR_TBIT(q->qh.current_qtd) == 0) &&
+ (q->qh.current_qtd != 0)) {
q->qtdaddr = q->qh.current_qtd;
ehci_set_state(ehci, async, EST_FETCHQTD);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 721beb5486..8f1a01a405 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1954,7 +1954,12 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
for (i = 0; i < length; i++) {
TRBType type;
type = xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL);
- assert(type);
+ if (!type) {
+ xhci_die(xhci);
+ xhci_ep_free_xfer(xfer);
+ epctx->kick_active--;
+ return;
+ }
}
xfer->streamid = streamid;
diff --git a/include/crypto/tlscredspsk.h b/include/crypto/tlscredspsk.h
new file mode 100644
index 0000000000..306d36c67d
--- /dev/null
+++ b/include/crypto/tlscredspsk.h
@@ -0,0 +1,106 @@
+/*
+ * QEMU crypto TLS Pre-Shared Key (PSK) support
+ *
+ * Copyright (c) 2018 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 QCRYPTO_TLSCREDSPSK_H
+#define QCRYPTO_TLSCREDSPSK_H
+
+#include "crypto/tlscreds.h"
+
+#define TYPE_QCRYPTO_TLS_CREDS_PSK "tls-creds-psk"
+#define QCRYPTO_TLS_CREDS_PSK(obj) \
+ OBJECT_CHECK(QCryptoTLSCredsPSK, (obj), TYPE_QCRYPTO_TLS_CREDS_PSK)
+
+typedef struct QCryptoTLSCredsPSK QCryptoTLSCredsPSK;
+typedef struct QCryptoTLSCredsPSKClass QCryptoTLSCredsPSKClass;
+
+#define QCRYPTO_TLS_CREDS_PSKFILE "keys.psk"
+
+/**
+ * QCryptoTLSCredsPSK:
+ *
+ * The QCryptoTLSCredsPSK object provides a representation
+ * of the Pre-Shared Key credential used to perform a TLS handshake.
+ *
+ * This is a user creatable object, which can be instantiated
+ * via object_new_propv():
+ *
+ * <example>
+ * <title>Creating TLS-PSK credential objects in code</title>
+ * <programlisting>
+ * Object *obj;
+ * Error *err = NULL;
+ * obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_PSK,
+ * "tlscreds0",
+ * &err,
+ * "dir", "/path/to/dir",
+ * "endpoint", "client",
+ * NULL);
+ * </programlisting>
+ * </example>
+ *
+ * Or via QMP:
+ *
+ * <example>
+ * <title>Creating TLS-PSK credential objects via QMP</title>
+ * <programlisting>
+ * {
+ * "execute": "object-add", "arguments": {
+ * "id": "tlscreds0",
+ * "qom-type": "tls-creds-psk",
+ * "props": {
+ * "dir": "/path/to/dir",
+ * "endpoint": "client"
+ * }
+ * }
+ * }
+ * </programlisting>
+ * </example>
+ *
+ * Or via the CLI:
+ *
+ * <example>
+ * <title>Creating TLS-PSK credential objects via CLI</title>
+ * <programlisting>
+ * qemu-system-x86_64 --object tls-creds-psk,id=tlscreds0,\
+ * endpoint=client,dir=/path/to/dir[,username=qemu]
+ * </programlisting>
+ * </example>
+ *
+ * The PSK file can be created and managed using psktool.
+ */
+
+struct QCryptoTLSCredsPSK {
+ QCryptoTLSCreds parent_obj;
+ char *username;
+#ifdef CONFIG_GNUTLS
+ union {
+ gnutls_psk_server_credentials_t server;
+ gnutls_psk_client_credentials_t client;
+ } data;
+#endif
+};
+
+
+struct QCryptoTLSCredsPSKClass {
+ QCryptoTLSCredsClass parent_class;
+};
+
+
+#endif /* QCRYPTO_TLSCREDSPSK_H */
diff --git a/include/hw/compat.h b/include/hw/compat.h
index 44d5964060..c08f4040bb 100644
--- a/include/hw/compat.h
+++ b/include/hw/compat.h
@@ -10,6 +10,22 @@
.driver = "hda-audio",\
.property = "use-timer",\
.value = "false",\
+ },{\
+ .driver = "cirrus-vga",\
+ .property = "global-vmstate",\
+ .value = "true",\
+ },{\
+ .driver = "VGA",\
+ .property = "global-vmstate",\
+ .value = "true",\
+ },{\
+ .driver = "vmware-svga",\
+ .property = "global-vmstate",\
+ .value = "true",\
+ },{\
+ .driver = "qxl-vga",\
+ .property = "global-vmstate",\
+ .value = "true",\
},
#define HW_COMPAT_2_11 \
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index 8be0b74001..232ad82b98 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -21,124 +21,69 @@
#include "signal-common.h"
#include "linux-user/trace.h"
-struct target_sigcontext {
+typedef struct target_sigcontext {
struct target_pt_regs regs;
abi_ulong oldmask;
- abi_ulong usp;
-};
+} target_sigcontext;
-struct target_ucontext {
+typedef struct target_ucontext {
abi_ulong tuc_flags;
abi_ulong tuc_link;
target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
+ target_sigcontext tuc_mcontext;
target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
+} target_ucontext;
-struct target_rt_sigframe {
- abi_ulong pinfo;
- uint64_t puc;
+typedef struct target_rt_sigframe {
struct target_siginfo info;
- struct target_sigcontext sc;
- struct target_ucontext uc;
- unsigned char retcode[16]; /* trampoline code */
-};
-
-/* This is the asm-generic/ucontext.h version */
-#if 0
-static int restore_sigcontext(CPUOpenRISCState *regs,
- struct target_sigcontext *sc)
-{
- unsigned int err = 0;
- unsigned long old_usp;
-
- /* Alwys make any pending restarted system call return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
+ target_ucontext uc;
+ uint32_t retcode[4]; /* trampoline code */
+} target_rt_sigframe;
- /* restore the regs from &sc->regs (same as sc, since regs is first)
- * (sc is already checked for VERIFY_READ since the sigframe was
- * checked in sys_sigreturn previously)
- */
+static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc)
+{
+ int i;
+ abi_ulong v;
- if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
- goto badframe;
+ for (i = 0; i < 32; ++i) {
+ __get_user(v, &sc->regs.gpr[i]);
+ cpu_set_gpr(env, i, v);
}
+ __get_user(env->pc, &sc->regs.pc);
- /* make sure the U-flag is set so user-mode cannot fool us */
-
- regs->sr &= ~SR_SM;
-
- /* restore the old USP as it was before we stacked the sc etc.
- * (we cannot just pop the sigcontext since we aligned the sp and
- * stuff after pushing it)
- */
-
- __get_user(old_usp, &sc->usp);
- phx_signal("old_usp 0x%lx", old_usp);
-
- __PHX__ REALLY /* ??? */
- wrusp(old_usp);
- regs->gpr[1] = old_usp;
-
- /* TODO: the other ports use regs->orig_XX to disable syscall checks
- * after this completes, but we don't use that mechanism. maybe we can
- * use it now ?
- */
-
- return err;
-
-badframe:
- return 1;
+ /* Make sure the supervisor flag is clear. */
+ __get_user(v, &sc->regs.sr);
+ cpu_set_sr(env, v & ~SR_SM);
}
-#endif
/* Set up a signal frame. */
-static void setup_sigcontext(struct target_sigcontext *sc,
- CPUOpenRISCState *regs,
- unsigned long mask)
+static void setup_sigcontext(target_sigcontext *sc, CPUOpenRISCState *env)
{
- unsigned long usp = cpu_get_gpr(regs, 1);
-
- /* copy the regs. they are first in sc so we can use sc directly */
+ int i;
- /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
-
- /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
- the signal handler. The frametype will be restored to its previous
- value in restore_sigcontext. */
- /*regs->frametype = CRIS_FRAME_NORMAL;*/
-
- /* then some other stuff */
- __put_user(mask, &sc->oldmask);
- __put_user(usp, &sc->usp);
-}
+ for (i = 0; i < 32; ++i) {
+ __put_user(cpu_get_gpr(env, i), &sc->regs.gpr[i]);
+ }
-static inline unsigned long align_sigframe(unsigned long sp)
-{
- return sp & ~3UL;
+ __put_user(env->pc, &sc->regs.pc);
+ __put_user(cpu_get_sr(env), &sc->regs.sr);
}
static inline abi_ulong get_sigframe(struct target_sigaction *ka,
- CPUOpenRISCState *regs,
+ CPUOpenRISCState *env,
size_t frame_size)
{
- unsigned long sp = get_sp_from_cpustate(regs);
- int onsigstack = on_sig_stack(sp);
-
- /* redzone */
- sp = target_sigsp(sp, ka);
-
- sp = align_sigframe(sp - frame_size);
+ target_ulong sp = get_sp_from_cpustate(env);
- /*
- * If we are on the alternate signal stack and would overflow it, don't.
- * Return an always-bogus address instead so we will die with SIGSEGV.
+ /* Honor redzone now. If we swap to signal stack, no need to waste
+ * the 128 bytes by subtracting afterward.
*/
+ sp -= 128;
- if (onsigstack && !likely(on_sig_stack(sp))) {
- return -1L;
- }
+ sp = target_sigsp(sp, ka);
+ sp -= frame_size;
+ sp = QEMU_ALIGN_DOWN(sp, 4);
return sp;
}
@@ -147,11 +92,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUOpenRISCState *env)
{
- int err = 0;
abi_ulong frame_addr;
- unsigned long return_ip;
- struct target_rt_sigframe *frame;
- abi_ulong info_addr, uc_addr;
+ target_rt_sigframe *frame;
+ int i;
frame_addr = get_sigframe(ka, env, sizeof(*frame));
trace_user_setup_rt_frame(env, frame_addr);
@@ -159,47 +102,37 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
goto give_sigsegv;
}
- info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
- __put_user(info_addr, &frame->pinfo);
- uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
- __put_user(uc_addr, &frame->puc);
-
if (ka->sa_flags & SA_SIGINFO) {
tswap_siginfo(&frame->info, info);
}
- /*err |= __clear_user(&frame->uc, offsetof(ucontext_t, uc_mcontext));*/
__put_user(0, &frame->uc.tuc_flags);
__put_user(0, &frame->uc.tuc_link);
- target_save_altstack(&frame->uc.tuc_stack, env);
- setup_sigcontext(&frame->sc, env, set->sig[0]);
- /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
-
- /* trampoline - the desired return ip is the retcode itself */
- return_ip = (unsigned long)&frame->retcode;
- /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
- __put_user(0xa960, (short *)(frame->retcode + 0));
- __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
- __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
- __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
-
- if (err) {
- goto give_sigsegv;
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ setup_sigcontext(&frame->uc.tuc_mcontext, env);
+ for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
}
- /* TODO what is the current->exec_domain stuff and invmap ? */
+ /* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */
+ __put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0);
+ __put_user(0x20000001, frame->retcode + 1);
+ __put_user(0x15000000, frame->retcode + 2);
+ __put_user(0x15000000, frame->retcode + 3);
/* Set up registers for signal handler */
- env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
- cpu_set_gpr(env, 9, (unsigned long)return_ip); /* what we enter LATER */
- cpu_set_gpr(env, 3, (unsigned long)sig); /* arg 1: signo */
- cpu_set_gpr(env, 4, (unsigned long)&frame->info); /* arg 2: (siginfo_t*) */
- cpu_set_gpr(env, 5, (unsigned long)&frame->uc); /* arg 3: ucontext */
-
- /* actually move the usp to reflect the stacked frame */
- cpu_set_gpr(env, 1, (unsigned long)frame);
-
+ cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode));
+ cpu_set_gpr(env, 3, sig);
+ cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info));
+ cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc));
+ cpu_set_gpr(env, 1, frame_addr);
+
+ /* For debugging convenience, set ppc to the insn that faulted. */
+ env->ppc = env->pc;
+ /* When setting the PC for the signal handler, exit delay slot. */
+ env->pc = ka->_sa_handler;
+ env->dflag = 0;
return;
give_sigsegv:
@@ -207,16 +140,34 @@ give_sigsegv:
force_sigsegv(sig);
}
-long do_sigreturn(CPUOpenRISCState *env)
-{
- trace_user_do_sigreturn(env, 0);
- fprintf(stderr, "do_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
long do_rt_sigreturn(CPUOpenRISCState *env)
{
+ abi_ulong frame_addr = get_sp_from_cpustate(env);
+ target_rt_sigframe *frame;
+ sigset_t set;
+
trace_user_do_rt_sigreturn(env, 0);
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ if (frame_addr & 3) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, &frame->uc.tuc_mcontext);
+ if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack),
+ 0, frame_addr) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return cpu_get_gpr(env, 11);
+
+ badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return 0;
}
diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h
index c352a8b333..8283eaf544 100644
--- a/linux-user/openrisc/target_signal.h
+++ b/linux-user/openrisc/target_signal.h
@@ -5,8 +5,8 @@
typedef struct target_sigaltstack {
abi_long ss_sp;
+ abi_int ss_flags;
abi_ulong ss_size;
- abi_long ss_flags;
} target_stack_t;
/* sigaltstack controls */
diff --git a/linux-user/openrisc/target_syscall.h b/linux-user/openrisc/target_syscall.h
index 03104f80af..d586d2a018 100644
--- a/linux-user/openrisc/target_syscall.h
+++ b/linux-user/openrisc/target_syscall.h
@@ -1,27 +1,15 @@
#ifndef OPENRISC_TARGET_SYSCALL_H
#define OPENRISC_TARGET_SYSCALL_H
+/* Note that in linux/arch/openrisc/include/uapi/asm/ptrace.h,
+ * this is called user_regs_struct. Given that this is what
+ * is used within struct sigcontext we need this definition.
+ * However, elfload.c wants this name.
+ */
struct target_pt_regs {
- union {
- struct {
- /* Named registers */
- uint32_t sr; /* Stored in place of r0 */
- target_ulong sp; /* r1 */
- };
- struct {
- /* Old style */
- target_ulong offset[2];
- target_ulong gprs[30];
- };
- struct {
- /* New style */
- target_ulong gpr[32];
- };
- };
- target_ulong pc;
- target_ulong orig_gpr11; /* For restarting system calls */
- uint32_t syscallno; /* Syscall number (used by strace) */
- target_ulong dummy; /* Cheap alignment fix */
+ abi_ulong gpr[32];
+ abi_ulong pc;
+ abi_ulong sr;
};
#define UNAME_MACHINE "openrisc"
diff --git a/linux-user/signal.c b/linux-user/signal.c
index be2815b45d..602b631b92 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -236,7 +236,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
return 0;
}
-#if !defined(TARGET_OPENRISC) && !defined(TARGET_NIOS2)
+#if !defined(TARGET_NIOS2)
/* Just set the guest's signal mask to the specified value; the
* caller is assumed to have called block_signals() already.
*/
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 2bc5ba04d4..ff8bb19f5f 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -59,10 +59,10 @@
{ TARGET_NR_cacheflush, "cacheflush" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_capget
-{ TARGET_NR_capget, "capget" , NULL, NULL, NULL },
+{ TARGET_NR_capget, "capget" , "%s(%p,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_capset
-{ TARGET_NR_capset, "capset" , NULL, NULL, NULL },
+{ TARGET_NR_capset, "capset" , "%s(%p,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_chdir
{ TARGET_NR_chdir, "chdir" , NULL, print_chdir, NULL },
@@ -1107,7 +1107,7 @@
{ TARGET_NR_recvmmsg, "recvmmsg" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_recvmsg
-{ TARGET_NR_recvmsg, "recvmsg" , NULL, NULL, NULL },
+{ TARGET_NR_recvmsg, "recvmsg" , "%s(%d,%p,%#x)", NULL, NULL },
#endif
#ifdef TARGET_NR_remap_file_pages
{ TARGET_NR_remap_file_pages, "remap_file_pages" , NULL, NULL, NULL },
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2117fb13b4..50e20fb659 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2522,6 +2522,8 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
case QEMU_IFLA_NUM_VF:
case QEMU_IFLA_GSO_MAX_SEGS:
case QEMU_IFLA_GSO_MAX_SIZE:
+ case QEMU_IFLA_CARRIER_UP_COUNT:
+ case QEMU_IFLA_CARRIER_DOWN_COUNT:
u32 = RTA_DATA(rtattr);
*u32 = tswap32(*u32);
break;
@@ -3017,6 +3019,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
case IPV6_V6ONLY:
case IPV6_RECVPKTINFO:
case IPV6_UNICAST_HOPS:
+ case IPV6_MULTICAST_HOPS:
+ case IPV6_MULTICAST_LOOP:
case IPV6_RECVERR:
case IPV6_RECVHOPLIMIT:
case IPV6_2292HOPLIMIT:
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 1cb3ba4341..d3924e928e 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1262,6 +1262,7 @@ The recommendation is for the server to keep its certificates in either
* tls_generate_server::
* tls_generate_client::
* tls_creds_setup::
+* tls_psk::
@end menu
@node tls_generate_ca
@subsection Setup the Certificate Authority
@@ -1510,6 +1511,42 @@ example with VNC:
$QEMU -vnc 0.0.0.0:0,tls-creds=tls0
@end example
+@node tls_psk
+@subsection TLS Pre-Shared Keys (PSK)
+
+Instead of using certificates, you may also use TLS Pre-Shared Keys
+(TLS-PSK). This can be simpler to set up than certificates but is
+less scalable.
+
+Use the GnuTLS @code{psktool} program to generate a @code{keys.psk}
+file containing one or more usernames and random keys:
+
+@example
+mkdir -m 0700 /tmp/keys
+psktool -u rich -p /tmp/keys/keys.psk
+@end example
+
+TLS-enabled servers such as qemu-nbd can use this directory like so:
+
+@example
+qemu-nbd \
+ -t -x / \
+ --object tls-creds-psk,id=tls0,endpoint=server,dir=/tmp/keys \
+ --tls-creds tls0 \
+ image.qcow2
+@end example
+
+When connecting from a qemu-based client you must specify the
+directory containing @code{keys.psk} and an optional @var{username}
+(defaults to ``qemu''):
+
+@example
+qemu-img info \
+ --object tls-creds-psk,id=tls0,dir=/tmp/keys,username=rich,endpoint=client \
+ --image-opts \
+ file.driver=nbd,file.host=localhost,file.port=10809,file.tls-creds=tls0,file.export=/
+@end example
+
@node gdb_usage
@section GDB usage
diff --git a/qemu-options.hx b/qemu-options.hx
index 81b1e99d58..16208f63f2 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4123,6 +4123,30 @@ expensive operation that consumes random pool entropy, so it is
recommended that a persistent set of parameters be generated
upfront and saved.
+@item -object tls-creds-psk,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/keys/dir}[,username=@var{username}]
+
+Creates a TLS Pre-Shared Keys (PSK) credentials object, which can be used to provide
+TLS support on network backends. The @option{id} parameter is a unique
+ID which network backends will use to access the credentials. The
+@option{endpoint} is either @option{server} or @option{client} depending
+on whether the QEMU network backend that uses the credentials will be
+acting as a client or as a server. For clients only, @option{username}
+is the username which will be sent to the server. If omitted
+it defaults to ``qemu''.
+
+The @var{dir} parameter tells QEMU where to find the keys file.
+It is called ``@var{dir}/keys.psk'' and contains ``username:key''
+pairs. This file can most easily be created using the GnuTLS
+@code{psktool} program.
+
+For server endpoints, @var{dir} may also contain a file
+@var{dh-params.pem} providing diffie-hellman parameters to use
+for the TLS server. If the file is missing, QEMU will generate
+a set of DH parameters at startup. This is a computationally
+expensive operation that consumes random pool entropy, so it is
+recommended that a persistent set of parameters be generated
+up front and saved.
+
@item -object tls-creds-x509,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},priority=@var{priority},verify-peer=@var{on|off},passwordid=@var{id}
Creates a TLS anonymous credentials object, which can be used to provide
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index eae817191b..233f78a406 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -46,6 +46,7 @@ extern char **environ;
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
+#include <sys/statvfs.h>
#ifdef FIFREEZE
#define CONFIG_FSFREEZE
@@ -458,7 +459,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
if (!has_count) {
count = QGA_READ_COUNT_DEFAULT;
- } else if (count < 0) {
+ } else if (count < 0 || count >= UINT32_MAX) {
error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
count);
return NULL;
@@ -875,13 +876,28 @@ static void build_guest_fsinfo_for_real_device(char const *syspath,
p = strstr(syspath, "/devices/pci");
if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
- g_debug("only pci device is supported: sysfs path \"%s\"", syspath);
+ g_debug("only pci device is supported: sysfs path '%s'", syspath);
return;
}
- driver = get_pci_driver(syspath, (p + 12 + pcilen) - syspath, errp);
- if (!driver) {
- goto cleanup;
+ p += 12 + pcilen;
+ while (true) {
+ driver = get_pci_driver(syspath, p - syspath, errp);
+ if (driver && (g_str_equal(driver, "ata_piix") ||
+ g_str_equal(driver, "sym53c8xx") ||
+ g_str_equal(driver, "virtio-pci") ||
+ g_str_equal(driver, "ahci"))) {
+ break;
+ }
+
+ if (sscanf(p, "/%x:%x:%x.%x%n",
+ pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) {
+ p += pcilen;
+ continue;
+ }
+
+ g_debug("unsupported driver or sysfs path '%s'", syspath);
+ return;
}
p = strstr(syspath, "/target");
@@ -1072,6 +1088,8 @@ static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
Error **errp)
{
GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
+ struct statvfs buf;
+ unsigned long used, nonroot_total, fr_size;
char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
mount->devmajor, mount->devminor);
@@ -1079,7 +1097,19 @@ static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
fs->type = g_strdup(mount->devtype);
build_guest_fsinfo_for_device(devpath, fs, errp);
+ if (statvfs(fs->mountpoint, &buf) == 0) {
+ fr_size = buf.f_frsize;
+ used = buf.f_blocks - buf.f_bfree;
+ nonroot_total = used + buf.f_bavail;
+ fs->used_bytes = used * fr_size;
+ fs->total_bytes = nonroot_total * fr_size;
+
+ fs->has_total_bytes = true;
+ fs->has_used_bytes = true;
+ }
+
g_free(devpath);
+
return fs;
}
@@ -1274,6 +1304,12 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
}
free_fs_mount_list(&mounts);
+ /* We may not issue any FIFREEZE here.
+ * Just unset ga_state here and ready for the next call.
+ */
+ if (i == 0) {
+ ga_unset_frozen(ga_state);
+ }
return i;
error:
@@ -1439,102 +1475,208 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
#define SUSPEND_SUPPORTED 0
#define SUSPEND_NOT_SUPPORTED 1
-static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
- const char *sysfile_str, Error **errp)
+typedef enum {
+ SUSPEND_MODE_DISK = 0,
+ SUSPEND_MODE_RAM = 1,
+ SUSPEND_MODE_HYBRID = 2,
+} SuspendMode;
+
+/*
+ * Executes a command in a child process using g_spawn_sync,
+ * returning an int >= 0 representing the exit status of the
+ * process.
+ *
+ * If the program wasn't found in path, returns -1.
+ *
+ * If a problem happened when creating the child process,
+ * returns -1 and errp is set.
+ */
+static int run_process_child(const char *command[], Error **errp)
+{
+ int exit_status, spawn_flag;
+ GError *g_err = NULL;
+ bool success;
+
+ spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL;
+
+ success = g_spawn_sync(NULL, (char **)command, environ, spawn_flag,
+ NULL, NULL, NULL, NULL,
+ &exit_status, &g_err);
+
+ if (success) {
+ return WEXITSTATUS(exit_status);
+ }
+
+ if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
+ error_setg(errp, "failed to create child process, error '%s'",
+ g_err->message);
+ }
+
+ g_error_free(g_err);
+ return -1;
+}
+
+static bool systemd_supports_mode(SuspendMode mode, Error **errp)
{
Error *local_err = NULL;
- char *pmutils_path;
- pid_t pid;
+ const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
+ "systemd-hybrid-sleep"};
+ const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
int status;
- pmutils_path = g_find_program_in_path(pmutils_bin);
+ status = run_process_child(cmd, &local_err);
- pid = fork();
- if (!pid) {
- char buf[32]; /* hopefully big enough */
- ssize_t ret;
- int fd;
+ /*
+ * systemctl status uses LSB return codes so we can expect
+ * status > 0 and be ok. To assert if the guest has support
+ * for the selected suspend mode, status should be < 4. 4 is
+ * the code for unknown service status, the return value when
+ * the service does not exist. A common value is status = 3
+ * (program is not running).
+ */
+ if (status > 0 && status < 4) {
+ return true;
+ }
- setsid();
- reopen_fd_to_null(0);
- reopen_fd_to_null(1);
- reopen_fd_to_null(2);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
- if (pmutils_path) {
- execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
- }
+ return false;
+}
- /*
- * If we get here either pm-utils is not installed or execle() has
- * failed. Let's try the manual method if the caller wants it.
- */
+static void systemd_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
+ const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
+ int status;
- if (!sysfile_str) {
- _exit(SUSPEND_NOT_SUPPORTED);
- }
+ status = run_process_child(cmd, &local_err);
- fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
- if (fd < 0) {
- _exit(SUSPEND_NOT_SUPPORTED);
- }
+ if (status == 0) {
+ return;
+ }
- ret = read(fd, buf, sizeof(buf)-1);
- if (ret <= 0) {
- _exit(SUSPEND_NOT_SUPPORTED);
- }
- buf[ret] = '\0';
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program 'systemctl %s' was not found",
+ systemctl_args[mode]);
+ return;
+ }
- if (strstr(buf, sysfile_str)) {
- _exit(SUSPEND_SUPPORTED);
- }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp, "the helper program 'systemctl %s' returned an "
+ "unexpected exit status code (%d)",
+ systemctl_args[mode], status);
+ }
+}
- _exit(SUSPEND_NOT_SUPPORTED);
- } else if (pid < 0) {
- error_setg_errno(errp, errno, "failed to create child process");
- goto out;
+static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_args[3] = {"--hibernate", "--suspend",
+ "--suspend-hybrid"};
+ const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == SUSPEND_SUPPORTED) {
+ return true;
+ }
+
+ if ((status == -1) && !local_err) {
+ return false;
}
- ga_wait_child(pid, &status, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- goto out;
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", "pm-is-supported", status);
}
- if (!WIFEXITED(status)) {
- error_setg(errp, "child process has terminated abnormally");
- goto out;
+ return false;
+}
+
+static void pmutils_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
+ "pm-suspend-hybrid"};
+ const char *cmd[2] = {pmutils_binaries[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
}
- switch (WEXITSTATUS(status)) {
- case SUSPEND_SUPPORTED:
- goto out;
- case SUSPEND_NOT_SUPPORTED:
- error_setg(errp,
- "the requested suspend mode is not supported by the guest");
- goto out;
- default:
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program '%s' was not found",
+ pmutils_binaries[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
error_setg(errp,
- "the helper program '%s' returned an unexpected exit status"
- " code (%d)", pmutils_path, WEXITSTATUS(status));
- goto out;
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", pmutils_binaries[mode], status);
}
+}
-out:
- g_free(pmutils_path);
+static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+ char buf[32]; /* hopefully big enough */
+ int fd;
+ ssize_t ret;
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return false;
+ }
+
+ fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
+ if (fd < 0) {
+ return false;
+ }
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ if (ret <= 0) {
+ return false;
+ }
+ buf[ret] = '\0';
+
+ if (strstr(buf, sysfile_str)) {
+ return true;
+ }
+ return false;
}
-static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
- Error **errp)
+static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
{
Error *local_err = NULL;
- char *pmutils_path;
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
pid_t pid;
int status;
- pmutils_path = g_find_program_in_path(pmutils_bin);
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return;
+ }
pid = fork();
- if (pid == 0) {
+ if (!pid) {
/* child */
int fd;
@@ -1543,19 +1685,6 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
reopen_fd_to_null(1);
reopen_fd_to_null(2);
- if (pmutils_path) {
- execle(pmutils_path, pmutils_bin, NULL, environ);
- }
-
- /*
- * If we get here either pm-utils is not installed or execle() has
- * failed. Let's try the manual method if the caller wants it.
- */
-
- if (!sysfile_str) {
- _exit(EXIT_FAILURE);
- }
-
fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
if (fd < 0) {
_exit(EXIT_FAILURE);
@@ -1568,67 +1697,74 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
_exit(EXIT_SUCCESS);
} else if (pid < 0) {
error_setg_errno(errp, errno, "failed to create child process");
- goto out;
+ return;
}
ga_wait_child(pid, &status, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- goto out;
- }
-
- if (!WIFEXITED(status)) {
- error_setg(errp, "child process has terminated abnormally");
- goto out;
+ return;
}
if (WEXITSTATUS(status)) {
error_setg(errp, "child process has failed to suspend");
- goto out;
}
-out:
- g_free(pmutils_path);
}
-void qmp_guest_suspend_disk(Error **errp)
+static void guest_suspend(SuspendMode mode, Error **errp)
{
Error *local_err = NULL;
+ bool mode_supported = false;
- bios_supports_mode("pm-is-supported", "--hibernate", "disk", &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (systemd_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ systemd_suspend(mode, &local_err);
+ }
+
+ if (!local_err) {
return;
}
- guest_suspend("pm-hibernate", "disk", errp);
-}
+ error_free(local_err);
-void qmp_guest_suspend_ram(Error **errp)
-{
- Error *local_err = NULL;
+ if (pmutils_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ pmutils_suspend(mode, &local_err);
+ }
- bios_supports_mode("pm-is-supported", "--suspend", "mem", &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!local_err) {
return;
}
- guest_suspend("pm-suspend", "mem", errp);
-}
+ error_free(local_err);
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- Error *local_err = NULL;
+ if (linux_sys_state_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ linux_sys_state_suspend(mode, &local_err);
+ }
- bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL,
- &local_err);
- if (local_err) {
+ if (!mode_supported) {
+ error_setg(errp,
+ "the requested suspend mode is not supported by the guest");
+ } else if (local_err) {
error_propagate(errp, local_err);
- return;
}
+}
- guest_suspend("pm-suspend-hybrid", NULL, errp);
+void qmp_guest_suspend_disk(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_DISK, errp);
+}
+
+void qmp_guest_suspend_ram(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_RAM, errp);
+}
+
+void qmp_guest_suspend_hybrid(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_HYBRID, errp);
}
static GuestNetworkInterfaceList *
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 70ee5379f6..318d760a74 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -318,7 +318,7 @@ GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
}
if (!has_count) {
count = QGA_READ_COUNT_DEFAULT;
- } else if (count < 0) {
+ } else if (count < 0 || count >= UINT32_MAX) {
error_setg(errp, "value '%" PRId64
"' is invalid for argument count", count);
return NULL;
@@ -670,6 +670,7 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
char fs_name[32];
char vol_info[MAX_PATH+1];
size_t len;
+ uint64_t i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
GuestFilesystemInfo *fs = NULL;
GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size);
@@ -699,10 +700,21 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
fs_name[sizeof(fs_name) - 1] = 0;
fs = g_malloc(sizeof(*fs));
fs->name = g_strdup(guid);
+ fs->has_total_bytes = false;
+ fs->has_used_bytes = false;
if (len == 0) {
fs->mountpoint = g_strdup("System Reserved");
} else {
fs->mountpoint = g_strndup(mnt_point, len);
+ if (GetDiskFreeSpaceEx(fs->mountpoint,
+ (PULARGE_INTEGER) & i64FreeBytesToCaller,
+ (PULARGE_INTEGER) & i64TotalBytes,
+ (PULARGE_INTEGER) & i64FreeBytes)) {
+ fs->used_bytes = i64TotalBytes - i64FreeBytes;
+ fs->total_bytes = i64TotalBytes;
+ fs->has_total_bytes = true;
+ fs->has_used_bytes = true;
+ }
}
fs->type = g_strdup(fs_name);
fs->disk = build_guest_disk_info(guid, errp);
diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs
index 5af11627f8..f751a7e9f7 100644
--- a/qga/installer/qemu-ga.wxs
+++ b/qga/installer/qemu-ga.wxs
@@ -41,7 +41,7 @@
<Product
Name="QEMU guest agent"
- Id="{DF9974AD-E41A-4304-81AD-69AA8F299766}"
+ Id="*"
UpgradeCode="{EB6B8302-C06E-4BEC-ADAC-932C68A3A98D}"
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
Version="$(env.QEMU_GA_VERSION)"
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 17884c7c70..dfbc4a5e32 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -435,7 +435,9 @@
# for up to 10 seconds by VSS.
#
# Returns: Number of file systems currently frozen. On error, all filesystems
-# will be thawed.
+# will be thawed. If no filesystems are frozen as a result of this call,
+# then @guest-fsfreeze-status will remain "thawed" and calling
+# @guest-fsfreeze-thaw is not necessary.
#
# Since: 0.15.0
##
@@ -846,6 +848,8 @@
# @name: disk name
# @mountpoint: mount point path
# @type: file system type string
+# @used-bytes: file system used bytes (since 3.0)
+# @total-bytes: non-root file system total bytes (since 3.0)
# @disk: an array of disk hardware information that the volume lies on,
# which may be empty if the disk type is not supported
#
@@ -853,6 +857,7 @@
##
{ 'struct': 'GuestFilesystemInfo',
'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
+ '*used-bytes': 'uint64', '*total-bytes': 'uint64',
'disk': ['GuestDiskAddress']} }
##
@@ -1168,10 +1173,10 @@
#
# @kernel-release:
# * POSIX: release field returned by uname(2)
-# * Windows: version number of the OS
+# * Windows: build number of the OS
# @kernel-version:
# * POSIX: version field returned by uname(2)
-# * Windows: build number of the OS
+# * Windows: version number of the OS
# @machine:
# * POSIX: machine field returned by uname(2)
# * Windows: one of x86, x86_64, arm, ia64
diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh
index d7eefda0b8..b0dc8a714a 100755
--- a/scripts/qemu-binfmt-conf.sh
+++ b/scripts/qemu-binfmt-conf.sh
@@ -1,10 +1,10 @@
#!/bin/sh
-# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390/HPPA/Xtensa/microblaze
-# program execution by the kernel
+# Enable automatic program execution by the kernel.
qemu_target_list="i386 i486 alpha arm armeb sparc32plus ppc ppc64 ppc64le m68k \
mips mipsel mipsn32 mipsn32el mips64 mips64el \
-sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb microblaze microblazeel"
+sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \
+microblaze microblazeel or1k"
i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
@@ -124,6 +124,10 @@ microblazeel_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\
microblazeel_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
microblazeel_family=microblazeel
+or1k_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5c'
+or1k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
+or1k_family=or1k
+
qemu_get_family() {
cpu=${HOST_ARCH:-$(uname -m)}
case "$cpu" in
@@ -161,21 +165,26 @@ usage() {
cat <<EOF
Usage: qemu-binfmt-conf.sh [--qemu-path PATH][--debian][--systemd CPU]
[--help][--credential yes|no][--exportdir PATH]
+ [--persistent yes|no][--qemu-suffix SUFFIX]
Configure binfmt_misc to use qemu interpreter
- --help: display this usage
- --qemu-path: set path to qemu interpreter ($QEMU_PATH)
- --debian: don't write into /proc,
- instead generate update-binfmts templates
- --systemd: don't write into /proc,
- instead generate file for systemd-binfmt.service
- for the given CPU. If CPU is "ALL", generate a
- file for all known cpus
- --exportdir: define where to write configuration files
- (default: $SYSTEMDDIR or $DEBIANDIR)
- --credential: if yes, credential and security tokens are
- calculated according to the binary to interpret
+ --help: display this usage
+ --qemu-path: set path to qemu interpreter ($QEMU_PATH)
+ --qemu-suffix: add a suffix to the default interpreter name
+ --debian: don't write into /proc,
+ instead generate update-binfmts templates
+ --systemd: don't write into /proc,
+ instead generate file for systemd-binfmt.service
+ for the given CPU. If CPU is "ALL", generate a
+ file for all known cpus
+ --exportdir: define where to write configuration files
+ (default: $SYSTEMDDIR or $DEBIANDIR)
+ --credential: if yes, credential and security tokens are
+ calculated according to the binary to interpret
+ --persistent: if yes, the interpreter is loaded when binfmt is
+ configured and remains in memory. All future uses
+ are cloned from the open file.
To import templates with update-binfmts, use :
@@ -241,7 +250,15 @@ qemu_check_systemd() {
}
qemu_generate_register() {
- echo ":qemu-$cpu:M::$magic:$mask:$qemu:$FLAGS"
+ flags=""
+ if [ "$CREDENTIAL" = "yes" ] ; then
+ flags="OC"
+ fi
+ if [ "$PERSISTENT" = "yes" ] ; then
+ flags="${flags}F"
+ fi
+
+ echo ":qemu-$cpu:M::$magic:$mask:$qemu:$flags"
}
qemu_register_interpreter() {
@@ -260,10 +277,8 @@ package qemu-$cpu
interpreter $qemu
magic $magic
mask $mask
+credential $CREDENTIAL
EOF
- if [ "$FLAGS" = "OC" ] ; then
- echo "credentials yes" >> "$EXPORTDIR/qemu-$cpu"
- fi
}
qemu_set_binfmts() {
@@ -287,6 +302,7 @@ qemu_set_binfmts() {
qemu="$QEMU_PATH/qemu-i386"
fi
+ qemu="$qemu$QEMU_SUFFIX"
if [ "$host_family" != "$family" ] ; then
$BINFMT_SET
fi
@@ -300,9 +316,11 @@ SYSTEMDDIR="/etc/binfmt.d"
DEBIANDIR="/usr/share/binfmts"
QEMU_PATH=/usr/local/bin
-FLAGS=""
+CREDENTIAL=no
+PERSISTENT=no
+QEMU_SUFFIX=""
-options=$(getopt -o ds:Q:e:hc: -l debian,systemd:,qemu-path:,exportdir:,help,credential: -- "$@")
+options=$(getopt -o ds:Q:S:e:hc:p: -l debian,systemd:,qemu-path:,qemu-suffix:,exportdir:,help,credential:,persistent: -- "$@")
eval set -- "$options"
while true ; do
@@ -338,6 +356,10 @@ while true ; do
shift
QEMU_PATH="$1"
;;
+ -F|--qemu-suffix)
+ shift
+ QEMU_SUFFIX="$1"
+ ;;
-e|--exportdir)
shift
EXPORTDIR="$1"
@@ -348,11 +370,11 @@ while true ; do
;;
-c|--credential)
shift
- if [ "$1" = "yes" ] ; then
- FLAGS="OC"
- else
- FLAGS=""
- fi
+ CREDENTIAL="$1"
+ ;;
+ -p|--persistent)
+ shift
+ PERSISTENT="$1"
;;
*)
break
diff --git a/target/openrisc/Makefile.objs b/target/openrisc/Makefile.objs
index 1b98a911ea..b5432f4684 100644
--- a/target/openrisc/Makefile.objs
+++ b/target/openrisc/Makefile.objs
@@ -1,7 +1,7 @@
obj-$(CONFIG_SOFTMMU) += machine.o
-obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
+obj-y += cpu.o exception.o interrupt.o mmu.o translate.o disas.o
obj-y += exception_helper.o fpu_helper.o \
- interrupt_helper.o mmu_helper.o sys_helper.o
+ interrupt_helper.o sys_helper.o
obj-y += gdbstub.o
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
@@ -12,3 +12,4 @@ target/openrisc/decode.inc.c: \
$(PYTHON) $(DECODETREE) -o $@ $<, "GEN", $(TARGET_DIR)$@)
target/openrisc/translate.o: target/openrisc/decode.inc.c
+target/openrisc/disas.o: target/openrisc/decode.inc.c
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index a692a98ec0..fb7cb5c507 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -27,6 +27,7 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value)
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
cpu->env.pc = value;
+ cpu->env.dflag = 0;
}
static bool openrisc_cpu_has_work(CPUState *cs)
@@ -35,6 +36,11 @@ static bool openrisc_cpu_has_work(CPUState *cs)
CPU_INTERRUPT_TIMER);
}
+static void openrisc_disas_set_info(CPUState *cpu, disassemble_info *info)
+{
+ info->print_insn = print_insn_or1k;
+}
+
/* CPUClass::reset() */
static void openrisc_cpu_reset(CPUState *s)
{
@@ -52,8 +58,10 @@ static void openrisc_cpu_reset(CPUState *s)
cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP |
UPR_PMP;
- cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2));
- cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2));
+ cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2))
+ | (DMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
+ cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2))
+ | (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
#ifndef CONFIG_USER_ONLY
cpu->env.picmr = 0x00000000;
@@ -87,10 +95,6 @@ static void openrisc_cpu_initfn(Object *obj)
OpenRISCCPU *cpu = OPENRISC_CPU(obj);
cs->env_ptr = &cpu->env;
-
-#ifndef CONFIG_USER_ONLY
- cpu_openrisc_mmu_init(cpu);
-#endif
}
/* CPU models */
@@ -152,6 +156,7 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
#endif
cc->gdb_num_core_regs = 32 + 3;
cc->tcg_initialize = openrisc_translate_init;
+ cc->disas_set_info = openrisc_disas_set_info;
}
/* Sort alphabetically by type name, except for "any". */
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 35cab65f11..f1b31bc24a 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -222,12 +222,8 @@ enum {
/* TLB size */
enum {
- DTLB_WAYS = 1,
- DTLB_SIZE = 64,
- DTLB_MASK = (DTLB_SIZE-1),
- ITLB_WAYS = 1,
- ITLB_SIZE = 64,
- ITLB_MASK = (ITLB_SIZE-1),
+ TLB_SIZE = 128,
+ TLB_MASK = TLB_SIZE - 1,
};
/* TLB prot */
@@ -241,14 +237,6 @@ enum {
UXE = (1 << 7),
};
-/* check if tlb available */
-enum {
- TLBRET_INVALID = -3,
- TLBRET_NOMATCH = -2,
- TLBRET_BADADDR = -1,
- TLBRET_MATCH = 0
-};
-
typedef struct OpenRISCTLBEntry {
uint32_t mr;
uint32_t tr;
@@ -256,8 +244,8 @@ typedef struct OpenRISCTLBEntry {
#ifndef CONFIG_USER_ONLY
typedef struct CPUOpenRISCTLBContext {
- OpenRISCTLBEntry itlb[ITLB_WAYS][ITLB_SIZE];
- OpenRISCTLBEntry dtlb[DTLB_WAYS][DTLB_SIZE];
+ OpenRISCTLBEntry itlb[TLB_SIZE];
+ OpenRISCTLBEntry dtlb[TLB_SIZE];
int (*cpu_openrisc_map_address_code)(struct OpenRISCCPU *cpu,
hwaddr *physical,
@@ -301,6 +289,10 @@ typedef struct CPUOpenRISCState {
uint32_t dflag; /* In delay slot (boolean) */
+#ifndef CONFIG_USER_ONLY
+ CPUOpenRISCTLBContext tlb;
+#endif
+
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
@@ -310,8 +302,6 @@ typedef struct CPUOpenRISCState {
uint32_t cpucfgr; /* CPU configure register */
#ifndef CONFIG_USER_ONLY
- CPUOpenRISCTLBContext * tlb;
-
QEMUTimer *timer;
uint32_t ttmr; /* Timer tick mode register */
int is_counting;
@@ -358,6 +348,7 @@ void openrisc_translate_init(void);
int openrisc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size,
int rw, int mmu_idx);
int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc);
+int print_insn_or1k(bfd_vma addr, disassemble_info *info);
#define cpu_list cpu_openrisc_list
#define cpu_signal_handler cpu_openrisc_signal_handler
@@ -376,17 +367,6 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu);
void cpu_openrisc_timer_update(OpenRISCCPU *cpu);
void cpu_openrisc_count_start(OpenRISCCPU *cpu);
void cpu_openrisc_count_stop(OpenRISCCPU *cpu);
-
-void cpu_openrisc_mmu_init(OpenRISCCPU *cpu);
-int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address, int rw);
-int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address, int rw);
-int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address, int rw);
#endif
#define OPENRISC_CPU_TYPE_SUFFIX "-" TYPE_OPENRISC_CPU
@@ -395,9 +375,12 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
#include "exec/cpu-all.h"
-#define TB_FLAGS_DFLAG 1
-#define TB_FLAGS_R0_0 2
+#define TB_FLAGS_SM SR_SM
+#define TB_FLAGS_DME SR_DME
+#define TB_FLAGS_IME SR_IME
#define TB_FLAGS_OVE SR_OVE
+#define TB_FLAGS_DFLAG 2 /* reuse SR_TEE */
+#define TB_FLAGS_R0_0 4 /* reuse SR_IEE */
static inline uint32_t cpu_get_gpr(const CPUOpenRISCState *env, int i)
{
@@ -415,17 +398,21 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
{
*pc = env->pc;
*cs_base = 0;
- *flags = (env->dflag
- | (cpu_get_gpr(env, 0) == 0 ? TB_FLAGS_R0_0 : 0)
- | (env->sr & SR_OVE));
+ *flags = (env->dflag ? TB_FLAGS_DFLAG : 0)
+ | (cpu_get_gpr(env, 0) ? 0 : TB_FLAGS_R0_0)
+ | (env->sr & (SR_SM | SR_DME | SR_IME | SR_OVE));
}
static inline int cpu_mmu_index(CPUOpenRISCState *env, bool ifetch)
{
- if (!(env->sr & SR_IME)) {
- return MMU_NOMMU_IDX;
+ int ret = MMU_NOMMU_IDX; /* mmu is disabled */
+
+ if (env->sr & (ifetch ? SR_IME : SR_DME)) {
+ /* The mmu is enabled; test supervisor state. */
+ ret = env->sr & SR_SM ? MMU_SUPERVISOR_IDX : MMU_USER_IDX;
}
- return (env->sr & SR_SM) == 0 ? MMU_USER_IDX : MMU_SUPERVISOR_IDX;
+
+ return ret;
}
static inline uint32_t cpu_get_sr(const CPUOpenRISCState *env)
diff --git a/target/openrisc/disas.c b/target/openrisc/disas.c
new file mode 100644
index 0000000000..4bfd2dd8a6
--- /dev/null
+++ b/target/openrisc/disas.c
@@ -0,0 +1,170 @@
+/*
+ * OpenRISC disassembler
+ *
+ * Copyright (c) 2018 Richard Henderson <rth@twiddle.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "disas/bfd.h"
+#include "qemu/bitops.h"
+#include "cpu.h"
+
+typedef disassemble_info DisasContext;
+
+/* Include the auto-generated decoder. */
+#include "decode.inc.c"
+
+#define output(mnemonic, format, ...) \
+ (info->fprintf_func(info->stream, "%-9s " format, \
+ mnemonic, ##__VA_ARGS__))
+
+int print_insn_or1k(bfd_vma addr, disassemble_info *info)
+{
+ bfd_byte buffer[4];
+ uint32_t insn;
+ int status;
+
+ status = info->read_memory_func(addr, buffer, 4, info);
+ if (status != 0) {
+ info->memory_error_func(status, addr, info);
+ return -1;
+ }
+ insn = bfd_getb32(buffer);
+
+ if (!decode(info, insn)) {
+ output(".long", "%#08x", insn);
+ }
+ return 4;
+}
+
+#define INSN(opcode, format, ...) \
+static bool trans_l_##opcode(disassemble_info *info, \
+ arg_l_##opcode *a, uint32_t insn) \
+{ \
+ output("l." #opcode, format, ##__VA_ARGS__); \
+ return true; \
+}
+
+INSN(add, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(addc, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(sub, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(and, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(or, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(xor, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(sll, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(srl, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(sra, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(ror, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(exths, "r%d, r%d", a->d, a->a)
+INSN(extbs, "r%d, r%d", a->d, a->a)
+INSN(exthz, "r%d, r%d", a->d, a->a)
+INSN(extbz, "r%d, r%d", a->d, a->a)
+INSN(cmov, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(ff1, "r%d, r%d", a->d, a->a)
+INSN(fl1, "r%d, r%d", a->d, a->a)
+INSN(mul, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(mulu, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(div, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(divu, "r%d, r%d, r%d", a->d, a->a, a->b)
+INSN(muld, "r%d, r%d", a->a, a->b)
+INSN(muldu, "r%d, r%d", a->a, a->b)
+INSN(j, "%d", a->n)
+INSN(jal, "%d", a->n)
+INSN(bf, "%d", a->n)
+INSN(bnf, "%d", a->n)
+INSN(jr, "r%d", a->b)
+INSN(jalr, "r%d", a->b)
+INSN(lwa, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(lwz, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(lws, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(lbz, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(lbs, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(lhz, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(lhs, "r%d, %d(r%d)", a->d, a->i, a->a)
+INSN(swa, "%d(r%d), r%d", a->i, a->a, a->b)
+INSN(sw, "%d(r%d), r%d", a->i, a->a, a->b)
+INSN(sb, "%d(r%d), r%d", a->i, a->a, a->b)
+INSN(sh, "%d(r%d), r%d", a->i, a->a, a->b)
+INSN(nop, "")
+INSN(addi, "r%d, r%d, %d", a->d, a->a, a->i)
+INSN(addic, "r%d, r%d, %d", a->d, a->a, a->i)
+INSN(muli, "r%d, r%d, %d", a->d, a->a, a->i)
+INSN(maci, "r%d, %d", a->a, a->i)
+INSN(andi, "r%d, r%d, %d", a->d, a->a, a->k)
+INSN(ori, "r%d, r%d, %d", a->d, a->a, a->k)
+INSN(xori, "r%d, r%d, %d", a->d, a->a, a->i)
+INSN(mfspr, "r%d, r%d, %d", a->d, a->a, a->k)
+INSN(mtspr, "r%d, r%d, %d", a->a, a->b, a->k)
+INSN(mac, "r%d, r%d", a->a, a->b)
+INSN(msb, "r%d, r%d", a->a, a->b)
+INSN(macu, "r%d, r%d", a->a, a->b)
+INSN(msbu, "r%d, r%d", a->a, a->b)
+INSN(slli, "r%d, r%d, %d", a->d, a->a, a->l)
+INSN(srli, "r%d, r%d, %d", a->d, a->a, a->l)
+INSN(srai, "r%d, r%d, %d", a->d, a->a, a->l)
+INSN(rori, "r%d, r%d, %d", a->d, a->a, a->l)
+INSN(movhi, "r%d, %d", a->d, a->k)
+INSN(macrc, "r%d", a->d)
+INSN(sfeq, "r%d, r%d", a->a, a->b)
+INSN(sfne, "r%d, r%d", a->a, a->b)
+INSN(sfgtu, "r%d, r%d", a->a, a->b)
+INSN(sfgeu, "r%d, r%d", a->a, a->b)
+INSN(sfltu, "r%d, r%d", a->a, a->b)
+INSN(sfleu, "r%d, r%d", a->a, a->b)
+INSN(sfgts, "r%d, r%d", a->a, a->b)
+INSN(sfges, "r%d, r%d", a->a, a->b)
+INSN(sflts, "r%d, r%d", a->a, a->b)
+INSN(sfles, "r%d, r%d", a->a, a->b)
+INSN(sfeqi, "r%d, %d", a->a, a->i)
+INSN(sfnei, "r%d, %d", a->a, a->i)
+INSN(sfgtui, "r%d, %d", a->a, a->i)
+INSN(sfgeui, "r%d, %d", a->a, a->i)
+INSN(sfltui, "r%d, %d", a->a, a->i)
+INSN(sfleui, "r%d, %d", a->a, a->i)
+INSN(sfgtsi, "r%d, %d", a->a, a->i)
+INSN(sfgesi, "r%d, %d", a->a, a->i)
+INSN(sfltsi, "r%d, %d", a->a, a->i)
+INSN(sflesi, "r%d, %d", a->a, a->i)
+INSN(sys, "%d", a->k)
+INSN(trap, "%d", a->k)
+INSN(msync, "")
+INSN(psync, "")
+INSN(csync, "")
+INSN(rfe, "")
+
+#define FP_INSN(opcode, suffix, format, ...) \
+static bool trans_lf_##opcode##_##suffix(disassemble_info *info, \
+ arg_lf_##opcode##_##suffix *a, uint32_t insn) \
+{ \
+ output("lf." #opcode "." #suffix, format, ##__VA_ARGS__); \
+ return true; \
+}
+
+FP_INSN(add, s, "r%d, r%d, r%d", a->d, a->a, a->b)
+FP_INSN(sub, s, "r%d, r%d, r%d", a->d, a->a, a->b)
+FP_INSN(mul, s, "r%d, r%d, r%d", a->d, a->a, a->b)
+FP_INSN(div, s, "r%d, r%d, r%d", a->d, a->a, a->b)
+FP_INSN(rem, s, "r%d, r%d, r%d", a->d, a->a, a->b)
+FP_INSN(itof, s, "r%d, r%d", a->d, a->a)
+FP_INSN(ftoi, s, "r%d, r%d", a->d, a->a)
+FP_INSN(madd, s, "r%d, r%d, r%d", a->d, a->a, a->b)
+FP_INSN(sfeq, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfne, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfgt, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfge, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sflt, s, "r%d, r%d", a->a, a->b)
+FP_INSN(sfle, s, "r%d, r%d", a->a, a->b)
diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h
index e37dabc77a..9db9bf3963 100644
--- a/target/openrisc/helper.h
+++ b/target/openrisc/helper.h
@@ -56,5 +56,5 @@ FOP_CMP(le)
DEF_HELPER_FLAGS_1(rfe, 0, void, env)
/* sys */
-DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
-DEF_HELPER_FLAGS_4(mfspr, TCG_CALL_NO_WG, tl, env, tl, tl, tl)
+DEF_HELPER_FLAGS_3(mtspr, 0, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(mfspr, TCG_CALL_NO_WG, tl, env, tl, tl)
diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c
index 3959671c59..bbae956361 100644
--- a/target/openrisc/interrupt.c
+++ b/target/openrisc/interrupt.c
@@ -32,29 +32,22 @@ void openrisc_cpu_do_interrupt(CPUState *cs)
#ifndef CONFIG_USER_ONLY
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
CPUOpenRISCState *env = &cpu->env;
+ int exception = cs->exception_index;
env->epcr = env->pc;
- if (env->dflag) {
- env->dflag = 0;
- env->sr |= SR_DSX;
- env->epcr -= 4;
- } else {
- env->sr &= ~SR_DSX;
- }
- if (cs->exception_index == EXCP_SYSCALL) {
+ if (exception == EXCP_SYSCALL) {
env->epcr += 4;
}
/* When we have an illegal instruction the error effective address
shall be set to the illegal instruction address. */
- if (cs->exception_index == EXCP_ILLEGAL) {
+ if (exception == EXCP_ILLEGAL) {
env->eear = env->pc;
}
- /* For machine-state changed between user-mode and supervisor mode,
- we need flush TLB when we enter&exit EXCP. */
- tlb_flush(cs);
-
+ /* During exceptions esr is populared with the pre-exception sr. */
env->esr = cpu_get_sr(env);
+ /* In parallel sr is updated to disable mmu, interrupts, timers and
+ set the delay slot exception flag. */
env->sr &= ~SR_DME;
env->sr &= ~SR_IME;
env->sr |= SR_SM;
@@ -62,12 +55,38 @@ void openrisc_cpu_do_interrupt(CPUState *cs)
env->sr &= ~SR_TEE;
env->pmr &= ~PMR_DME;
env->pmr &= ~PMR_SME;
- env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
- env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
env->lock_addr = -1;
- if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) {
- hwaddr vect_pc = cs->exception_index << 8;
+ /* Set/clear dsx to indicate if we are in a delay slot exception. */
+ if (env->dflag) {
+ env->dflag = 0;
+ env->sr |= SR_DSX;
+ env->epcr -= 4;
+ } else {
+ env->sr &= ~SR_DSX;
+ }
+
+ if (exception > 0 && exception < EXCP_NR) {
+ static const char * const int_name[EXCP_NR] = {
+ [EXCP_RESET] = "RESET",
+ [EXCP_BUSERR] = "BUSERR (bus error)",
+ [EXCP_DPF] = "DFP (data protection fault)",
+ [EXCP_IPF] = "IPF (code protection fault)",
+ [EXCP_TICK] = "TICK (timer interrupt)",
+ [EXCP_ALIGN] = "ALIGN",
+ [EXCP_ILLEGAL] = "ILLEGAL",
+ [EXCP_INT] = "INT (device interrupt)",
+ [EXCP_DTLBMISS] = "DTLBMISS (data tlb miss)",
+ [EXCP_ITLBMISS] = "ITLBMISS (code tlb miss)",
+ [EXCP_RANGE] = "RANGE",
+ [EXCP_SYSCALL] = "SYSCALL",
+ [EXCP_FPE] = "FPE",
+ [EXCP_TRAP] = "TRAP",
+ };
+
+ qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]);
+
+ hwaddr vect_pc = exception << 8;
if (env->cpucfgr & CPUCFGR_EVBARP) {
vect_pc |= env->evbar;
}
@@ -76,7 +95,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs)
}
env->pc = vect_pc;
} else {
- cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
+ cpu_abort(cs, "Unhandled exception 0x%x\n", exception);
}
#endif
diff --git a/target/openrisc/interrupt_helper.c b/target/openrisc/interrupt_helper.c
index 56620e0571..9c5489f5f7 100644
--- a/target/openrisc/interrupt_helper.c
+++ b/target/openrisc/interrupt_helper.c
@@ -25,36 +25,7 @@
void HELPER(rfe)(CPUOpenRISCState *env)
{
- OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
- CPUState *cs = CPU(cpu);
-#ifndef CONFIG_USER_ONLY
- int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^
- (cpu->env.esr & (SR_SM | SR_IME | SR_DME));
-#endif
- cpu->env.pc = cpu->env.epcr;
- cpu_set_sr(&cpu->env, cpu->env.esr);
- cpu->env.lock_addr = -1;
-
-#ifndef CONFIG_USER_ONLY
- if (cpu->env.sr & SR_DME) {
- cpu->env.tlb->cpu_openrisc_map_address_data =
- &cpu_openrisc_get_phys_data;
- } else {
- cpu->env.tlb->cpu_openrisc_map_address_data =
- &cpu_openrisc_get_phys_nommu;
- }
-
- if (cpu->env.sr & SR_IME) {
- cpu->env.tlb->cpu_openrisc_map_address_code =
- &cpu_openrisc_get_phys_code;
- } else {
- cpu->env.tlb->cpu_openrisc_map_address_code =
- &cpu_openrisc_get_phys_nommu;
- }
-
- if (need_flush_tlb) {
- tlb_flush(cs);
- }
-#endif
- cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+ env->pc = env->epcr;
+ env->lock_addr = -1;
+ cpu_set_sr(env, env->esr);
}
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 0a793eb14d..1eedbf3dbe 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -24,31 +24,6 @@
#include "hw/boards.h"
#include "migration/cpu.h"
-static int env_post_load(void *opaque, int version_id)
-{
- CPUOpenRISCState *env = opaque;
-
- /* Restore MMU handlers */
- if (env->sr & SR_DME) {
- env->tlb->cpu_openrisc_map_address_data =
- &cpu_openrisc_get_phys_data;
- } else {
- env->tlb->cpu_openrisc_map_address_data =
- &cpu_openrisc_get_phys_nommu;
- }
-
- if (env->sr & SR_IME) {
- env->tlb->cpu_openrisc_map_address_code =
- &cpu_openrisc_get_phys_code;
- } else {
- env->tlb->cpu_openrisc_map_address_code =
- &cpu_openrisc_get_phys_nommu;
- }
-
-
- return 0;
-}
-
static const VMStateDescription vmstate_tlb_entry = {
.name = "tlb_entry",
.version_id = 1,
@@ -63,24 +38,17 @@ static const VMStateDescription vmstate_tlb_entry = {
static const VMStateDescription vmstate_cpu_tlb = {
.name = "cpu_tlb",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_2DARRAY(itlb, CPUOpenRISCTLBContext,
- ITLB_WAYS, ITLB_SIZE, 0,
+ VMSTATE_STRUCT_ARRAY(itlb, CPUOpenRISCTLBContext, TLB_SIZE, 0,
vmstate_tlb_entry, OpenRISCTLBEntry),
- VMSTATE_STRUCT_2DARRAY(dtlb, CPUOpenRISCTLBContext,
- DTLB_WAYS, DTLB_SIZE, 0,
+ VMSTATE_STRUCT_ARRAY(dtlb, CPUOpenRISCTLBContext, TLB_SIZE, 0,
vmstate_tlb_entry, OpenRISCTLBEntry),
VMSTATE_END_OF_LIST()
}
};
-#define VMSTATE_CPU_TLB(_f, _s) \
- VMSTATE_STRUCT_POINTER(_f, _s, vmstate_cpu_tlb, CPUOpenRISCTLBContext)
-
-
static int get_sr(QEMUFile *f, void *opaque, size_t size, VMStateField *field)
{
CPUOpenRISCState *env = opaque;
@@ -106,7 +74,6 @@ static const VMStateDescription vmstate_env = {
.name = "env",
.version_id = 6,
.minimum_version_id = 6,
- .post_load = env_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINTTL_2DARRAY(shadow_gpr, CPUOpenRISCState, 16, 32),
VMSTATE_UINTTL(pc, CPUOpenRISCState),
@@ -143,7 +110,8 @@ static const VMStateDescription vmstate_env = {
VMSTATE_UINT32(fpcsr, CPUOpenRISCState),
VMSTATE_UINT64(mac, CPUOpenRISCState),
- VMSTATE_CPU_TLB(tlb, CPUOpenRISCState),
+ VMSTATE_STRUCT(tlb, CPUOpenRISCState, 1,
+ vmstate_cpu_tlb, CPUOpenRISCTLBContext),
VMSTATE_TIMER_PTR(timer, CPUOpenRISCState),
VMSTATE_UINT32(ttmr, CPUOpenRISCState),
diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c
index 2bd782f89b..e7d5219e11 100644
--- a/target/openrisc/mmu.c
+++ b/target/openrisc/mmu.c
@@ -29,227 +29,156 @@
#endif
#ifndef CONFIG_USER_ONLY
-int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address, int rw)
+static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
+ target_ulong address)
{
- *physical = address;
+ *phys_addr = address;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return TLBRET_MATCH;
}
-int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address, int rw)
+static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
+ target_ulong addr, int need, bool super)
{
- int vpn = address >> TARGET_PAGE_BITS;
- int idx = vpn & ITLB_MASK;
- int right = 0;
-
- if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
- return TLBRET_NOMATCH;
- }
- if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
- return TLBRET_INVALID;
- }
-
- if (cpu->env.sr & SR_SM) { /* supervisor mode */
- if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
- right |= PAGE_EXEC;
- }
- } else {
- if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
- right |= PAGE_EXEC;
+ int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK;
+ uint32_t imr = cpu->env.tlb.itlb[idx].mr;
+ uint32_t itr = cpu->env.tlb.itlb[idx].tr;
+ uint32_t dmr = cpu->env.tlb.dtlb[idx].mr;
+ uint32_t dtr = cpu->env.tlb.dtlb[idx].tr;
+ int right, match, valid;
+
+ /* If the ITLB and DTLB indexes map to the same page, we want to
+ load all permissions all at once. If the destination pages do
+ not match, zap the one we don't need. */
+ if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) {
+ if (need & PAGE_EXEC) {
+ dmr = dtr = 0;
+ } else {
+ imr = itr = 0;
}
}
- if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
- return TLBRET_BADADDR;
- }
-
- *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
- (address & (TARGET_PAGE_SIZE-1));
+ /* Check if either of the entries matches the source address. */
+ match = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC;
+ match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE;
+
+ /* Check if either of the entries is valid. */
+ valid = imr & 1 ? PAGE_EXEC : 0;
+ valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0;
+ valid &= match;
+
+ /* Collect the permissions from the entries. */
+ right = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0;
+ right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0;
+ right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0;
+ right &= valid;
+
+ /* Note that above we validated that itr and dtr match on page.
+ So oring them together changes nothing without having to
+ check which one we needed. We also want to store to these
+ variables even on failure, as it avoids compiler warnings. */
+ *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
*prot = right;
- return TLBRET_MATCH;
-}
-int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address, int rw)
-{
- int vpn = address >> TARGET_PAGE_BITS;
- int idx = vpn & DTLB_MASK;
- int right = 0;
+ qemu_log_mask(CPU_LOG_MMU,
+ "MMU lookup: need %d match %d valid %d right %d -> %s\n",
+ need, match, valid, right, (need & right) ? "OK" : "FAIL");
- if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
- return TLBRET_NOMATCH;
- }
- if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
- return TLBRET_INVALID;
+ /* Check the collective permissions are present. */
+ if (likely(need & right)) {
+ return 0; /* success! */
}
- if (cpu->env.sr & SR_SM) { /* supervisor mode */
- if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
- right |= PAGE_READ;
- }
- if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
- right |= PAGE_WRITE;
- }
+ /* Determine what kind of failure we have. */
+ if (need & valid) {
+ return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF;
} else {
- if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
- right |= PAGE_READ;
- }
- if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
- right |= PAGE_WRITE;
- }
+ return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
}
-
- if (!(rw & 1) && ((right & PAGE_READ) == 0)) {
- return TLBRET_BADADDR;
- }
- if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
- return TLBRET_BADADDR;
- }
-
- *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
- (address & (TARGET_PAGE_SIZE-1));
- *prot = right;
- return TLBRET_MATCH;
-}
-
-static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
- hwaddr *physical,
- int *prot, target_ulong address,
- int rw)
-{
- int ret = TLBRET_MATCH;
-
- if (rw == MMU_INST_FETCH) { /* ITLB */
- *physical = 0;
- ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
- prot, address, rw);
- } else { /* DTLB */
- ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
- prot, address, rw);
- }
-
- return ret;
}
#endif
-static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
- target_ulong address,
- int rw, int tlb_error)
+static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
+ int exception)
{
CPUState *cs = CPU(cpu);
- int exception = 0;
-
- switch (tlb_error) {
- default:
- if (rw == 2) {
- exception = EXCP_IPF;
- } else {
- exception = EXCP_DPF;
- }
- break;
-#ifndef CONFIG_USER_ONLY
- case TLBRET_BADADDR:
- if (rw == 2) {
- exception = EXCP_IPF;
- } else {
- exception = EXCP_DPF;
- }
- break;
- case TLBRET_INVALID:
- case TLBRET_NOMATCH:
- /* No TLB match for a mapped address */
- if (rw == 2) {
- exception = EXCP_ITLBMISS;
- } else {
- exception = EXCP_DTLBMISS;
- }
- break;
-#endif
- }
cs->exception_index = exception;
cpu->env.eear = address;
cpu->env.lock_addr = -1;
}
-#ifndef CONFIG_USER_ONLY
int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
int rw, int mmu_idx)
{
+#ifdef CONFIG_USER_ONLY
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
- int ret = 0;
- hwaddr physical = 0;
- int prot = 0;
-
- ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
- address, rw);
-
- if (ret == TLBRET_MATCH) {
- tlb_set_page(cs, address & TARGET_PAGE_MASK,
- physical & TARGET_PAGE_MASK, prot,
- mmu_idx, TARGET_PAGE_SIZE);
- ret = 0;
- } else if (ret < 0) {
- cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
- ret = 1;
- }
-
- return ret;
-}
+ raise_mmu_exception(cpu, address, EXCP_DPF);
+ return 1;
#else
-int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
- int rw, int mmu_idx)
-{
- OpenRISCCPU *cpu = OPENRISC_CPU(cs);
- int ret = 0;
-
- cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
- ret = 1;
-
- return ret;
-}
+ g_assert_not_reached();
#endif
+}
#ifndef CONFIG_USER_ONLY
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ int prot, excp, sr = cpu->env.sr;
hwaddr phys_addr;
- int prot;
- int miss;
- /* Check memory for any kind of address, since during debug the
- gdb can ask for anything, check data tlb for address */
- miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0);
-
- /* Check instruction tlb */
- if (miss) {
- miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr,
- MMU_INST_FETCH);
- }
+ switch (sr & (SR_DME | SR_IME)) {
+ case SR_DME | SR_IME:
+ /* The mmu is definitely enabled. */
+ excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
+ PAGE_EXEC | PAGE_READ | PAGE_WRITE,
+ (sr & SR_SM) != 0);
+ return excp ? -1 : phys_addr;
- /* Last, fall back to a plain address */
- if (miss) {
- miss = cpu_openrisc_get_phys_nommu(cpu, &phys_addr, &prot, addr, 0);
- }
+ default:
+ /* The mmu is partially enabled, and we don't really have
+ a "real" access type. Begin by trying the mmu, but if
+ that fails try again without. */
+ excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
+ PAGE_EXEC | PAGE_READ | PAGE_WRITE,
+ (sr & SR_SM) != 0);
+ if (!excp) {
+ return phys_addr;
+ }
+ /* fallthru */
- if (miss) {
- return -1;
- } else {
+ case 0:
+ /* The mmu is definitely disabled; lookups never fail. */
+ get_phys_nommu(&phys_addr, &prot, addr);
return phys_addr;
}
}
-void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
+void tlb_fill(CPUState *cs, target_ulong addr, int size,
+ MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
{
- cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
+ OpenRISCCPU *cpu = OPENRISC_CPU(cs);
+ int prot, excp;
+ hwaddr phys_addr;
+
+ if (mmu_idx == MMU_NOMMU_IDX) {
+ /* The mmu is disabled; lookups never fail. */
+ get_phys_nommu(&phys_addr, &prot, addr);
+ excp = 0;
+ } else {
+ bool super = mmu_idx == MMU_SUPERVISOR_IDX;
+ int need = (access_type == MMU_INST_FETCH ? PAGE_EXEC
+ : access_type == MMU_DATA_STORE ? PAGE_WRITE
+ : PAGE_READ);
+ excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super);
+ }
+
+ if (unlikely(excp)) {
+ raise_mmu_exception(cpu, addr, excp);
+ cpu_loop_exit_restore(cs, retaddr);
+ }
- cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
- cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
+ tlb_set_page(cs, addr & TARGET_PAGE_MASK,
+ phys_addr & TARGET_PAGE_MASK, prot,
+ mmu_idx, TARGET_PAGE_SIZE);
}
#endif
diff --git a/target/openrisc/mmu_helper.c b/target/openrisc/mmu_helper.c
deleted file mode 100644
index 97e1d17b5a..0000000000
--- a/target/openrisc/mmu_helper.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * OpenRISC MMU helper routines
- *
- * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * Zhizhou Zhang <etouzh@gmail.com>
- *
- * 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 "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-
-#ifndef CONFIG_USER_ONLY
-
-void tlb_fill(CPUState *cs, target_ulong addr, int size,
- MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
-{
- int ret;
-
- ret = openrisc_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
-
- if (ret) {
- /* Raise Exception. */
- cpu_loop_exit_restore(cs, retaddr);
- }
-}
-#endif
diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c
index b284064381..b66a45c1e0 100644
--- a/target/openrisc/sys_helper.c
+++ b/target/openrisc/sys_helper.c
@@ -27,13 +27,12 @@
#define TO_SPR(group, number) (((group) << 11) + (number))
-void HELPER(mtspr)(CPUOpenRISCState *env,
- target_ulong ra, target_ulong rb, target_ulong offset)
+void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
{
#ifndef CONFIG_USER_ONLY
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
CPUState *cs = CPU(cpu);
- int spr = (ra | offset);
+ target_ulong mr;
int idx;
switch (spr) {
@@ -57,26 +56,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
break;
case TO_SPR(0, 17): /* SR */
- if ((env->sr & (SR_IME | SR_DME | SR_SM)) ^
- (rb & (SR_IME | SR_DME | SR_SM))) {
- tlb_flush(cs);
- }
cpu_set_sr(env, rb);
- if (env->sr & SR_DME) {
- env->tlb->cpu_openrisc_map_address_data =
- &cpu_openrisc_get_phys_data;
- } else {
- env->tlb->cpu_openrisc_map_address_data =
- &cpu_openrisc_get_phys_nommu;
- }
-
- if (env->sr & SR_IME) {
- env->tlb->cpu_openrisc_map_address_code =
- &cpu_openrisc_get_phys_code;
- } else {
- env->tlb->cpu_openrisc_map_address_code =
- &cpu_openrisc_get_phys_nommu;
- }
break;
case TO_SPR(0, 18): /* PPC */
@@ -98,18 +78,22 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
idx = (spr - 1024);
env->shadow_gpr[idx / 32][idx % 32] = rb;
+ break;
- case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
+ case TO_SPR(1, 512) ... TO_SPR(1, 512 + TLB_SIZE - 1): /* DTLBW0MR 0-127 */
idx = spr - TO_SPR(1, 512);
- if (!(rb & 1)) {
- tlb_flush_page(cs, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK);
+ mr = env->tlb.dtlb[idx].mr;
+ if (mr & 1) {
+ tlb_flush_page(cs, mr & TARGET_PAGE_MASK);
+ }
+ if (rb & 1) {
+ tlb_flush_page(cs, rb & TARGET_PAGE_MASK);
}
- env->tlb->dtlb[0][idx].mr = rb;
+ env->tlb.dtlb[idx].mr = rb;
break;
-
- case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */
+ case TO_SPR(1, 640) ... TO_SPR(1, 640 + TLB_SIZE - 1): /* DTLBW0TR 0-127 */
idx = spr - TO_SPR(1, 640);
- env->tlb->dtlb[0][idx].tr = rb;
+ env->tlb.dtlb[idx].tr = rb;
break;
case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */
case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */
@@ -118,17 +102,21 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */
case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */
break;
- case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */
+
+ case TO_SPR(2, 512) ... TO_SPR(2, 512 + TLB_SIZE - 1): /* ITLBW0MR 0-127 */
idx = spr - TO_SPR(2, 512);
- if (!(rb & 1)) {
- tlb_flush_page(cs, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK);
+ mr = env->tlb.itlb[idx].mr;
+ if (mr & 1) {
+ tlb_flush_page(cs, mr & TARGET_PAGE_MASK);
+ }
+ if (rb & 1) {
+ tlb_flush_page(cs, rb & TARGET_PAGE_MASK);
}
- env->tlb->itlb[0][idx].mr = rb;
+ env->tlb.itlb[idx].mr = rb;
break;
-
- case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */
+ case TO_SPR(2, 640) ... TO_SPR(2, 640 + TLB_SIZE - 1): /* ITLBW0TR 0-127 */
idx = spr - TO_SPR(2, 640);
- env->tlb->itlb[0][idx].tr = rb;
+ env->tlb.itlb[idx].tr = rb;
break;
case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */
case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */
@@ -137,6 +125,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */
case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */
break;
+
case TO_SPR(5, 1): /* MACLO */
env->mac = deposit64(env->mac, 0, 32, rb);
break;
@@ -153,7 +142,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
}
break;
case TO_SPR(9, 0): /* PICMR */
- env->picmr |= rb;
+ env->picmr = rb;
break;
case TO_SPR(9, 2): /* PICSR */
env->picsr &= ~rb;
@@ -201,13 +190,12 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
#endif
}
-target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
- target_ulong rd, target_ulong ra, uint32_t offset)
+target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
+ target_ulong spr)
{
#ifndef CONFIG_USER_ONLY
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
CPUState *cs = CPU(cpu);
- int spr = (ra | offset);
int idx;
switch (spr) {
@@ -259,13 +247,13 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
idx = (spr - 1024);
return env->shadow_gpr[idx / 32][idx % 32];
- case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
+ case TO_SPR(1, 512) ... TO_SPR(1, 512 + TLB_SIZE - 1): /* DTLBW0MR 0-127 */
idx = spr - TO_SPR(1, 512);
- return env->tlb->dtlb[0][idx].mr;
+ return env->tlb.dtlb[idx].mr;
- case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */
+ case TO_SPR(1, 640) ... TO_SPR(1, 640 + TLB_SIZE - 1): /* DTLBW0TR 0-127 */
idx = spr - TO_SPR(1, 640);
- return env->tlb->dtlb[0][idx].tr;
+ return env->tlb.dtlb[idx].tr;
case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */
case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */
@@ -275,13 +263,13 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */
break;
- case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */
+ case TO_SPR(2, 512) ... TO_SPR(2, 512 + TLB_SIZE - 1): /* ITLBW0MR 0-127 */
idx = spr - TO_SPR(2, 512);
- return env->tlb->itlb[0][idx].mr;
+ return env->tlb.itlb[idx].mr;
- case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */
+ case TO_SPR(2, 640) ... TO_SPR(2, 640 + TLB_SIZE - 1): /* ITLBW0TR 0-127 */
idx = spr - TO_SPR(2, 640);
- return env->tlb->itlb[0][idx].tr;
+ return env->tlb.itlb[idx].tr;
case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */
case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index d69f8d0422..a271cd3903 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -36,22 +36,29 @@
#include "trace-tcg.h"
#include "exec/log.h"
-#define LOG_DIS(str, ...) \
- qemu_log_mask(CPU_LOG_TB_IN_ASM, "%08x: " str, dc->base.pc_next, \
- ## __VA_ARGS__)
-
/* is_jmp field values */
-#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
-#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
-#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
+#define DISAS_EXIT DISAS_TARGET_0 /* force exit to main loop */
+#define DISAS_JUMP DISAS_TARGET_1 /* exit via jmp_pc/jmp_pc_imm */
typedef struct DisasContext {
DisasContextBase base;
uint32_t mem_idx;
uint32_t tb_flags;
uint32_t delayed_branch;
+
+ /* If not -1, jmp_pc contains this value and so is a direct jump. */
+ target_ulong jmp_pc_imm;
} DisasContext;
+static inline bool is_user(DisasContext *dc)
+{
+#ifdef CONFIG_USER_ONLY
+ return true;
+#else
+ return !(dc->tb_flags & TB_FLAGS_SM);
+#endif
+}
+
/* Include the auto-generated decoder. */
#include "decode.inc.c"
@@ -165,34 +172,6 @@ static void check_ov64s(DisasContext *dc)
} \
} while (0)
-static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
-{
- if (unlikely(dc->base.singlestep_enabled)) {
- return false;
- }
-
-#ifndef CONFIG_USER_ONLY
- return (dc->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
-#else
- return true;
-#endif
-}
-
-static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
-{
- if (use_goto_tb(dc, dest)) {
- tcg_gen_movi_tl(cpu_pc, dest);
- tcg_gen_goto_tb(n);
- tcg_gen_exit_tb(dc->base.tb, n);
- } else {
- tcg_gen_movi_tl(cpu_pc, dest);
- if (dc->base.singlestep_enabled) {
- gen_exception(dc, EXCP_DEBUG);
- }
- tcg_gen_exit_tb(NULL, 0);
- }
-}
-
static void gen_ove_cy(DisasContext *dc)
{
if (dc->tb_flags & SR_OVE) {
@@ -457,7 +436,6 @@ static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb)
static bool trans_l_add(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.add r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
gen_add(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -465,7 +443,6 @@ static bool trans_l_add(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_addc(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.addc r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
gen_addc(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -473,7 +450,6 @@ static bool trans_l_addc(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_sub(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.sub r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
gen_sub(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -481,7 +457,6 @@ static bool trans_l_sub(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_and(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.and r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_and_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -489,7 +464,6 @@ static bool trans_l_and(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_or(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.or r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_or_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -497,7 +471,6 @@ static bool trans_l_or(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_xor(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.xor r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_xor_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -505,7 +478,6 @@ static bool trans_l_xor(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_sll(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.sll r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_shl_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -513,7 +485,6 @@ static bool trans_l_sll(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_srl(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.srl r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_shr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -521,7 +492,6 @@ static bool trans_l_srl(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_sra(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.sra r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_sar_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -529,7 +499,6 @@ static bool trans_l_sra(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_ror(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.ror r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
tcg_gen_rotr_tl(cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -537,7 +506,6 @@ static bool trans_l_ror(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_exths(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("l.exths r%d, r%d\n", a->d, a->a);
check_r0_write(a->d);
tcg_gen_ext16s_tl(cpu_R[a->d], cpu_R[a->a]);
return true;
@@ -545,7 +513,6 @@ static bool trans_l_exths(DisasContext *dc, arg_da *a, uint32_t insn)
static bool trans_l_extbs(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("l.extbs r%d, r%d\n", a->d, a->a);
check_r0_write(a->d);
tcg_gen_ext8s_tl(cpu_R[a->d], cpu_R[a->a]);
return true;
@@ -553,7 +520,6 @@ static bool trans_l_extbs(DisasContext *dc, arg_da *a, uint32_t insn)
static bool trans_l_exthz(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("l.exthz r%d, r%d\n", a->d, a->a);
check_r0_write(a->d);
tcg_gen_ext16u_tl(cpu_R[a->d], cpu_R[a->a]);
return true;
@@ -561,7 +527,6 @@ static bool trans_l_exthz(DisasContext *dc, arg_da *a, uint32_t insn)
static bool trans_l_extbz(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("l.extbz r%d, r%d\n", a->d, a->a);
check_r0_write(a->d);
tcg_gen_ext8u_tl(cpu_R[a->d], cpu_R[a->a]);
return true;
@@ -570,7 +535,6 @@ static bool trans_l_extbz(DisasContext *dc, arg_da *a, uint32_t insn)
static bool trans_l_cmov(DisasContext *dc, arg_dab *a, uint32_t insn)
{
TCGv zero;
- LOG_DIS("l.cmov r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
zero = tcg_const_tl(0);
@@ -582,8 +546,6 @@ static bool trans_l_cmov(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_ff1(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("l.ff1 r%d, r%d\n", a->d, a->a);
-
check_r0_write(a->d);
tcg_gen_ctzi_tl(cpu_R[a->d], cpu_R[a->a], -1);
tcg_gen_addi_tl(cpu_R[a->d], cpu_R[a->d], 1);
@@ -592,8 +554,6 @@ static bool trans_l_ff1(DisasContext *dc, arg_da *a, uint32_t insn)
static bool trans_l_fl1(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("l.fl1 r%d, r%d\n", a->d, a->a);
-
check_r0_write(a->d);
tcg_gen_clzi_tl(cpu_R[a->d], cpu_R[a->a], TARGET_LONG_BITS);
tcg_gen_subfi_tl(cpu_R[a->d], TARGET_LONG_BITS, cpu_R[a->d]);
@@ -602,8 +562,6 @@ static bool trans_l_fl1(DisasContext *dc, arg_da *a, uint32_t insn)
static bool trans_l_mul(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.mul r%d, r%d, r%d\n", a->d, a->a, a->b);
-
check_r0_write(a->d);
gen_mul(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -611,8 +569,6 @@ static bool trans_l_mul(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_mulu(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.mulu r%d, r%d, r%d\n", a->d, a->a, a->b);
-
check_r0_write(a->d);
gen_mulu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -620,8 +576,6 @@ static bool trans_l_mulu(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_div(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.div r%d, r%d, r%d\n", a->d, a->a, a->b);
-
check_r0_write(a->d);
gen_div(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -629,8 +583,6 @@ static bool trans_l_div(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_divu(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("l.divu r%d, r%d, r%d\n", a->d, a->a, a->b);
-
check_r0_write(a->d);
gen_divu(dc, cpu_R[a->d], cpu_R[a->a], cpu_R[a->b]);
return true;
@@ -638,14 +590,12 @@ static bool trans_l_divu(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_l_muld(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("l.muld r%d, r%d\n", a->a, a->b);
gen_muld(dc, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_muldu(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("l.muldu r%d, r%d\n", a->a, a->b);
gen_muldu(dc, cpu_R[a->a], cpu_R[a->b]);
return true;
}
@@ -654,8 +604,8 @@ static bool trans_l_j(DisasContext *dc, arg_l_j *a, uint32_t insn)
{
target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
- LOG_DIS("l.j %d\n", a->n);
tcg_gen_movi_tl(jmp_pc, tmp_pc);
+ dc->jmp_pc_imm = tmp_pc;
dc->delayed_branch = 2;
return true;
}
@@ -665,11 +615,11 @@ static bool trans_l_jal(DisasContext *dc, arg_l_jal *a, uint32_t insn)
target_ulong tmp_pc = dc->base.pc_next + a->n * 4;
target_ulong ret_pc = dc->base.pc_next + 8;
- LOG_DIS("l.jal %d\n", a->n);
tcg_gen_movi_tl(cpu_R[9], ret_pc);
/* Optimize jal being used to load the PC for PIC. */
if (tmp_pc != ret_pc) {
tcg_gen_movi_tl(jmp_pc, tmp_pc);
+ dc->jmp_pc_imm = tmp_pc;
dc->delayed_branch = 2;
}
return true;
@@ -692,21 +642,18 @@ static void do_bf(DisasContext *dc, arg_l_bf *a, TCGCond cond)
static bool trans_l_bf(DisasContext *dc, arg_l_bf *a, uint32_t insn)
{
- LOG_DIS("l.bf %d\n", a->n);
do_bf(dc, a, TCG_COND_NE);
return true;
}
static bool trans_l_bnf(DisasContext *dc, arg_l_bf *a, uint32_t insn)
{
- LOG_DIS("l.bnf %d\n", a->n);
do_bf(dc, a, TCG_COND_EQ);
return true;
}
static bool trans_l_jr(DisasContext *dc, arg_l_jr *a, uint32_t insn)
{
- LOG_DIS("l.jr r%d\n", a->b);
tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]);
dc->delayed_branch = 2;
return true;
@@ -714,7 +661,6 @@ static bool trans_l_jr(DisasContext *dc, arg_l_jr *a, uint32_t insn)
static bool trans_l_jalr(DisasContext *dc, arg_l_jalr *a, uint32_t insn)
{
- LOG_DIS("l.jalr r%d\n", a->b);
tcg_gen_mov_tl(jmp_pc, cpu_R[a->b]);
tcg_gen_movi_tl(cpu_R[9], dc->base.pc_next + 8);
dc->delayed_branch = 2;
@@ -725,8 +671,6 @@ static bool trans_l_lwa(DisasContext *dc, arg_load *a, uint32_t insn)
{
TCGv ea;
- LOG_DIS("l.lwa r%d, r%d, %d\n", a->d, a->a, a->i);
-
check_r0_write(a->d);
ea = tcg_temp_new();
tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
@@ -750,42 +694,36 @@ static void do_load(DisasContext *dc, arg_load *a, TCGMemOp mop)
static bool trans_l_lwz(DisasContext *dc, arg_load *a, uint32_t insn)
{
- LOG_DIS("l.lwz r%d, r%d, %d\n", a->d, a->a, a->i);
do_load(dc, a, MO_TEUL);
return true;
}
static bool trans_l_lws(DisasContext *dc, arg_load *a, uint32_t insn)
{
- LOG_DIS("l.lws r%d, r%d, %d\n", a->d, a->a, a->i);
do_load(dc, a, MO_TESL);
return true;
}
static bool trans_l_lbz(DisasContext *dc, arg_load *a, uint32_t insn)
{
- LOG_DIS("l.lbz r%d, r%d, %d\n", a->d, a->a, a->i);
do_load(dc, a, MO_UB);
return true;
}
static bool trans_l_lbs(DisasContext *dc, arg_load *a, uint32_t insn)
{
- LOG_DIS("l.lbs r%d, r%d, %d\n", a->d, a->a, a->i);
do_load(dc, a, MO_SB);
return true;
}
static bool trans_l_lhz(DisasContext *dc, arg_load *a, uint32_t insn)
{
- LOG_DIS("l.lhz r%d, r%d, %d\n", a->d, a->a, a->i);
do_load(dc, a, MO_TEUW);
return true;
}
static bool trans_l_lhs(DisasContext *dc, arg_load *a, uint32_t insn)
{
- LOG_DIS("l.lhs r%d, r%d, %d\n", a->d, a->a, a->i);
do_load(dc, a, MO_TESW);
return true;
}
@@ -795,8 +733,6 @@ static bool trans_l_swa(DisasContext *dc, arg_store *a, uint32_t insn)
TCGv ea, val;
TCGLabel *lab_fail, *lab_done;
- LOG_DIS("l.swa r%d, r%d, %d\n", a->a, a->b, a->i);
-
ea = tcg_temp_new();
tcg_gen_addi_tl(ea, cpu_R[a->a], a->i);
@@ -837,28 +773,24 @@ static void do_store(DisasContext *dc, arg_store *a, TCGMemOp mop)
static bool trans_l_sw(DisasContext *dc, arg_store *a, uint32_t insn)
{
- LOG_DIS("l.sw r%d, r%d, %d\n", a->a, a->b, a->i);
do_store(dc, a, MO_TEUL);
return true;
}
static bool trans_l_sb(DisasContext *dc, arg_store *a, uint32_t insn)
{
- LOG_DIS("l.sb r%d, r%d, %d\n", a->a, a->b, a->i);
do_store(dc, a, MO_UB);
return true;
}
static bool trans_l_sh(DisasContext *dc, arg_store *a, uint32_t insn)
{
- LOG_DIS("l.sh r%d, r%d, %d\n", a->a, a->b, a->i);
do_store(dc, a, MO_TEUW);
return true;
}
static bool trans_l_nop(DisasContext *dc, arg_l_nop *a, uint32_t insn)
{
- LOG_DIS("l.nop %d\n", a->k);
return true;
}
@@ -866,7 +798,6 @@ static bool trans_l_addi(DisasContext *dc, arg_rri *a, uint32_t insn)
{
TCGv t0;
- LOG_DIS("l.addi r%d, r%d, %d\n", a->d, a->a, a->i);
check_r0_write(a->d);
t0 = tcg_const_tl(a->i);
gen_add(dc, cpu_R[a->d], cpu_R[a->a], t0);
@@ -878,7 +809,6 @@ static bool trans_l_addic(DisasContext *dc, arg_rri *a, uint32_t insn)
{
TCGv t0;
- LOG_DIS("l.addic r%d, r%d, %d\n", a->d, a->a, a->i);
check_r0_write(a->d);
t0 = tcg_const_tl(a->i);
gen_addc(dc, cpu_R[a->d], cpu_R[a->a], t0);
@@ -890,7 +820,6 @@ static bool trans_l_muli(DisasContext *dc, arg_rri *a, uint32_t insn)
{
TCGv t0;
- LOG_DIS("l.muli r%d, r%d, %d\n", a->d, a->a, a->i);
check_r0_write(a->d);
t0 = tcg_const_tl(a->i);
gen_mul(dc, cpu_R[a->d], cpu_R[a->a], t0);
@@ -902,7 +831,6 @@ static bool trans_l_maci(DisasContext *dc, arg_l_maci *a, uint32_t insn)
{
TCGv t0;
- LOG_DIS("l.maci r%d, %d\n", a->a, a->i);
t0 = tcg_const_tl(a->i);
gen_mac(dc, cpu_R[a->a], t0);
tcg_temp_free(t0);
@@ -911,7 +839,6 @@ static bool trans_l_maci(DisasContext *dc, arg_l_maci *a, uint32_t insn)
static bool trans_l_andi(DisasContext *dc, arg_rrk *a, uint32_t insn)
{
- LOG_DIS("l.andi r%d, r%d, %d\n", a->d, a->a, a->k);
check_r0_write(a->d);
tcg_gen_andi_tl(cpu_R[a->d], cpu_R[a->a], a->k);
return true;
@@ -919,7 +846,6 @@ static bool trans_l_andi(DisasContext *dc, arg_rrk *a, uint32_t insn)
static bool trans_l_ori(DisasContext *dc, arg_rrk *a, uint32_t insn)
{
- LOG_DIS("l.ori r%d, r%d, %d\n", a->d, a->a, a->k);
check_r0_write(a->d);
tcg_gen_ori_tl(cpu_R[a->d], cpu_R[a->a], a->k);
return true;
@@ -927,7 +853,6 @@ static bool trans_l_ori(DisasContext *dc, arg_rrk *a, uint32_t insn)
static bool trans_l_xori(DisasContext *dc, arg_rri *a, uint32_t insn)
{
- LOG_DIS("l.xori r%d, r%d, %d\n", a->d, a->a, a->i);
check_r0_write(a->d);
tcg_gen_xori_tl(cpu_R[a->d], cpu_R[a->a], a->i);
return true;
@@ -935,72 +860,73 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a, uint32_t insn)
static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a, uint32_t insn)
{
- LOG_DIS("l.mfspr r%d, r%d, %d\n", a->d, a->a, a->k);
check_r0_write(a->d);
-#ifdef CONFIG_USER_ONLY
- gen_illegal_exception(dc);
-#else
- if (dc->mem_idx == MMU_USER_IDX) {
+ if (is_user(dc)) {
gen_illegal_exception(dc);
} else {
- TCGv_i32 ti = tcg_const_i32(a->k);
- gen_helper_mfspr(cpu_R[a->d], cpu_env, cpu_R[a->d], cpu_R[a->a], ti);
- tcg_temp_free_i32(ti);
+ TCGv spr = tcg_temp_new();
+ tcg_gen_ori_tl(spr, cpu_R[a->a], a->k);
+ gen_helper_mfspr(cpu_R[a->d], cpu_env, cpu_R[a->d], spr);
+ tcg_temp_free(spr);
}
-#endif
return true;
}
static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a, uint32_t insn)
{
- LOG_DIS("l.mtspr r%d, r%d, %d\n", a->a, a->b, a->k);
-
-#ifdef CONFIG_USER_ONLY
- gen_illegal_exception(dc);
-#else
- if (dc->mem_idx == MMU_USER_IDX) {
+ if (is_user(dc)) {
gen_illegal_exception(dc);
} else {
- TCGv_i32 ti = tcg_const_i32(a->k);
- gen_helper_mtspr(cpu_env, cpu_R[a->a], cpu_R[a->b], ti);
- tcg_temp_free_i32(ti);
+ TCGv spr;
+
+ /* For SR, we will need to exit the TB to recognize the new
+ * exception state. For NPC, in theory this counts as a branch
+ * (although the SPR only exists for use by an ICE). Save all
+ * of the cpu state first, allowing it to be overwritten.
+ */
+ if (dc->delayed_branch) {
+ tcg_gen_mov_tl(cpu_pc, jmp_pc);
+ tcg_gen_discard_tl(jmp_pc);
+ } else {
+ tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4);
+ }
+ dc->base.is_jmp = DISAS_EXIT;
+
+ spr = tcg_temp_new();
+ tcg_gen_ori_tl(spr, cpu_R[a->a], a->k);
+ gen_helper_mtspr(cpu_env, spr, cpu_R[a->b]);
+ tcg_temp_free(spr);
}
-#endif
return true;
}
static bool trans_l_mac(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("l.mac r%d, r%d\n", a->a, a->b);
gen_mac(dc, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_msb(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("l.msb r%d, r%d\n", a->a, a->b);
gen_msb(dc, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_macu(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("l.mac r%d, r%d\n", a->a, a->b);
gen_macu(dc, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_msbu(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("l.msb r%d, r%d\n", a->a, a->b);
gen_msbu(dc, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_slli(DisasContext *dc, arg_dal *a, uint32_t insn)
{
- LOG_DIS("l.slli r%d, r%d, %d\n", a->d, a->a, a->l);
check_r0_write(a->d);
tcg_gen_shli_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
return true;
@@ -1008,7 +934,6 @@ static bool trans_l_slli(DisasContext *dc, arg_dal *a, uint32_t insn)
static bool trans_l_srli(DisasContext *dc, arg_dal *a, uint32_t insn)
{
- LOG_DIS("l.srli r%d, r%d, %d\n", a->d, a->a, a->l);
check_r0_write(a->d);
tcg_gen_shri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
return true;
@@ -1016,7 +941,6 @@ static bool trans_l_srli(DisasContext *dc, arg_dal *a, uint32_t insn)
static bool trans_l_srai(DisasContext *dc, arg_dal *a, uint32_t insn)
{
- LOG_DIS("l.srai r%d, r%d, %d\n", a->d, a->a, a->l);
check_r0_write(a->d);
tcg_gen_sari_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
return true;
@@ -1024,7 +948,6 @@ static bool trans_l_srai(DisasContext *dc, arg_dal *a, uint32_t insn)
static bool trans_l_rori(DisasContext *dc, arg_dal *a, uint32_t insn)
{
- LOG_DIS("l.rori r%d, r%d, %d\n", a->d, a->a, a->l);
check_r0_write(a->d);
tcg_gen_rotri_tl(cpu_R[a->d], cpu_R[a->a], a->l & (TARGET_LONG_BITS - 1));
return true;
@@ -1032,7 +955,6 @@ static bool trans_l_rori(DisasContext *dc, arg_dal *a, uint32_t insn)
static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a, uint32_t insn)
{
- LOG_DIS("l.movhi r%d, %d\n", a->d, a->k);
check_r0_write(a->d);
tcg_gen_movi_tl(cpu_R[a->d], a->k << 16);
return true;
@@ -1040,7 +962,6 @@ static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a, uint32_t insn)
static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a, uint32_t insn)
{
- LOG_DIS("l.macrc r%d\n", a->d);
check_r0_write(a->d);
tcg_gen_trunc_i64_tl(cpu_R[a->d], cpu_mac);
tcg_gen_movi_i64(cpu_mac, 0);
@@ -1049,147 +970,126 @@ static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a, uint32_t insn)
static bool trans_l_sfeq(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfeq r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfne(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfne r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfgtu(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfgtu r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfgeu(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfgeu r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfltu(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfltu r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfleu(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfleu r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfgts(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfgts r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfges(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfges r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sflts(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sflts r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfles(DisasContext *dc, arg_ab *a, TCGCond cond)
{
- LOG_DIS("l.sfles r%d, r%d\n", a->a, a->b);
tcg_gen_setcond_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], cpu_R[a->b]);
return true;
}
static bool trans_l_sfeqi(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfeqi r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfnei(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfnei r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfgtui(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfgtui r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfgeui(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfgeui r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfltui(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfltui r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfleui(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfleui r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfgtsi(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfgtsi r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfgesi(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfgesi r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sfltsi(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sfltsi r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sflesi(DisasContext *dc, arg_ai *a, TCGCond cond)
{
- LOG_DIS("l.sflesi r%d, %d\n", a->a, a->i);
tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R[a->a], a->i);
return true;
}
static bool trans_l_sys(DisasContext *dc, arg_l_sys *a, uint32_t insn)
{
- LOG_DIS("l.sys %d\n", a->k);
tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
gen_exception(dc, EXCP_SYSCALL);
dc->base.is_jmp = DISAS_NORETURN;
@@ -1198,7 +1098,6 @@ static bool trans_l_sys(DisasContext *dc, arg_l_sys *a, uint32_t insn)
static bool trans_l_trap(DisasContext *dc, arg_l_trap *a, uint32_t insn)
{
- LOG_DIS("l.trap %d\n", a->k);
tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
gen_exception(dc, EXCP_TRAP);
dc->base.is_jmp = DISAS_NORETURN;
@@ -1207,37 +1106,28 @@ static bool trans_l_trap(DisasContext *dc, arg_l_trap *a, uint32_t insn)
static bool trans_l_msync(DisasContext *dc, arg_l_msync *a, uint32_t insn)
{
- LOG_DIS("l.msync\n");
tcg_gen_mb(TCG_MO_ALL);
return true;
}
static bool trans_l_psync(DisasContext *dc, arg_l_psync *a, uint32_t insn)
{
- LOG_DIS("l.psync\n");
return true;
}
static bool trans_l_csync(DisasContext *dc, arg_l_csync *a, uint32_t insn)
{
- LOG_DIS("l.csync\n");
return true;
}
static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a, uint32_t insn)
{
- LOG_DIS("l.rfe\n");
-
-#ifdef CONFIG_USER_ONLY
- gen_illegal_exception(dc);
-#else
- if (dc->mem_idx == MMU_USER_IDX) {
+ if (is_user(dc)) {
gen_illegal_exception(dc);
} else {
gen_helper_rfe(cpu_env);
- dc->base.is_jmp = DISAS_UPDATE;
+ dc->base.is_jmp = DISAS_EXIT;
}
-#endif
return true;
}
@@ -1274,56 +1164,48 @@ static void do_fpcmp(DisasContext *dc, arg_ab *a,
static bool trans_lf_add_s(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("lf.add.s r%d, r%d, r%d\n", a->d, a->a, a->b);
do_fp3(dc, a, gen_helper_float_add_s);
return true;
}
static bool trans_lf_sub_s(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("lf.sub.s r%d, r%d, r%d\n", a->d, a->a, a->b);
do_fp3(dc, a, gen_helper_float_sub_s);
return true;
}
static bool trans_lf_mul_s(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("lf.mul.s r%d, r%d, r%d\n", a->d, a->a, a->b);
do_fp3(dc, a, gen_helper_float_mul_s);
return true;
}
static bool trans_lf_div_s(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("lf.div.s r%d, r%d, r%d\n", a->d, a->a, a->b);
do_fp3(dc, a, gen_helper_float_div_s);
return true;
}
static bool trans_lf_rem_s(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("lf.rem.s r%d, r%d, r%d\n", a->d, a->a, a->b);
do_fp3(dc, a, gen_helper_float_rem_s);
return true;
}
static bool trans_lf_itof_s(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("lf.itof.s r%d, r%d\n", a->d, a->a);
do_fp2(dc, a, gen_helper_itofs);
return true;
}
static bool trans_lf_ftoi_s(DisasContext *dc, arg_da *a, uint32_t insn)
{
- LOG_DIS("lf.ftoi.s r%d, r%d\n", a->d, a->a);
do_fp2(dc, a, gen_helper_ftois);
return true;
}
static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a, uint32_t insn)
{
- LOG_DIS("lf.madd.s r%d, r%d, r%d\n", a->d, a->a, a->b);
check_r0_write(a->d);
gen_helper_float_madd_s(cpu_R[a->d], cpu_env, cpu_R[a->d],
cpu_R[a->a], cpu_R[a->b]);
@@ -1333,42 +1215,36 @@ static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a, uint32_t insn)
static bool trans_lf_sfeq_s(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("lf.sfeq.s r%d, r%d\n", a->a, a->b);
do_fpcmp(dc, a, gen_helper_float_eq_s, false, false);
return true;
}
static bool trans_lf_sfne_s(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("lf.sfne.s r%d, r%d\n", a->a, a->b);
do_fpcmp(dc, a, gen_helper_float_eq_s, true, false);
return true;
}
static bool trans_lf_sfgt_s(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("lf.sfgt.s r%d, r%d\n", a->a, a->b);
do_fpcmp(dc, a, gen_helper_float_lt_s, false, true);
return true;
}
static bool trans_lf_sfge_s(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("lf.sfge.s r%d, r%d\n", a->a, a->b);
do_fpcmp(dc, a, gen_helper_float_le_s, false, true);
return true;
}
static bool trans_lf_sflt_s(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("lf.sflt.s r%d, r%d\n", a->a, a->b);
do_fpcmp(dc, a, gen_helper_float_lt_s, false, false);
return true;
}
static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a, uint32_t insn)
{
- LOG_DIS("lf.sfle.s r%d, r%d\n", a->a, a->b);
do_fpcmp(dc, a, gen_helper_float_le_s, false, false);
return true;
}
@@ -1382,6 +1258,8 @@ static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
dc->mem_idx = cpu_mmu_index(env, false);
dc->tb_flags = dc->base.tb->flags;
dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0;
+ dc->jmp_pc_imm = -1;
+
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
dc->base.max_insns = MIN(dc->base.max_insns, bound);
}
@@ -1434,50 +1312,81 @@ static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
}
dc->base.pc_next += 4;
- /* delay slot */
- if (dc->delayed_branch) {
- dc->delayed_branch--;
- if (!dc->delayed_branch) {
- tcg_gen_mov_tl(cpu_pc, jmp_pc);
- tcg_gen_discard_tl(jmp_pc);
- dc->base.is_jmp = DISAS_UPDATE;
- return;
- }
+ /* When exiting the delay slot normally, exit via jmp_pc.
+ * For DISAS_NORETURN, we have raised an exception and already exited.
+ * For DISAS_EXIT, we found l.rfe in a delay slot. There's nothing
+ * in the manual saying this is illegal, but it surely it should.
+ * At least or1ksim overrides pcnext and ignores the branch.
+ */
+ if (dc->delayed_branch
+ && --dc->delayed_branch == 0
+ && dc->base.is_jmp == DISAS_NEXT) {
+ dc->base.is_jmp = DISAS_JUMP;
}
}
static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
+ target_ulong jmp_dest;
+
+ /* If we have already exited the TB, nothing following has effect. */
+ if (dc->base.is_jmp == DISAS_NORETURN) {
+ return;
+ }
+ /* Adjust the delayed branch state for the next TB. */
if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) {
tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0);
}
- tcg_gen_movi_tl(cpu_ppc, dc->base.pc_next - 4);
- if (dc->base.is_jmp == DISAS_NEXT) {
- dc->base.is_jmp = DISAS_UPDATE;
- tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
- }
- if (unlikely(dc->base.singlestep_enabled)) {
- gen_exception(dc, EXCP_DEBUG);
- } else {
- switch (dc->base.is_jmp) {
- case DISAS_TOO_MANY:
- gen_goto_tb(dc, 0, dc->base.pc_next);
- break;
- case DISAS_NORETURN:
- case DISAS_JUMP:
- case DISAS_TB_JUMP:
+ /* For DISAS_TOO_MANY, jump to the next insn. */
+ jmp_dest = dc->base.pc_next;
+ tcg_gen_movi_tl(cpu_ppc, jmp_dest - 4);
+
+ switch (dc->base.is_jmp) {
+ case DISAS_JUMP:
+ jmp_dest = dc->jmp_pc_imm;
+ if (jmp_dest == -1) {
+ /* The jump destination is indirect/computed; use jmp_pc. */
+ tcg_gen_mov_tl(cpu_pc, jmp_pc);
+ tcg_gen_discard_tl(jmp_pc);
+ if (unlikely(dc->base.singlestep_enabled)) {
+ gen_exception(dc, EXCP_DEBUG);
+ } else {
+ tcg_gen_lookup_and_goto_ptr();
+ }
break;
- case DISAS_UPDATE:
- /* indicate that the hash table must be used
- to find the next TB */
+ }
+ /* The jump destination is direct; use jmp_pc_imm.
+ However, we will have stored into jmp_pc as well;
+ we know now that it wasn't needed. */
+ tcg_gen_discard_tl(jmp_pc);
+ /* fallthru */
+
+ case DISAS_TOO_MANY:
+ if (unlikely(dc->base.singlestep_enabled)) {
+ tcg_gen_movi_tl(cpu_pc, jmp_dest);
+ gen_exception(dc, EXCP_DEBUG);
+ } else if ((dc->base.pc_first ^ jmp_dest) & TARGET_PAGE_MASK) {
+ tcg_gen_movi_tl(cpu_pc, jmp_dest);
+ tcg_gen_lookup_and_goto_ptr();
+ } else {
+ tcg_gen_goto_tb(0);
+ tcg_gen_movi_tl(cpu_pc, jmp_dest);
+ tcg_gen_exit_tb(dc->base.tb, 0);
+ }
+ break;
+
+ case DISAS_EXIT:
+ if (unlikely(dc->base.singlestep_enabled)) {
+ gen_exception(dc, EXCP_DEBUG);
+ } else {
tcg_gen_exit_tb(NULL, 0);
- break;
- default:
- g_assert_not_reached();
}
+ break;
+ default:
+ g_assert_not_reached();
}
}
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 9faefd7cd2..1affc49ca3 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -727,7 +727,9 @@ tests/test-crypto-tlscredsx509$(EXESUF): tests/test-crypto-tlscredsx509.o \
tests/test-crypto-tlssession.o-cflags := $(TASN1_CFLAGS)
tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \
- tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y)
+ tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \
+ tests/crypto-tls-psk-helpers.o \
+ $(test-crypto-obj-y)
tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \
tests/socket-helpers.o $(test-util-obj-y)
tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y)
diff --git a/tests/crypto-tls-psk-helpers.c b/tests/crypto-tls-psk-helpers.c
new file mode 100644
index 0000000000..a8395477c3
--- /dev/null
+++ b/tests/crypto-tls-psk-helpers.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015-2018 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.1 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/>.
+ *
+ * Author: Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include "qemu/osdep.h"
+
+/* Include this first because it defines QCRYPTO_HAVE_TLS_TEST_SUPPORT */
+#include "crypto-tls-x509-helpers.h"
+
+#include "crypto-tls-psk-helpers.h"
+#include "qemu/sockets.h"
+
+#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
+
+void test_tls_psk_init(const char *pskfile)
+{
+ FILE *fp;
+
+ fp = fopen(pskfile, "w");
+ if (fp == NULL) {
+ g_critical("Failed to create pskfile %s", pskfile);
+ abort();
+ }
+ /* Don't do this in real applications! Use psktool. */
+ fprintf(fp, "qemu:009d5638c40fde0c\n");
+ fclose(fp);
+}
+
+void test_tls_psk_cleanup(const char *pskfile)
+{
+ unlink(pskfile);
+}
+
+#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */
diff --git a/tests/crypto-tls-psk-helpers.h b/tests/crypto-tls-psk-helpers.h
new file mode 100644
index 0000000000..9aec29f1a0
--- /dev/null
+++ b/tests/crypto-tls-psk-helpers.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015-2018 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.1 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/>.
+ *
+ * Author: Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include <gnutls/gnutls.h>
+
+#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
+# include "qemu-common.h"
+
+void test_tls_psk_init(const char *keyfile);
+void test_tls_psk_cleanup(const char *keyfile);
+
+#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */
diff --git a/tests/test-crypto-tlssession.c b/tests/test-crypto-tlssession.c
index 82f21c27f2..7bd811796e 100644
--- a/tests/test-crypto-tlssession.c
+++ b/tests/test-crypto-tlssession.c
@@ -21,7 +21,9 @@
#include "qemu/osdep.h"
#include "crypto-tls-x509-helpers.h"
+#include "crypto-tls-psk-helpers.h"
#include "crypto/tlscredsx509.h"
+#include "crypto/tlscredspsk.h"
#include "crypto/tlssession.h"
#include "qom/object_interfaces.h"
#include "qapi/error.h"
@@ -31,20 +33,9 @@
#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
#define WORKDIR "tests/test-crypto-tlssession-work/"
+#define PSKFILE WORKDIR "keys.psk"
#define KEYFILE WORKDIR "key-ctx.pem"
-struct QCryptoTLSSessionTestData {
- const char *servercacrt;
- const char *clientcacrt;
- const char *servercrt;
- const char *clientcrt;
- bool expectServerFail;
- bool expectClientFail;
- const char *hostname;
- const char *const *wildcards;
-};
-
-
static ssize_t testWrite(const char *buf, size_t len, void *opaque)
{
int *fd = opaque;
@@ -59,9 +50,150 @@ static ssize_t testRead(char *buf, size_t len, void *opaque)
return read(*fd, buf, len);
}
-static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
- const char *certdir,
- Error **errp)
+static QCryptoTLSCreds *test_tls_creds_psk_create(
+ QCryptoTLSCredsEndpoint endpoint,
+ const char *dir,
+ Error **errp)
+{
+ Error *err = NULL;
+ Object *parent = object_get_objects_root();
+ Object *creds = object_new_with_props(
+ TYPE_QCRYPTO_TLS_CREDS_PSK,
+ parent,
+ (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
+ "testtlscredsserver" : "testtlscredsclient"),
+ &err,
+ "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
+ "server" : "client"),
+ "dir", dir,
+ "priority", "NORMAL",
+ NULL
+ );
+
+ if (err) {
+ error_propagate(errp, err);
+ return NULL;
+ }
+ return QCRYPTO_TLS_CREDS(creds);
+}
+
+
+static void test_crypto_tls_session_psk(void)
+{
+ QCryptoTLSCreds *clientCreds;
+ QCryptoTLSCreds *serverCreds;
+ QCryptoTLSSession *clientSess = NULL;
+ QCryptoTLSSession *serverSess = NULL;
+ int channel[2];
+ bool clientShake = false;
+ bool serverShake = false;
+ Error *err = NULL;
+ int ret;
+
+ /* We'll use this for our fake client-server connection */
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
+ g_assert(ret == 0);
+
+ /*
+ * We have an evil loop to do the handshake in a single
+ * thread, so we need these non-blocking to avoid deadlock
+ * of ourselves
+ */
+ qemu_set_nonblock(channel[0]);
+ qemu_set_nonblock(channel[1]);
+
+ clientCreds = test_tls_creds_psk_create(
+ QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
+ WORKDIR,
+ &err);
+ g_assert(clientCreds != NULL);
+
+ serverCreds = test_tls_creds_psk_create(
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
+ WORKDIR,
+ &err);
+ g_assert(serverCreds != NULL);
+
+ /* Now the real part of the test, setup the sessions */
+ clientSess = qcrypto_tls_session_new(
+ clientCreds, NULL, NULL,
+ QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &err);
+ serverSess = qcrypto_tls_session_new(
+ serverCreds, NULL, NULL,
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &err);
+
+ g_assert(clientSess != NULL);
+ g_assert(serverSess != NULL);
+
+ /* For handshake to work, we need to set the I/O callbacks
+ * to read/write over the socketpair
+ */
+ qcrypto_tls_session_set_callbacks(serverSess,
+ testWrite, testRead,
+ &channel[0]);
+ qcrypto_tls_session_set_callbacks(clientSess,
+ testWrite, testRead,
+ &channel[1]);
+
+ /*
+ * Finally we loop around & around doing handshake on each
+ * session until we get an error, or the handshake completes.
+ * This relies on the socketpair being nonblocking to avoid
+ * deadlocking ourselves upon handshake
+ */
+ do {
+ int rv;
+ if (!serverShake) {
+ rv = qcrypto_tls_session_handshake(serverSess,
+ &err);
+ g_assert(rv >= 0);
+ if (qcrypto_tls_session_get_handshake_status(serverSess) ==
+ QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ serverShake = true;
+ }
+ }
+ if (!clientShake) {
+ rv = qcrypto_tls_session_handshake(clientSess,
+ &err);
+ g_assert(rv >= 0);
+ if (qcrypto_tls_session_get_handshake_status(clientSess) ==
+ QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ clientShake = true;
+ }
+ }
+ } while (!clientShake && !serverShake);
+
+
+ /* Finally make sure the server & client validation is successful. */
+ g_assert(qcrypto_tls_session_check_credentials(serverSess, &err) == 0);
+ g_assert(qcrypto_tls_session_check_credentials(clientSess, &err) == 0);
+
+ object_unparent(OBJECT(serverCreds));
+ object_unparent(OBJECT(clientCreds));
+
+ qcrypto_tls_session_free(serverSess);
+ qcrypto_tls_session_free(clientSess);
+
+ close(channel[0]);
+ close(channel[1]);
+}
+
+
+struct QCryptoTLSSessionTestData {
+ const char *servercacrt;
+ const char *clientcacrt;
+ const char *servercrt;
+ const char *clientcrt;
+ bool expectServerFail;
+ bool expectClientFail;
+ const char *hostname;
+ const char *const *wildcards;
+};
+
+static QCryptoTLSCreds *test_tls_creds_x509_create(
+ QCryptoTLSCredsEndpoint endpoint,
+ const char *certdir,
+ Error **errp)
{
Error *err = NULL;
Object *parent = object_get_objects_root();
@@ -104,7 +236,7 @@ static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
* initiate a TLS session across them. Finally do
* do actual cert validation tests
*/
-static void test_crypto_tls_session(const void *opaque)
+static void test_crypto_tls_session_x509(const void *opaque)
{
struct QCryptoTLSSessionTestData *data =
(struct QCryptoTLSSessionTestData *)opaque;
@@ -159,13 +291,13 @@ static void test_crypto_tls_session(const void *opaque)
g_assert(link(KEYFILE,
CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
- clientCreds = test_tls_creds_create(
+ clientCreds = test_tls_creds_x509_create(
QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
CLIENT_CERT_DIR,
&err);
g_assert(clientCreds != NULL);
- serverCreds = test_tls_creds_create(
+ serverCreds = test_tls_creds_x509_create(
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
SERVER_CERT_DIR,
&err);
@@ -285,7 +417,13 @@ int main(int argc, char **argv)
mkdir(WORKDIR, 0700);
test_tls_init(KEYFILE);
+ test_tls_psk_init(PSKFILE);
+
+ /* Simple initial test using Pre-Shared Keys. */
+ g_test_add_func("/qcrypto/tlssession/psk",
+ test_crypto_tls_session_psk);
+ /* More complex tests using X.509 certificates. */
# define TEST_SESS_REG(name, caCrt, \
serverCrt, clientCrt, \
expectServerFail, expectClientFail, \
@@ -296,7 +434,7 @@ int main(int argc, char **argv)
hostname, wildcards \
}; \
g_test_add_data_func("/qcrypto/tlssession/" # name, \
- &name, test_crypto_tls_session); \
+ &name, test_crypto_tls_session_x509); \
# define TEST_SESS_REG_EXT(name, serverCaCrt, clientCaCrt, \
@@ -309,7 +447,7 @@ int main(int argc, char **argv)
hostname, wildcards \
}; \
g_test_add_data_func("/qcrypto/tlssession/" # name, \
- &name, test_crypto_tls_session); \
+ &name, test_crypto_tls_session_x509); \
/* A perfect CA, perfect client & perfect server */
@@ -518,6 +656,7 @@ int main(int argc, char **argv)
test_tls_discard_cert(&clientcertlevel2breq);
unlink(WORKDIR "cacertchain-sess.pem");
+ test_tls_psk_cleanup(PSKFILE);
test_tls_cleanup(KEYFILE);
rmdir(WORKDIR);
diff --git a/tests/test-qga.c b/tests/test-qga.c
index 30c9643257..350f27812a 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -854,6 +854,54 @@ static void test_qga_guest_exec_invalid(gconstpointer fix)
qobject_unref(ret);
}
+static void test_qga_guest_get_host_name(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret, *val;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ val = qdict_get_qdict(ret, "return");
+ g_assert(qdict_haskey(val, "host-name"));
+
+ qobject_unref(ret);
+}
+
+static void test_qga_guest_get_timezone(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret, *val;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ /* Make sure there's at least offset */
+ val = qdict_get_qdict(ret, "return");
+ g_assert(qdict_haskey(val, "offset"));
+
+ qobject_unref(ret);
+}
+
+static void test_qga_guest_get_users(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret;
+ QList *val;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ /* There is not much to test here */
+ val = qdict_get_qlist(ret, "return");
+ g_assert_nonnull(val);
+
+ qobject_unref(ret);
+}
+
static void test_qga_guest_get_osinfo(gconstpointer data)
{
TestFixture fixture;
@@ -946,6 +994,12 @@ int main(int argc, char **argv)
test_qga_guest_exec_invalid);
g_test_add_data_func("/qga/guest-get-osinfo", &fix,
test_qga_guest_get_osinfo);
+ g_test_add_data_func("/qga/guest-get-host-name", &fix,
+ test_qga_guest_get_host_name);
+ g_test_add_data_func("/qga/guest-get-timezone", &fix,
+ test_qga_guest_get_timezone);
+ g_test_add_data_func("/qga/guest-get-users", &fix,
+ test_qga_guest_get_users);
ret = g_test_run();