summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--Makefile6
-rw-r--r--Makefile.objs1
-rw-r--r--accel/Makefile.objs2
-rw-r--r--accel/kvm/Makefile.objs3
-rw-r--r--accel/kvm/kvm-all.c39
-rw-r--r--accel/kvm/sev-stub.c26
-rw-r--r--accel/stubs/kvm-stub.c10
-rw-r--r--audio/Makefile.objs30
-rw-r--r--audio/alsaaudio.c8
-rw-r--r--audio/audio.c83
-rw-r--r--audio/audio_int.h14
-rw-r--r--audio/coreaudio.c8
-rw-r--r--audio/dsoundaudio.c8
-rw-r--r--audio/noaudio.c8
-rw-r--r--audio/ossaudio.c8
-rw-r--r--audio/paaudio.c8
-rw-r--r--audio/sdlaudio.c8
-rw-r--r--audio/spiceaudio.c8
-rw-r--r--audio/wavaudio.c8
-rw-r--r--block/gluster.c2
-rw-r--r--block/sheepdog.c2
-rw-r--r--chardev/char-socket.c34
-rw-r--r--chardev/char.c3
-rwxr-xr-xconfigure12
-rw-r--r--default-configs/i386-softmmu.mak1
-rw-r--r--default-configs/x86_64-softmmu.mak1
-rw-r--r--docs/amd-memory-encryption.txt109
-rw-r--r--hmp-commands-info.hx16
-rw-r--r--hmp-commands.hx7
-rw-r--r--hmp.c4
-rw-r--r--hmp.h1
-rw-r--r--hw/core/machine.c22
-rw-r--r--hw/display/vga-pci.c9
-rw-r--r--hw/display/vga.c2
-rw-r--r--hw/i386/pc_sysfw.c13
-rw-r--r--hw/ppc/spapr.c7
-rw-r--r--hw/usb/redirect.c4
-rw-r--r--hw/vfio/Makefile.objs2
-rw-r--r--hw/vfio/common.c77
-rw-r--r--hw/vfio/display.c347
-rw-r--r--hw/vfio/pci.c32
-rw-r--r--hw/vfio/pci.h5
-rw-r--r--include/block/aio-wait.h61
-rw-r--r--include/exec/cpu-all.h6
-rw-r--r--include/exec/cpu_ldst.h16
-rw-r--r--include/hw/boards.h1
-rw-r--r--include/hw/vfio/vfio-common.h23
-rw-r--r--include/qemu/cutils.h4
-rw-r--r--include/qemu/log-for-trace.h35
-rw-r--r--include/qemu/log.h18
-rw-r--r--include/qemu/module.h1
-rw-r--r--include/qemu/sockets.h1
-rw-r--r--include/standard-headers/drm/drm_fourcc.h411
-rw-r--r--include/standard-headers/linux/input-event-codes.h1
-rw-r--r--include/standard-headers/linux/input.h11
-rw-r--r--include/standard-headers/linux/pci_regs.h30
-rw-r--r--include/standard-headers/linux/virtio_net.h13
-rw-r--r--include/standard-headers/linux/virtio_ring.h2
-rw-r--r--include/standard-headers/rdma/vmw_pvrdma-abi.h13
-rw-r--r--include/sysemu/kvm.h17
-rw-r--r--include/sysemu/sev.h21
-rw-r--r--include/ui/console.h4
-rw-r--r--include/ui/gtk.h14
-rw-r--r--include/ui/qemu-pixman.h5
-rw-r--r--include/ui/spice-display.h9
-rw-r--r--io/channel-util.c13
-rw-r--r--linux-headers/asm-powerpc/kvm.h2
-rw-r--r--linux-headers/asm-powerpc/unistd.h3
-rw-r--r--linux-headers/asm-s390/unistd.h401
-rw-r--r--linux-headers/asm-s390/unistd_32.h364
-rw-r--r--linux-headers/asm-s390/unistd_64.h331
-rw-r--r--linux-headers/asm-x86/kvm_para.h5
-rw-r--r--linux-headers/linux/kvm.h92
-rw-r--r--linux-headers/linux/psci.h3
-rw-r--r--linux-headers/linux/psp-sev.h142
-rw-r--r--linux-headers/linux/vfio.h72
-rw-r--r--linux-user/elfload.c168
-rw-r--r--linux-user/main.c99
-rw-r--r--linux-user/mmap.c43
-rw-r--r--linux-user/qemu.h6
-rw-r--r--linux-user/signal.c32
-rw-r--r--linux-user/syscall.c18
-rw-r--r--linux-user/syscall_defs.h47
-rw-r--r--linux-user/unicore32/syscall_nr.h371
-rw-r--r--linux-user/unicore32/target_cpu.h27
-rw-r--r--linux-user/unicore32/target_elf.h14
-rw-r--r--linux-user/unicore32/target_signal.h30
-rw-r--r--linux-user/unicore32/target_structs.h58
-rw-r--r--linux-user/unicore32/target_syscall.h62
-rw-r--r--linux-user/unicore32/termbits.h2
-rw-r--r--monitor.c21
-rw-r--r--qapi/misc.json148
-rw-r--r--qapi/sockets.json7
-rw-r--r--qapi/ui.json10
-rw-r--r--qemu-options.hx49
-rwxr-xr-xscripts/create_config2
-rwxr-xr-xscripts/device-crash-test6
-rwxr-xr-xscripts/qemu-binfmt-conf.sh37
-rw-r--r--scripts/qemu.py2
-rw-r--r--scripts/qmp/qmp.py2
-rwxr-xr-xscripts/simpletrace.py6
-rwxr-xr-xscripts/tracetool.py2
-rw-r--r--scripts/tracetool/__init__.py52
-rw-r--r--scripts/tracetool/backend/log.py13
-rwxr-xr-xscripts/update-linux-headers.sh10
-rw-r--r--target/i386/Makefile.objs2
-rw-r--r--target/i386/cpu.c106
-rw-r--r--target/i386/cpu.h29
-rw-r--r--target/i386/kvm.c91
-rw-r--r--target/i386/machine.c58
-rw-r--r--target/i386/monitor.c66
-rw-r--r--target/i386/sev-stub.c51
-rw-r--r--target/i386/sev.c811
-rw-r--r--target/i386/sev_i386.h88
-rw-r--r--target/i386/trace-events10
-rw-r--r--target/m68k/fpu_helper.c61
-rw-r--r--target/m68k/helper.h11
-rw-r--r--target/m68k/softfloat.c1637
-rw-r--r--target/m68k/softfloat.h11
-rw-r--r--target/m68k/softfloat_fpsp_tables.h267
-rw-r--r--target/m68k/translate.c38
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.include5
-rw-r--r--tests/docker/dockerfiles/fedora.docker2
-rwxr-xr-xtests/docker/test-debug6
-rw-r--r--tests/qmp-test.c5
-rw-r--r--tests/socket-helpers.c149
-rw-r--r--tests/socket-helpers.h42
-rw-r--r--tests/test-char.c47
-rw-r--r--tests/test-cutils.c657
-rw-r--r--tests/test-io-channel-socket.c72
-rw-r--r--tests/test-util-sockets.c266
-rw-r--r--trace-events6
-rw-r--r--ui/Makefile.objs25
-rw-r--r--ui/console.c113
-rw-r--r--ui/gtk-egl.c63
-rw-r--r--ui/gtk.c68
-rw-r--r--ui/qemu-pixman.c22
-rw-r--r--ui/spice-display.c194
-rw-r--r--ui/trace-events14
-rw-r--r--ui/vnc.c10
-rw-r--r--util/aio-wait.c2
-rw-r--r--util/coroutine-ucontext.c4
-rw-r--r--util/cutils.c109
-rw-r--r--util/qemu-sockets.c36
146 files changed, 8097 insertions, 1652 deletions
diff --git a/.travis.yml b/.travis.yml
index 79377c8de0..c1e99237b2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -49,9 +49,10 @@ env:
- TEST_CMD="make check"
- MAKEFLAGS="-j3"
matrix:
- - CONFIG=""
- - CONFIG="--enable-debug --enable-debug-tcg --enable-trace-backends=log"
- - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb"
+ - CONFIG="--disable-system"
+ - CONFIG="--disable-user"
+ - CONFIG="--enable-debug --enable-debug-tcg"
+ - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb --disable-user"
- CONFIG="--enable-modules --disable-linux-user"
- CONFIG="--with-coroutine=ucontext --disable-linux-user"
- CONFIG="--with-coroutine=sigaltstack --disable-linux-user"
diff --git a/Makefile b/Makefile
index 416a81c7ca..8f7ed4c3f2 100644
--- a/Makefile
+++ b/Makefile
@@ -425,6 +425,10 @@ dummy := $(call unnest-vars,, \
io-obj-y \
common-obj-y \
common-obj-m \
+ ui-obj-y \
+ ui-obj-m \
+ audio-obj-y \
+ audio-obj-m \
trace-obj-y)
include $(SRC_PATH)/tests/Makefile.include
@@ -853,7 +857,7 @@ ifneq ($(BLOBS),)
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
-ifeq ($(CONFIG_GTK),y)
+ifeq ($(CONFIG_GTK),m)
$(MAKE) -C po $@
endif
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
diff --git a/Makefile.objs b/Makefile.objs
index d8b44a2d3c..c6c9b8fc21 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -104,6 +104,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration/
common-obj-y += audio/
+common-obj-m += audio/
common-obj-y += hw/
common-obj-y += replay/
diff --git a/accel/Makefile.objs b/accel/Makefile.objs
index 10666eda71..c3718a10c5 100644
--- a/accel/Makefile.objs
+++ b/accel/Makefile.objs
@@ -1,4 +1,4 @@
obj-$(CONFIG_SOFTMMU) += accel.o
-obj-y += kvm/
+obj-$(CONFIG_KVM) += kvm/
obj-$(CONFIG_TCG) += tcg/
obj-y += stubs/
diff --git a/accel/kvm/Makefile.objs b/accel/kvm/Makefile.objs
index 85351e7de7..fdfa481578 100644
--- a/accel/kvm/Makefile.objs
+++ b/accel/kvm/Makefile.objs
@@ -1 +1,2 @@
-obj-$(CONFIG_KVM) += kvm-all.o
+obj-y += kvm-all.o
+obj-$(call lnot,$(CONFIG_SEV)) += sev-stub.o
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index b91fcb7160..ffee68e603 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -38,6 +38,7 @@
#include "qemu/event_notifier.h"
#include "trace.h"
#include "hw/irq.h"
+#include "sysemu/sev.h"
#include "hw/boards.h"
@@ -103,6 +104,10 @@ struct KVMState
#endif
KVMMemoryListener memory_listener;
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
+
+ /* memory encryption */
+ void *memcrypt_handle;
+ int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
};
KVMState *kvm_state;
@@ -138,6 +143,26 @@ int kvm_get_max_memslots(void)
return s->nr_slots;
}
+bool kvm_memcrypt_enabled(void)
+{
+ if (kvm_state && kvm_state->memcrypt_handle) {
+ return true;
+ }
+
+ return false;
+}
+
+int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
+{
+ if (kvm_state->memcrypt_handle &&
+ kvm_state->memcrypt_encrypt_data) {
+ return kvm_state->memcrypt_encrypt_data(kvm_state->memcrypt_handle,
+ ptr, len);
+ }
+
+ return 1;
+}
+
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{
KVMState *s = kvm_state;
@@ -1636,6 +1661,20 @@ static int kvm_init(MachineState *ms)
kvm_state = s;
+ /*
+ * if memory encryption object is specified then initialize the memory
+ * encryption context.
+ */
+ if (ms->memory_encryption) {
+ kvm_state->memcrypt_handle = sev_guest_init(ms->memory_encryption);
+ if (!kvm_state->memcrypt_handle) {
+ ret = -1;
+ goto err;
+ }
+
+ kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
+ }
+
ret = kvm_arch_init(ms, s);
if (ret < 0) {
goto err;
diff --git a/accel/kvm/sev-stub.c b/accel/kvm/sev-stub.c
new file mode 100644
index 0000000000..4f97452585
--- /dev/null
+++ b/accel/kvm/sev-stub.c
@@ -0,0 +1,26 @@
+/*
+ * QEMU SEV stub
+ *
+ * Copyright Advanced Micro Devices 2018
+ *
+ * Authors:
+ * Brijesh Singh <brijesh.singh@amd.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sysemu/sev.h"
+
+int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
+{
+ abort();
+}
+
+void *sev_guest_init(const char *id)
+{
+ return NULL;
+}
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index c964af3e1c..02d5170031 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -105,6 +105,16 @@ int kvm_on_sigbus(int code, void *addr)
return 1;
}
+bool kvm_memcrypt_enabled(void)
+{
+ return false;
+}
+
+int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
+{
+ return 1;
+}
+
#ifndef CONFIG_USER_ONLY
int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
{
diff --git a/audio/Makefile.objs b/audio/Makefile.objs
index f6ce5c6744..db4fa7f18f 100644
--- a/audio/Makefile.objs
+++ b/audio/Makefile.objs
@@ -1,19 +1,31 @@
common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
-common-obj-$(CONFIG_AUDIO_SDL) += sdlaudio.o
-common-obj-$(CONFIG_AUDIO_OSS) += ossaudio.o
common-obj-$(CONFIG_SPICE) += spiceaudio.o
common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o
-common-obj-$(CONFIG_AUDIO_ALSA) += alsaaudio.o
common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o
-common-obj-$(CONFIG_AUDIO_PA) += paaudio.o
common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
common-obj-y += wavcapture.o
-sdlaudio.o-cflags := $(SDL_CFLAGS)
-sdlaudio.o-libs := $(SDL_LIBS)
-alsaaudio.o-libs := $(ALSA_LIBS)
-paaudio.o-libs := $(PULSE_LIBS)
coreaudio.o-libs := $(COREAUDIO_LIBS)
dsoundaudio.o-libs := $(DSOUND_LIBS)
-ossaudio.o-libs := $(OSS_LIBS)
+
+# alsa module
+common-obj-$(CONFIG_AUDIO_ALSA) += alsa.mo
+alsa.mo-objs = alsaaudio.o
+alsa.mo-libs := $(ALSA_LIBS)
+
+# oss module
+common-obj-$(CONFIG_AUDIO_OSS) += oss.mo
+oss.mo-objs = ossaudio.o
+oss.mo-libs := $(OSS_LIBS)
+
+# pulseaudio module
+common-obj-$(CONFIG_AUDIO_PA) += pa.mo
+pa.mo-objs = paaudio.o
+pa.mo-libs := $(PULSE_LIBS)
+
+# sdl module
+common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo
+sdl.mo-objs = sdlaudio.o
+sdl.mo-cflags := $(SDL_CFLAGS)
+sdl.mo-libs := $(SDL_LIBS)
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 92a96f8b2b..362a2276fd 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -1213,7 +1213,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.ctl_in = alsa_ctl_in,
};
-struct audio_driver alsa_audio_driver = {
+static struct audio_driver alsa_audio_driver = {
.name = "alsa",
.descr = "ALSA http://www.alsa-project.org",
.options = alsa_options,
@@ -1226,3 +1226,9 @@ struct audio_driver alsa_audio_driver = {
.voice_size_out = sizeof (ALSAVoiceOut),
.voice_size_in = sizeof (ALSAVoiceIn)
};
+
+static void register_audio_alsa(void)
+{
+ audio_driver_register(&alsa_audio_driver);
+}
+type_init(register_audio_alsa);
diff --git a/audio/audio.c b/audio/audio.c
index 7658d2af66..6eccdb17ee 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -45,15 +45,49 @@
The 1st one is the one used by default, that is the reason
that we generate the list.
*/
-static struct audio_driver *drvtab[] = {
-#ifdef CONFIG_SPICE
- &spice_audio_driver,
-#endif
+static const char *audio_prio_list[] = {
+ "spice",
CONFIG_AUDIO_DRIVERS
- &no_audio_driver,
- &wav_audio_driver
+ "none",
+ "wav",
};
+static QLIST_HEAD(, audio_driver) audio_drivers;
+
+void audio_driver_register(audio_driver *drv)
+{
+ QLIST_INSERT_HEAD(&audio_drivers, drv, next);
+}
+
+audio_driver *audio_driver_lookup(const char *name)
+{
+ struct audio_driver *d;
+
+ QLIST_FOREACH(d, &audio_drivers, next) {
+ if (strcmp(name, d->name) == 0) {
+ return d;
+ }
+ }
+
+ audio_module_load_one(name);
+ QLIST_FOREACH(d, &audio_drivers, next) {
+ if (strcmp(name, d->name) == 0) {
+ return d;
+ }
+ }
+
+ return NULL;
+}
+
+static void audio_module_load_all(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(audio_prio_list); i++) {
+ audio_driver_lookup(audio_prio_list[i]);
+ }
+}
+
struct fixed_settings {
int enabled;
int nb_voices;
@@ -1656,11 +1690,13 @@ static void audio_pp_nb_voices (const char *typ, int nb)
void AUD_help (void)
{
- size_t i;
+ struct audio_driver *d;
+
+ /* make sure we print the help text for modular drivers too */
+ audio_module_load_all();
audio_process_options ("AUDIO", audio_options);
- for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
- struct audio_driver *d = drvtab[i];
+ QLIST_FOREACH(d, &audio_drivers, next) {
if (d->options) {
audio_process_options (d->name, d->options);
}
@@ -1672,8 +1708,7 @@ void AUD_help (void)
printf ("Available drivers:\n");
- for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
- struct audio_driver *d = drvtab[i];
+ QLIST_FOREACH(d, &audio_drivers, next) {
printf ("Name: %s\n", d->name);
printf ("Description: %s\n", d->descr);
@@ -1807,6 +1842,7 @@ static void audio_init (void)
const char *drvname;
VMChangeStateEntry *e;
AudioState *s = &glob_audio_state;
+ struct audio_driver *driver;
if (s->drv) {
return;
@@ -1842,32 +1878,27 @@ static void audio_init (void)
}
if (drvname) {
- int found = 0;
-
- for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
- if (!strcmp (drvname, drvtab[i]->name)) {
- done = !audio_driver_init (s, drvtab[i]);
- found = 1;
- break;
- }
- }
-
- if (!found) {
+ driver = audio_driver_lookup(drvname);
+ if (driver) {
+ done = !audio_driver_init(s, driver);
+ } else {
dolog ("Unknown audio driver `%s'\n", drvname);
dolog ("Run with -audio-help to list available drivers\n");
}
}
if (!done) {
- for (i = 0; !done && i < ARRAY_SIZE (drvtab); i++) {
- if (drvtab[i]->can_be_default) {
- done = !audio_driver_init (s, drvtab[i]);
+ for (i = 0; !done && i < ARRAY_SIZE(audio_prio_list); i++) {
+ driver = audio_driver_lookup(audio_prio_list[i]);
+ if (driver && driver->can_be_default) {
+ done = !audio_driver_init(s, driver);
}
}
}
if (!done) {
- done = !audio_driver_init (s, &no_audio_driver);
+ driver = audio_driver_lookup("none");
+ done = !audio_driver_init(s, driver);
assert(done);
dolog("warning: Using timer based audio emulation\n");
}
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 700bd43143..244b454012 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -141,6 +141,7 @@ struct SWVoiceIn {
QLIST_ENTRY (SWVoiceIn) entries;
};
+typedef struct audio_driver audio_driver;
struct audio_driver {
const char *name;
const char *descr;
@@ -154,6 +155,7 @@ struct audio_driver {
int voice_size_out;
int voice_size_in;
int ctl_caps;
+ QLIST_ENTRY(audio_driver) next;
};
struct audio_pcm_ops {
@@ -203,17 +205,11 @@ struct AudioState {
int vm_running;
};
-extern struct audio_driver no_audio_driver;
-extern struct audio_driver oss_audio_driver;
-extern struct audio_driver sdl_audio_driver;
-extern struct audio_driver wav_audio_driver;
-extern struct audio_driver alsa_audio_driver;
-extern struct audio_driver coreaudio_audio_driver;
-extern struct audio_driver dsound_audio_driver;
-extern struct audio_driver pa_audio_driver;
-extern struct audio_driver spice_audio_driver;
extern const struct mixeng_volume nominal_volume;
+void audio_driver_register(audio_driver *drv);
+audio_driver *audio_driver_lookup(const char *name);
+
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index c75142084f..638c60b300 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -722,7 +722,7 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
.ctl_out = coreaudio_ctl_out
};
-struct audio_driver coreaudio_audio_driver = {
+static struct audio_driver coreaudio_audio_driver = {
.name = "coreaudio",
.descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
.options = coreaudio_options,
@@ -735,3 +735,9 @@ struct audio_driver coreaudio_audio_driver = {
.voice_size_out = sizeof (coreaudioVoiceOut),
.voice_size_in = 0
};
+
+static void register_audio_coreaudio(void)
+{
+ audio_driver_register(&coreaudio_audio_driver);
+}
+type_init(register_audio_coreaudio);
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index bc39cb9b4d..3ed73a30d1 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -890,7 +890,7 @@ static struct audio_pcm_ops dsound_pcm_ops = {
.ctl_in = dsound_ctl_in
};
-struct audio_driver dsound_audio_driver = {
+static struct audio_driver dsound_audio_driver = {
.name = "dsound",
.descr = "DirectSound http://wikipedia.org/wiki/DirectSound",
.options = dsound_options,
@@ -903,3 +903,9 @@ struct audio_driver dsound_audio_driver = {
.voice_size_out = sizeof (DSoundVoiceOut),
.voice_size_in = sizeof (DSoundVoiceIn)
};
+
+static void register_audio_dsound(void)
+{
+ audio_driver_register(&dsound_audio_driver);
+}
+type_init(register_audio_dsound);
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 9ca9eaf01f..1bfebeca7d 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -160,7 +160,7 @@ static struct audio_pcm_ops no_pcm_ops = {
.ctl_in = no_ctl_in
};
-struct audio_driver no_audio_driver = {
+static struct audio_driver no_audio_driver = {
.name = "none",
.descr = "Timer based audio emulation",
.options = NULL,
@@ -173,3 +173,9 @@ struct audio_driver no_audio_driver = {
.voice_size_out = sizeof (NoVoiceOut),
.voice_size_in = sizeof (NoVoiceIn)
};
+
+static void register_audio_none(void)
+{
+ audio_driver_register(&no_audio_driver);
+}
+type_init(register_audio_none);
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index a0428881c2..6c69622b4c 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -922,7 +922,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
.ctl_in = oss_ctl_in
};
-struct audio_driver oss_audio_driver = {
+static struct audio_driver oss_audio_driver = {
.name = "oss",
.descr = "OSS http://www.opensound.com",
.options = oss_options,
@@ -935,3 +935,9 @@ struct audio_driver oss_audio_driver = {
.voice_size_out = sizeof (OSSVoiceOut),
.voice_size_in = sizeof (OSSVoiceIn)
};
+
+static void register_audio_oss(void)
+{
+ audio_driver_register(&oss_audio_driver);
+}
+type_init(register_audio_oss);
diff --git a/audio/paaudio.c b/audio/paaudio.c
index aa0a7477d3..949769774d 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -937,7 +937,7 @@ static struct audio_pcm_ops qpa_pcm_ops = {
.ctl_in = qpa_ctl_in
};
-struct audio_driver pa_audio_driver = {
+static struct audio_driver pa_audio_driver = {
.name = "pa",
.descr = "http://www.pulseaudio.org/",
.options = qpa_options,
@@ -951,3 +951,9 @@ struct audio_driver pa_audio_driver = {
.voice_size_in = sizeof (PAVoiceIn),
.ctl_caps = VOICE_VOLUME_CAP
};
+
+static void register_audio_pa(void)
+{
+ audio_driver_register(&pa_audio_driver);
+}
+type_init(register_audio_pa);
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index e92135bd2f..9db5ac92bc 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -500,7 +500,7 @@ static struct audio_pcm_ops sdl_pcm_ops = {
.ctl_out = sdl_ctl_out,
};
-struct audio_driver sdl_audio_driver = {
+static struct audio_driver sdl_audio_driver = {
.name = "sdl",
.descr = "SDL http://www.libsdl.org",
.options = sdl_options,
@@ -513,3 +513,9 @@ struct audio_driver sdl_audio_driver = {
.voice_size_out = sizeof (SDLVoiceOut),
.voice_size_in = 0
};
+
+static void register_audio_sdl(void)
+{
+ audio_driver_register(&sdl_audio_driver);
+}
+type_init(register_audio_sdl);
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 5580e76307..6ad0eafbc6 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -391,7 +391,7 @@ static struct audio_pcm_ops audio_callbacks = {
.ctl_in = line_in_ctl,
};
-struct audio_driver spice_audio_driver = {
+static struct audio_driver spice_audio_driver = {
.name = "spice",
.descr = "spice audio driver",
.options = audio_options,
@@ -411,3 +411,9 @@ void qemu_spice_audio_init (void)
{
spice_audio_driver.can_be_default = 1;
}
+
+static void register_audio_spice(void)
+{
+ audio_driver_register(&spice_audio_driver);
+}
+type_init(register_audio_spice);
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 068a595732..40adfa30c3 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -278,7 +278,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
.ctl_out = wav_ctl_out,
};
-struct audio_driver wav_audio_driver = {
+static struct audio_driver wav_audio_driver = {
.name = "wav",
.descr = "WAV renderer http://wikipedia.org/wiki/WAV",
.options = wav_options,
@@ -291,3 +291,9 @@ struct audio_driver wav_audio_driver = {
.voice_size_out = sizeof (WAVVoiceOut),
.voice_size_in = 0
};
+
+static void register_audio_wav(void)
+{
+ audio_driver_register(&wav_audio_driver);
+}
+type_init(register_audio_wav);
diff --git a/block/gluster.c b/block/gluster.c
index 63d3c37d4c..296e036b3d 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -665,7 +665,7 @@ static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
if (filename) {
ret = qemu_gluster_parse_uri(gconf, filename);
if (ret < 0) {
- error_setg(errp, "invalid URI");
+ error_setg(errp, "invalid URI %s", filename);
error_append_hint(errp, "Usage: file=gluster[+transport]://"
"[host[:port]]volume/path[?socket=...]"
"[,file.debug=N]"
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 8680b2926f..797ea5953b 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1036,7 +1036,7 @@ static void sd_parse_uri(SheepdogConfig *cfg, const char *filename,
cfg->uri = uri = uri_parse(filename);
if (!uri) {
- error_setg(&err, "invalid URI");
+ error_setg(&err, "invalid URI '%s'", filename);
goto out;
}
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 36a8fcc194..d92c5aee73 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -706,8 +706,7 @@ static void tcp_chr_tls_handshake(QIOTask *task,
if (qio_task_propagate_error(task, NULL)) {
tcp_chr_disconnect(chr);
} else {
- /* tn3270 does not support TLS yet */
- if (s->do_telnetopt && !s->is_tn3270) {
+ if (s->do_telnetopt) {
tcp_chr_telnet_init(chr);
} else {
tcp_chr_connect(chr);
@@ -1060,25 +1059,36 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
const char *path = qemu_opt_get(opts, "path");
const char *host = qemu_opt_get(opts, "host");
const char *port = qemu_opt_get(opts, "port");
+ const char *fd = qemu_opt_get(opts, "fd");
const char *tls_creds = qemu_opt_get(opts, "tls-creds");
SocketAddressLegacy *addr;
ChardevSocket *sock;
+ if ((!!path + !!fd + !!host) != 1) {
+ error_setg(errp,
+ "Exactly one of 'path', 'fd' or 'host' required");
+ return;
+ }
+
backend->type = CHARDEV_BACKEND_KIND_SOCKET;
- if (!path) {
- if (!host) {
- error_setg(errp, "chardev: socket: no host given");
+ if (path) {
+ if (tls_creds) {
+ error_setg(errp, "TLS can only be used over TCP socket");
return;
}
+ } else if (host) {
if (!port) {
error_setg(errp, "chardev: socket: no port given");
return;
}
- } else {
- if (tls_creds) {
- error_setg(errp, "TLS can only be used over TCP socket");
+ } else if (fd) {
+ /* We don't know what host to validate against when in client mode */
+ if (tls_creds && !is_listen) {
+ error_setg(errp, "TLS can not be used with pre-opened client FD");
return;
}
+ } else {
+ g_assert_not_reached();
}
sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
@@ -1104,7 +1114,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
q_unix->path = g_strdup(path);
- } else {
+ } else if (host) {
addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
addr->u.inet.data = g_new(InetSocketAddress, 1);
*addr->u.inet.data = (InetSocketAddress) {
@@ -1117,6 +1127,12 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
.has_ipv6 = qemu_opt_get(opts, "ipv6"),
.ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
};
+ } else if (fd) {
+ addr->type = SOCKET_ADDRESS_LEGACY_KIND_FD;
+ addr->u.fd.data = g_new(String, 1);
+ addr->u.fd.data->str = g_strdup(fd);
+ } else {
+ g_assert_not_reached();
}
sock->addr = addr;
}
diff --git a/chardev/char.c b/chardev/char.c
index a6250cac80..76d866e6fe 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -799,6 +799,9 @@ QemuOptsList qemu_chardev_opts = {
.name = "port",
.type = QEMU_OPT_STRING,
},{
+ .name = "fd",
+ .type = QEMU_OPT_STRING,
+ },{
.name = "localaddr",
.type = QEMU_OPT_STRING,
},{
diff --git a/configure b/configure
index db87fc4fed..73cdc2a2a9 100755
--- a/configure
+++ b/configure
@@ -1697,6 +1697,7 @@ gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags"
gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags"
gcc_flags="-Wno-string-plus-int $gcc_flags"
+gcc_flags="-Wno-error=address-of-packed-member $gcc_flags"
# Note that we do not add -Werror to gcc_flags here, because that would
# enable it for all configure tests. If a configure test failed due
# to -Werror this would just silently disable some features,
@@ -2879,6 +2880,7 @@ if test "$sdl" != "no" ; then
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
EOF
sdl_cflags=$($sdlconfig --cflags 2>/dev/null)
+ sdl_cflags="$sdl_cflags -Wno-undef" # workaround 2.0.8 bug
if test "$static" = "yes" ; then
if $pkg_config $sdlname --exists; then
sdl_libs=$($pkg_config $sdlname --static --libs 2>/dev/null)
@@ -3357,7 +3359,7 @@ else
fi
glib_modules=gthread-2.0
if test "$modules" = yes; then
- glib_modules="$glib_modules gmodule-2.0"
+ glib_modules="$glib_modules gmodule-export-2.0"
fi
# This workaround is required due to a bug in pkg-config file for glib as it
@@ -4865,7 +4867,6 @@ fi
pragma_disable_unused_but_set=no
cat > $TMPC << EOF
#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#pragma GCC diagnostic pop
@@ -6010,7 +6011,12 @@ fi
echo "CONFIG_AUDIO_DRIVERS=$audio_drv_list" >> $config_host_mak
for drv in $audio_drv_list; do
def=CONFIG_AUDIO_$(echo $drv | LC_ALL=C tr '[a-z]' '[A-Z]')
- echo "$def=y" >> $config_host_mak
+ case "$drv" in
+ alsa | oss | pa | sdl)
+ echo "$def=m" >> $config_host_mak ;;
+ *)
+ echo "$def=y" >> $config_host_mak ;;
+ esac
done
echo "ALSA_LIBS=$alsa_libs" >> $config_host_mak
echo "PULSE_LIBS=$pulse_libs" >> $config_host_mak
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 9e5a29fa4a..8c7d4a0fa0 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -63,5 +63,6 @@ CONFIG_PXB=y
CONFIG_ACPI_VMGENID=y
CONFIG_FW_CFG_DMA=y
CONFIG_I2C=y
+CONFIG_SEV=$(CONFIG_KVM)
CONFIG_VTD=y
CONFIG_AMD_IOMMU=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 7baf91b921..0390b4303c 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -63,5 +63,6 @@ CONFIG_PXB=y
CONFIG_ACPI_VMGENID=y
CONFIG_FW_CFG_DMA=y
CONFIG_I2C=y
+CONFIG_SEV=$(CONFIG_KVM)
CONFIG_VTD=y
CONFIG_AMD_IOMMU=y
diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
new file mode 100644
index 0000000000..f483795eaa
--- /dev/null
+++ b/docs/amd-memory-encryption.txt
@@ -0,0 +1,109 @@
+Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
+
+SEV is an extension to the AMD-V architecture which supports running encrypted
+virtual machine (VMs) under the control of KVM. Encrypted VMs have their pages
+(code and data) secured such that only the guest itself has access to the
+unencrypted version. Each encrypted VM is associated with a unique encryption
+key; if its data is accessed to a different entity using a different key the
+encrypted guests data will be incorrectly decrypted, leading to unintelligible
+data.
+
+The key management of this feature is handled by separate processor known as
+AMD secure processor (AMD-SP) which is present in AMD SOCs. Firmware running
+inside the AMD-SP provide commands to support common VM lifecycle. This
+includes commands for launching, snapshotting, migrating and debugging the
+encrypted guest. Those SEV command can be issued via KVM_MEMORY_ENCRYPT_OP
+ioctls.
+
+Launching
+---------
+Boot images (such as bios) must be encrypted before guest can be booted.
+MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images :LAUNCH_START,
+LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
+together generate a fresh memory encryption key for the VM, encrypt the boot
+images and provide a measurement than can be used as an attestation of the
+successful launch.
+
+LAUNCH_START is called first to create a cryptographic launch context within
+the firmware. To create this context, guest owner must provides guest policy,
+its public Diffie-Hellman key (PDH) and session parameters. These inputs
+should be treated as binary blob and must be passed as-is to the SEV firmware.
+
+The guest policy is passed as plaintext and hypervisor may able to read it
+but should not modify it (any modification of the policy bits will result
+in bad measurement). The guest policy is a 4-byte data structure containing
+several flags that restricts what can be done on running SEV guest.
+See KM Spec section 3 and 6.2 for more details.
+
+The guest policy can be provided via the 'policy' property (see below)
+
+# ${QEMU} \
+ sev-guest,id=sev0,policy=0x1...\
+
+Guest owners provided DH certificate and session parameters will be used to
+establish a cryptographic session with the guest owner to negotiate keys used
+for the attestation.
+
+The DH certificate and session blob can be provided via 'dh-cert-file' and
+'session-file' property (see below
+
+# ${QEMU} \
+ sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
+
+LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
+created via LAUNCH_START command. If required, this command can be called
+multiple times to encrypt different memory regions. The command also calculates
+the measurement of the memory contents as it encrypts.
+
+LAUNCH_MEASURE command can be used to retrieve the measurement of encrypted
+memory. This measurement is a signature of the memory contents that can be
+sent to the guest owner as an attestation that the memory was encrypted
+correctly by the firmware. The guest owner may wait to provide the guest
+confidential information until it can verify the attestation measurement.
+Since the guest owner knows the initial contents of the guest at boot, the
+attestation measurement can be verified by comparing it to what the guest owner
+expects.
+
+LAUNCH_FINISH command finalizes the guest launch and destroy's the cryptographic
+context.
+
+See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
+complete flow chart.
+
+To launch a SEV guest
+
+# ${QEMU} \
+ -machine ...,memory-encryption=sev0 \
+ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
+
+Debugging
+-----------
+Since memory contents of SEV guest is encrypted hence hypervisor access to the
+guest memory will get a cipher text. If guest policy allows debugging, then
+hypervisor can use DEBUG_DECRYPT and DEBUG_ENCRYPT commands access the guest
+memory region for debug purposes. This is not supported in QEMU yet.
+
+Snapshot/Restore
+-----------------
+TODO
+
+Live Migration
+----------------
+TODO
+
+References
+-----------------
+
+AMD Memory Encryption whitepaper:
+http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
+
+Secure Encrypted Virutualization Key Management:
+[1] http://support.amd.com/TechDocs/55766_SEV-KM API_Specification.pdf
+
+KVM Forum slides:
+http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
+
+AMD64 Architecture Programmer's Manual:
+ http://support.amd.com/TechDocs/24593.pdf
+ SME is section 7.10
+ SEV is section 15.34
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index ad590a4ffb..ddfcd5adcc 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -867,6 +867,22 @@ Display the amount of initially allocated and present hotpluggable (if
enabled) memory in bytes.
ETEXI
+#if defined(TARGET_I386)
+ {
+ .name = "sev",
+ .args_type = "",
+ .params = "",
+ .help = "show SEV information",
+ .cmd = hmp_info_sev,
+ },
+#endif
+
+STEXI
+@item info sev
+@findex info sev
+Show SEV information.
+ETEXI
+
STEXI
@end table
ETEXI
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 964eb515cf..1723cbe1df 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -253,9 +253,10 @@ ETEXI
{
.name = "screendump",
- .args_type = "filename:F",
- .params = "filename",
- .help = "save screen into PPM image 'filename'",
+ .args_type = "filename:F,device:s?,head:i?",
+ .params = "filename [device [head]]",
+ .help = "save screen from head 'head' of display device 'device' "
+ "into PPM image 'filename'",
.cmd = hmp_screendump,
},
diff --git a/hmp.c b/hmp.c
index 016cb5c4f1..ba9e299ee2 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2140,9 +2140,11 @@ err_out:
void hmp_screendump(Monitor *mon, const QDict *qdict)
{
const char *filename = qdict_get_str(qdict, "filename");
+ const char *id = qdict_get_try_str(qdict, "device");
+ int64_t head = qdict_get_try_int(qdict, "head", 0);
Error *err = NULL;
- qmp_screendump(filename, &err);
+ qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
hmp_handle_error(mon, &err);
}
diff --git a/hmp.h b/hmp.h
index b89733876d..4e2ec375b0 100644
--- a/hmp.h
+++ b/hmp.h
@@ -143,5 +143,6 @@ void hmp_info_ramblock(Monitor *mon, const QDict *qdict);
void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
+void hmp_info_sev(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 5e2bbcdace..2040177664 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -334,6 +334,22 @@ static bool machine_get_enforce_config_section(Object *obj, Error **errp)
return ms->enforce_config_section;
}
+static char *machine_get_memory_encryption(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return g_strdup(ms->memory_encryption);
+}
+
+static void machine_set_memory_encryption(Object *obj, const char *value,
+ Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ g_free(ms->memory_encryption);
+ ms->memory_encryption = g_strdup(value);
+}
+
void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
{
strList *item = g_new0(strList, 1);
@@ -612,6 +628,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
&error_abort);
object_class_property_set_description(oc, "enforce-config-section",
"Set on to enforce configuration section migration", &error_abort);
+
+ object_class_property_add_str(oc, "memory-encryption",
+ machine_get_memory_encryption, machine_set_memory_encryption,
+ &error_abort);
+ object_class_property_set_description(oc, "memory-encryption",
+ "Set memory encyption object to use", &error_abort);
}
static void machine_class_base_init(ObjectClass *oc, void *data)
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 1674bd3581..f312930664 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -292,6 +292,14 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
}
+static void pci_secondary_vga_exit(PCIDevice *dev)
+{
+ PCIVGAState *d = PCI_VGA(dev);
+ VGACommonState *s = &d->vga;
+
+ graphic_console_close(s->con);
+}
+
static void pci_secondary_vga_init(Object *obj)
{
/* Expose framebuffer byteorder via QOM */
@@ -361,6 +369,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->realize = pci_secondary_vga_realize;
+ k->exit = pci_secondary_vga_exit;
k->class_id = PCI_CLASS_DISPLAY_OTHER;
dc->props = secondary_pci_properties;
dc->reset = pci_secondary_vga_reset;
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 28f298b342..72181330b8 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1483,6 +1483,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
region_start = (s->start_addr * 4);
region_end = region_start + (ram_addr_t)s->line_offset * height;
+ region_end += width * s->get_bpp(s) / 8; /* scanline length */
+ region_end -= s->line_offset;
if (region_end > s->vbe_size) {
/* wraps around (can happen with cirrus vbe modes) */
region_start = 0;
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 4325575e7d..73ac783f20 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -113,6 +113,8 @@ static void pc_system_flash_init(MemoryRegion *rom_memory)
pflash_t *system_flash;
MemoryRegion *flash_mem;
char name[64];
+ void *flash_ptr;
+ int ret, flash_size;
sector_bits = 12;
sector_size = 1 << sector_bits;
@@ -169,6 +171,17 @@ static void pc_system_flash_init(MemoryRegion *rom_memory)
if (unit == 0) {
flash_mem = pflash_cfi01_get_memory(system_flash);
pc_isa_bios_init(rom_memory, flash_mem, size);
+
+ /* Encrypt the pflash boot ROM */
+ if (kvm_memcrypt_enabled()) {
+ flash_ptr = memory_region_get_ram_ptr(flash_mem);
+ flash_size = memory_region_size(flash_mem);
+ ret = kvm_memcrypt_encrypt_data(flash_ptr, flash_size);
+ if (ret) {
+ error_report("failed to encrypt pflash rom");
+ exit(1);
+ }
+ }
}
}
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 7e1c858566..032d03423f 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2855,6 +2855,11 @@ static void spapr_set_modern_hotplug_events(Object *obj, bool value,
spapr->use_hotplug_event_source = value;
}
+static bool spapr_get_msix_emulation(Object *obj, Error **errp)
+{
+ return true;
+}
+
static char *spapr_get_resize_hpt(Object *obj, Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
@@ -2936,6 +2941,8 @@ static void spapr_instance_init(Object *obj)
object_property_set_description(obj, "vsmt",
"Virtual SMT: KVM behaves as if this were"
" the host's SMT mode", &error_abort);
+ object_property_add_bool(obj, "vfio-no-msix-emulation",
+ spapr_get_msix_emulation, NULL, NULL);
}
static void spapr_machine_finalizefn(Object *obj)
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index ec174309db..65a9196c1a 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -106,10 +106,10 @@ struct USBRedirDevice {
USBDevice dev;
/* Properties */
CharBackend cs;
+ bool enable_streams;
uint8_t debug;
- char *filter_str;
int32_t bootindex;
- bool enable_streams;
+ char *filter_str;
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
const uint8_t *read_buf;
int read_buf_size;
diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs
index c3ab9097f1..a2e7a0a7cf 100644
--- a/hw/vfio/Makefile.objs
+++ b/hw/vfio/Makefile.objs
@@ -1,6 +1,6 @@
ifeq ($(CONFIG_LINUX), y)
obj-$(CONFIG_SOFTMMU) += common.o
-obj-$(CONFIG_PCI) += pci.o pci-quirks.o
+obj-$(CONFIG_PCI) += pci.o pci-quirks.o display.o
obj-$(CONFIG_VFIO_CCW) += ccw.o
obj-$(CONFIG_SOFTMMU) += platform.o
obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index f895e3c335..5e84716218 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -544,18 +544,40 @@ static void vfio_listener_region_add(MemoryListener *listener,
llsize = int128_sub(llend, int128_make64(iova));
+ if (memory_region_is_ram_device(section->mr)) {
+ hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1;
+
+ if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) {
+ error_report("Region 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx
+ " is not aligned to 0x%"HWADDR_PRIx
+ " and cannot be mapped for DMA",
+ section->offset_within_region,
+ int128_getlo(section->size),
+ pgmask + 1);
+ return;
+ }
+ }
+
ret = vfio_dma_map(container, iova, int128_get64(llsize),
vaddr, section->readonly);
if (ret) {
error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
"0x%"HWADDR_PRIx", %p) = %d (%m)",
container, iova, int128_get64(llsize), vaddr, ret);
+ if (memory_region_is_ram_device(section->mr)) {
+ /* Allow unexpected mappings not to be fatal for RAM devices */
+ return;
+ }
goto fail;
}
return;
fail:
+ if (memory_region_is_ram_device(section->mr)) {
+ error_report("failed to vfio_dma_map. pci p2p may not work");
+ return;
+ }
/*
* On the initfn path, store the first error in the container so we
* can gracefully fail. Runtime, there's not much we can do other
@@ -577,6 +599,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
hwaddr iova, end;
Int128 llend, llsize;
int ret;
+ bool try_unmap = true;
if (vfio_listener_skipped_section(section)) {
trace_vfio_listener_region_del_skip(
@@ -629,14 +652,34 @@ static void vfio_listener_region_del(MemoryListener *listener,
trace_vfio_listener_region_del(iova, end);
- ret = vfio_dma_unmap(container, iova, int128_get64(llsize));
- memory_region_unref(section->mr);
- if (ret) {
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
- "0x%"HWADDR_PRIx") = %d (%m)",
- container, iova, int128_get64(llsize), ret);
+ if (memory_region_is_ram_device(section->mr)) {
+ hwaddr pgmask;
+ VFIOHostDMAWindow *hostwin;
+ bool hostwin_found = false;
+
+ QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) {
+ if (hostwin->min_iova <= iova && end <= hostwin->max_iova) {
+ hostwin_found = true;
+ break;
+ }
+ }
+ assert(hostwin_found); /* or region_add() would have failed */
+
+ pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1;
+ try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask));
}
+ if (try_unmap) {
+ ret = vfio_dma_unmap(container, iova, int128_get64(llsize));
+ if (ret) {
+ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
+ "0x%"HWADDR_PRIx") = %d (%m)",
+ container, iova, int128_get64(llsize), ret);
+ }
+ }
+
+ memory_region_unref(section->mr);
+
if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) {
vfio_spapr_remove_window(container,
section->offset_within_address_space);
@@ -858,6 +901,13 @@ void vfio_region_finalize(VFIORegion *region)
g_free(region->mmaps);
trace_vfio_region_finalize(region->vbasedev->name, region->nr);
+
+ region->mem = NULL;
+ region->mmaps = NULL;
+ region->nr_mmaps = 0;
+ region->size = 0;
+ region->flags = 0;
+ region->nr = 0;
}
void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled)
@@ -1421,6 +1471,21 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
return -ENODEV;
}
+bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type)
+{
+ struct vfio_region_info *info = NULL;
+ bool ret = false;
+
+ if (!vfio_get_region_info(vbasedev, region, &info)) {
+ if (vfio_get_region_info_cap(info, cap_type)) {
+ ret = true;
+ }
+ g_free(info);
+ }
+
+ return ret;
+}
+
/*
* Interfaces for IBM EEH (Enhanced Error Handling)
*/
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
new file mode 100644
index 0000000000..7d727ce910
--- /dev/null
+++ b/hw/vfio/display.c
@@ -0,0 +1,347 @@
+/*
+ * display support for mdev based vgpu devices
+ *
+ * Copyright Red Hat, Inc. 2017
+ *
+ * Authors:
+ * Gerd Hoffmann
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include <linux/vfio.h>
+#include <sys/ioctl.h>
+
+#include "sysemu/sysemu.h"
+#include "ui/console.h"
+#include "qapi/error.h"
+#include "pci.h"
+
+#ifndef DRM_PLANE_TYPE_PRIMARY
+# define DRM_PLANE_TYPE_PRIMARY 1
+# define DRM_PLANE_TYPE_CURSOR 2
+#endif
+
+static void vfio_display_update_cursor(VFIODMABuf *dmabuf,
+ struct vfio_device_gfx_plane_info *plane)
+{
+ if (dmabuf->pos_x != plane->x_pos || dmabuf->pos_y != plane->y_pos) {
+ dmabuf->pos_x = plane->x_pos;
+ dmabuf->pos_y = plane->y_pos;
+ dmabuf->pos_updates++;
+ }
+ if (dmabuf->hot_x != plane->x_hot || dmabuf->hot_y != plane->y_hot) {
+ dmabuf->hot_x = plane->x_hot;
+ dmabuf->hot_y = plane->y_hot;
+ dmabuf->hot_updates++;
+ }
+}
+
+static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev,
+ uint32_t plane_type)
+{
+ VFIODisplay *dpy = vdev->dpy;
+ struct vfio_device_gfx_plane_info plane;
+ VFIODMABuf *dmabuf;
+ int fd, ret;
+
+ memset(&plane, 0, sizeof(plane));
+ plane.argsz = sizeof(plane);
+ plane.flags = VFIO_GFX_PLANE_TYPE_DMABUF;
+ plane.drm_plane_type = plane_type;
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
+ if (ret < 0) {
+ return NULL;
+ }
+ if (!plane.drm_format || !plane.size) {
+ return NULL;
+ }
+
+ QTAILQ_FOREACH(dmabuf, &dpy->dmabuf.bufs, next) {
+ if (dmabuf->dmabuf_id == plane.dmabuf_id) {
+ /* found in list, move to head, return it */
+ QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
+ QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next);
+ if (plane_type == DRM_PLANE_TYPE_CURSOR) {
+ vfio_display_update_cursor(dmabuf, &plane);
+ }
+ return dmabuf;
+ }
+ }
+
+ fd = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_GFX_DMABUF, &plane.dmabuf_id);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ dmabuf = g_new0(VFIODMABuf, 1);
+ dmabuf->dmabuf_id = plane.dmabuf_id;
+ dmabuf->buf.width = plane.width;
+ dmabuf->buf.height = plane.height;
+ dmabuf->buf.stride = plane.stride;
+ dmabuf->buf.fourcc = plane.drm_format;
+ dmabuf->buf.fd = fd;
+ if (plane_type == DRM_PLANE_TYPE_CURSOR) {
+ vfio_display_update_cursor(dmabuf, &plane);
+ }
+
+ QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next);
+ return dmabuf;
+}
+
+static void vfio_display_free_one_dmabuf(VFIODisplay *dpy, VFIODMABuf *dmabuf)
+{
+ QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
+ dpy_gl_release_dmabuf(dpy->con, &dmabuf->buf);
+ close(dmabuf->buf.fd);
+ g_free(dmabuf);
+}
+
+static void vfio_display_free_dmabufs(VFIOPCIDevice *vdev)
+{
+ VFIODisplay *dpy = vdev->dpy;
+ VFIODMABuf *dmabuf, *tmp;
+ uint32_t keep = 5;
+
+ QTAILQ_FOREACH_SAFE(dmabuf, &dpy->dmabuf.bufs, next, tmp) {
+ if (keep > 0) {
+ keep--;
+ continue;
+ }
+ assert(dmabuf != dpy->dmabuf.primary);
+ vfio_display_free_one_dmabuf(dpy, dmabuf);
+ }
+}
+
+static void vfio_display_dmabuf_update(void *opaque)
+{
+ VFIOPCIDevice *vdev = opaque;
+ VFIODisplay *dpy = vdev->dpy;
+ VFIODMABuf *primary, *cursor;
+ bool free_bufs = false, new_cursor = false;;
+
+ primary = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_PRIMARY);
+ if (primary == NULL) {
+ return;
+ }
+
+ if (dpy->dmabuf.primary != primary) {
+ dpy->dmabuf.primary = primary;
+ qemu_console_resize(dpy->con,
+ primary->buf.width, primary->buf.height);
+ dpy_gl_scanout_dmabuf(dpy->con, &primary->buf);
+ free_bufs = true;
+ }
+
+ cursor = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_CURSOR);
+ if (dpy->dmabuf.cursor != cursor) {
+ dpy->dmabuf.cursor = cursor;
+ new_cursor = true;
+ free_bufs = true;
+ }
+
+ if (cursor && (new_cursor || cursor->hot_updates)) {
+ bool have_hot = (cursor->hot_x != 0xffffffff &&
+ cursor->hot_y != 0xffffffff);
+ dpy_gl_cursor_dmabuf(dpy->con, &cursor->buf, have_hot,
+ cursor->hot_x, cursor->hot_y);
+ cursor->hot_updates = 0;
+ } else if (!cursor && new_cursor) {
+ dpy_gl_cursor_dmabuf(dpy->con, NULL, false, 0, 0);
+ }
+
+ if (cursor && cursor->pos_updates) {
+ dpy_gl_cursor_position(dpy->con,
+ cursor->pos_x,
+ cursor->pos_y);
+ cursor->pos_updates = 0;
+ }
+
+ dpy_gl_update(dpy->con, 0, 0, primary->buf.width, primary->buf.height);
+
+ if (free_bufs) {
+ vfio_display_free_dmabufs(vdev);
+ }
+}
+
+static const GraphicHwOps vfio_display_dmabuf_ops = {
+ .gfx_update = vfio_display_dmabuf_update,
+};
+
+static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
+{
+ if (!display_opengl) {
+ error_setg(errp, "vfio-display-dmabuf: opengl not available");
+ return -1;
+ }
+
+ vdev->dpy = g_new0(VFIODisplay, 1);
+ vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
+ &vfio_display_dmabuf_ops,
+ vdev);
+ return 0;
+}
+
+static void vfio_display_dmabuf_exit(VFIODisplay *dpy)
+{
+ VFIODMABuf *dmabuf;
+
+ if (QTAILQ_EMPTY(&dpy->dmabuf.bufs)) {
+ return;
+ }
+
+ while ((dmabuf = QTAILQ_FIRST(&dpy->dmabuf.bufs)) != NULL) {
+ vfio_display_free_one_dmabuf(dpy, dmabuf);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void vfio_display_region_update(void *opaque)
+{
+ VFIOPCIDevice *vdev = opaque;
+ VFIODisplay *dpy = vdev->dpy;
+ struct vfio_device_gfx_plane_info plane = {
+ .argsz = sizeof(plane),
+ .flags = VFIO_GFX_PLANE_TYPE_REGION
+ };
+ pixman_format_code_t format;
+ int ret;
+
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &plane);
+ if (ret < 0) {
+ error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
+ strerror(errno));
+ return;
+ }
+ if (!plane.drm_format || !plane.size) {
+ return;
+ }
+ format = qemu_drm_format_to_pixman(plane.drm_format);
+ if (!format) {
+ return;
+ }
+
+ if (dpy->region.buffer.size &&
+ dpy->region.buffer.nr != plane.region_index) {
+ /* region changed */
+ vfio_region_exit(&dpy->region.buffer);
+ vfio_region_finalize(&dpy->region.buffer);
+ dpy->region.surface = NULL;
+ }
+
+ if (dpy->region.surface &&
+ (surface_width(dpy->region.surface) != plane.width ||
+ surface_height(dpy->region.surface) != plane.height ||
+ surface_format(dpy->region.surface) != format)) {
+ /* size changed */
+ dpy->region.surface = NULL;
+ }
+
+ if (!dpy->region.buffer.size) {
+ /* mmap region */
+ ret = vfio_region_setup(OBJECT(vdev), &vdev->vbasedev,
+ &dpy->region.buffer,
+ plane.region_index,
+ "display");
+ if (ret != 0) {
+ error_report("%s: vfio_region_setup(%d): %s",
+ __func__, plane.region_index, strerror(-ret));
+ goto err;
+ }
+ ret = vfio_region_mmap(&dpy->region.buffer);
+ if (ret != 0) {
+ error_report("%s: vfio_region_mmap(%d): %s", __func__,
+ plane.region_index, strerror(-ret));
+ goto err;
+ }
+ assert(dpy->region.buffer.mmaps[0].mmap != NULL);
+ }
+
+ if (dpy->region.surface == NULL) {
+ /* create surface */
+ dpy->region.surface = qemu_create_displaysurface_from
+ (plane.width, plane.height, format,
+ plane.stride, dpy->region.buffer.mmaps[0].mmap);
+ dpy_gfx_replace_surface(dpy->con, dpy->region.surface);
+ }
+
+ /* full screen update */
+ dpy_gfx_update(dpy->con, 0, 0,
+ surface_width(dpy->region.surface),
+ surface_height(dpy->region.surface));
+ return;
+
+err:
+ vfio_region_exit(&dpy->region.buffer);
+ vfio_region_finalize(&dpy->region.buffer);
+}
+
+static const GraphicHwOps vfio_display_region_ops = {
+ .gfx_update = vfio_display_region_update,
+};
+
+static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
+{
+ vdev->dpy = g_new0(VFIODisplay, 1);
+ vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
+ &vfio_display_region_ops,
+ vdev);
+ return 0;
+}
+
+static void vfio_display_region_exit(VFIODisplay *dpy)
+{
+ if (!dpy->region.buffer.size) {
+ return;
+ }
+
+ vfio_region_exit(&dpy->region.buffer);
+ vfio_region_finalize(&dpy->region.buffer);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp)
+{
+ struct vfio_device_gfx_plane_info probe;
+ int ret;
+
+ memset(&probe, 0, sizeof(probe));
+ probe.argsz = sizeof(probe);
+ probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_DMABUF;
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
+ if (ret == 0) {
+ return vfio_display_dmabuf_init(vdev, errp);
+ }
+
+ memset(&probe, 0, sizeof(probe));
+ probe.argsz = sizeof(probe);
+ probe.flags = VFIO_GFX_PLANE_TYPE_PROBE | VFIO_GFX_PLANE_TYPE_REGION;
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_QUERY_GFX_PLANE, &probe);
+ if (ret == 0) {
+ return vfio_display_region_init(vdev, errp);
+ }
+
+ if (vdev->display == ON_OFF_AUTO_AUTO) {
+ /* not an error in automatic mode */
+ return 0;
+ }
+
+ error_setg(errp, "vfio: device doesn't support any (known) display method");
+ return -1;
+}
+
+void vfio_display_finalize(VFIOPCIDevice *vdev)
+{
+ if (!vdev->dpy) {
+ return;
+ }
+
+ graphic_console_close(vdev->dpy->con);
+ vfio_display_dmabuf_exit(vdev->dpy);
+ vfio_display_region_exit(vdev->dpy);
+ g_free(vdev->dpy);
+}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 3ba3cbc146..b9bc6cd310 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1295,6 +1295,15 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev)
VFIORegion *region = &vdev->bars[vdev->msix->table_bar].region;
/*
+ * If the host driver allows mapping of a MSIX data, we are going to
+ * do map the entire BAR and emulate MSIX table on top of that.
+ */
+ if (vfio_has_region_cap(&vdev->vbasedev, region->nr,
+ VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) {
+ return;
+ }
+
+ /*
* We expect to find a single mmap covering the whole BAR, anything else
* means it's either unsupported or already setup.
*/
@@ -1572,6 +1581,19 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
*/
memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false);
+ /*
+ * The emulated machine may provide a paravirt interface for MSIX setup
+ * so it is not strictly necessary to emulate MSIX here. This becomes
+ * helpful when frequently accessed MMIO registers are located in
+ * subpages adjacent to the MSIX table but the MSIX data containing page
+ * cannot be mapped because of a host page size bigger than the MSIX table
+ * alignment.
+ */
+ if (object_property_get_bool(OBJECT(qdev_get_machine()),
+ "vfio-no-msix-emulation", NULL)) {
+ memory_region_set_enabled(&vdev->pdev.msix_table_mmio, false);
+ }
+
return 0;
}
@@ -3015,6 +3037,13 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
}
}
+ if (vdev->display != ON_OFF_AUTO_OFF) {
+ ret = vfio_display_probe(vdev, errp);
+ if (ret) {
+ goto out_teardown;
+ }
+ }
+
vfio_register_err_notifier(vdev);
vfio_register_req_notifier(vdev);
vfio_setup_resetfn_quirk(vdev);
@@ -3035,6 +3064,7 @@ static void vfio_instance_finalize(Object *obj)
VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev);
VFIOGroup *group = vdev->vbasedev.group;
+ vfio_display_finalize(vdev);
vfio_bars_finalize(vdev);
g_free(vdev->emulated_config_bits);
g_free(vdev->rom);
@@ -3123,6 +3153,8 @@ static void vfio_instance_init(Object *obj)
static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host),
DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev),
+ DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice,
+ display, ON_OFF_AUTO_AUTO),
DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice,
intx.mmap_timeout, 1100),
DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index f4aa13e021..629c875701 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -133,6 +133,7 @@ typedef struct VFIOPCIDevice {
#define VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT 2
#define VFIO_FEATURE_ENABLE_IGD_OPREGION \
(1 << VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT)
+ OnOffAuto display;
int32_t bootindex;
uint32_t igd_gms;
OffAutoPCIBAR msix_relo;
@@ -147,6 +148,7 @@ typedef struct VFIOPCIDevice {
bool no_kvm_msi;
bool no_kvm_msix;
bool no_geforce_quirks;
+ VFIODisplay *dpy;
} VFIOPCIDevice;
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
@@ -174,4 +176,7 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
struct vfio_region_info *info,
Error **errp);
+int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp);
+void vfio_display_finalize(VFIOPCIDevice *vdev);
+
#endif /* HW_VFIO_VFIO_PCI_H */
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
index f7a3972200..8c90a2e66e 100644
--- a/include/block/aio-wait.h
+++ b/include/block/aio-wait.h
@@ -50,8 +50,8 @@
* }
*/
typedef struct {
- /* Is the main loop waiting for a kick? Accessed with atomic ops. */
- bool need_kick;
+ /* Number of waiting AIO_WAIT_WHILE() callers. Accessed with atomic ops. */
+ unsigned num_waiters;
} AioWait;
/**
@@ -71,35 +71,34 @@ typedef struct {
* wait on conditions between two IOThreads since that could lead to deadlock,
* go via the main loop instead.
*/
-#define AIO_WAIT_WHILE(wait, ctx, cond) ({ \
- bool waited_ = false; \
- bool busy_ = true; \
- AioWait *wait_ = (wait); \
- AioContext *ctx_ = (ctx); \
- if (in_aio_context_home_thread(ctx_)) { \
- while ((cond) || busy_) { \
- busy_ = aio_poll(ctx_, (cond)); \
- waited_ |= !!(cond) | busy_; \
- } \
- } else { \
- assert(qemu_get_current_aio_context() == \
- qemu_get_aio_context()); \
- assert(!wait_->need_kick); \
- /* Set wait_->need_kick before evaluating cond. */ \
- atomic_mb_set(&wait_->need_kick, true); \
- while (busy_) { \
- if ((cond)) { \
- waited_ = busy_ = true; \
- aio_context_release(ctx_); \
- aio_poll(qemu_get_aio_context(), true); \
- aio_context_acquire(ctx_); \
- } else { \
- busy_ = aio_poll(ctx_, false); \
- waited_ |= busy_; \
- } \
- } \
- atomic_set(&wait_->need_kick, false); \
- } \
+#define AIO_WAIT_WHILE(wait, ctx, cond) ({ \
+ bool waited_ = false; \
+ bool busy_ = true; \
+ AioWait *wait_ = (wait); \
+ AioContext *ctx_ = (ctx); \
+ if (in_aio_context_home_thread(ctx_)) { \
+ while ((cond) || busy_) { \
+ busy_ = aio_poll(ctx_, (cond)); \
+ waited_ |= !!(cond) | busy_; \
+ } \
+ } else { \
+ assert(qemu_get_current_aio_context() == \
+ qemu_get_aio_context()); \
+ /* Increment wait_->num_waiters before evaluating cond. */ \
+ atomic_inc(&wait_->num_waiters); \
+ while (busy_) { \
+ if ((cond)) { \
+ waited_ = busy_ = true; \
+ aio_context_release(ctx_); \
+ aio_poll(qemu_get_aio_context(), true); \
+ aio_context_acquire(ctx_); \
+ } else { \
+ busy_ = aio_poll(ctx_, false); \
+ waited_ |= busy_; \
+ } \
+ } \
+ atomic_dec(&wait_->num_waiters); \
+ } \
waited_; })
/**
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 0b141683f0..f4fa94e966 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -159,8 +159,12 @@ extern unsigned long guest_base;
extern int have_guest_base;
extern unsigned long reserved_va;
-#define GUEST_ADDR_MAX (reserved_va ? reserved_va : \
+#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
+#define GUEST_ADDR_MAX (~0ul)
+#else
+#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : \
(1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
+#endif
#else
#include "exec/hwaddr.h"
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 191f2e962a..5de8c8a5af 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -51,15 +51,13 @@
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(target_ulong)(x) + guest_base))
-#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
-#define h2g_valid(x) 1
-#else
-#define h2g_valid(x) ({ \
- unsigned long __guest = (unsigned long)(x) - guest_base; \
- (__guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) && \
- (!reserved_va || (__guest < reserved_va)); \
-})
-#endif
+#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX)
+#define h2g_valid(x) guest_addr_valid((unsigned long)(x) - guest_base)
+
+static inline int guest_range_valid(unsigned long start, unsigned long len)
+{
+ return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1;
+}
#define h2g_nocheck(x) ({ \
unsigned long __ret = (unsigned long)(x) - guest_base; \
diff --git a/include/hw/boards.h b/include/hw/boards.h
index efb0a9edfd..8ce9a7a21d 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -243,6 +243,7 @@ struct MachineState {
bool suppress_vmdesc;
bool enforce_config_section;
bool enable_graphics;
+ char *memory_encryption;
ram_addr_t ram_size;
ram_addr_t maxram_size;
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index f3a2ac9fee..d9360148e6 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -26,6 +26,7 @@
#include "exec/memory.h"
#include "qemu/queue.h"
#include "qemu/notify.h"
+#include "ui/console.h"
#ifdef CONFIG_LINUX
#include <linux/vfio.h>
#endif
@@ -142,6 +143,27 @@ typedef struct VFIOGroup {
QLIST_ENTRY(VFIOGroup) container_next;
} VFIOGroup;
+typedef struct VFIODMABuf {
+ QemuDmaBuf buf;
+ uint32_t pos_x, pos_y, pos_updates;
+ uint32_t hot_x, hot_y, hot_updates;
+ int dmabuf_id;
+ QTAILQ_ENTRY(VFIODMABuf) next;
+} VFIODMABuf;
+
+typedef struct VFIODisplay {
+ QemuConsole *con;
+ struct {
+ VFIORegion buffer;
+ DisplaySurface *surface;
+ } region;
+ struct {
+ QTAILQ_HEAD(, VFIODMABuf) bufs;
+ VFIODMABuf *primary;
+ VFIODMABuf *cursor;
+ } dmabuf;
+} VFIODisplay;
+
void vfio_put_base_device(VFIODevice *vbasedev);
void vfio_disable_irqindex(VFIODevice *vbasedev, int index);
void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index);
@@ -171,6 +193,7 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index,
struct vfio_region_info **info);
int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
uint32_t subtype, struct vfio_region_info **info);
+bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type);
#endif
extern const MemoryListener vfio_prereg_listener;
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index f0878eaafa..a663340b23 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -126,6 +126,10 @@ time_t mktimegm(struct tm *tm);
int qemu_fdatasync(int fd);
int fcntl_setfl(int fd, int flag);
int qemu_parse_fd(const char *param);
+int qemu_strtoi(const char *nptr, const char **endptr, int base,
+ int *result);
+int qemu_strtoui(const char *nptr, const char **endptr, int base,
+ unsigned int *result);
int qemu_strtol(const char *nptr, const char **endptr, int base,
long *result);
int qemu_strtoul(const char *nptr, const char **endptr, int base,
diff --git a/include/qemu/log-for-trace.h b/include/qemu/log-for-trace.h
new file mode 100644
index 0000000000..2f0a5b080e
--- /dev/null
+++ b/include/qemu/log-for-trace.h
@@ -0,0 +1,35 @@
+/* log-for-trace.h: logging basics required by the trace.h generated
+ * by the log trace backend.
+ *
+ * This should not be included directly by any .c file: if you
+ * need to use the logging functions include "qemu/log.h".
+ *
+ * The purpose of splitting these parts out into their own header
+ * is to catch the easy mistake where a .c file includes trace.h
+ * but forgets to include qemu/log.h. Without this split, that
+ * would result in the .c file compiling fine when the default
+ * trace backend is in use but failing to compile with any other
+ * backend.
+ *
+ * This code is licensed under the GNU General Public License,
+ * version 2 or (at your option) any later version.
+ */
+
+#ifndef QEMU_LOG_FOR_TRACE_H
+#define QEMU_LOG_FOR_TRACE_H
+
+/* Private global variable, don't use */
+extern int qemu_loglevel;
+
+#define LOG_TRACE (1 << 15)
+
+/* Returns true if a bit is set in the current loglevel mask */
+static inline bool qemu_loglevel_mask(int mask)
+{
+ return (qemu_loglevel & mask) != 0;
+}
+
+/* main logging function */
+int GCC_FMT_ATTR(1, 2) qemu_log(const char *fmt, ...);
+
+#endif
diff --git a/include/qemu/log.h b/include/qemu/log.h
index a50e994c21..ff92a8b86a 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -1,10 +1,11 @@
#ifndef QEMU_LOG_H
#define QEMU_LOG_H
+/* A small part of this API is split into its own header */
+#include "qemu/log-for-trace.h"
-/* Private global variables, don't use */
+/* Private global variable, don't use */
extern FILE *qemu_logfile;
-extern int qemu_loglevel;
/*
* The new API:
@@ -41,16 +42,9 @@ static inline bool qemu_log_separate(void)
#define CPU_LOG_MMU (1 << 12)
#define CPU_LOG_TB_NOCHAIN (1 << 13)
#define CPU_LOG_PAGE (1 << 14)
-#define LOG_TRACE (1 << 15)
+/* LOG_TRACE (1 << 15) is defined in log-for-trace.h */
#define CPU_LOG_TB_OP_IND (1 << 16)
-/* Returns true if a bit is set in the current loglevel mask
- */
-static inline bool qemu_loglevel_mask(int mask)
-{
- return (qemu_loglevel & mask) != 0;
-}
-
/* Lock output for a series of related logs. Since this is not needed
* for a single qemu_log / qemu_log_mask / qemu_log_mask_and_addr, we
* assume that qemu_loglevel_mask has already been tested, and that
@@ -69,10 +63,6 @@ static inline void qemu_log_unlock(void)
/* Logging functions: */
-/* main logging function
- */
-int GCC_FMT_ATTR(1, 2) qemu_log(const char *fmt, ...);
-
/* vfprintf-like logging function
*/
static inline void GCC_FMT_ATTR(1, 0)
diff --git a/include/qemu/module.h b/include/qemu/module.h
index 9fea75aaeb..54300ab6e5 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -54,6 +54,7 @@ typedef enum {
#define block_module_load_one(lib) module_load_one("block-", lib)
#define ui_module_load_one(lib) module_load_one("ui-", lib)
+#define audio_module_load_one(lib) module_load_one("audio-", lib)
void register_module_init(void (*fn)(void), module_init_type type);
void register_dso_module_init(void (*fn)(void), module_init_type type);
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index e88d4c37ab..8140fea685 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -12,6 +12,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
#include "qapi/qapi-types-sockets.h"
/* misc helpers */
+bool fd_is_socket(int fd);
int qemu_socket(int domain, int type, int protocol);
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int socket_set_cork(int fd, int v);
diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h
new file mode 100644
index 0000000000..11912fde24
--- /dev/null
+++ b/include/standard-headers/drm/drm_fourcc.h
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DRM_FOURCC_H
+#define DRM_FOURCC_H
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
+ ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
+
+#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
+
+/* color index */
+#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */
+
+/* 8 bpp Red */
+#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
+
+/* 16 bpp Red */
+#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
+
+/* 16 bpp RG */
+#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
+#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
+
+/* 32 bpp RG */
+#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
+#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
+
+/* 8 bpp RGB */
+#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
+#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
+
+/* 16 bpp RGB */
+#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */
+#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */
+#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */
+#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */
+
+#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */
+#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */
+#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */
+#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */
+
+#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */
+#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */
+#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */
+#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */
+
+#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */
+#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */
+#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */
+#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */
+
+#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
+#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */
+
+/* 24 bpp RGB */
+#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
+#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */
+
+/* 32 bpp RGB */
+#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */
+#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */
+#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */
+#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */
+
+#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */
+#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */
+#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */
+#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */
+
+#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */
+#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */
+#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */
+#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */
+
+#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */
+#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */
+#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */
+#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
+
+/* packed YCbCr */
+#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
+#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */
+#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
+#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */
+
+#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
+
+/*
+ * 2 plane RGB + A
+ * index 0 = RGB plane, same format as the corresponding non _A8 format has
+ * index 1 = A plane, [7:0] A
+ */
+#define DRM_FORMAT_XRGB8888_A8 fourcc_code('X', 'R', 'A', '8')
+#define DRM_FORMAT_XBGR8888_A8 fourcc_code('X', 'B', 'A', '8')
+#define DRM_FORMAT_RGBX8888_A8 fourcc_code('R', 'X', 'A', '8')
+#define DRM_FORMAT_BGRX8888_A8 fourcc_code('B', 'X', 'A', '8')
+#define DRM_FORMAT_RGB888_A8 fourcc_code('R', '8', 'A', '8')
+#define DRM_FORMAT_BGR888_A8 fourcc_code('B', '8', 'A', '8')
+#define DRM_FORMAT_RGB565_A8 fourcc_code('R', '5', 'A', '8')
+#define DRM_FORMAT_BGR565_A8 fourcc_code('B', '5', 'A', '8')
+
+/*
+ * 2 plane YCbCr
+ * index 0 = Y plane, [7:0] Y
+ * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
+ * or
+ * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian
+ */
+#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */
+#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
+#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
+
+/*
+ * 3 plane YCbCr
+ * index 0: Y plane, [7:0] Y
+ * index 1: Cb plane, [7:0] Cb
+ * index 2: Cr plane, [7:0] Cr
+ * or
+ * index 1: Cr plane, [7:0] Cr
+ * index 2: Cb plane, [7:0] Cb
+ */
+#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
+
+
+/*
+ * Format Modifiers:
+ *
+ * Format modifiers describe, typically, a re-ordering or modification
+ * of the data in a plane of an FB. This can be used to express tiled/
+ * swizzled formats, or compression, or a combination of the two.
+ *
+ * The upper 8 bits of the format modifier are a vendor-id as assigned
+ * below. The lower 56 bits are assigned as vendor sees fit.
+ */
+
+/* Vendor Ids: */
+#define DRM_FORMAT_MOD_NONE 0
+#define DRM_FORMAT_MOD_VENDOR_NONE 0
+#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01
+#define DRM_FORMAT_MOD_VENDOR_AMD 0x02
+#define DRM_FORMAT_MOD_VENDOR_NVIDIA 0x03
+#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04
+#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05
+#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06
+#define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07
+/* add more to the end as needed */
+
+#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1)
+
+#define fourcc_mod_code(vendor, val) \
+ ((((uint64_t)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL))
+
+/*
+ * Format Modifier tokens:
+ *
+ * When adding a new token please document the layout with a code comment,
+ * similar to the fourcc codes above. drm_fourcc.h is considered the
+ * authoritative source for all of these.
+ */
+
+/*
+ * Invalid Modifier
+ *
+ * This modifier can be used as a sentinel to terminate the format modifiers
+ * list, or to initialize a variable with an invalid modifier. It might also be
+ * used to report an error back to userspace for certain APIs.
+ */
+#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
+
+/*
+ * Linear Layout
+ *
+ * Just plain linear layout. Note that this is different from no specifying any
+ * modifier (e.g. not setting DRM_MODE_FB_MODIFIERS in the DRM_ADDFB2 ioctl),
+ * which tells the driver to also take driver-internal information into account
+ * and so might actually result in a tiled framebuffer.
+ */
+#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0)
+
+/* Intel framebuffer modifiers */
+
+/*
+ * Intel X-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb)
+ * in row-major layout. Within the tile bytes are laid out row-major, with
+ * a platform-dependent stride. On top of that the memory can apply
+ * platform-depending swizzling of some higher address bits into bit6.
+ *
+ * This format is highly platforms specific and not useful for cross-driver
+ * sharing. It exists since on a given platform it does uniquely identify the
+ * layout in a simple way for i915-specific userspace.
+ */
+#define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1)
+
+/*
+ * Intel Y-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb)
+ * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes)
+ * chunks column-major, with a platform-dependent height. On top of that the
+ * memory can apply platform-depending swizzling of some higher address bits
+ * into bit6.
+ *
+ * This format is highly platforms specific and not useful for cross-driver
+ * sharing. It exists since on a given platform it does uniquely identify the
+ * layout in a simple way for i915-specific userspace.
+ */
+#define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2)
+
+/*
+ * Intel Yf-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles in row-major layout.
+ * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which
+ * are arranged in four groups (two wide, two high) with column-major layout.
+ * Each group therefore consits out of four 256 byte units, which are also laid
+ * out as 2x2 column-major.
+ * 256 byte units are made out of four 64 byte blocks of pixels, producing
+ * either a square block or a 2:1 unit.
+ * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width
+ * in pixel depends on the pixel depth.
+ */
+#define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3)
+
+/*
+ * Intel color control surface (CCS) for render compression
+ *
+ * The framebuffer format must be one of the 8:8:8:8 RGB formats.
+ * The main surface will be plane index 0 and must be Y/Yf-tiled,
+ * the CCS will be plane index 1.
+ *
+ * Each CCS tile matches a 1024x512 pixel area of the main surface.
+ * To match certain aspects of the 3D hardware the CCS is
+ * considered to be made up of normal 128Bx32 Y tiles, Thus
+ * the CCS pitch must be specified in multiples of 128 bytes.
+ *
+ * In reality the CCS tile appears to be a 64Bx64 Y tile, composed
+ * of QWORD (8 bytes) chunks instead of OWORD (16 bytes) chunks.
+ * But that fact is not relevant unless the memory is accessed
+ * directly.
+ */
+#define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4)
+#define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5)
+
+/*
+ * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks
+ *
+ * Macroblocks are laid in a Z-shape, and each pixel data is following the
+ * standard NV12 style.
+ * As for NV12, an image is the result of two frame buffers: one for Y,
+ * one for the interleaved Cb/Cr components (1/2 the height of the Y buffer).
+ * Alignment requirements are (for each buffer):
+ * - multiple of 128 pixels for the width
+ * - multiple of 32 pixels for the height
+ *
+ * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html
+ */
+#define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1)
+
+/* Vivante framebuffer modifiers */
+
+/*
+ * Vivante 4x4 tiling layout
+ *
+ * This is a simple tiled layout using tiles of 4x4 pixels in a row-major
+ * layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1)
+
+/*
+ * Vivante 64x64 super-tiling layout
+ *
+ * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile
+ * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row-
+ * major layout.
+ *
+ * For more information: see
+ * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2)
+
+/*
+ * Vivante 4x4 tiling layout for dual-pipe
+ *
+ * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a
+ * different base address. Offsets from the base addresses are therefore halved
+ * compared to the non-split tiled layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED fourcc_mod_code(VIVANTE, 3)
+
+/*
+ * Vivante 64x64 super-tiling layout for dual-pipe
+ *
+ * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile
+ * starts at a different base address. Offsets from the base addresses are
+ * therefore halved compared to the non-split super-tiled layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4)
+
+/* NVIDIA frame buffer modifiers */
+
+/*
+ * Tegra Tiled Layout, used by Tegra 2, 3 and 4.
+ *
+ * Pixels are arranged in simple tiles of 16 x 16 bytes.
+ */
+#define DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED fourcc_mod_code(NVIDIA, 1)
+
+/*
+ * 16Bx2 Block Linear layout, used by desktop GPUs, and Tegra K1 and later
+ *
+ * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked
+ * vertically by a power of 2 (1 to 32 GOBs) to form a block.
+ *
+ * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape.
+ *
+ * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically.
+ * Valid values are:
+ *
+ * 0 == ONE_GOB
+ * 1 == TWO_GOBS
+ * 2 == FOUR_GOBS
+ * 3 == EIGHT_GOBS
+ * 4 == SIXTEEN_GOBS
+ * 5 == THIRTYTWO_GOBS
+ *
+ * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format
+ * in full detail.
+ */
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \
+ fourcc_mod_code(NVIDIA, 0x10 | ((v) & 0xf))
+
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \
+ fourcc_mod_code(NVIDIA, 0x10)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \
+ fourcc_mod_code(NVIDIA, 0x11)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \
+ fourcc_mod_code(NVIDIA, 0x12)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \
+ fourcc_mod_code(NVIDIA, 0x13)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \
+ fourcc_mod_code(NVIDIA, 0x14)
+#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \
+ fourcc_mod_code(NVIDIA, 0x15)
+
+/*
+ * Broadcom VC4 "T" format
+ *
+ * This is the primary layout that the V3D GPU can texture from (it
+ * can't do linear). The T format has:
+ *
+ * - 64b utiles of pixels in a raster-order grid according to cpp. It's 4x4
+ * pixels at 32 bit depth.
+ *
+ * - 1k subtiles made of a 4x4 raster-order grid of 64b utiles (so usually
+ * 16x16 pixels).
+ *
+ * - 4k tiles made of a 2x2 grid of 1k subtiles (so usually 32x32 pixels). On
+ * even 4k tile rows, they're arranged as (BL, TL, TR, BR), and on odd rows
+ * they're (TR, BR, BL, TL), where bottom left is start of memory.
+ *
+ * - an image made of 4k tiles in rows either left-to-right (even rows of 4k
+ * tiles) or right-to-left (odd rows of 4k tiles).
+ */
+#define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* DRM_FOURCC_H */
diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h
index 79841b543f..9e6a8ba4ce 100644
--- a/include/standard-headers/linux/input-event-codes.h
+++ b/include/standard-headers/linux/input-event-codes.h
@@ -594,6 +594,7 @@
#define BTN_DPAD_RIGHT 0x223
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
+#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h
index bc3e6d3d5b..939b62775c 100644
--- a/include/standard-headers/linux/input.h
+++ b/include/standard-headers/linux/input.h
@@ -18,10 +18,21 @@
/*
* The event structure itself
+ * Note that __USE_TIME_BITS64 is defined by libc based on
+ * application's request to use 64 bit time_t.
*/
struct input_event {
+#if (HOST_LONG_BITS != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL)
struct timeval time;
+#define input_event_sec time.tv_sec
+#define input_event_usec time.tv_usec
+#else
+ __kernel_ulong_t __sec;
+ __kernel_ulong_t __usec;
+#define input_event_sec __sec
+#define input_event_usec __usec
+#endif
uint16_t type;
uint16_t code;
int32_t value;
diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index 70c2b2ade0..0c79eac5e9 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -622,15 +622,19 @@
* safely.
*/
#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
+#define PCI_EXP_DEVCAP2_COMP_TMOUT_DIS 0x00000010 /* Completion Timeout Disable supported */
#define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */
#define PCI_EXP_DEVCAP2_ATOMIC_ROUTE 0x00000040 /* Atomic Op routing */
-#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* Atomic 64-bit compare */
+#define PCI_EXP_DEVCAP2_ATOMIC_COMP32 0x00000080 /* 32b AtomicOp completion */
+#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* 64b AtomicOp completion */
+#define PCI_EXP_DEVCAP2_ATOMIC_COMP128 0x00000200 /* 128b AtomicOp completion */
#define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */
#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */
#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */
#define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */
#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */
+#define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS 0x0010 /* Completion Timeout Disable */
#define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */
#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */
#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */
@@ -966,26 +970,28 @@
/* Downstream Port Containment */
#define PCI_EXP_DPC_CAP 4 /* DPC Capability */
-#define PCI_EXP_DPC_IRQ 0x1f /* DPC Interrupt Message Number */
-#define PCI_EXP_DPC_CAP_RP_EXT 0x20 /* Root Port Extensions for DPC */
-#define PCI_EXP_DPC_CAP_POISONED_TLP 0x40 /* Poisoned TLP Egress Blocking Supported */
-#define PCI_EXP_DPC_CAP_SW_TRIGGER 0x80 /* Software Triggering Supported */
-#define PCI_EXP_DPC_RP_PIO_LOG_SIZE 0xF00 /* RP PIO log size */
+#define PCI_EXP_DPC_IRQ 0x001F /* Interrupt Message Number */
+#define PCI_EXP_DPC_CAP_RP_EXT 0x0020 /* Root Port Extensions */
+#define PCI_EXP_DPC_CAP_POISONED_TLP 0x0040 /* Poisoned TLP Egress Blocking Supported */
+#define PCI_EXP_DPC_CAP_SW_TRIGGER 0x0080 /* Software Triggering Supported */
+#define PCI_EXP_DPC_RP_PIO_LOG_SIZE 0x0F00 /* RP PIO Log Size */
#define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */
#define PCI_EXP_DPC_CTL 6 /* DPC control */
-#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x02 /* Enable trigger on ERR_NONFATAL message */
-#define PCI_EXP_DPC_CTL_INT_EN 0x08 /* DPC Interrupt Enable */
+#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */
+#define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */
#define PCI_EXP_DPC_STATUS 8 /* DPC Status */
-#define PCI_EXP_DPC_STATUS_TRIGGER 0x01 /* Trigger Status */
-#define PCI_EXP_DPC_STATUS_INTERRUPT 0x08 /* Interrupt Status */
-#define PCI_EXP_DPC_RP_BUSY 0x10 /* Root Port Busy */
+#define PCI_EXP_DPC_STATUS_TRIGGER 0x0001 /* Trigger Status */
+#define PCI_EXP_DPC_STATUS_TRIGGER_RSN 0x0006 /* Trigger Reason */
+#define PCI_EXP_DPC_STATUS_INTERRUPT 0x0008 /* Interrupt Status */
+#define PCI_EXP_DPC_RP_BUSY 0x0010 /* Root Port Busy */
+#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT 0x0060 /* Trig Reason Extension */
#define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */
#define PCI_EXP_DPC_RP_PIO_STATUS 0x0C /* RP PIO Status */
-#define PCI_EXP_DPC_RP_PIO_MASK 0x10 /* RP PIO MASK */
+#define PCI_EXP_DPC_RP_PIO_MASK 0x10 /* RP PIO Mask */
#define PCI_EXP_DPC_RP_PIO_SEVERITY 0x14 /* RP PIO Severity */
#define PCI_EXP_DPC_RP_PIO_SYSERROR 0x18 /* RP PIO SysError */
#define PCI_EXP_DPC_RP_PIO_EXCEPTION 0x1C /* RP PIO Exception */
diff --git a/include/standard-headers/linux/virtio_net.h b/include/standard-headers/linux/virtio_net.h
index 30ff24940d..e9f255ea3f 100644
--- a/include/standard-headers/linux/virtio_net.h
+++ b/include/standard-headers/linux/virtio_net.h
@@ -57,6 +57,8 @@
* Steering */
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
+#define VIRTIO_NET_F_SPEED_DUPLEX 63 /* Device set linkspeed and duplex */
+
#ifndef VIRTIO_NET_NO_LEGACY
#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
#endif /* VIRTIO_NET_NO_LEGACY */
@@ -76,6 +78,17 @@ struct virtio_net_config {
uint16_t max_virtqueue_pairs;
/* Default maximum transmit unit advice */
uint16_t mtu;
+ /*
+ * speed, in units of 1Mb. All values 0 to INT_MAX are legal.
+ * Any other value stands for unknown.
+ */
+ uint32_t speed;
+ /*
+ * 0x00 - half duplex
+ * 0x01 - full duplex
+ * Any other value stands for unknown.
+ */
+ uint8_t duplex;
} QEMU_PACKED;
/*
diff --git a/include/standard-headers/linux/virtio_ring.h b/include/standard-headers/linux/virtio_ring.h
index f1dc05df25..d26e72bc6b 100644
--- a/include/standard-headers/linux/virtio_ring.h
+++ b/include/standard-headers/linux/virtio_ring.h
@@ -78,7 +78,7 @@ struct vring_avail {
__virtio16 ring[];
};
-/* u32 is used here for ids for padding reasons. */
+/* uint32_t is used here for ids for padding reasons. */
struct vring_used_elem {
/* Index of start of used descriptor chain. */
__virtio32 id;
diff --git a/include/standard-headers/rdma/vmw_pvrdma-abi.h b/include/standard-headers/rdma/vmw_pvrdma-abi.h
index 0d0f7a8aca..07a820d337 100644
--- a/include/standard-headers/rdma/vmw_pvrdma-abi.h
+++ b/include/standard-headers/rdma/vmw_pvrdma-abi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
/*
* Copyright (c) 2012-2016 VMware, Inc. All rights reserved.
*
@@ -51,12 +52,14 @@
#define PVRDMA_UVERBS_ABI_VERSION 3 /* ABI Version. */
#define PVRDMA_UAR_HANDLE_MASK 0x00FFFFFF /* Bottom 24 bits. */
#define PVRDMA_UAR_QP_OFFSET 0 /* QP doorbell. */
-#define PVRDMA_UAR_QP_SEND BIT(30) /* Send bit. */
-#define PVRDMA_UAR_QP_RECV BIT(31) /* Recv bit. */
+#define PVRDMA_UAR_QP_SEND (1 << 30) /* Send bit. */
+#define PVRDMA_UAR_QP_RECV (1 << 31) /* Recv bit. */
#define PVRDMA_UAR_CQ_OFFSET 4 /* CQ doorbell. */
-#define PVRDMA_UAR_CQ_ARM_SOL BIT(29) /* Arm solicited bit. */
-#define PVRDMA_UAR_CQ_ARM BIT(30) /* Arm bit. */
-#define PVRDMA_UAR_CQ_POLL BIT(31) /* Poll bit. */
+#define PVRDMA_UAR_CQ_ARM_SOL (1 << 29) /* Arm solicited bit. */
+#define PVRDMA_UAR_CQ_ARM (1 << 30) /* Arm bit. */
+#define PVRDMA_UAR_CQ_POLL (1 << 31) /* Poll bit. */
+#define PVRDMA_UAR_SRQ_OFFSET 8 /* SRQ doorbell. */
+#define PVRDMA_UAR_SRQ_RECV (1 << 30) /* Recv bit. */
enum pvrdma_wr_opcode {
PVRDMA_WR_RDMA_WRITE,
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 85002ac49a..23669c4d5a 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -231,6 +231,23 @@ int kvm_destroy_vcpu(CPUState *cpu);
*/
bool kvm_arm_supports_user_irq(void);
+/**
+ * kvm_memcrypt_enabled - return boolean indicating whether memory encryption
+ * is enabled
+ * Returns: 1 memory encryption is enabled
+ * 0 memory encryption is disabled
+ */
+bool kvm_memcrypt_enabled(void);
+
+/**
+ * kvm_memcrypt_encrypt_data: encrypt the memory range
+ *
+ * Return: 1 failed to encrypt the range
+ * 0 succesfully encrypted memory region
+ */
+int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len);
+
+
#ifdef NEED_CPU_H
#include "cpu.h"
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
new file mode 100644
index 0000000000..98c1ec8d38
--- /dev/null
+++ b/include/sysemu/sev.h
@@ -0,0 +1,21 @@
+/*
+ * QEMU Secure Encrypted Virutualization (SEV) support
+ *
+ * Copyright: Advanced Micro Devices, 2016-2018
+ *
+ * Authors:
+ * Brijesh Singh <brijesh.singh@amd.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_SEV_H
+#define QEMU_SEV_H
+
+#include "sysemu/kvm.h"
+
+void *sev_guest_init(const char *id);
+int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
+#endif
diff --git a/include/ui/console.h b/include/ui/console.h
index aae9e44cb3..6d2c052068 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -260,6 +260,8 @@ DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
pixman_format_code_t format,
int linesize,
uint64_t addr);
+DisplaySurface *qemu_create_message_surface(int w, int h,
+ const char *msg);
PixelFormat qemu_default_pixelformat(int bpp);
DisplaySurface *qemu_create_displaysurface(int width, int height);
@@ -384,6 +386,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
void graphic_console_set_hwops(QemuConsole *con,
const GraphicHwOps *hw_ops,
void *opaque);
+void graphic_console_close(QemuConsole *con);
void graphic_hw_update(QemuConsole *con);
void graphic_hw_invalidate(QemuConsole *con);
@@ -396,6 +399,7 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index);
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
uint32_t head, Error **errp);
+QemuConsole *qemu_console_lookup_unused(void);
bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con);
bool qemu_console_is_fixedsize(QemuConsole *con);
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 849c896eef..2922fc64b2 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -54,6 +54,9 @@ typedef struct VirtualGfxConsole {
int x, y, w, h;
egl_fb guest_fb;
egl_fb win_fb;
+ egl_fb cursor_fb;
+ int cursor_x;
+ int cursor_y;
bool y0_top;
bool scanout_mode;
#endif
@@ -90,6 +93,8 @@ typedef struct VirtualConsole {
};
} VirtualConsole;
+extern bool gtk_use_gl_area;
+
/* ui/gtk.c */
void gd_update_windowsize(VirtualConsole *vc);
@@ -111,6 +116,15 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h);
+void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf);
+void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf, bool have_hot,
+ uint32_t hot_x, uint32_t hot_y);
+void gd_egl_cursor_position(DisplayChangeListener *dcl,
+ uint32_t pos_x, uint32_t pos_y);
+void gd_egl_release_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf);
void gd_egl_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void gtk_egl_init(void);
diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h
index 4a67e01232..b7c82d17fc 100644
--- a/include/ui/qemu-pixman.h
+++ b/include/ui/qemu-pixman.h
@@ -33,6 +33,8 @@
# define PIXMAN_BE_r8g8b8a8 PIXMAN_r8g8b8a8
# define PIXMAN_BE_x8b8g8r8 PIXMAN_x8b8g8r8
# define PIXMAN_BE_a8b8g8r8 PIXMAN_a8b8g8r8
+# define PIXMAN_LE_r8g8b8 PIXMAN_b8g8r8
+# define PIXMAN_LE_a8r8g8b8 PIXMAN_b8g8r8a8
# define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8
#else
# define PIXMAN_BE_r8g8b8 PIXMAN_b8g8r8
@@ -44,6 +46,8 @@
# define PIXMAN_BE_r8g8b8a8 PIXMAN_a8b8g8r8
# define PIXMAN_BE_x8b8g8r8 PIXMAN_r8g8b8x8
# define PIXMAN_BE_a8b8g8r8 PIXMAN_r8g8b8a8
+# define PIXMAN_LE_r8g8b8 PIXMAN_r8g8b8
+# define PIXMAN_LE_a8r8g8b8 PIXMAN_a8r8g8b8
# define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8
#endif
@@ -51,6 +55,7 @@
PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format);
pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian);
+pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format);
int qemu_pixman_get_type(int rshift, int gshift, int bshift);
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf);
bool qemu_pixman_check_format(DisplayChangeListener *dcl,
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
index 6b5c73b21c..87a84a59d4 100644
--- a/include/ui/spice-display.h
+++ b/include/ui/spice-display.h
@@ -122,6 +122,15 @@ struct SimpleSpiceDisplay {
int gl_updates;
bool have_scanout;
bool have_surface;
+
+ QemuDmaBuf *guest_dmabuf;
+ bool guest_dmabuf_refresh;
+ bool render_cursor;
+
+ egl_fb guest_fb;
+ egl_fb blit_fb;
+ egl_fb cursor_fb;
+ bool have_hot;
#endif
};
diff --git a/io/channel-util.c b/io/channel-util.c
index 0fb4bd0837..423d79845a 100644
--- a/io/channel-util.c
+++ b/io/channel-util.c
@@ -24,19 +24,6 @@
#include "io/channel-socket.h"
-static bool fd_is_socket(int fd)
-{
- int optval;
- socklen_t optlen;
- optlen = sizeof(optval);
- return qemu_getsockopt(fd,
- SOL_SOCKET,
- SO_TYPE,
- (char *)&optval,
- &optlen) == 0;
-}
-
-
QIOChannel *qio_channel_new_fd(int fd,
Error **errp)
{
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 637b7263cb..833ed9a16a 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -632,6 +632,8 @@ struct kvm_ppc_cpu_char {
#define KVM_REG_PPC_TIDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbc)
#define KVM_REG_PPC_PSSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd)
+#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe)
+
/* Transactional Memory checkpointed state:
* This is all GPRs, all VSX regs and a subset of SPRs
*/
diff --git a/linux-headers/asm-powerpc/unistd.h b/linux-headers/asm-powerpc/unistd.h
index 36abf58582..0c08edcfcd 100644
--- a/linux-headers/asm-powerpc/unistd.h
+++ b/linux-headers/asm-powerpc/unistd.h
@@ -395,5 +395,8 @@
#define __NR_pwritev2 381
#define __NR_kexec_file_load 382
#define __NR_statx 383
+#define __NR_pkey_alloc 384
+#define __NR_pkey_free 385
+#define __NR_pkey_mprotect 386
#endif /* _ASM_POWERPC_UNISTD_H_ */
diff --git a/linux-headers/asm-s390/unistd.h b/linux-headers/asm-s390/unistd.h
index 99223b874a..27b8b211c8 100644
--- a/linux-headers/asm-s390/unistd.h
+++ b/linux-headers/asm-s390/unistd.h
@@ -8,405 +8,10 @@
#ifndef _ASM_S390_UNISTD_H_
#define _ASM_S390_UNISTD_H_
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_exit 1
-#define __NR_fork 2
-#define __NR_read 3
-#define __NR_write 4
-#define __NR_open 5
-#define __NR_close 6
-#define __NR_restart_syscall 7
-#define __NR_creat 8
-#define __NR_link 9
-#define __NR_unlink 10
-#define __NR_execve 11
-#define __NR_chdir 12
-#define __NR_mknod 14
-#define __NR_chmod 15
-#define __NR_lseek 19
-#define __NR_getpid 20
-#define __NR_mount 21
-#define __NR_umount 22
-#define __NR_ptrace 26
-#define __NR_alarm 27
-#define __NR_pause 29
-#define __NR_utime 30
-#define __NR_access 33
-#define __NR_nice 34
-#define __NR_sync 36
-#define __NR_kill 37
-#define __NR_rename 38
-#define __NR_mkdir 39
-#define __NR_rmdir 40
-#define __NR_dup 41
-#define __NR_pipe 42
-#define __NR_times 43
-#define __NR_brk 45
-#define __NR_signal 48
-#define __NR_acct 51
-#define __NR_umount2 52
-#define __NR_ioctl 54
-#define __NR_fcntl 55
-#define __NR_setpgid 57
-#define __NR_umask 60
-#define __NR_chroot 61
-#define __NR_ustat 62
-#define __NR_dup2 63
-#define __NR_getppid 64
-#define __NR_getpgrp 65
-#define __NR_setsid 66
-#define __NR_sigaction 67
-#define __NR_sigsuspend 72
-#define __NR_sigpending 73
-#define __NR_sethostname 74
-#define __NR_setrlimit 75
-#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
-#define __NR_symlink 83
-#define __NR_readlink 85
-#define __NR_uselib 86
-#define __NR_swapon 87
-#define __NR_reboot 88
-#define __NR_readdir 89
-#define __NR_mmap 90
-#define __NR_munmap 91
-#define __NR_truncate 92
-#define __NR_ftruncate 93
-#define __NR_fchmod 94
-#define __NR_getpriority 96
-#define __NR_setpriority 97
-#define __NR_statfs 99
-#define __NR_fstatfs 100
-#define __NR_socketcall 102
-#define __NR_syslog 103
-#define __NR_setitimer 104
-#define __NR_getitimer 105
-#define __NR_stat 106
-#define __NR_lstat 107
-#define __NR_fstat 108
-#define __NR_lookup_dcookie 110
-#define __NR_vhangup 111
-#define __NR_idle 112
-#define __NR_wait4 114
-#define __NR_swapoff 115
-#define __NR_sysinfo 116
-#define __NR_ipc 117
-#define __NR_fsync 118
-#define __NR_sigreturn 119
-#define __NR_clone 120
-#define __NR_setdomainname 121
-#define __NR_uname 122
-#define __NR_adjtimex 124
-#define __NR_mprotect 125
-#define __NR_sigprocmask 126
-#define __NR_create_module 127
-#define __NR_init_module 128
-#define __NR_delete_module 129
-#define __NR_get_kernel_syms 130
-#define __NR_quotactl 131
-#define __NR_getpgid 132
-#define __NR_fchdir 133
-#define __NR_bdflush 134
-#define __NR_sysfs 135
-#define __NR_personality 136
-#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
-#define __NR_getdents 141
-#define __NR_flock 143
-#define __NR_msync 144
-#define __NR_readv 145
-#define __NR_writev 146
-#define __NR_getsid 147
-#define __NR_fdatasync 148
-#define __NR__sysctl 149
-#define __NR_mlock 150
-#define __NR_munlock 151
-#define __NR_mlockall 152
-#define __NR_munlockall 153
-#define __NR_sched_setparam 154
-#define __NR_sched_getparam 155
-#define __NR_sched_setscheduler 156
-#define __NR_sched_getscheduler 157
-#define __NR_sched_yield 158
-#define __NR_sched_get_priority_max 159
-#define __NR_sched_get_priority_min 160
-#define __NR_sched_rr_get_interval 161
-#define __NR_nanosleep 162
-#define __NR_mremap 163
-#define __NR_query_module 167
-#define __NR_poll 168
-#define __NR_nfsservctl 169
-#define __NR_prctl 172
-#define __NR_rt_sigreturn 173
-#define __NR_rt_sigaction 174
-#define __NR_rt_sigprocmask 175
-#define __NR_rt_sigpending 176
-#define __NR_rt_sigtimedwait 177
-#define __NR_rt_sigqueueinfo 178
-#define __NR_rt_sigsuspend 179
-#define __NR_pread64 180
-#define __NR_pwrite64 181
-#define __NR_getcwd 183
-#define __NR_capget 184
-#define __NR_capset 185
-#define __NR_sigaltstack 186
-#define __NR_sendfile 187
-#define __NR_getpmsg 188
-#define __NR_putpmsg 189
-#define __NR_vfork 190
-#define __NR_pivot_root 217
-#define __NR_mincore 218
-#define __NR_madvise 219
-#define __NR_getdents64 220
-#define __NR_readahead 222
-#define __NR_setxattr 224
-#define __NR_lsetxattr 225
-#define __NR_fsetxattr 226
-#define __NR_getxattr 227
-#define __NR_lgetxattr 228
-#define __NR_fgetxattr 229
-#define __NR_listxattr 230
-#define __NR_llistxattr 231
-#define __NR_flistxattr 232
-#define __NR_removexattr 233
-#define __NR_lremovexattr 234
-#define __NR_fremovexattr 235
-#define __NR_gettid 236
-#define __NR_tkill 237
-#define __NR_futex 238
-#define __NR_sched_setaffinity 239
-#define __NR_sched_getaffinity 240
-#define __NR_tgkill 241
-/* Number 242 is reserved for tux */
-#define __NR_io_setup 243
-#define __NR_io_destroy 244
-#define __NR_io_getevents 245
-#define __NR_io_submit 246
-#define __NR_io_cancel 247
-#define __NR_exit_group 248
-#define __NR_epoll_create 249
-#define __NR_epoll_ctl 250
-#define __NR_epoll_wait 251
-#define __NR_set_tid_address 252
-#define __NR_fadvise64 253
-#define __NR_timer_create 254
-#define __NR_timer_settime 255
-#define __NR_timer_gettime 256
-#define __NR_timer_getoverrun 257
-#define __NR_timer_delete 258
-#define __NR_clock_settime 259
-#define __NR_clock_gettime 260
-#define __NR_clock_getres 261
-#define __NR_clock_nanosleep 262
-/* Number 263 is reserved for vserver */
-#define __NR_statfs64 265
-#define __NR_fstatfs64 266
-#define __NR_remap_file_pages 267
-#define __NR_mbind 268
-#define __NR_get_mempolicy 269
-#define __NR_set_mempolicy 270
-#define __NR_mq_open 271
-#define __NR_mq_unlink 272
-#define __NR_mq_timedsend 273
-#define __NR_mq_timedreceive 274
-#define __NR_mq_notify 275
-#define __NR_mq_getsetattr 276
-#define __NR_kexec_load 277
-#define __NR_add_key 278
-#define __NR_request_key 279
-#define __NR_keyctl 280
-#define __NR_waitid 281
-#define __NR_ioprio_set 282
-#define __NR_ioprio_get 283
-#define __NR_inotify_init 284
-#define __NR_inotify_add_watch 285
-#define __NR_inotify_rm_watch 286
-#define __NR_migrate_pages 287
-#define __NR_openat 288
-#define __NR_mkdirat 289
-#define __NR_mknodat 290
-#define __NR_fchownat 291
-#define __NR_futimesat 292
-#define __NR_unlinkat 294
-#define __NR_renameat 295
-#define __NR_linkat 296
-#define __NR_symlinkat 297
-#define __NR_readlinkat 298
-#define __NR_fchmodat 299
-#define __NR_faccessat 300
-#define __NR_pselect6 301
-#define __NR_ppoll 302
-#define __NR_unshare 303
-#define __NR_set_robust_list 304
-#define __NR_get_robust_list 305
-#define __NR_splice 306
-#define __NR_sync_file_range 307
-#define __NR_tee 308
-#define __NR_vmsplice 309
-#define __NR_move_pages 310
-#define __NR_getcpu 311
-#define __NR_epoll_pwait 312
-#define __NR_utimes 313
-#define __NR_fallocate 314
-#define __NR_utimensat 315
-#define __NR_signalfd 316
-#define __NR_timerfd 317
-#define __NR_eventfd 318
-#define __NR_timerfd_create 319
-#define __NR_timerfd_settime 320
-#define __NR_timerfd_gettime 321
-#define __NR_signalfd4 322
-#define __NR_eventfd2 323
-#define __NR_inotify_init1 324
-#define __NR_pipe2 325
-#define __NR_dup3 326
-#define __NR_epoll_create1 327
-#define __NR_preadv 328
-#define __NR_pwritev 329
-#define __NR_rt_tgsigqueueinfo 330
-#define __NR_perf_event_open 331
-#define __NR_fanotify_init 332
-#define __NR_fanotify_mark 333
-#define __NR_prlimit64 334
-#define __NR_name_to_handle_at 335
-#define __NR_open_by_handle_at 336
-#define __NR_clock_adjtime 337
-#define __NR_syncfs 338
-#define __NR_setns 339
-#define __NR_process_vm_readv 340
-#define __NR_process_vm_writev 341
-#define __NR_s390_runtime_instr 342
-#define __NR_kcmp 343
-#define __NR_finit_module 344
-#define __NR_sched_setattr 345
-#define __NR_sched_getattr 346
-#define __NR_renameat2 347
-#define __NR_seccomp 348
-#define __NR_getrandom 349
-#define __NR_memfd_create 350
-#define __NR_bpf 351
-#define __NR_s390_pci_mmio_write 352
-#define __NR_s390_pci_mmio_read 353
-#define __NR_execveat 354
-#define __NR_userfaultfd 355
-#define __NR_membarrier 356
-#define __NR_recvmmsg 357
-#define __NR_sendmmsg 358
-#define __NR_socket 359
-#define __NR_socketpair 360
-#define __NR_bind 361
-#define __NR_connect 362
-#define __NR_listen 363
-#define __NR_accept4 364
-#define __NR_getsockopt 365
-#define __NR_setsockopt 366
-#define __NR_getsockname 367
-#define __NR_getpeername 368
-#define __NR_sendto 369
-#define __NR_sendmsg 370
-#define __NR_recvfrom 371
-#define __NR_recvmsg 372
-#define __NR_shutdown 373
-#define __NR_mlock2 374
-#define __NR_copy_file_range 375
-#define __NR_preadv2 376
-#define __NR_pwritev2 377
-#define __NR_s390_guarded_storage 378
-#define __NR_statx 379
-#define __NR_s390_sthyi 380
-#define NR_syscalls 381
-
-/*
- * There are some system calls that are not present on 64 bit, some
- * have a different name although they do the same (e.g. __NR_chown32
- * is __NR_chown on 64 bit).
- */
-#ifndef __s390x__
-
-#define __NR_time 13
-#define __NR_lchown 16
-#define __NR_setuid 23
-#define __NR_getuid 24
-#define __NR_stime 25
-#define __NR_setgid 46
-#define __NR_getgid 47
-#define __NR_geteuid 49
-#define __NR_getegid 50
-#define __NR_setreuid 70
-#define __NR_setregid 71
-#define __NR_getrlimit 76
-#define __NR_getgroups 80
-#define __NR_setgroups 81
-#define __NR_fchown 95
-#define __NR_ioperm 101
-#define __NR_setfsuid 138
-#define __NR_setfsgid 139
-#define __NR__llseek 140
-#define __NR__newselect 142
-#define __NR_setresuid 164
-#define __NR_getresuid 165
-#define __NR_setresgid 170
-#define __NR_getresgid 171
-#define __NR_chown 182
-#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
-#define __NR_mmap2 192
-#define __NR_truncate64 193
-#define __NR_ftruncate64 194
-#define __NR_stat64 195
-#define __NR_lstat64 196
-#define __NR_fstat64 197
-#define __NR_lchown32 198
-#define __NR_getuid32 199
-#define __NR_getgid32 200
-#define __NR_geteuid32 201
-#define __NR_getegid32 202
-#define __NR_setreuid32 203
-#define __NR_setregid32 204
-#define __NR_getgroups32 205
-#define __NR_setgroups32 206
-#define __NR_fchown32 207
-#define __NR_setresuid32 208
-#define __NR_getresuid32 209
-#define __NR_setresgid32 210
-#define __NR_getresgid32 211
-#define __NR_chown32 212
-#define __NR_setuid32 213
-#define __NR_setgid32 214
-#define __NR_setfsuid32 215
-#define __NR_setfsgid32 216
-#define __NR_fcntl64 221
-#define __NR_sendfile64 223
-#define __NR_fadvise64_64 264
-#define __NR_fstatat64 293
-
+#ifdef __s390x__
+#include <asm/unistd_64.h>
#else
-
-#define __NR_select 142
-#define __NR_getrlimit 191 /* SuS compliant getrlimit */
-#define __NR_lchown 198
-#define __NR_getuid 199
-#define __NR_getgid 200
-#define __NR_geteuid 201
-#define __NR_getegid 202
-#define __NR_setreuid 203
-#define __NR_setregid 204
-#define __NR_getgroups 205
-#define __NR_setgroups 206
-#define __NR_fchown 207
-#define __NR_setresuid 208
-#define __NR_getresuid 209
-#define __NR_setresgid 210
-#define __NR_getresgid 211
-#define __NR_chown 212
-#define __NR_setuid 213
-#define __NR_setgid 214
-#define __NR_setfsuid 215
-#define __NR_setfsgid 216
-#define __NR_newfstatat 293
-
+#include <asm/unistd_32.h>
#endif
#endif /* _ASM_S390_UNISTD_H_ */
diff --git a/linux-headers/asm-s390/unistd_32.h b/linux-headers/asm-s390/unistd_32.h
new file mode 100644
index 0000000000..1ae66a263b
--- /dev/null
+++ b/linux-headers/asm-s390/unistd_32.h
@@ -0,0 +1,364 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASM_S390_UNISTD_32_H
+#define _ASM_S390_UNISTD_32_H
+
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_restart_syscall 7
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_chdir 12
+#define __NR_time 13
+#define __NR_mknod 14
+#define __NR_chmod 15
+#define __NR_lchown 16
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+#define __NR_umount 22
+#define __NR_setuid 23
+#define __NR_getuid 24
+#define __NR_stime 25
+#define __NR_ptrace 26
+#define __NR_alarm 27
+#define __NR_pause 29
+#define __NR_utime 30
+#define __NR_access 33
+#define __NR_nice 34
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+#define __NR_brk 45
+#define __NR_setgid 46
+#define __NR_getgid 47
+#define __NR_signal 48
+#define __NR_geteuid 49
+#define __NR_getegid 50
+#define __NR_acct 51
+#define __NR_umount2 52
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+#define __NR_setpgid 57
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+#define __NR_setsid 66
+#define __NR_sigaction 67
+#define __NR_setreuid 70
+#define __NR_setregid 71
+#define __NR_sigsuspend 72
+#define __NR_sigpending 73
+#define __NR_sethostname 74
+#define __NR_setrlimit 75
+#define __NR_getrlimit 76
+#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+#define __NR_settimeofday 79
+#define __NR_getgroups 80
+#define __NR_setgroups 81
+#define __NR_symlink 83
+#define __NR_readlink 85
+#define __NR_uselib 86
+#define __NR_swapon 87
+#define __NR_reboot 88
+#define __NR_readdir 89
+#define __NR_mmap 90
+#define __NR_munmap 91
+#define __NR_truncate 92
+#define __NR_ftruncate 93
+#define __NR_fchmod 94
+#define __NR_fchown 95
+#define __NR_getpriority 96
+#define __NR_setpriority 97
+#define __NR_statfs 99
+#define __NR_fstatfs 100
+#define __NR_ioperm 101
+#define __NR_socketcall 102
+#define __NR_syslog 103
+#define __NR_setitimer 104
+#define __NR_getitimer 105
+#define __NR_stat 106
+#define __NR_lstat 107
+#define __NR_fstat 108
+#define __NR_lookup_dcookie 110
+#define __NR_vhangup 111
+#define __NR_idle 112
+#define __NR_wait4 114
+#define __NR_swapoff 115
+#define __NR_sysinfo 116
+#define __NR_ipc 117
+#define __NR_fsync 118
+#define __NR_sigreturn 119
+#define __NR_clone 120
+#define __NR_setdomainname 121
+#define __NR_uname 122
+#define __NR_adjtimex 124
+#define __NR_mprotect 125
+#define __NR_sigprocmask 126
+#define __NR_create_module 127
+#define __NR_init_module 128
+#define __NR_delete_module 129
+#define __NR_get_kernel_syms 130
+#define __NR_quotactl 131
+#define __NR_getpgid 132
+#define __NR_fchdir 133
+#define __NR_bdflush 134
+#define __NR_sysfs 135
+#define __NR_personality 136
+#define __NR_afs_syscall 137
+#define __NR_setfsuid 138
+#define __NR_setfsgid 139
+#define __NR__llseek 140
+#define __NR_getdents 141
+#define __NR__newselect 142
+#define __NR_flock 143
+#define __NR_msync 144
+#define __NR_readv 145
+#define __NR_writev 146
+#define __NR_getsid 147
+#define __NR_fdatasync 148
+#define __NR__sysctl 149
+#define __NR_mlock 150
+#define __NR_munlock 151
+#define __NR_mlockall 152
+#define __NR_munlockall 153
+#define __NR_sched_setparam 154
+#define __NR_sched_getparam 155
+#define __NR_sched_setscheduler 156
+#define __NR_sched_getscheduler 157
+#define __NR_sched_yield 158
+#define __NR_sched_get_priority_max 159
+#define __NR_sched_get_priority_min 160
+#define __NR_sched_rr_get_interval 161
+#define __NR_nanosleep 162
+#define __NR_mremap 163
+#define __NR_setresuid 164
+#define __NR_getresuid 165
+#define __NR_query_module 167
+#define __NR_poll 168
+#define __NR_nfsservctl 169
+#define __NR_setresgid 170
+#define __NR_getresgid 171
+#define __NR_prctl 172
+#define __NR_rt_sigreturn 173
+#define __NR_rt_sigaction 174
+#define __NR_rt_sigprocmask 175
+#define __NR_rt_sigpending 176
+#define __NR_rt_sigtimedwait 177
+#define __NR_rt_sigqueueinfo 178
+#define __NR_rt_sigsuspend 179
+#define __NR_pread64 180
+#define __NR_pwrite64 181
+#define __NR_chown 182
+#define __NR_getcwd 183
+#define __NR_capget 184
+#define __NR_capset 185
+#define __NR_sigaltstack 186
+#define __NR_sendfile 187
+#define __NR_getpmsg 188
+#define __NR_putpmsg 189
+#define __NR_vfork 190
+#define __NR_ugetrlimit 191
+#define __NR_mmap2 192
+#define __NR_truncate64 193
+#define __NR_ftruncate64 194
+#define __NR_stat64 195
+#define __NR_lstat64 196
+#define __NR_fstat64 197
+#define __NR_lchown32 198
+#define __NR_getuid32 199
+#define __NR_getgid32 200
+#define __NR_geteuid32 201
+#define __NR_getegid32 202
+#define __NR_setreuid32 203
+#define __NR_setregid32 204
+#define __NR_getgroups32 205
+#define __NR_setgroups32 206
+#define __NR_fchown32 207
+#define __NR_setresuid32 208
+#define __NR_getresuid32 209
+#define __NR_setresgid32 210
+#define __NR_getresgid32 211
+#define __NR_chown32 212
+#define __NR_setuid32 213
+#define __NR_setgid32 214
+#define __NR_setfsuid32 215
+#define __NR_setfsgid32 216
+#define __NR_pivot_root 217
+#define __NR_mincore 218
+#define __NR_madvise 219
+#define __NR_getdents64 220
+#define __NR_fcntl64 221
+#define __NR_readahead 222
+#define __NR_sendfile64 223
+#define __NR_setxattr 224
+#define __NR_lsetxattr 225
+#define __NR_fsetxattr 226
+#define __NR_getxattr 227
+#define __NR_lgetxattr 228
+#define __NR_fgetxattr 229
+#define __NR_listxattr 230
+#define __NR_llistxattr 231
+#define __NR_flistxattr 232
+#define __NR_removexattr 233
+#define __NR_lremovexattr 234
+#define __NR_fremovexattr 235
+#define __NR_gettid 236
+#define __NR_tkill 237
+#define __NR_futex 238
+#define __NR_sched_setaffinity 239
+#define __NR_sched_getaffinity 240
+#define __NR_tgkill 241
+#define __NR_io_setup 243
+#define __NR_io_destroy 244
+#define __NR_io_getevents 245
+#define __NR_io_submit 246
+#define __NR_io_cancel 247
+#define __NR_exit_group 248
+#define __NR_epoll_create 249
+#define __NR_epoll_ctl 250
+#define __NR_epoll_wait 251
+#define __NR_set_tid_address 252
+#define __NR_fadvise64 253
+#define __NR_timer_create 254
+#define __NR_timer_settime 255
+#define __NR_timer_gettime 256
+#define __NR_timer_getoverrun 257
+#define __NR_timer_delete 258
+#define __NR_clock_settime 259
+#define __NR_clock_gettime 260
+#define __NR_clock_getres 261
+#define __NR_clock_nanosleep 262
+#define __NR_fadvise64_64 264
+#define __NR_statfs64 265
+#define __NR_fstatfs64 266
+#define __NR_remap_file_pages 267
+#define __NR_mbind 268
+#define __NR_get_mempolicy 269
+#define __NR_set_mempolicy 270
+#define __NR_mq_open 271
+#define __NR_mq_unlink 272
+#define __NR_mq_timedsend 273
+#define __NR_mq_timedreceive 274
+#define __NR_mq_notify 275
+#define __NR_mq_getsetattr 276
+#define __NR_kexec_load 277
+#define __NR_add_key 278
+#define __NR_request_key 279
+#define __NR_keyctl 280
+#define __NR_waitid 281
+#define __NR_ioprio_set 282
+#define __NR_ioprio_get 283
+#define __NR_inotify_init 284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch 286
+#define __NR_migrate_pages 287
+#define __NR_openat 288
+#define __NR_mkdirat 289
+#define __NR_mknodat 290
+#define __NR_fchownat 291
+#define __NR_futimesat 292
+#define __NR_fstatat64 293
+#define __NR_unlinkat 294
+#define __NR_renameat 295
+#define __NR_linkat 296
+#define __NR_symlinkat 297
+#define __NR_readlinkat 298
+#define __NR_fchmodat 299
+#define __NR_faccessat 300
+#define __NR_pselect6 301
+#define __NR_ppoll 302
+#define __NR_unshare 303
+#define __NR_set_robust_list 304
+#define __NR_get_robust_list 305
+#define __NR_splice 306
+#define __NR_sync_file_range 307
+#define __NR_tee 308
+#define __NR_vmsplice 309
+#define __NR_move_pages 310
+#define __NR_getcpu 311
+#define __NR_epoll_pwait 312
+#define __NR_utimes 313
+#define __NR_fallocate 314
+#define __NR_utimensat 315
+#define __NR_signalfd 316
+#define __NR_timerfd 317
+#define __NR_eventfd 318
+#define __NR_timerfd_create 319
+#define __NR_timerfd_settime 320
+#define __NR_timerfd_gettime 321
+#define __NR_signalfd4 322
+#define __NR_eventfd2 323
+#define __NR_inotify_init1 324
+#define __NR_pipe2 325
+#define __NR_dup3 326
+#define __NR_epoll_create1 327
+#define __NR_preadv 328
+#define __NR_pwritev 329
+#define __NR_rt_tgsigqueueinfo 330
+#define __NR_perf_event_open 331
+#define __NR_fanotify_init 332
+#define __NR_fanotify_mark 333
+#define __NR_prlimit64 334
+#define __NR_name_to_handle_at 335
+#define __NR_open_by_handle_at 336
+#define __NR_clock_adjtime 337
+#define __NR_syncfs 338
+#define __NR_setns 339
+#define __NR_process_vm_readv 340
+#define __NR_process_vm_writev 341
+#define __NR_s390_runtime_instr 342
+#define __NR_kcmp 343
+#define __NR_finit_module 344
+#define __NR_sched_setattr 345
+#define __NR_sched_getattr 346
+#define __NR_renameat2 347
+#define __NR_seccomp 348
+#define __NR_getrandom 349
+#define __NR_memfd_create 350
+#define __NR_bpf 351
+#define __NR_s390_pci_mmio_write 352
+#define __NR_s390_pci_mmio_read 353
+#define __NR_execveat 354
+#define __NR_userfaultfd 355
+#define __NR_membarrier 356
+#define __NR_recvmmsg 357
+#define __NR_sendmmsg 358
+#define __NR_socket 359
+#define __NR_socketpair 360
+#define __NR_bind 361
+#define __NR_connect 362
+#define __NR_listen 363
+#define __NR_accept4 364
+#define __NR_getsockopt 365
+#define __NR_setsockopt 366
+#define __NR_getsockname 367
+#define __NR_getpeername 368
+#define __NR_sendto 369
+#define __NR_sendmsg 370
+#define __NR_recvfrom 371
+#define __NR_recvmsg 372
+#define __NR_shutdown 373
+#define __NR_mlock2 374
+#define __NR_copy_file_range 375
+#define __NR_preadv2 376
+#define __NR_pwritev2 377
+#define __NR_s390_guarded_storage 378
+#define __NR_statx 379
+#define __NR_s390_sthyi 380
+
+#endif /* _ASM_S390_UNISTD_32_H */
diff --git a/linux-headers/asm-s390/unistd_64.h b/linux-headers/asm-s390/unistd_64.h
new file mode 100644
index 0000000000..8aa9d046a9
--- /dev/null
+++ b/linux-headers/asm-s390/unistd_64.h
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASM_S390_UNISTD_64_H
+#define _ASM_S390_UNISTD_64_H
+
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_restart_syscall 7
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_chdir 12
+#define __NR_mknod 14
+#define __NR_chmod 15
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+#define __NR_umount 22
+#define __NR_ptrace 26
+#define __NR_alarm 27
+#define __NR_pause 29
+#define __NR_utime 30
+#define __NR_access 33
+#define __NR_nice 34
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+#define __NR_brk 45
+#define __NR_signal 48
+#define __NR_acct 51
+#define __NR_umount2 52
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+#define __NR_setpgid 57
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+#define __NR_setsid 66
+#define __NR_sigaction 67
+#define __NR_sigsuspend 72
+#define __NR_sigpending 73
+#define __NR_sethostname 74
+#define __NR_setrlimit 75
+#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+#define __NR_settimeofday 79
+#define __NR_symlink 83
+#define __NR_readlink 85
+#define __NR_uselib 86
+#define __NR_swapon 87
+#define __NR_reboot 88
+#define __NR_readdir 89
+#define __NR_mmap 90
+#define __NR_munmap 91
+#define __NR_truncate 92
+#define __NR_ftruncate 93
+#define __NR_fchmod 94
+#define __NR_getpriority 96
+#define __NR_setpriority 97
+#define __NR_statfs 99
+#define __NR_fstatfs 100
+#define __NR_socketcall 102
+#define __NR_syslog 103
+#define __NR_setitimer 104
+#define __NR_getitimer 105
+#define __NR_stat 106
+#define __NR_lstat 107
+#define __NR_fstat 108
+#define __NR_lookup_dcookie 110
+#define __NR_vhangup 111
+#define __NR_idle 112
+#define __NR_wait4 114
+#define __NR_swapoff 115
+#define __NR_sysinfo 116
+#define __NR_ipc 117
+#define __NR_fsync 118
+#define __NR_sigreturn 119
+#define __NR_clone 120
+#define __NR_setdomainname 121
+#define __NR_uname 122
+#define __NR_adjtimex 124
+#define __NR_mprotect 125
+#define __NR_sigprocmask 126
+#define __NR_create_module 127
+#define __NR_init_module 128
+#define __NR_delete_module 129
+#define __NR_get_kernel_syms 130
+#define __NR_quotactl 131
+#define __NR_getpgid 132
+#define __NR_fchdir 133
+#define __NR_bdflush 134
+#define __NR_sysfs 135
+#define __NR_personality 136
+#define __NR_afs_syscall 137
+#define __NR_getdents 141
+#define __NR_select 142
+#define __NR_flock 143
+#define __NR_msync 144
+#define __NR_readv 145
+#define __NR_writev 146
+#define __NR_getsid 147
+#define __NR_fdatasync 148
+#define __NR__sysctl 149
+#define __NR_mlock 150
+#define __NR_munlock 151
+#define __NR_mlockall 152
+#define __NR_munlockall 153
+#define __NR_sched_setparam 154
+#define __NR_sched_getparam 155
+#define __NR_sched_setscheduler 156
+#define __NR_sched_getscheduler 157
+#define __NR_sched_yield 158
+#define __NR_sched_get_priority_max 159
+#define __NR_sched_get_priority_min 160
+#define __NR_sched_rr_get_interval 161
+#define __NR_nanosleep 162
+#define __NR_mremap 163
+#define __NR_query_module 167
+#define __NR_poll 168
+#define __NR_nfsservctl 169
+#define __NR_prctl 172
+#define __NR_rt_sigreturn 173
+#define __NR_rt_sigaction 174
+#define __NR_rt_sigprocmask 175
+#define __NR_rt_sigpending 176
+#define __NR_rt_sigtimedwait 177
+#define __NR_rt_sigqueueinfo 178
+#define __NR_rt_sigsuspend 179
+#define __NR_pread64 180
+#define __NR_pwrite64 181
+#define __NR_getcwd 183
+#define __NR_capget 184
+#define __NR_capset 185
+#define __NR_sigaltstack 186
+#define __NR_sendfile 187
+#define __NR_getpmsg 188
+#define __NR_putpmsg 189
+#define __NR_vfork 190
+#define __NR_getrlimit 191
+#define __NR_lchown 198
+#define __NR_getuid 199
+#define __NR_getgid 200
+#define __NR_geteuid 201
+#define __NR_getegid 202
+#define __NR_setreuid 203
+#define __NR_setregid 204
+#define __NR_getgroups 205
+#define __NR_setgroups 206
+#define __NR_fchown 207
+#define __NR_setresuid 208
+#define __NR_getresuid 209
+#define __NR_setresgid 210
+#define __NR_getresgid 211
+#define __NR_chown 212
+#define __NR_setuid 213
+#define __NR_setgid 214
+#define __NR_setfsuid 215
+#define __NR_setfsgid 216
+#define __NR_pivot_root 217
+#define __NR_mincore 218
+#define __NR_madvise 219
+#define __NR_getdents64 220
+#define __NR_readahead 222
+#define __NR_setxattr 224
+#define __NR_lsetxattr 225
+#define __NR_fsetxattr 226
+#define __NR_getxattr 227
+#define __NR_lgetxattr 228
+#define __NR_fgetxattr 229
+#define __NR_listxattr 230
+#define __NR_llistxattr 231
+#define __NR_flistxattr 232
+#define __NR_removexattr 233
+#define __NR_lremovexattr 234
+#define __NR_fremovexattr 235
+#define __NR_gettid 236
+#define __NR_tkill 237
+#define __NR_futex 238
+#define __NR_sched_setaffinity 239
+#define __NR_sched_getaffinity 240
+#define __NR_tgkill 241
+#define __NR_io_setup 243
+#define __NR_io_destroy 244
+#define __NR_io_getevents 245
+#define __NR_io_submit 246
+#define __NR_io_cancel 247
+#define __NR_exit_group 248
+#define __NR_epoll_create 249
+#define __NR_epoll_ctl 250
+#define __NR_epoll_wait 251
+#define __NR_set_tid_address 252
+#define __NR_fadvise64 253
+#define __NR_timer_create 254
+#define __NR_timer_settime 255
+#define __NR_timer_gettime 256
+#define __NR_timer_getoverrun 257
+#define __NR_timer_delete 258
+#define __NR_clock_settime 259
+#define __NR_clock_gettime 260
+#define __NR_clock_getres 261
+#define __NR_clock_nanosleep 262
+#define __NR_statfs64 265
+#define __NR_fstatfs64 266
+#define __NR_remap_file_pages 267
+#define __NR_mbind 268
+#define __NR_get_mempolicy 269
+#define __NR_set_mempolicy 270
+#define __NR_mq_open 271
+#define __NR_mq_unlink 272
+#define __NR_mq_timedsend 273
+#define __NR_mq_timedreceive 274
+#define __NR_mq_notify 275
+#define __NR_mq_getsetattr 276
+#define __NR_kexec_load 277
+#define __NR_add_key 278
+#define __NR_request_key 279
+#define __NR_keyctl 280
+#define __NR_waitid 281
+#define __NR_ioprio_set 282
+#define __NR_ioprio_get 283
+#define __NR_inotify_init 284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch 286
+#define __NR_migrate_pages 287
+#define __NR_openat 288
+#define __NR_mkdirat 289
+#define __NR_mknodat 290
+#define __NR_fchownat 291
+#define __NR_futimesat 292
+#define __NR_newfstatat 293
+#define __NR_unlinkat 294
+#define __NR_renameat 295
+#define __NR_linkat 296
+#define __NR_symlinkat 297
+#define __NR_readlinkat 298
+#define __NR_fchmodat 299
+#define __NR_faccessat 300
+#define __NR_pselect6 301
+#define __NR_ppoll 302
+#define __NR_unshare 303
+#define __NR_set_robust_list 304
+#define __NR_get_robust_list 305
+#define __NR_splice 306
+#define __NR_sync_file_range 307
+#define __NR_tee 308
+#define __NR_vmsplice 309
+#define __NR_move_pages 310
+#define __NR_getcpu 311
+#define __NR_epoll_pwait 312
+#define __NR_utimes 313
+#define __NR_fallocate 314
+#define __NR_utimensat 315
+#define __NR_signalfd 316
+#define __NR_timerfd 317
+#define __NR_eventfd 318
+#define __NR_timerfd_create 319
+#define __NR_timerfd_settime 320
+#define __NR_timerfd_gettime 321
+#define __NR_signalfd4 322
+#define __NR_eventfd2 323
+#define __NR_inotify_init1 324
+#define __NR_pipe2 325
+#define __NR_dup3 326
+#define __NR_epoll_create1 327
+#define __NR_preadv 328
+#define __NR_pwritev 329
+#define __NR_rt_tgsigqueueinfo 330
+#define __NR_perf_event_open 331
+#define __NR_fanotify_init 332
+#define __NR_fanotify_mark 333
+#define __NR_prlimit64 334
+#define __NR_name_to_handle_at 335
+#define __NR_open_by_handle_at 336
+#define __NR_clock_adjtime 337
+#define __NR_syncfs 338
+#define __NR_setns 339
+#define __NR_process_vm_readv 340
+#define __NR_process_vm_writev 341
+#define __NR_s390_runtime_instr 342
+#define __NR_kcmp 343
+#define __NR_finit_module 344
+#define __NR_sched_setattr 345
+#define __NR_sched_getattr 346
+#define __NR_renameat2 347
+#define __NR_seccomp 348
+#define __NR_getrandom 349
+#define __NR_memfd_create 350
+#define __NR_bpf 351
+#define __NR_s390_pci_mmio_write 352
+#define __NR_s390_pci_mmio_read 353
+#define __NR_execveat 354
+#define __NR_userfaultfd 355
+#define __NR_membarrier 356
+#define __NR_recvmmsg 357
+#define __NR_sendmmsg 358
+#define __NR_socket 359
+#define __NR_socketpair 360
+#define __NR_bind 361
+#define __NR_connect 362
+#define __NR_listen 363
+#define __NR_accept4 364
+#define __NR_getsockopt 365
+#define __NR_setsockopt 366
+#define __NR_getsockname 367
+#define __NR_getpeername 368
+#define __NR_sendto 369
+#define __NR_sendmsg 370
+#define __NR_recvfrom 371
+#define __NR_recvmsg 372
+#define __NR_shutdown 373
+#define __NR_mlock2 374
+#define __NR_copy_file_range 375
+#define __NR_preadv2 376
+#define __NR_pwritev2 377
+#define __NR_s390_guarded_storage 378
+#define __NR_statx 379
+#define __NR_s390_sthyi 380
+
+#endif /* _ASM_S390_UNISTD_64_H */
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
index 4c300f6aaa..4c58184395 100644
--- a/linux-headers/asm-x86/kvm_para.h
+++ b/linux-headers/asm-x86/kvm_para.h
@@ -25,6 +25,8 @@
#define KVM_FEATURE_STEAL_TIME 5
#define KVM_FEATURE_PV_EOI 6
#define KVM_FEATURE_PV_UNHALT 7
+#define KVM_FEATURE_PV_TLB_FLUSH 9
+#define KVM_FEATURE_ASYNC_PF_VMEXIT 10
/* The last 8 bits are used to indicate how to interpret the flags field
* in pvclock structure. If no bits are set, all flags are ignored.
@@ -51,6 +53,9 @@ struct kvm_steal_time {
__u32 pad[11];
};
+#define KVM_VCPU_PREEMPTED (1 << 0)
+#define KVM_VCPU_FLUSH_TLB (1 << 1)
+
#define KVM_CLOCK_PAIRING_WALLCLOCK 0
struct kvm_clock_pairing {
__s64 sec;
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index d92c9b2f0e..a167be89d1 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
+#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
/*
* Extension capability list.
@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_S390_AIS_MIGRATION 150
#define KVM_CAP_PPC_GET_CPU_CHAR 151
#define KVM_CAP_S390_BPB 152
+#define KVM_CAP_GET_MSR_FEATURES 153
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1362,6 +1364,96 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_S390_CMMA_MIGRATION */
#define KVM_S390_GET_CMMA_BITS _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
#define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
+/* Memory Encryption Commands */
+#define KVM_MEMORY_ENCRYPT_OP _IOWR(KVMIO, 0xba, unsigned long)
+
+struct kvm_enc_region {
+ __u64 addr;
+ __u64 size;
+};
+
+#define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region)
+#define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region)
+
+/* Secure Encrypted Virtualization command */
+enum sev_cmd_id {
+ /* Guest initialization commands */
+ KVM_SEV_INIT = 0,
+ KVM_SEV_ES_INIT,
+ /* Guest launch commands */
+ KVM_SEV_LAUNCH_START,
+ KVM_SEV_LAUNCH_UPDATE_DATA,
+ KVM_SEV_LAUNCH_UPDATE_VMSA,
+ KVM_SEV_LAUNCH_SECRET,
+ KVM_SEV_LAUNCH_MEASURE,
+ KVM_SEV_LAUNCH_FINISH,
+ /* Guest migration commands (outgoing) */
+ KVM_SEV_SEND_START,
+ KVM_SEV_SEND_UPDATE_DATA,
+ KVM_SEV_SEND_UPDATE_VMSA,
+ KVM_SEV_SEND_FINISH,
+ /* Guest migration commands (incoming) */
+ KVM_SEV_RECEIVE_START,
+ KVM_SEV_RECEIVE_UPDATE_DATA,
+ KVM_SEV_RECEIVE_UPDATE_VMSA,
+ KVM_SEV_RECEIVE_FINISH,
+ /* Guest status and debug commands */
+ KVM_SEV_GUEST_STATUS,
+ KVM_SEV_DBG_DECRYPT,
+ KVM_SEV_DBG_ENCRYPT,
+ /* Guest certificates commands */
+ KVM_SEV_CERT_EXPORT,
+
+ KVM_SEV_NR_MAX,
+};
+
+struct kvm_sev_cmd {
+ __u32 id;
+ __u64 data;
+ __u32 error;
+ __u32 sev_fd;
+};
+
+struct kvm_sev_launch_start {
+ __u32 handle;
+ __u32 policy;
+ __u64 dh_uaddr;
+ __u32 dh_len;
+ __u64 session_uaddr;
+ __u32 session_len;
+};
+
+struct kvm_sev_launch_update_data {
+ __u64 uaddr;
+ __u32 len;
+};
+
+
+struct kvm_sev_launch_secret {
+ __u64 hdr_uaddr;
+ __u32 hdr_len;
+ __u64 guest_uaddr;
+ __u32 guest_len;
+ __u64 trans_uaddr;
+ __u32 trans_len;
+};
+
+struct kvm_sev_launch_measure {
+ __u64 uaddr;
+ __u32 len;
+};
+
+struct kvm_sev_guest_status {
+ __u32 handle;
+ __u32 policy;
+ __u32 state;
+};
+
+struct kvm_sev_dbg {
+ __u64 src_uaddr;
+ __u64 dst_uaddr;
+ __u32 len;
+};
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
diff --git a/linux-headers/linux/psci.h b/linux-headers/linux/psci.h
index ccd17731c6..3905492d18 100644
--- a/linux-headers/linux/psci.h
+++ b/linux-headers/linux/psci.h
@@ -88,6 +88,9 @@
(((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
#define PSCI_VERSION_MINOR(ver) \
((ver) & PSCI_VERSION_MINOR_MASK)
+#define PSCI_VERSION(maj, min) \
+ ((((maj) << PSCI_VERSION_MAJOR_SHIFT) & PSCI_VERSION_MAJOR_MASK) | \
+ ((min) & PSCI_VERSION_MINOR_MASK))
/* PSCI features decoding (>=1.0) */
#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1
diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h
new file mode 100644
index 0000000000..33e247471a
--- /dev/null
+++ b/linux-headers/linux/psp-sev.h
@@ -0,0 +1,142 @@
+/*
+ * Userspace interface for AMD Secure Encrypted Virtualization (SEV)
+ * platform management commands.
+ *
+ * Copyright (C) 2016-2017 Advanced Micro Devices, Inc.
+ *
+ * Author: Brijesh Singh <brijesh.singh@amd.com>
+ *
+ * SEV spec 0.14 is available at:
+ * http://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PSP_SEV_USER_H__
+#define __PSP_SEV_USER_H__
+
+#include <linux/types.h>
+
+/**
+ * SEV platform commands
+ */
+enum {
+ SEV_FACTORY_RESET = 0,
+ SEV_PLATFORM_STATUS,
+ SEV_PEK_GEN,
+ SEV_PEK_CSR,
+ SEV_PDH_GEN,
+ SEV_PDH_CERT_EXPORT,
+ SEV_PEK_CERT_IMPORT,
+
+ SEV_MAX,
+};
+
+/**
+ * SEV Firmware status code
+ */
+typedef enum {
+ SEV_RET_SUCCESS = 0,
+ SEV_RET_INVALID_PLATFORM_STATE,
+ SEV_RET_INVALID_GUEST_STATE,
+ SEV_RET_INAVLID_CONFIG,
+ SEV_RET_INVALID_LEN,
+ SEV_RET_ALREADY_OWNED,
+ SEV_RET_INVALID_CERTIFICATE,
+ SEV_RET_POLICY_FAILURE,
+ SEV_RET_INACTIVE,
+ SEV_RET_INVALID_ADDRESS,
+ SEV_RET_BAD_SIGNATURE,
+ SEV_RET_BAD_MEASUREMENT,
+ SEV_RET_ASID_OWNED,
+ SEV_RET_INVALID_ASID,
+ SEV_RET_WBINVD_REQUIRED,
+ SEV_RET_DFFLUSH_REQUIRED,
+ SEV_RET_INVALID_GUEST,
+ SEV_RET_INVALID_COMMAND,
+ SEV_RET_ACTIVE,
+ SEV_RET_HWSEV_RET_PLATFORM,
+ SEV_RET_HWSEV_RET_UNSAFE,
+ SEV_RET_UNSUPPORTED,
+ SEV_RET_MAX,
+} sev_ret_code;
+
+/**
+ * struct sev_user_data_status - PLATFORM_STATUS command parameters
+ *
+ * @major: major API version
+ * @minor: minor API version
+ * @state: platform state
+ * @flags: platform config flags
+ * @build: firmware build id for API version
+ * @guest_count: number of active guests
+ */
+struct sev_user_data_status {
+ __u8 api_major; /* Out */
+ __u8 api_minor; /* Out */
+ __u8 state; /* Out */
+ __u32 flags; /* Out */
+ __u8 build; /* Out */
+ __u32 guest_count; /* Out */
+} __attribute__((packed));
+
+/**
+ * struct sev_user_data_pek_csr - PEK_CSR command parameters
+ *
+ * @address: PEK certificate chain
+ * @length: length of certificate
+ */
+struct sev_user_data_pek_csr {
+ __u64 address; /* In */
+ __u32 length; /* In/Out */
+} __attribute__((packed));
+
+/**
+ * struct sev_user_data_cert_import - PEK_CERT_IMPORT command parameters
+ *
+ * @pek_address: PEK certificate chain
+ * @pek_len: length of PEK certificate
+ * @oca_address: OCA certificate chain
+ * @oca_len: length of OCA certificate
+ */
+struct sev_user_data_pek_cert_import {
+ __u64 pek_cert_address; /* In */
+ __u32 pek_cert_len; /* In */
+ __u64 oca_cert_address; /* In */
+ __u32 oca_cert_len; /* In */
+} __attribute__((packed));
+
+/**
+ * struct sev_user_data_pdh_cert_export - PDH_CERT_EXPORT command parameters
+ *
+ * @pdh_address: PDH certificate address
+ * @pdh_len: length of PDH certificate
+ * @cert_chain_address: PDH certificate chain
+ * @cert_chain_len: length of PDH certificate chain
+ */
+struct sev_user_data_pdh_cert_export {
+ __u64 pdh_cert_address; /* In */
+ __u32 pdh_cert_len; /* In/Out */
+ __u64 cert_chain_address; /* In */
+ __u32 cert_chain_len; /* In/Out */
+} __attribute__((packed));
+
+/**
+ * struct sev_issue_cmd - SEV ioctl parameters
+ *
+ * @cmd: SEV commands to execute
+ * @opaque: pointer to the command structure
+ * @error: SEV FW return code on failure
+ */
+struct sev_issue_cmd {
+ __u32 cmd; /* In */
+ __u64 data; /* In */
+ __u32 error; /* Out */
+} __attribute__((packed));
+
+#define SEV_IOC_TYPE 'S'
+#define SEV_ISSUE_CMD _IOWR(SEV_IOC_TYPE, 0x0, struct sev_issue_cmd)
+
+#endif /* __PSP_USER_SEV_H */
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 4312e961ff..3a0a305c8c 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -301,6 +301,16 @@ struct vfio_region_info_cap_type {
#define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2)
#define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3)
+/*
+ * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped
+ * which allows direct access to non-MSIX registers which happened to be within
+ * the same system page.
+ *
+ * Even though the userspace gets direct access to the MSIX data, the existing
+ * VFIO_DEVICE_SET_IRQS interface must still be used for MSIX configuration.
+ */
+#define VFIO_REGION_INFO_CAP_MSIX_MAPPABLE 3
+
/**
* VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
* struct vfio_irq_info)
@@ -503,6 +513,68 @@ struct vfio_pci_hot_reset {
#define VFIO_DEVICE_PCI_HOT_RESET _IO(VFIO_TYPE, VFIO_BASE + 13)
+/**
+ * VFIO_DEVICE_QUERY_GFX_PLANE - _IOW(VFIO_TYPE, VFIO_BASE + 14,
+ * struct vfio_device_query_gfx_plane)
+ *
+ * Set the drm_plane_type and flags, then retrieve the gfx plane info.
+ *
+ * flags supported:
+ * - VFIO_GFX_PLANE_TYPE_PROBE and VFIO_GFX_PLANE_TYPE_DMABUF are set
+ * to ask if the mdev supports dma-buf. 0 on support, -EINVAL on no
+ * support for dma-buf.
+ * - VFIO_GFX_PLANE_TYPE_PROBE and VFIO_GFX_PLANE_TYPE_REGION are set
+ * to ask if the mdev supports region. 0 on support, -EINVAL on no
+ * support for region.
+ * - VFIO_GFX_PLANE_TYPE_DMABUF or VFIO_GFX_PLANE_TYPE_REGION is set
+ * with each call to query the plane info.
+ * - Others are invalid and return -EINVAL.
+ *
+ * Note:
+ * 1. Plane could be disabled by guest. In that case, success will be
+ * returned with zero-initialized drm_format, size, width and height
+ * fields.
+ * 2. x_hot/y_hot is set to 0xFFFFFFFF if no hotspot information available
+ *
+ * Return: 0 on success, -errno on other failure.
+ */
+struct vfio_device_gfx_plane_info {
+ __u32 argsz;
+ __u32 flags;
+#define VFIO_GFX_PLANE_TYPE_PROBE (1 << 0)
+#define VFIO_GFX_PLANE_TYPE_DMABUF (1 << 1)
+#define VFIO_GFX_PLANE_TYPE_REGION (1 << 2)
+ /* in */
+ __u32 drm_plane_type; /* type of plane: DRM_PLANE_TYPE_* */
+ /* out */
+ __u32 drm_format; /* drm format of plane */
+ __u64 drm_format_mod; /* tiled mode */
+ __u32 width; /* width of plane */
+ __u32 height; /* height of plane */
+ __u32 stride; /* stride of plane */
+ __u32 size; /* size of plane in bytes, align on page*/
+ __u32 x_pos; /* horizontal position of cursor plane */
+ __u32 y_pos; /* vertical position of cursor plane*/
+ __u32 x_hot; /* horizontal position of cursor hotspot */
+ __u32 y_hot; /* vertical position of cursor hotspot */
+ union {
+ __u32 region_index; /* region index */
+ __u32 dmabuf_id; /* dma-buf id */
+ };
+};
+
+#define VFIO_DEVICE_QUERY_GFX_PLANE _IO(VFIO_TYPE, VFIO_BASE + 14)
+
+/**
+ * VFIO_DEVICE_GET_GFX_DMABUF - _IOW(VFIO_TYPE, VFIO_BASE + 15, __u32)
+ *
+ * Return a new dma-buf file descriptor for an exposed guest framebuffer
+ * described by the provided dmabuf_id. The dmabuf_id is returned from VFIO_
+ * DEVICE_QUERY_GFX_PLANE as a token of the exposed guest framebuffer.
+ */
+
+#define VFIO_DEVICE_GET_GFX_DMABUF _IO(VFIO_TYPE, VFIO_BASE + 15)
+
/* -------- API for Type1 VFIO IOMMU -------- */
/**
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5fc130cc20..9d10a5f592 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -354,7 +354,6 @@ enum {
/* The commpage only exists for 32 bit kernels */
-#define TARGET_HAS_VALIDATE_GUEST_SPACE
/* Return 1 if the proposed guest space is suitable for the guest.
* Return 0 if the proposed guest space isn't suitable, but another
* address space should be tried.
@@ -363,8 +362,8 @@ enum {
* The guest code may leave a page mapped and populate it if the
* address is suitable.
*/
-static int validate_guest_space(unsigned long guest_base,
- unsigned long guest_size)
+static int init_guest_commpage(unsigned long guest_base,
+ unsigned long guest_size)
{
unsigned long real_start, test_page_addr;
@@ -375,6 +374,11 @@ static int validate_guest_space(unsigned long guest_base,
/* If the commpage lies within the already allocated guest space,
* then there is no way we can allocate it.
+ *
+ * You may be thinking that that this check is redundant because
+ * we already validated the guest size against MAX_RESERVED_VA;
+ * but if qemu_host_page_mask is unusually large, then
+ * test_page_addr may be lower.
*/
if (test_page_addr >= guest_base
&& test_page_addr < (guest_base + guest_size)) {
@@ -563,78 +567,6 @@ static uint32_t get_elf_hwcap(void)
#endif /* not TARGET_AARCH64 */
#endif /* TARGET_ARM */
-#ifdef TARGET_UNICORE32
-
-#define ELF_START_MMAP 0x80000000
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
-#define ELF_ARCH EM_UNICORE32
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- abi_long stack = infop->start_stack;
- memset(regs, 0, sizeof(*regs));
- regs->UC32_REG_asr = 0x10;
- regs->UC32_REG_pc = infop->entry & 0xfffffffe;
- regs->UC32_REG_sp = infop->start_stack;
- /* FIXME - what to for failure of get_user()? */
- get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */
- get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */
- /* XXX: it seems that r0 is zeroed after ! */
- regs->UC32_REG_00 = 0;
-}
-
-#define ELF_NREG 34
-typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
-
-static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUUniCore32State *env)
-{
- (*regs)[0] = env->regs[0];
- (*regs)[1] = env->regs[1];
- (*regs)[2] = env->regs[2];
- (*regs)[3] = env->regs[3];
- (*regs)[4] = env->regs[4];
- (*regs)[5] = env->regs[5];
- (*regs)[6] = env->regs[6];
- (*regs)[7] = env->regs[7];
- (*regs)[8] = env->regs[8];
- (*regs)[9] = env->regs[9];
- (*regs)[10] = env->regs[10];
- (*regs)[11] = env->regs[11];
- (*regs)[12] = env->regs[12];
- (*regs)[13] = env->regs[13];
- (*regs)[14] = env->regs[14];
- (*regs)[15] = env->regs[15];
- (*regs)[16] = env->regs[16];
- (*regs)[17] = env->regs[17];
- (*regs)[18] = env->regs[18];
- (*regs)[19] = env->regs[19];
- (*regs)[20] = env->regs[20];
- (*regs)[21] = env->regs[21];
- (*regs)[22] = env->regs[22];
- (*regs)[23] = env->regs[23];
- (*regs)[24] = env->regs[24];
- (*regs)[25] = env->regs[25];
- (*regs)[26] = env->regs[26];
- (*regs)[27] = env->regs[27];
- (*regs)[28] = env->regs[28];
- (*regs)[29] = env->regs[29];
- (*regs)[30] = env->regs[30];
- (*regs)[31] = env->regs[31];
-
- (*regs)[32] = cpu_asr_read((CPUUniCore32State *)env);
- (*regs)[33] = env->regs[0]; /* XXX */
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#define ELF_HWCAP (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64)
-
-#endif
-
#ifdef TARGET_SPARC
#ifdef TARGET_SPARC64
@@ -1869,21 +1801,12 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
return sp;
}
-#ifndef TARGET_HAS_VALIDATE_GUEST_SPACE
-/* If the guest doesn't have a validation function just agree */
-static int validate_guest_space(unsigned long guest_base,
- unsigned long guest_size)
-{
- return 1;
-}
-#endif
-
unsigned long init_guest_space(unsigned long host_start,
unsigned long host_size,
unsigned long guest_start,
bool fixed)
{
- unsigned long current_start, real_start;
+ unsigned long current_start, aligned_start;
int flags;
assert(host_start || host_size);
@@ -1891,11 +1814,12 @@ unsigned long init_guest_space(unsigned long host_start,
/* If just a starting address is given, then just verify that
* address. */
if (host_start && !host_size) {
- if (validate_guest_space(host_start, host_size) == 1) {
- return host_start;
- } else {
+#if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
+ if (init_guest_commpage(host_start, host_size) != 1) {
return (unsigned long)-1;
}
+#endif
+ return host_start;
}
/* Setup the initial flags and start address. */
@@ -1908,7 +1832,8 @@ unsigned long init_guest_space(unsigned long host_start,
/* Otherwise, a non-zero size region of memory needs to be mapped
* and validated. */
while (1) {
- unsigned long real_size = host_size;
+ unsigned long real_start, real_size, aligned_size;
+ aligned_size = real_size = host_size;
/* Do not use mmap_find_vma here because that is limited to the
* guest address space. We are going to make the
@@ -1920,30 +1845,63 @@ unsigned long init_guest_space(unsigned long host_start,
return (unsigned long)-1;
}
+ /* Check to see if the address is valid. */
+ if (host_start && real_start != current_start) {
+ goto try_again;
+ }
+
/* Ensure the address is properly aligned. */
if (real_start & ~qemu_host_page_mask) {
+ /* Ideally, we adjust like
+ *
+ * pages: [ ][ ][ ][ ][ ]
+ * old: [ real ]
+ * [ aligned ]
+ * new: [ real ]
+ * [ aligned ]
+ *
+ * But if there is something else mapped right after it,
+ * then obviously it won't have room to grow, and the
+ * kernel will put the new larger real someplace else with
+ * unknown alignment (if we made it to here, then
+ * fixed=false). Which is why we grow real by a full page
+ * size, instead of by part of one; so that even if we get
+ * moved, we can still guarantee alignment. But this does
+ * mean that there is a padding of < 1 page both before
+ * and after the aligned range; the "after" could could
+ * cause problems for ARM emulation where it could butt in
+ * to where we need to put the commpage.
+ */
munmap((void *)real_start, host_size);
- real_size = host_size + qemu_host_page_size;
+ real_size = aligned_size + qemu_host_page_size;
real_start = (unsigned long)
mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0);
if (real_start == (unsigned long)-1) {
return (unsigned long)-1;
}
- real_start = HOST_PAGE_ALIGN(real_start);
+ aligned_start = HOST_PAGE_ALIGN(real_start);
+ } else {
+ aligned_start = real_start;
}
- /* Check to see if the address is valid. */
- if (!host_start || real_start == current_start) {
- int valid = validate_guest_space(real_start - guest_start,
- real_size);
- if (valid == 1) {
- break;
- } else if (valid == -1) {
- return (unsigned long)-1;
- }
- /* valid == 0, so try again. */
+#if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
+ /* On 32-bit ARM, we need to also be able to map the commpage. */
+ int valid = init_guest_commpage(aligned_start - guest_start,
+ aligned_size + guest_start);
+ if (valid == -1) {
+ munmap((void *)real_start, real_size);
+ return (unsigned long)-1;
+ } else if (valid == 0) {
+ goto try_again;
}
+#endif
+
+ /* If nothing has said `return -1` or `goto try_again` yet,
+ * then the address we have is good.
+ */
+ break;
+ try_again:
/* That address didn't work. Unmap and try a different one.
* The address the host picked because is typically right at
* the top of the host address space and leaves the guest with
@@ -1952,8 +1910,12 @@ unsigned long init_guest_space(unsigned long host_start,
* happen often. Probably means we got unlucky and host
* address space randomization put a shared library somewhere
* inconvenient.
+ *
+ * This is probably a good strategy if host_start, but is
+ * probably a bad strategy if not, which means we got here
+ * because of trouble with ARM commpage setup.
*/
- munmap((void *)real_start, host_size);
+ munmap((void *)real_start, real_size);
current_start += qemu_host_page_size;
if (host_start == current_start) {
/* Theoretically possible if host doesn't have any suitably
@@ -1965,7 +1927,7 @@ unsigned long init_guest_space(unsigned long host_start,
qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size);
- return real_start;
+ return aligned_start;
}
static void probe_guest_base(const char *image_name,
diff --git a/linux-user/main.c b/linux-user/main.c
index abbd14e208..73aafcf1e0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -884,95 +884,6 @@ void cpu_loop(CPUARMState *env)
#endif
-#ifdef TARGET_UNICORE32
-
-void cpu_loop(CPUUniCore32State *env)
-{
- CPUState *cs = CPU(uc32_env_get_cpu(env));
- int trapnr;
- unsigned int n, insn;
- target_siginfo_t info;
-
- for (;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case UC32_EXCP_PRIV:
- {
- /* system call */
- get_user_u32(insn, env->regs[31] - 4);
- n = insn & 0xffffff;
-
- if (n >= UC32_SYSCALL_BASE) {
- /* linux syscall */
- n -= UC32_SYSCALL_BASE;
- if (n == UC32_SYSCALL_NR_set_tls) {
- cpu_set_tls(env, env->regs[0]);
- env->regs[0] = 0;
- } else {
- abi_long ret = do_syscall(env,
- n,
- env->regs[0],
- env->regs[1],
- env->regs[2],
- env->regs[3],
- env->regs[4],
- env->regs[5],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->regs[31] -= 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[0] = ret;
- }
- }
- } else {
- goto error;
- }
- }
- break;
- case UC32_EXCP_DTRAP:
- case UC32_EXCP_ITRAP:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig) {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- goto error;
- }
- process_pending_signals(env);
- }
-
-error:
- EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- abort();
-}
-#endif
-
#ifdef TARGET_SPARC
#define SPARC64_STACK_BIAS 2047
@@ -4737,14 +4648,6 @@ int main(int argc, char **argv, char **envp)
}
#endif
}
-#elif defined(TARGET_UNICORE32)
- {
- int i;
- cpu_asr_write(env, regs->uregs[32], 0xffffffff);
- for (i = 0; i < 32; i++) {
- env->regs[i] = regs->uregs[i];
- }
- }
#elif defined(TARGET_SPARC)
{
int i;
@@ -4974,7 +4877,7 @@ int main(int argc, char **argv, char **envp)
#error unsupported target CPU
#endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
ts->stack_base = info->start_stack;
ts->heap_base = info->brk;
/* This will be filled in on the first SYS_HEAPINFO call. */
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 0fbfd6dff2..9168a2051c 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -77,11 +77,12 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
#endif
if ((start & ~TARGET_PAGE_MASK) != 0)
- return -EINVAL;
+ return -TARGET_EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
- if (end < start)
- return -EINVAL;
+ if (!guest_range_valid(start, len)) {
+ return -TARGET_ENOMEM;
+ }
prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
if (len == 0)
return 0;
@@ -481,8 +482,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
* It can fail only on 64-bit host with 32-bit target.
* On any other target/host host mmap() handles this error correctly.
*/
- if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
- errno = EINVAL;
+ if (!guest_range_valid(start, len)) {
+ errno = ENOMEM;
goto fail;
}
@@ -620,10 +621,12 @@ int target_munmap(abi_ulong start, abi_ulong len)
start, len);
#endif
if (start & ~TARGET_PAGE_MASK)
- return -EINVAL;
+ return -TARGET_EINVAL;
len = TARGET_PAGE_ALIGN(len);
- if (len == 0)
- return -EINVAL;
+ if (len == 0 || !guest_range_valid(start, len)) {
+ return -TARGET_EINVAL;
+ }
+
mmap_lock();
end = start + len;
real_start = start & qemu_host_page_mask;
@@ -678,6 +681,13 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
int prot;
void *host_addr;
+ if (!guest_range_valid(old_addr, old_size) ||
+ ((flags & MREMAP_FIXED) &&
+ !guest_range_valid(new_addr, new_size))) {
+ errno = ENOMEM;
+ return -1;
+ }
+
mmap_lock();
if (flags & MREMAP_FIXED) {
@@ -744,20 +754,3 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
mmap_unlock();
return new_addr;
}
-
-int target_msync(abi_ulong start, abi_ulong len, int flags)
-{
- abi_ulong end;
-
- if (start & ~TARGET_PAGE_MASK)
- return -EINVAL;
- len = TARGET_PAGE_ALIGN(len);
- end = start + len;
- if (end < start)
- return -EINVAL;
- if (end == start)
- return 0;
-
- start &= qemu_host_page_mask;
- return msync(g2h(start), end - start, flags);
-}
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index f4b4ca72ad..192a0d2fef 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -100,9 +100,6 @@ typedef struct TaskState {
# endif
int swi_errno;
#endif
-#ifdef TARGET_UNICORE32
- int swi_errno;
-#endif
#if defined(TARGET_I386) && !defined(TARGET_X86_64)
abi_ulong target_v86;
struct vm86_saved_state vm86_saved_regs;
@@ -115,7 +112,7 @@ typedef struct TaskState {
int sim_syscalls;
abi_ulong tp_value;
#endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
/* Extra fields for semihosted binaries. */
abi_ulong heap_base;
abi_ulong heap_limit;
@@ -428,7 +425,6 @@ int target_munmap(abi_ulong start, abi_ulong len);
abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
abi_ulong new_size, unsigned long flags,
abi_ulong new_addr);
-int target_msync(abi_ulong start, abi_ulong len, int flags);
extern unsigned long last_brk;
extern abi_ulong mmap_next_start;
abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 2ce5d7a3c7..2461edf463 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -253,8 +253,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
return 0;
}
-#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
- !defined(TARGET_NIOS2)
+#if !defined(TARGET_OPENRISC) && !defined(TARGET_NIOS2)
/* Just set the guest's signal mask to the specified value; the
* caller is assumed to have called block_signals() already.
*/
@@ -512,7 +511,6 @@ void signal_init(void)
}
}
-#ifndef TARGET_UNICORE32
/* Force a synchronously taken signal. The kernel force_sig() function
* also forces the signal to "not blocked, not ignored", but for QEMU
* that work is done in process_pending_signals().
@@ -546,7 +544,6 @@ static void force_sigsegv(int oldsig)
}
force_sig(TARGET_SIGSEGV);
}
-#endif
#endif
@@ -7052,32 +7049,7 @@ long do_rt_sigreturn(CPUArchState *env)
}
#else
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUArchState *env)
-{
- fprintf(stderr, "setup_frame: not implemented\n");
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUArchState *env)
-{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUArchState *env)
-{
- fprintf(stderr, "do_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-long do_rt_sigreturn(CPUArchState *env)
-{
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
+#error Target needs to add support for signal handling
#endif
static void handle_pending_signal(CPUArchState *cpu_env, int sig,
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b4f7b14fbe..f7ebe6233b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4900,6 +4900,9 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
return -TARGET_EINVAL;
}
}
+ if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
+ return -TARGET_EINVAL;
+ }
mmap_lock();
@@ -4944,6 +4947,9 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
static inline abi_long do_shmdt(abi_ulong shmaddr)
{
int i;
+ abi_long rv;
+
+ mmap_lock();
for (i = 0; i < N_SHM_REGIONS; ++i) {
if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
@@ -4952,8 +4958,11 @@ static inline abi_long do_shmdt(abi_ulong shmaddr)
break;
}
}
+ rv = get_errno(shmdt(g2h(shmaddr)));
- return get_errno(shmdt(g2h(shmaddr)));
+ mmap_unlock();
+
+ return rv;
}
#ifdef TARGET_NR_ipc
@@ -7468,7 +7477,7 @@ static int open_self_maps(void *cpu_env, int fd)
}
if (h2g_valid(min)) {
int flags = page_get_flags(h2g(min));
- max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX);
+ max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
if (page_check_range(h2g(min), max - min, flags) == -1) {
continue;
}
@@ -9545,6 +9554,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
__put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
__put_user(stfs.f_namelen, &target_stfs->f_namelen);
__put_user(stfs.f_frsize, &target_stfs->f_frsize);
+#ifdef _STATFS_F_FLAGS
+ __put_user(stfs.f_flags, &target_stfs->f_flags);
+#else
+ __put_user(0, &target_stfs->f_flags);
+#endif
memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
unlock_user_struct(target_stfs, arg2, 1);
}
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index e00e1b3862..e53583e921 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -69,7 +69,7 @@
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
|| defined(TARGET_M68K) || defined(TARGET_CRIS) \
- || defined(TARGET_UNICORE32) || defined(TARGET_S390X) \
+ || defined(TARGET_S390X) \
|| defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \
|| defined(TARGET_NIOS2) || defined(TARGET_RISCV)
@@ -352,19 +352,6 @@ typedef struct {
int val[2];
} kernel_fsid_t;
-struct kernel_statfs {
- int f_type;
- int f_bsize;
- int f_blocks;
- int f_bfree;
- int f_bavail;
- int f_files;
- int f_ffree;
- kernel_fsid_t f_fsid;
- int f_namelen;
- int f_spare[6];
-};
-
struct target_dirent {
abi_long d_ino;
abi_long d_off;
@@ -433,7 +420,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
|| defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \
|| defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \
- || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) \
+ || defined(TARGET_MICROBLAZE) \
|| defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
|| defined(TARGET_TILEGX) || defined(TARGET_HPPA) || defined(TARGET_NIOS2) \
|| defined(TARGET_RISCV)
@@ -1409,7 +1396,7 @@ struct target_winsize {
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) \
|| (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
- || defined(TARGET_CRIS) || defined(TARGET_UNICORE32)
+ || defined(TARGET_CRIS)
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
@@ -2226,7 +2213,8 @@ struct target_statfs {
/* Linux specials */
target_fsid_t f_fsid;
int32_t f_namelen;
- int32_t f_spare[6];
+ int32_t f_flags;
+ int32_t f_spare[5];
};
#else
struct target_statfs {
@@ -2242,7 +2230,8 @@ struct target_statfs {
/* Linux specials */
target_fsid_t f_fsid;
abi_long f_namelen;
- abi_long f_spare[6];
+ abi_long f_flags;
+ abi_long f_spare[5];
};
#endif
@@ -2258,7 +2247,8 @@ struct target_statfs64 {
uint64_t f_bavail;
target_fsid_t f_fsid;
uint32_t f_namelen;
- uint32_t f_spare[6];
+ uint32_t f_flags;
+ uint32_t f_spare[5];
};
#elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \
defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \
@@ -2274,7 +2264,8 @@ struct target_statfs {
target_fsid_t f_fsid;
abi_long f_namelen;
abi_long f_frsize;
- abi_long f_spare[5];
+ abi_long f_flags;
+ abi_long f_spare[4];
};
struct target_statfs64 {
@@ -2288,7 +2279,8 @@ struct target_statfs64 {
target_fsid_t f_fsid;
abi_long f_namelen;
abi_long f_frsize;
- abi_long f_spare[5];
+ abi_long f_flags;
+ abi_long f_spare[4];
};
#elif defined(TARGET_S390X)
struct target_statfs {
@@ -2302,7 +2294,9 @@ struct target_statfs {
kernel_fsid_t f_fsid;
int32_t f_namelen;
int32_t f_frsize;
- int32_t f_spare[5];
+ int32_t f_flags;
+ int32_t f_spare[4];
+
};
struct target_statfs64 {
@@ -2316,7 +2310,8 @@ struct target_statfs64 {
kernel_fsid_t f_fsid;
int32_t f_namelen;
int32_t f_frsize;
- int32_t f_spare[5];
+ int32_t f_flags;
+ int32_t f_spare[4];
};
#else
struct target_statfs {
@@ -2330,7 +2325,8 @@ struct target_statfs {
target_fsid_t f_fsid;
uint32_t f_namelen;
uint32_t f_frsize;
- uint32_t f_spare[5];
+ uint32_t f_flags;
+ uint32_t f_spare[4];
};
struct target_statfs64 {
@@ -2344,7 +2340,8 @@ struct target_statfs64 {
target_fsid_t f_fsid;
uint32_t f_namelen;
uint32_t f_frsize;
- uint32_t f_spare[5];
+ uint32_t f_flags;
+ uint32_t f_spare[4];
};
#endif
diff --git a/linux-user/unicore32/syscall_nr.h b/linux-user/unicore32/syscall_nr.h
deleted file mode 100644
index 486b8c45a0..0000000000
--- a/linux-user/unicore32/syscall_nr.h
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * This file contains the system call numbers for UniCore32 oldabi.
- *
- * Copyright (C) 2010-2011 GUAN Xue-tao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define TARGET_NR_restart_syscall 0
-#define TARGET_NR_exit 1
-#define TARGET_NR_fork 2
-#define TARGET_NR_read 3
-#define TARGET_NR_write 4
-#define TARGET_NR_open 5
-#define TARGET_NR_close 6
-#define TARGET_NR_waitpid 7
-#define TARGET_NR_creat 8
-#define TARGET_NR_link 9
-#define TARGET_NR_unlink 10
-#define TARGET_NR_execve 11
-#define TARGET_NR_chdir 12
-#define TARGET_NR_time 13
-#define TARGET_NR_mknod 14
-#define TARGET_NR_chmod 15
-#define TARGET_NR_lchown 16
-#define TARGET_NR_break 17
- /* 18 */
-#define TARGET_NR_lseek 19
-#define TARGET_NR_getpid 20
-#define TARGET_NR_mount 21
-#define TARGET_NR_umount 22
-#define TARGET_NR_setuid 23
-#define TARGET_NR_getuid 24
-#define TARGET_NR_stime 25
-#define TARGET_NR_ptrace 26
-#define TARGET_NR_alarm 27
- /* 28 */
-#define TARGET_NR_pause 29
-#define TARGET_NR_utime 30
-#define TARGET_NR_stty 31
-#define TARGET_NR_gtty 32
-#define TARGET_NR_access 33
-#define TARGET_NR_nice 34
-#define TARGET_NR_ftime 35
-#define TARGET_NR_sync 36
-#define TARGET_NR_kill 37
-#define TARGET_NR_rename 38
-#define TARGET_NR_mkdir 39
-#define TARGET_NR_rmdir 40
-#define TARGET_NR_dup 41
-#define TARGET_NR_pipe 42
-#define TARGET_NR_times 43
-#define TARGET_NR_prof 44
-#define TARGET_NR_brk 45
-#define TARGET_NR_setgid 46
-#define TARGET_NR_getgid 47
-#define TARGET_NR_signal 48
-#define TARGET_NR_geteuid 49
-#define TARGET_NR_getegid 50
-#define TARGET_NR_acct 51
-#define TARGET_NR_umount2 52
-#define TARGET_NR_lock 53
-#define TARGET_NR_ioctl 54
-#define TARGET_NR_fcntl 55
-#define TARGET_NR_mpx 56
-#define TARGET_NR_setpgid 57
-#define TARGET_NR_ulimit 58
- /* 59 */
-#define TARGET_NR_umask 60
-#define TARGET_NR_chroot 61
-#define TARGET_NR_ustat 62
-#define TARGET_NR_dup2 63
-#define TARGET_NR_getppid 64
-#define TARGET_NR_getpgrp 65
-#define TARGET_NR_setsid 66
-#define TARGET_NR_sigaction 67
-#define TARGET_NR_sgetmask 68
-#define TARGET_NR_ssetmask 69
-#define TARGET_NR_setreuid 70
-#define TARGET_NR_setregid 71
-#define TARGET_NR_sigsuspend 72
-#define TARGET_NR_sigpending 73
-#define TARGET_NR_sethostname 74
-#define TARGET_NR_setrlimit 75
-#define TARGET_NR_getrlimit 76
-#define TARGET_NR_getrusage 77
-#define TARGET_NR_gettimeofday 78
-#define TARGET_NR_settimeofday 79
-#define TARGET_NR_getgroups 80
-#define TARGET_NR_setgroups 81
-#define TARGET_NR_select 82
-#define TARGET_NR_symlink 83
- /* 84 */
-#define TARGET_NR_readlink 85
-#define TARGET_NR_uselib 86
-#define TARGET_NR_swapon 87
-#define TARGET_NR_reboot 88
-#define TARGET_NR_readdir 89
-#define TARGET_NR_mmap 90
-#define TARGET_NR_munmap 91
-#define TARGET_NR_truncate 92
-#define TARGET_NR_ftruncate 93
-#define TARGET_NR_fchmod 94
-#define TARGET_NR_fchown 95
-#define TARGET_NR_getpriority 96
-#define TARGET_NR_setpriority 97
-#define TARGET_NR_profil 98
-#define TARGET_NR_statfs 99
-#define TARGET_NR_fstatfs 100
-#define TARGET_NR_ioperm 101
-#define TARGET_NR_socketcall 102
-#define TARGET_NR_syslog 103
-#define TARGET_NR_setitimer 104
-#define TARGET_NR_getitimer 105
-#define TARGET_NR_stat 106
-#define TARGET_NR_lstat 107
-#define TARGET_NR_fstat 108
- /* 109 */
- /* 110 */
-#define TARGET_NR_vhangup 111
-#define TARGET_NR_idle 112
-#define TARGET_NR_syscall 113
-#define TARGET_NR_wait4 114
-#define TARGET_NR_swapoff 115
-#define TARGET_NR_sysinfo 116
-#define TARGET_NR_ipc 117
-#define TARGET_NR_fsync 118
-#define TARGET_NR_sigreturn 119
-#define TARGET_NR_clone 120
-#define TARGET_NR_setdomainname 121
-#define TARGET_NR_uname 122
-#define TARGET_NR_modify_ldt 123
-#define TARGET_NR_adjtimex 124
-#define TARGET_NR_mprotect 125
-#define TARGET_NR_sigprocmask 126
-#define TARGET_NR_create_module 127
-#define TARGET_NR_init_module 128
-#define TARGET_NR_delete_module 129
-#define TARGET_NR_get_kernel_syms 130
-#define TARGET_NR_quotactl 131
-#define TARGET_NR_getpgid 132
-#define TARGET_NR_fchdir 133
-#define TARGET_NR_bdflush 134
-#define TARGET_NR_sysfs 135
-#define TARGET_NR_personality 136
-#define TARGET_NR_afs_syscall 137
-#define TARGET_NR_setfsuid 138
-#define TARGET_NR_setfsgid 139
-#define TARGET_NR__llseek 140
-#define TARGET_NR_getdents 141
-#define TARGET_NR__newselect 142
-#define TARGET_NR_flock 143
-#define TARGET_NR_msync 144
-#define TARGET_NR_readv 145
-#define TARGET_NR_writev 146
-#define TARGET_NR_getsid 147
-#define TARGET_NR_fdatasync 148
-#define TARGET_NR__sysctl 149
-#define TARGET_NR_mlock 150
-#define TARGET_NR_munlock 151
-#define TARGET_NR_mlockall 152
-#define TARGET_NR_munlockall 153
-#define TARGET_NR_sched_setparam 154
-#define TARGET_NR_sched_getparam 155
-#define TARGET_NR_sched_setscheduler 156
-#define TARGET_NR_sched_getscheduler 157
-#define TARGET_NR_sched_yield 158
-#define TARGET_NR_sched_get_priority_max 159
-#define TARGET_NR_sched_get_priority_min 160
-#define TARGET_NR_sched_rr_get_interval 161
-#define TARGET_NR_nanosleep 162
-#define TARGET_NR_mremap 163
-#define TARGET_NR_setresuid 164
-#define TARGET_NR_getresuid 165
-#define TARGET_NR_vm86 166
-#define TARGET_NR_query_module 167
-#define TARGET_NR_poll 168
-#define TARGET_NR_nfsservctl 169
-#define TARGET_NR_setresgid 170
-#define TARGET_NR_getresgid 171
-#define TARGET_NR_prctl 172
-#define TARGET_NR_rt_sigreturn 173
-#define TARGET_NR_rt_sigaction 174
-#define TARGET_NR_rt_sigprocmask 175
-#define TARGET_NR_rt_sigpending 176
-#define TARGET_NR_rt_sigtimedwait 177
-#define TARGET_NR_rt_sigqueueinfo 178
-#define TARGET_NR_rt_sigsuspend 179
-#define TARGET_NR_pread64 180
-#define TARGET_NR_pwrite64 181
-#define TARGET_NR_chown 182
-#define TARGET_NR_getcwd 183
-#define TARGET_NR_capget 184
-#define TARGET_NR_capset 185
-#define TARGET_NR_sigaltstack 186
-#define TARGET_NR_sendfile 187
- /* 188 */
- /* 189 */
-#define TARGET_NR_vfork 190
-#define TARGET_NR_ugetrlimit 191
-#define TARGET_NR_mmap2 192
-#define TARGET_NR_truncate64 193
-#define TARGET_NR_ftruncate64 194
-#define TARGET_NR_stat64 195
-#define TARGET_NR_lstat64 196
-#define TARGET_NR_fstat64 197
-#define TARGET_NR_lchown32 198
-#define TARGET_NR_getuid32 199
-#define TARGET_NR_getgid32 200
-#define TARGET_NR_geteuid32 201
-#define TARGET_NR_getegid32 202
-#define TARGET_NR_setreuid32 203
-#define TARGET_NR_setregid32 204
-#define TARGET_NR_getgroups32 205
-#define TARGET_NR_setgroups32 206
-#define TARGET_NR_fchown32 207
-#define TARGET_NR_setresuid32 208
-#define TARGET_NR_getresuid32 209
-#define TARGET_NR_setresgid32 210
-#define TARGET_NR_getresgid32 211
-#define TARGET_NR_chown32 212
-#define TARGET_NR_setuid32 213
-#define TARGET_NR_setgid32 214
-#define TARGET_NR_setfsuid32 215
-#define TARGET_NR_setfsgid32 216
-#define TARGET_NR_getdents64 217
-#define TARGET_NR_pivot_root 218
-#define TARGET_NR_mincore 219
-#define TARGET_NR_madvise 220
-#define TARGET_NR_fcntl64 221
- /* 222 */
- /* 223 */
-#define TARGET_NR_gettid 224
-#define TARGET_NR_readahead 225
-#define TARGET_NR_setxattr 226
-#define TARGET_NR_lsetxattr 227
-#define TARGET_NR_fsetxattr 228
-#define TARGET_NR_getxattr 229
-#define TARGET_NR_lgetxattr 230
-#define TARGET_NR_fgetxattr 231
-#define TARGET_NR_listxattr 232
-#define TARGET_NR_llistxattr 233
-#define TARGET_NR_flistxattr 234
-#define TARGET_NR_removexattr 235
-#define TARGET_NR_lremovexattr 236
-#define TARGET_NR_fremovexattr 237
-#define TARGET_NR_tkill 238
-#define TARGET_NR_sendfile64 239
-#define TARGET_NR_futex 240
-#define TARGET_NR_sched_setaffinity 241
-#define TARGET_NR_sched_getaffinity 242
-#define TARGET_NR_io_setup 243
-#define TARGET_NR_io_destroy 244
-#define TARGET_NR_io_getevents 245
-#define TARGET_NR_io_submit 246
-#define TARGET_NR_io_cancel 247
-#define TARGET_NR_exit_group 248
-#define TARGET_NR_lookup_dcookie 249
-#define TARGET_NR_epoll_create 250
-#define TARGET_NR_epoll_ctl 251
-#define TARGET_NR_epoll_wait 252
-#define TARGET_NR_remap_file_pages 253
- /* 254 */
- /* 255 */
- /* 256 */
-#define TARGET_NR_set_tid_address 256
-#define TARGET_NR_timer_create 257
-#define TARGET_NR_timer_settime 258
-#define TARGET_NR_timer_gettime 259
-#define TARGET_NR_timer_getoverrun 260
-#define TARGET_NR_timer_delete 261
-#define TARGET_NR_clock_settime 262
-#define TARGET_NR_clock_gettime 263
-#define TARGET_NR_clock_getres 264
-#define TARGET_NR_clock_nanosleep 265
-#define TARGET_NR_statfs64 266
-#define TARGET_NR_fstatfs64 267
-#define TARGET_NR_tgkill 268
-#define TARGET_NR_utimes 269
-#define TARGET_NR_fadvise64_64 270
-#define TARGET_NR_pciconfig_iobase 271
-#define TARGET_NR_pciconfig_read 272
-#define TARGET_NR_pciconfig_write 273
-#define TARGET_NR_mq_open 274
-#define TARGET_NR_mq_unlink 275
-#define TARGET_NR_mq_timedsend 276
-#define TARGET_NR_mq_timedreceive 277
-#define TARGET_NR_mq_notify 278
-#define TARGET_NR_mq_getsetattr 279
-#define TARGET_NR_waitid 280
-#define TARGET_NR_socket 281
-#define TARGET_NR_bind 282
-#define TARGET_NR_connect 283
-#define TARGET_NR_listen 284
-#define TARGET_NR_accept 285
-#define TARGET_NR_getsockname 286
-#define TARGET_NR_getpeername 287
-#define TARGET_NR_socketpair 288
-#define TARGET_NR_send 289
-#define TARGET_NR_sendto 290
-#define TARGET_NR_recv 291
-#define TARGET_NR_recvfrom 292
-#define TARGET_NR_shutdown 293
-#define TARGET_NR_setsockopt 294
-#define TARGET_NR_getsockopt 295
-#define TARGET_NR_sendmsg 296
-#define TARGET_NR_recvmsg 297
-#define TARGET_NR_semop 298
-#define TARGET_NR_semget 299
-#define TARGET_NR_semctl 300
-#define TARGET_NR_msgsnd 301
-#define TARGET_NR_msgrcv 302
-#define TARGET_NR_msgget 303
-#define TARGET_NR_msgctl 304
-#define TARGET_NR_shmat 305
-#define TARGET_NR_shmdt 306
-#define TARGET_NR_shmget 307
-#define TARGET_NR_shmctl 308
-#define TARGET_NR_add_key 309
-#define TARGET_NR_request_key 310
-#define TARGET_NR_keyctl 311
-#define TARGET_NR_semtimedop 312
-#define TARGET_NR_vserver 313
-#define TARGET_NR_ioprio_set 314
-#define TARGET_NR_ioprio_get 315
-#define TARGET_NR_inotify_init 316
-#define TARGET_NR_inotify_add_watch 317
-#define TARGET_NR_inotify_rm_watch 318
-#define TARGET_NR_mbind 319
-#define TARGET_NR_get_mempolicy 320
-#define TARGET_NR_set_mempolicy 321
-#define TARGET_NR_openat 322
-#define TARGET_NR_mkdirat 323
-#define TARGET_NR_mknodat 324
-#define TARGET_NR_fchownat 325
-#define TARGET_NR_futimesat 326
-#define TARGET_NR_fstatat64 327
-#define TARGET_NR_unlinkat 328
-#define TARGET_NR_renameat 329
-#define TARGET_NR_linkat 330
-#define TARGET_NR_symlinkat 331
-#define TARGET_NR_readlinkat 332
-#define TARGET_NR_fchmodat 333
-#define TARGET_NR_faccessat 334
- /* 335 */
- /* 336 */
-#define TARGET_NR_unshare 337
-#define TARGET_NR_set_robust_list 338
-#define TARGET_NR_get_robust_list 339
-#define TARGET_NR_splice 340
-#define TARGET_NR_sync_file_range2 341
-#define TARGET_NR_tee 342
-#define TARGET_NR_vmsplice 343
-#define TARGET_NR_move_pages 344
-#define TARGET_NR_getcpu 345
- /* 346 */
-#define TARGET_NR_kexec_load 347
-#define TARGET_NR_utimensat 348
-#define TARGET_NR_signalfd 349
-#define TARGET_NR_timerfd 350
-#define TARGET_NR_eventfd 351
-#define TARGET_NR_fallocate 352
-#define TARGET_NR_timerfd_settime 353
-#define TARGET_NR_timerfd_gettime 354
-#define TARGET_NR_signalfd4 355
-#define TARGET_NR_eventfd2 356
-#define TARGET_NR_epoll_create1 357
-#define TARGET_NR_dup3 358
-#define TARGET_NR_pipe2 359
-#define TARGET_NR_inotify_init1 360
diff --git a/linux-user/unicore32/target_cpu.h b/linux-user/unicore32/target_cpu.h
deleted file mode 100644
index d7d2e7b083..0000000000
--- a/linux-user/unicore32/target_cpu.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * UniCore32 specific CPU ABI and functions for linux-user
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-#ifndef UNICORE32_TARGET_CPU_H
-#define UNICORE32_TARGET_CPU_H
-
-static inline void cpu_clone_regs(CPUUniCore32State *env, target_ulong newsp)
-{
- if (newsp) {
- env->regs[29] = newsp;
- }
- env->regs[0] = 0;
-}
-
-static inline void cpu_set_tls(CPUUniCore32State *env, target_ulong newtls)
-{
- env->regs[16] = newtls;
-}
-
-#endif
diff --git a/linux-user/unicore32/target_elf.h b/linux-user/unicore32/target_elf.h
deleted file mode 100644
index e2bfcb2ca3..0000000000
--- a/linux-user/unicore32/target_elf.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-
-#ifndef UNICORE32_TARGET_ELF_H
-#define UNICORE32_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "any";
-}
-#endif
diff --git a/linux-user/unicore32/target_signal.h b/linux-user/unicore32/target_signal.h
deleted file mode 100644
index c6496fb9ea..0000000000
--- a/linux-user/unicore32/target_signal.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010-2011 GUAN Xue-tao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef UNICORE32_TARGET_SIGNAL_H
-#define UNICORE32_TARGET_SIGNAL_H
-
-/* this struct defines a stack used during syscall handling */
-typedef struct target_sigaltstack {
- abi_ulong ss_sp;
- abi_ulong ss_flags;
- abi_ulong ss_size;
-} target_stack_t;
-
-/*
- * sigaltstack controls
- */
-#define TARGET_SS_ONSTACK 1
-#define TARGET_SS_DISABLE 2
-
-static inline abi_ulong get_sp_from_cpustate(CPUUniCore32State *state)
-{
- return state->regs[29];
-}
-
-
-#endif /* UNICORE32_TARGET_SIGNAL_H */
diff --git a/linux-user/unicore32/target_structs.h b/linux-user/unicore32/target_structs.h
deleted file mode 100644
index fbd4fa3f53..0000000000
--- a/linux-user/unicore32/target_structs.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * UniCore32 specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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 UNICORE32_TARGET_STRUCTS_H
-#define UNICORE32_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
diff --git a/linux-user/unicore32/target_syscall.h b/linux-user/unicore32/target_syscall.h
deleted file mode 100644
index 346b207700..0000000000
--- a/linux-user/unicore32/target_syscall.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010-2011 GUAN Xue-tao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef UNICORE32_TARGET_SYSCALL_H
-#define UNICORE32_TARGET_SYSCALL_H
-
-struct target_pt_regs {
- abi_ulong uregs[34];
-};
-
-#define UC32_REG_pc uregs[31]
-#define UC32_REG_lr uregs[30]
-#define UC32_REG_sp uregs[29]
-#define UC32_REG_ip uregs[28]
-#define UC32_REG_fp uregs[27]
-#define UC32_REG_26 uregs[26]
-#define UC32_REG_25 uregs[25]
-#define UC32_REG_24 uregs[24]
-#define UC32_REG_23 uregs[23]
-#define UC32_REG_22 uregs[22]
-#define UC32_REG_21 uregs[21]
-#define UC32_REG_20 uregs[20]
-#define UC32_REG_19 uregs[19]
-#define UC32_REG_18 uregs[18]
-#define UC32_REG_17 uregs[17]
-#define UC32_REG_16 uregs[16]
-#define UC32_REG_15 uregs[15]
-#define UC32_REG_14 uregs[14]
-#define UC32_REG_13 uregs[13]
-#define UC32_REG_12 uregs[12]
-#define UC32_REG_11 uregs[11]
-#define UC32_REG_10 uregs[10]
-#define UC32_REG_09 uregs[9]
-#define UC32_REG_08 uregs[8]
-#define UC32_REG_07 uregs[7]
-#define UC32_REG_06 uregs[6]
-#define UC32_REG_05 uregs[5]
-#define UC32_REG_04 uregs[4]
-#define UC32_REG_03 uregs[3]
-#define UC32_REG_02 uregs[2]
-#define UC32_REG_01 uregs[1]
-#define UC32_REG_00 uregs[0]
-#define UC32_REG_asr uregs[32]
-#define UC32_REG_ORIG_00 uregs[33]
-
-#define UC32_SYSCALL_BASE 0x900000
-#define UC32_SYSCALL_ARCH_BASE 0xf0000
-#define UC32_SYSCALL_NR_set_tls (UC32_SYSCALL_ARCH_BASE + 5)
-
-#define UNAME_MACHINE "UniCore-II"
-#define UNAME_MINIMUM_RELEASE "2.6.32"
-
-#define TARGET_MINSIGSTKSZ 2048
-#define TARGET_MLOCKALL_MCL_CURRENT 1
-#define TARGET_MLOCKALL_MCL_FUTURE 2
-
-#endif /* UNICORE32_TARGET_SYSCALL_H */
diff --git a/linux-user/unicore32/termbits.h b/linux-user/unicore32/termbits.h
deleted file mode 100644
index a5fcd64abf..0000000000
--- a/linux-user/unicore32/termbits.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* NOTE: exactly the same as i386 */
-#include "../i386/termbits.h"
diff --git a/monitor.c b/monitor.c
index a4417f26cd..3117a3e689 100644
--- a/monitor.c
+++ b/monitor.c
@@ -983,6 +983,9 @@ static void qmp_unregister_commands_hack(void)
#endif
#ifndef TARGET_I386
qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
+ qmp_unregister_command(&qmp_commands, "query-sev");
+ qmp_unregister_command(&qmp_commands, "query-sev-launch-measure");
+ qmp_unregister_command(&qmp_commands, "query-sev-capabilities");
#endif
#ifndef TARGET_S390X
qmp_unregister_command(&qmp_commands, "dump-skeys");
@@ -4103,6 +4106,24 @@ void qmp_rtc_reset_reinjection(Error **errp)
{
error_setg(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
}
+
+SevInfo *qmp_query_sev(Error **errp)
+{
+ error_setg(errp, QERR_FEATURE_DISABLED, "query-sev");
+ return NULL;
+}
+
+SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp)
+{
+ error_setg(errp, QERR_FEATURE_DISABLED, "query-sev-launch-measure");
+ return NULL;
+}
+
+SevCapability *qmp_query_sev_capabilities(Error **errp)
+{
+ error_setg(errp, QERR_FEATURE_DISABLED, "query-sev-capabilities");
+ return NULL;
+}
#endif
#ifndef TARGET_S390X
diff --git a/qapi/misc.json b/qapi/misc.json
index bcd5d10778..6150b9a003 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -3216,3 +3216,151 @@
# Since: 2.9
##
{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
+
+
+##
+# @SevState:
+#
+# An enumeration of SEV state information used during @query-sev.
+#
+# @uninit: The guest is uninitialized.
+#
+# @launch-update: The guest is currently being launched; plaintext data and
+# register state is being imported.
+#
+# @launch-secret: The guest is currently being launched; ciphertext data
+# is being imported.
+#
+# @running: The guest is fully launched or migrated in.
+#
+# @send-update: The guest is currently being migrated out to another machine.
+#
+# @receive-update: The guest is currently being migrated from another machine.
+#
+# Since: 2.12
+##
+{ 'enum': 'SevState',
+ 'data': ['uninit', 'launch-update', 'launch-secret', 'running',
+ 'send-update', 'receive-update' ] }
+
+##
+# @SevInfo:
+#
+# Information about Secure Encrypted Virtualization (SEV) support
+#
+# @enabled: true if SEV is active
+#
+# @api-major: SEV API major version
+#
+# @api-minor: SEV API minor version
+#
+# @build-id: SEV FW build id
+#
+# @policy: SEV policy value
+#
+# @state: SEV guest state
+#
+# @handle: SEV firmware handle
+#
+# Since: 2.12
+##
+{ 'struct': 'SevInfo',
+ 'data': { 'enabled': 'bool',
+ 'api-major': 'uint8',
+ 'api-minor' : 'uint8',
+ 'build-id' : 'uint8',
+ 'policy' : 'uint32',
+ 'state' : 'SevState',
+ 'handle' : 'uint32'
+ }
+}
+
+##
+# @query-sev:
+#
+# Returns information about SEV
+#
+# Returns: @SevInfo
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-sev" }
+# <- { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0,
+# "build-id" : 0, "policy" : 0, "state" : "running",
+# "handle" : 1 } }
+#
+##
+{ 'command': 'query-sev', 'returns': 'SevInfo' }
+
+##
+# @SevLaunchMeasureInfo:
+#
+# SEV Guest Launch measurement information
+#
+# @data: the measurement value encoded in base64
+#
+# Since: 2.12
+#
+##
+{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'} }
+
+##
+# @query-sev-launch-measure:
+#
+# Query the SEV guest launch information.
+#
+# Returns: The @SevLaunchMeasureInfo for the guest
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-sev-launch-measure" }
+# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } }
+#
+##
+{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo' }
+
+##
+# @SevCapability:
+#
+# The struct describes capability for a Secure Encrypted Virtualization
+# feature.
+#
+# @pdh: Platform Diffie-Hellman key (base64 encoded)
+#
+# @cert-chain: PDH certificate chain (base64 encoded)
+#
+# @cbitpos: C-bit location in page table entry
+#
+# @reduced-phys-bits: Number of physical Address bit reduction when SEV is
+# enabled
+#
+# Since: 2.12
+##
+{ 'struct': 'SevCapability',
+ 'data': { 'pdh': 'str',
+ 'cert-chain': 'str',
+ 'cbitpos': 'int',
+ 'reduced-phys-bits': 'int'} }
+
+##
+# @query-sev-capabilities:
+#
+# This command is used to get the SEV capabilities, and is supported on AMD
+# X86 platforms only.
+#
+# Returns: SevCapability objects.
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "query-sev-capabilities" }
+# <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE",
+# "cbitpos": 47, "reduced-phys-bits": 5}}
+#
+##
+{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability' }
diff --git a/qapi/sockets.json b/qapi/sockets.json
index ac022c6ad0..fc81d8d5e8 100644
--- a/qapi/sockets.json
+++ b/qapi/sockets.json
@@ -123,6 +123,13 @@
#
# @unix: Unix domain socket
#
+# @vsock: VMCI address
+#
+# @fd: decimal is for file descriptor number, otherwise a file descriptor name.
+# Named file descriptors are permitted in monitor commands, in combination
+# with the 'getfd' command. Decimal file descriptors are permitted at
+# startup or other contexts where no monitor context is active.
+#
# Since: 2.9
##
{ 'enum': 'SocketAddressType',
diff --git a/qapi/ui.json b/qapi/ui.json
index 3e82f25ac5..5d01ad4304 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -77,6 +77,13 @@
#
# @filename: the path of a new PPM file to store the image
#
+# @device: ID of the display device that should be dumped. If this parameter
+# is missing, the primary display will be used. (Since 2.12)
+#
+# @head: head to use in case the device supports multiple heads. If this
+# parameter is missing, head #0 will be used. Also note that the head
+# can only be specified in conjunction with the device ID. (Since 2.12)
+#
# Returns: Nothing on success
#
# Since: 0.14.0
@@ -88,7 +95,8 @@
# <- { "return": {} }
#
##
-{ 'command': 'screendump', 'data': {'filename': 'str'} }
+{ 'command': 'screendump',
+ 'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
##
# == Spice
diff --git a/qemu-options.hx b/qemu-options.hx
index 6585058c6c..6113bce08a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -43,7 +43,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" suppress-vmdesc=on|off disables self-describing migration (default=off)\n"
" nvdimm=on|off controls NVDIMM support (default=off)\n"
" enforce-config-section=on|off enforce configuration section migration (default=off)\n"
- " s390-squash-mcss=on|off (deprecated) controls support for squashing into default css (default=off)\n",
+ " s390-squash-mcss=on|off (deprecated) controls support for squashing into default css (default=off)\n"
+ " memory-encryption=@var{} memory encryption object to use (default=none)\n",
QEMU_ARCH_ALL)
STEXI
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -110,6 +111,8 @@ code to send configuration section even if the machine-type sets the
@option{migration.send-configuration} property to @var{off}.
NOTE: this parameter is deprecated. Please use @option{-global}
@option{migration.send-configuration}=@var{on|off} instead.
+@item memory-encryption=@var{}
+Memory encryption object to use. The default is none.
@end table
ETEXI
@@ -4350,6 +4353,50 @@ contents of @code{iv.b64} to the second secret
data=$SECRET,iv=$(<iv.b64)
@end example
+@item -object sev-guest,id=@var{id},cbitpos=@var{cbitpos},reduced-phys-bits=@var{val},[sev-device=@var{string},policy=@var{policy},handle=@var{handle},dh-cert-file=@var{file},session-file=@var{file}]
+
+Create a Secure Encrypted Virtualization (SEV) guest object, which can be used
+to provide the guest memory encryption support on AMD processors.
+
+When memory encryption is enabled, one of the physical address bit (aka the
+C-bit) is utilized to mark if a memory page is protected. The @option{cbitpos}
+is used to provide the C-bit position. The C-bit position is Host family dependent
+hence user must provide this value. On EPYC, the value should be 47.
+
+When memory encryption is enabled, we loose certain bits in physical address space.
+The @option{reduced-phys-bits} is used to provide the number of bits we loose in
+physical address space. Similar to C-bit, the value is Host family dependent.
+On EPYC, the value should be 5.
+
+The @option{sev-device} provides the device file to use for communicating with
+the SEV firmware running inside AMD Secure Processor. The default device is
+'/dev/sev'. If hardware supports memory encryption then /dev/sev devices are
+created by CCP driver.
+
+The @option{policy} provides the guest policy to be enforced by the SEV firmware
+and restrict what configuration and operational commands can be performed on this
+guest by the hypervisor. The policy should be provided by the guest owner and is
+bound to the guest and cannot be changed throughout the lifetime of the guest.
+The default is 0.
+
+If guest @option{policy} allows sharing the key with another SEV guest then
+@option{handle} can be use to provide handle of the guest from which to share
+the key.
+
+The @option{dh-cert-file} and @option{session-file} provides the guest owner's
+Public Diffie-Hillman key defined in SEV spec. The PDH and session parameters
+are used for establishing a cryptographic session with the guest owner to
+negotiate keys used for attestation. The file must be encoded in base64.
+
+e.g to launch a SEV guest
+@example
+ # $QEMU \
+ ......
+ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 \
+ -machine ...,memory-encryption=sev0
+ .....
+
+@end example
@end table
ETEXI
diff --git a/scripts/create_config b/scripts/create_config
index 603b826886..d727e5e36e 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -36,7 +36,7 @@ case $line in
drivers=${line#*=}
echo "#define CONFIG_AUDIO_DRIVERS \\"
for drv in $drivers; do
- echo " &${drv}_audio_driver,\\"
+ echo " \"${drv}\",\\"
done
echo ""
;;
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index 7417177ebb..f04f34924e 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python
#
# Copyright (c) 2017 Red Hat Inc
#
@@ -217,11 +217,15 @@ ERROR_WHITELIST = [
{'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR},
{'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR},
{'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR},
+ {'exitcode':-6, 'device':'isa-fdc', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'device':'gus', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'device':'isa-serial', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'device':'sb16', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'device':'cs4231a', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'machine':'isapc', 'device':'.*-iommu', 'loglevel':logging.ERROR, 'expected':True},
+ {'exitcode':-11, 'device':'mioe3680_pci', 'loglevel':logging.ERROR, 'expected':True},
+ {'exitcode':-11, 'device':'pcm3680_pci', 'loglevel':logging.ERROR, 'expected':True},
+ {'exitcode':-11, 'device':'kvaser_pci', 'loglevel':logging.ERROR, 'expected':True},
# everything else (including SIGABRT and SIGSEGV) will be a fatal error:
{'exitcode':None, 'fatal':True, 'loglevel':logging.FATAL},
diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh
index bdb21bdd58..f39ad344fc 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
+# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390/HPPA/Xtensa
# 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"
+sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb"
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\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
@@ -108,6 +108,14 @@ riscv64_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x
riscv64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
riscv64_family=riscv
+xtensa_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e\x00'
+xtensa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
+xtensa_family=xtensa
+
+xtensaeb_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e'
+xtensaeb_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
+xtensaeb_family=xtensaeb
+
qemu_get_family() {
cpu=${HOST_ARCH:-$(uname -m)}
case "$cpu" in
@@ -154,7 +162,8 @@ Usage: qemu-binfmt-conf.sh [--qemu-path PATH][--debian][--systemd CPU]
instead generate update-binfmts templates
--systemd: don't write into /proc,
instead generate file for systemd-binfmt.service
- for the given CPU
+ 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
@@ -301,18 +310,20 @@ while true ; do
EXPORTDIR=${EXPORTDIR:-$SYSTEMDDIR}
shift
# check given cpu is in the supported CPU list
- for cpu in ${qemu_target_list} ; do
+ if [ "$1" != "ALL" ] ; then
+ for cpu in ${qemu_target_list} ; do
+ if [ "$cpu" = "$1" ] ; then
+ break
+ fi
+ done
+
if [ "$cpu" = "$1" ] ; then
- break
+ qemu_target_list="$1"
+ else
+ echo "ERROR: unknown CPU \"$1\"" 1>&2
+ usage
+ exit 1
fi
- done
-
- if [ "$cpu" = "$1" ] ; then
- qemu_target_list="$1"
- else
- echo "ERROR: unknown CPU \"$1\"" 1>&2
- usage
- exit 1
fi
;;
-Q|--qemu-path)
diff --git a/scripts/qemu.py b/scripts/qemu.py
index 305a946562..08a3e9af5a 100644
--- a/scripts/qemu.py
+++ b/scripts/qemu.py
@@ -277,7 +277,7 @@ class QEMUMachine(object):
def qmp(self, cmd, conv_keys=True, **args):
'''Invoke a QMP command and return the response dict'''
qmp_args = dict()
- for key, value in args.iteritems():
+ for key, value in args.items():
if conv_keys:
qmp_args[key.replace('_', '-')] = value
else:
diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py
index 07c9632e9e..5c8cf6a056 100644
--- a/scripts/qmp/qmp.py
+++ b/scripts/qmp/qmp.py
@@ -166,7 +166,7 @@ class QEMUMonitorProtocol(object):
"""
self.logger.debug(">>> %s", qmp_cmd)
try:
- self.__sock.sendall(json.dumps(qmp_cmd))
+ self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
except socket.error as err:
if err[0] == errno.EPIPE:
return
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index a3a6315055..9d45c6ba4e 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -168,7 +168,7 @@ class Analyzer(object):
def process(events, log, analyzer, read_header=True):
"""Invoke an analyzer on each event in a log."""
if isinstance(events, str):
- events = read_events(open(events, 'r'))
+ events = read_events(open(events, 'r'), events)
if isinstance(log, str):
log = open(log, 'rb')
@@ -199,7 +199,7 @@ def process(events, log, analyzer, read_header=True):
fn_argcount = len(inspect.getargspec(fn)[0]) - 1
if fn_argcount == event_argcount + 1:
# Include timestamp as first argument
- return lambda _, rec: fn(*((rec[1:2],) + rec[3:3 + event_argcount]))
+ return lambda _, rec: fn(*(rec[1:2] + rec[3:3 + event_argcount]))
elif fn_argcount == event_argcount + 2:
# Include timestamp and pid
return lambda _, rec: fn(*rec[1:3 + event_argcount])
@@ -233,7 +233,7 @@ def run(analyzer):
'<trace-file>\n' % sys.argv[0])
sys.exit(1)
- events = read_events(open(sys.argv[1], 'r'))
+ events = read_events(open(sys.argv[1], 'r'), sys.argv[1])
process(events, sys.argv[2], analyzer, read_header=read_header)
if __name__ == '__main__':
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
index c55a21518b..fe2b0771f2 100755
--- a/scripts/tracetool.py
+++ b/scripts/tracetool.py
@@ -142,7 +142,7 @@ def main(args):
events = []
for arg in args:
with open(arg, "r") as fh:
- events.extend(tracetool.read_events(fh))
+ events.extend(tracetool.read_events(fh, arg))
try:
tracetool.generate(events, arg_group, arg_format, arg_backends,
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 3646c2b9fc..b20fac34a3 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -41,6 +41,51 @@ def out(*lines, **kwargs):
lines = [ l % kwargs for l in lines ]
sys.stdout.writelines("\n".join(lines) + "\n")
+# We only want to allow standard C types or fixed sized
+# integer types. We don't want QEMU specific types
+# as we can't assume trace backends can resolve all the
+# typedefs
+ALLOWED_TYPES = [
+ "int",
+ "long",
+ "short",
+ "char",
+ "bool",
+ "unsigned",
+ "signed",
+ "float",
+ "double",
+ "int8_t",
+ "uint8_t",
+ "int16_t",
+ "uint16_t",
+ "int32_t",
+ "uint32_t",
+ "int64_t",
+ "uint64_t",
+ "void",
+ "size_t",
+ "ssize_t",
+ "uintptr_t",
+ "ptrdiff_t",
+ # Magic substitution is done by tracetool
+ "TCGv",
+]
+
+def validate_type(name):
+ bits = name.split(" ")
+ for bit in bits:
+ bit = re.sub("\*", "", bit)
+ if bit == "":
+ continue
+ if bit == "const":
+ continue
+ if bit not in ALLOWED_TYPES:
+ raise ValueError("Argument type '%s' is not in whitelist. "
+ "Only standard C types and fixed size integer "
+ "types should be used. struct, union, and "
+ "other complex pointer types should be "
+ "declared as 'void *'" % name)
class Arguments:
"""Event arguments description."""
@@ -87,6 +132,7 @@ class Arguments:
else:
arg_type, identifier = arg.rsplit(None, 1)
+ validate_type(arg_type)
res.append((arg_type, identifier))
return Arguments(res)
@@ -291,13 +337,15 @@ class Event(object):
self)
-def read_events(fobj):
+def read_events(fobj, fname):
"""Generate the output for the given (format, backends) pair.
Parameters
----------
fobj : file
Event description file.
+ fname : str
+ Name of event file
Returns a list of Event objects
"""
@@ -312,7 +360,7 @@ def read_events(fobj):
try:
event = Event.build(line)
except ValueError as e:
- arg0 = 'Error on line %d: %s' % (lineno, e.args[0])
+ arg0 = 'Error at %s:%d: %s' % (fname, lineno, e.args[0])
e.args = (arg0,) + e.args[1:]
raise
diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py
index da86f6b882..78933d03ad 100644
--- a/scripts/tracetool/backend/log.py
+++ b/scripts/tracetool/backend/log.py
@@ -20,7 +20,7 @@ PUBLIC = True
def generate_h_begin(events, group):
- out('#include "qemu/log.h"',
+ out('#include "qemu/log-for-trace.h"',
'')
@@ -35,14 +35,13 @@ def generate_h(event, group):
else:
cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
- out(' if (%(cond)s) {',
+ out(' if (%(cond)s && qemu_loglevel_mask(LOG_TRACE)) {',
' struct timeval _now;',
' gettimeofday(&_now, NULL);',
- ' qemu_log_mask(LOG_TRACE,',
- ' "%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",',
- ' getpid(),',
- ' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
- ' %(argnames)s);',
+ ' qemu_log("%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",',
+ ' getpid(),',
+ ' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
+ ' %(argnames)s);',
' }',
cond=cond,
name=event.name,
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index be065704df..da9030a01c 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -39,6 +39,7 @@ cp_portable() {
-e 'input-event-codes' \
-e 'sys/' \
-e 'pvrdma_verbs' \
+ -e 'drm.h' \
> /dev/null
then
echo "Unexpected #include in input file $f".
@@ -56,6 +57,8 @@ cp_portable() {
-e 's/__bitwise//' \
-e 's/__attribute__((packed))/QEMU_PACKED/' \
-e 's/__inline__/inline/' \
+ -e 's/__BITS_PER_LONG/HOST_LONG_BITS/' \
+ -e '/\"drm.h\"/d' \
-e '/sys\/ioctl.h/d' \
-e 's/SW_MAX/SW_MAX_/' \
-e 's/atomic_t/int/' \
@@ -99,6 +102,8 @@ for arch in $ARCHLIST; do
mkdir -p "$output/include/standard-headers/asm-$arch"
if [ $arch = s390 ]; then
cp_portable "$tmpdir/include/asm/virtio-ccw.h" "$output/include/standard-headers/asm-s390/"
+ cp "$tmpdir/include/asm/unistd_32.h" "$output/linux-headers/asm-s390/"
+ cp "$tmpdir/include/asm/unistd_64.h" "$output/linux-headers/asm-s390/"
fi
if [ $arch = arm ]; then
cp "$tmpdir/include/asm/unistd-eabi.h" "$output/linux-headers/asm-arm/"
@@ -118,7 +123,7 @@ done
rm -rf "$output/linux-headers/linux"
mkdir -p "$output/linux-headers/linux"
for header in kvm.h kvm_para.h vfio.h vfio_ccw.h vhost.h \
- psci.h userfaultfd.h; do
+ psci.h psp-sev.h userfaultfd.h; do
cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
done
rm -rf "$output/linux-headers/asm-generic"
@@ -149,6 +154,9 @@ for i in "$tmpdir"/include/linux/*virtio*.h "$tmpdir/include/linux/input.h" \
"$tmpdir/include/linux/pci_regs.h"; do
cp_portable "$i" "$output/include/standard-headers/linux"
done
+mkdir -p "$output/include/standard-headers/drm"
+cp_portable "$tmpdir/include/drm/drm_fourcc.h" \
+ "$output/include/standard-headers/drm"
rm -rf "$output/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma"
mkdir -p "$output/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma"
diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs
index f5c6ef20a7..04678f5503 100644
--- a/target/i386/Makefile.objs
+++ b/target/i386/Makefile.objs
@@ -5,7 +5,9 @@ obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o mpx_helper.o
obj-$(CONFIG_TCG) += seg_helper.o smm_helper.o svm_helper.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
+obj-$(CONFIG_SEV) += sev.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
+obj-$(call lnot,$(CONFIG_SEV)) += sev-stub.o
# HAX support
ifdef CONFIG_WIN32
obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-windows.o
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 2c04645cea..6bb4ce8719 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -26,6 +26,7 @@
#include "sysemu/hvf.h"
#include "sysemu/cpus.h"
#include "kvm_i386.h"
+#include "sev_i386.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
@@ -173,7 +174,32 @@
#define L2_ITLB_4K_ASSOC 4
#define L2_ITLB_4K_ENTRIES 512
-
+/* CPUID Leaf 0x14 constants: */
+#define INTEL_PT_MAX_SUBLEAF 0x1
+/*
+ * bit[00]: IA32_RTIT_CTL.CR3 filter can be set to 1 and IA32_RTIT_CR3_MATCH
+ * MSR can be accessed;
+ * bit[01]: Support Configurable PSB and Cycle-Accurate Mode;
+ * bit[02]: Support IP Filtering, TraceStop filtering, and preservation
+ * of Intel PT MSRs across warm reset;
+ * bit[03]: Support MTC timing packet and suppression of COFI-based packets;
+ */
+#define INTEL_PT_MINIMAL_EBX 0xf
+/*
+ * bit[00]: Tracing can be enabled with IA32_RTIT_CTL.ToPA = 1 and
+ * IA32_RTIT_OUTPUT_BASE and IA32_RTIT_OUTPUT_MASK_PTRS MSRs can be
+ * accessed;
+ * bit[01]: ToPA tables can hold any number of output entries, up to the
+ * maximum allowed by the MaskOrTableOffset field of
+ * IA32_RTIT_OUTPUT_MASK_PTRS;
+ * bit[02]: Support Single-Range Output scheme;
+ */
+#define INTEL_PT_MINIMAL_ECX 0x7
+#define INTEL_PT_ADDR_RANGES_NUM 0x2 /* Number of configurable address ranges */
+#define INTEL_PT_ADDR_RANGES_NUM_MASK 0x3
+#define INTEL_PT_MTC_BITMAP (0x0249 << 16) /* Support ART(0,3,6,9) */
+#define INTEL_PT_CYCLE_BITMAP 0x1fff /* Support 0,2^(0~11) */
+#define INTEL_PT_PSB_BITMAP (0x003f << 16) /* Support 2K,4K,8K,16K,32K,64K */
static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
uint32_t vendor2, uint32_t vendor3)
@@ -359,6 +385,20 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX,
.tcg_features = TCG_KVM_FEATURES,
},
+ [FEAT_KVM_HINTS] = {
+ .feat_names = {
+ "kvm-hint-dedicated", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EDX,
+ .tcg_features = TCG_KVM_FEATURES,
+ },
[FEAT_HYPERV_EAX] = {
.feat_names = {
NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */,
@@ -428,7 +468,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
NULL, NULL, "mpx", NULL,
"avx512f", "avx512dq", "rdseed", "adx",
"smap", "avx512ifma", "pcommit", "clflushopt",
- "clwb", NULL, "avx512pf", "avx512er",
+ "clwb", "intel-pt", "avx512pf", "avx512er",
"avx512cd", "sha-ni", "avx512bw", "avx512vl",
},
.cpuid_eax = 7,
@@ -3453,6 +3493,27 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
break;
}
+ case 0x14: {
+ /* Intel Processor Trace Enumeration */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) ||
+ !kvm_enabled()) {
+ break;
+ }
+
+ if (count == 0) {
+ *eax = INTEL_PT_MAX_SUBLEAF;
+ *ebx = INTEL_PT_MINIMAL_EBX;
+ *ecx = INTEL_PT_MINIMAL_ECX;
+ } else if (count == 1) {
+ *eax = INTEL_PT_MTC_BITMAP | INTEL_PT_ADDR_RANGES_NUM;
+ *ebx = INTEL_PT_PSB_BITMAP | INTEL_PT_CYCLE_BITMAP;
+ }
+ break;
+ }
case 0x40000000:
/*
* CPUID code in kvm_arch_init_vcpu() ignores stuff
@@ -3612,6 +3673,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = 0;
*edx = 0;
break;
+ case 0x8000001F:
+ *eax = sev_enabled() ? 0x2 : 0;
+ *ebx = sev_get_cbit_position();
+ *ebx |= sev_get_reduced_phys_bits() << 6;
+ *ecx = 0;
+ *edx = 0;
+ break;
default:
/* reserved values: zero */
*eax = 0;
@@ -3645,6 +3713,7 @@ static void x86_cpu_reset(CPUState *s)
cpu_x86_update_cr0(env, 0x60000010);
env->a20_mask = ~0x0;
env->smbase = 0x30000;
+ env->msr_smi_count = 0;
env->idt.limit = 0xffff;
env->gdt.limit = 0xffff;
@@ -4041,6 +4110,11 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A);
}
+
+ /* SEV requires CPUID[0x8000001F] */
+ if (sev_enabled()) {
+ x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000001F);
+ }
}
/* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */
@@ -4083,6 +4157,34 @@ static int x86_cpu_filter_features(X86CPU *cpu)
}
}
+ if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
+ kvm_enabled()) {
+ KVMState *s = CPU(cpu)->kvm_state;
+ uint32_t eax_0 = kvm_arch_get_supported_cpuid(s, 0x14, 0, R_EAX);
+ uint32_t ebx_0 = kvm_arch_get_supported_cpuid(s, 0x14, 0, R_EBX);
+ uint32_t ecx_0 = kvm_arch_get_supported_cpuid(s, 0x14, 0, R_ECX);
+ uint32_t eax_1 = kvm_arch_get_supported_cpuid(s, 0x14, 1, R_EAX);
+ uint32_t ebx_1 = kvm_arch_get_supported_cpuid(s, 0x14, 1, R_EBX);
+
+ if (!eax_0 ||
+ ((ebx_0 & INTEL_PT_MINIMAL_EBX) != INTEL_PT_MINIMAL_EBX) ||
+ ((ecx_0 & INTEL_PT_MINIMAL_ECX) != INTEL_PT_MINIMAL_ECX) ||
+ ((eax_1 & INTEL_PT_MTC_BITMAP) != INTEL_PT_MTC_BITMAP) ||
+ ((eax_1 & INTEL_PT_ADDR_RANGES_NUM_MASK) <
+ INTEL_PT_ADDR_RANGES_NUM) ||
+ ((ebx_1 & (INTEL_PT_PSB_BITMAP | INTEL_PT_CYCLE_BITMAP)) !=
+ (INTEL_PT_PSB_BITMAP | INTEL_PT_CYCLE_BITMAP))) {
+ /*
+ * Processor Trace capabilities aren't configurable, so if the
+ * host can't emulate the capabilities we report on
+ * cpu_x86_cpuid(), intel-pt can't be enabled on the current host.
+ */
+ env->features[FEAT_7_0_EBX] &= ~CPUID_7_0_EBX_INTEL_PT;
+ cpu->filtered_features[FEAT_7_0_EBX] |= CPUID_7_0_EBX_INTEL_PT;
+ rv = 1;
+ }
+ }
+
return rv;
}
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index faf39ec1ce..2e2bab5ff3 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1,3 +1,4 @@
+
/*
* i386 virtual CPU header
*
@@ -359,6 +360,7 @@ typedef enum X86Seg {
#define MSR_P6_PERFCTR0 0xc1
#define MSR_IA32_SMBASE 0x9e
+#define MSR_SMI_COUNT 0x34
#define MSR_MTRRcap 0xfe
#define MSR_MTRRcap_VCNT 8
#define MSR_MTRRcap_FIXRANGE_SUPPORT (1 << 8)
@@ -415,6 +417,21 @@ typedef enum X86Seg {
#define MSR_MC0_ADDR 0x402
#define MSR_MC0_MISC 0x403
+#define MSR_IA32_RTIT_OUTPUT_BASE 0x560
+#define MSR_IA32_RTIT_OUTPUT_MASK 0x561
+#define MSR_IA32_RTIT_CTL 0x570
+#define MSR_IA32_RTIT_STATUS 0x571
+#define MSR_IA32_RTIT_CR3_MATCH 0x572
+#define MSR_IA32_RTIT_ADDR0_A 0x580
+#define MSR_IA32_RTIT_ADDR0_B 0x581
+#define MSR_IA32_RTIT_ADDR1_A 0x582
+#define MSR_IA32_RTIT_ADDR1_B 0x583
+#define MSR_IA32_RTIT_ADDR2_A 0x584
+#define MSR_IA32_RTIT_ADDR2_B 0x585
+#define MSR_IA32_RTIT_ADDR3_A 0x586
+#define MSR_IA32_RTIT_ADDR3_B 0x587
+#define MAX_RTIT_ADDRS 8
+
#define MSR_EFER 0xc0000080
#define MSR_EFER_SCE (1 << 0)
@@ -471,6 +488,7 @@ typedef enum FeatureWord {
FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
+ FEAT_KVM_HINTS, /* CPUID[4000_0001].EDX */
FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */
FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */
FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */
@@ -640,6 +658,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_7_0_EBX_PCOMMIT (1U << 22) /* Persistent Commit */
#define CPUID_7_0_EBX_CLFLUSHOPT (1U << 23) /* Flush a Cache Line Optimized */
#define CPUID_7_0_EBX_CLWB (1U << 24) /* Cache Line Write Back */
+#define CPUID_7_0_EBX_INTEL_PT (1U << 25) /* Intel Processor Trace */
#define CPUID_7_0_EBX_AVX512PF (1U << 26) /* AVX-512 Prefetch */
#define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */
#define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */
@@ -666,6 +685,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */
+#define KVM_HINTS_DEDICATED (1U << 0)
+
#define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
@@ -1123,6 +1144,7 @@ typedef struct CPUX86State {
uint64_t pat;
uint32_t smbase;
+ uint64_t msr_smi_count;
uint32_t pkru;
@@ -1153,6 +1175,13 @@ typedef struct CPUX86State {
uint64_t msr_hv_stimer_config[HV_STIMER_COUNT];
uint64_t msr_hv_stimer_count[HV_STIMER_COUNT];
+ uint64_t msr_rtit_ctrl;
+ uint64_t msr_rtit_status;
+ uint64_t msr_rtit_output_base;
+ uint64_t msr_rtit_output_mask;
+ uint64_t msr_rtit_cr3_match;
+ uint64_t msr_rtit_addrs[MAX_RTIT_ADDRS];
+
/* exception/interrupt handling */
int error_code;
int exception_is_int;
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index ad4b159b28..d23fff12f5 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -92,6 +92,7 @@ static bool has_msr_hv_stimer;
static bool has_msr_hv_frequencies;
static bool has_msr_xss;
static bool has_msr_spec_ctrl;
+static bool has_msr_smi_count;
static uint32_t has_architectural_pmu_version;
static uint32_t num_architectural_pmu_gp_counters;
@@ -383,6 +384,9 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
if (!kvm_irqchip_in_kernel()) {
ret &= ~(1U << KVM_FEATURE_PV_UNHALT);
}
+ } else if (function == KVM_CPUID_FEATURES && reg == R_EDX) {
+ ret |= KVM_HINTS_DEDICATED;
+ found = 1;
}
/* fallback for older kernels */
@@ -801,6 +805,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_FEATURES | kvm_base;
c->eax = env->features[FEAT_KVM];
+ c->edx = env->features[FEAT_KVM_HINTS];
}
cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
@@ -865,6 +870,29 @@ int kvm_arch_init_vcpu(CPUState *cs)
c = &cpuid_data.entries[cpuid_i++];
}
break;
+ case 0x14: {
+ uint32_t times;
+
+ c->function = i;
+ c->index = 0;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ times = c->eax;
+
+ for (j = 1; j <= times; ++j) {
+ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+ fprintf(stderr, "cpuid_data is full, no space for "
+ "cpuid(eax:0x14,ecx:0x%x)\n", j);
+ abort();
+ }
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = i;
+ c->index = j;
+ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ break;
+ }
default:
c->function = i;
c->flags = 0;
@@ -1124,6 +1152,9 @@ static int kvm_get_supported_msrs(KVMState *s)
case MSR_IA32_SMBASE:
has_msr_smbase = true;
break;
+ case MSR_SMI_COUNT:
+ has_msr_smi_count = true;
+ break;
case MSR_IA32_MISC_ENABLE:
has_msr_misc_enable = true;
break;
@@ -1633,6 +1664,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
if (has_msr_smbase) {
kvm_msr_entry_add(cpu, MSR_IA32_SMBASE, env->smbase);
}
+ if (has_msr_smi_count) {
+ kvm_msr_entry_add(cpu, MSR_SMI_COUNT, env->msr_smi_count);
+ }
if (has_msr_bndcfgs) {
kvm_msr_entry_add(cpu, MSR_IA32_BNDCFGS, env->msr_bndcfgs);
}
@@ -1788,6 +1822,25 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_add(cpu, MSR_MTRRphysMask(i), mask);
}
}
+ if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) {
+ int addr_num = kvm_arch_get_supported_cpuid(kvm_state,
+ 0x14, 1, R_EAX) & 0x7;
+
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_CTL,
+ env->msr_rtit_ctrl);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_STATUS,
+ env->msr_rtit_status);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_OUTPUT_BASE,
+ env->msr_rtit_output_base);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_OUTPUT_MASK,
+ env->msr_rtit_output_mask);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_CR3_MATCH,
+ env->msr_rtit_cr3_match);
+ for (i = 0; i < addr_num; i++) {
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_ADDR0_A + i,
+ env->msr_rtit_addrs[i]);
+ }
+ }
/* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
* kvm_put_msr_feature_control. */
@@ -1979,6 +2032,9 @@ static int kvm_get_msrs(X86CPU *cpu)
if (has_msr_smbase) {
kvm_msr_entry_add(cpu, MSR_IA32_SMBASE, 0);
}
+ if (has_msr_smi_count) {
+ kvm_msr_entry_add(cpu, MSR_SMI_COUNT, 0);
+ }
if (has_msr_feature_control) {
kvm_msr_entry_add(cpu, MSR_IA32_FEATURE_CONTROL, 0);
}
@@ -2101,6 +2157,20 @@ static int kvm_get_msrs(X86CPU *cpu)
}
}
+ if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) {
+ int addr_num =
+ kvm_arch_get_supported_cpuid(kvm_state, 0x14, 1, R_EAX) & 0x7;
+
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_CTL, 0);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_STATUS, 0);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_OUTPUT_BASE, 0);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_OUTPUT_MASK, 0);
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_CR3_MATCH, 0);
+ for (i = 0; i < addr_num; i++) {
+ kvm_msr_entry_add(cpu, MSR_IA32_RTIT_ADDR0_A + i, 0);
+ }
+ }
+
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf);
if (ret < 0) {
return ret;
@@ -2205,6 +2275,9 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_IA32_SMBASE:
env->smbase = msrs[i].data;
break;
+ case MSR_SMI_COUNT:
+ env->msr_smi_count = msrs[i].data;
+ break;
case MSR_IA32_FEATURE_CONTROL:
env->msr_ia32_feature_control = msrs[i].data;
break;
@@ -2341,6 +2414,24 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_IA32_SPEC_CTRL:
env->spec_ctrl = msrs[i].data;
break;
+ case MSR_IA32_RTIT_CTL:
+ env->msr_rtit_ctrl = msrs[i].data;
+ break;
+ case MSR_IA32_RTIT_STATUS:
+ env->msr_rtit_status = msrs[i].data;
+ break;
+ case MSR_IA32_RTIT_OUTPUT_BASE:
+ env->msr_rtit_output_base = msrs[i].data;
+ break;
+ case MSR_IA32_RTIT_OUTPUT_MASK:
+ env->msr_rtit_output_mask = msrs[i].data;
+ break;
+ case MSR_IA32_RTIT_CR3_MATCH:
+ env->msr_rtit_cr3_match = msrs[i].data;
+ break;
+ case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B:
+ env->msr_rtit_addrs[index - MSR_IA32_RTIT_ADDR0_A] = msrs[i].data;
+ break;
}
}
diff --git a/target/i386/machine.c b/target/i386/machine.c
index 361c05aedf..bd2d82e91b 100644
--- a/target/i386/machine.c
+++ b/target/i386/machine.c
@@ -395,6 +395,25 @@ static const VMStateDescription vmstate_msr_tsc_adjust = {
}
};
+static bool msr_smi_count_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->msr_smi_count != 0;
+}
+
+static const VMStateDescription vmstate_msr_smi_count = {
+ .name = "cpu/msr_smi_count",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = msr_smi_count_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(env.msr_smi_count, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool tscdeadline_needed(void *opaque)
{
X86CPU *cpu = opaque;
@@ -837,6 +856,43 @@ static const VMStateDescription vmstate_spec_ctrl = {
}
};
+static bool intel_pt_enable_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+ int i;
+
+ if (env->msr_rtit_ctrl || env->msr_rtit_status ||
+ env->msr_rtit_output_base || env->msr_rtit_output_mask ||
+ env->msr_rtit_cr3_match) {
+ return true;
+ }
+
+ for (i = 0; i < MAX_RTIT_ADDRS; i++) {
+ if (env->msr_rtit_addrs[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static const VMStateDescription vmstate_msr_intel_pt = {
+ .name = "cpu/intel_pt",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = intel_pt_enable_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(env.msr_rtit_ctrl, X86CPU),
+ VMSTATE_UINT64(env.msr_rtit_status, X86CPU),
+ VMSTATE_UINT64(env.msr_rtit_output_base, X86CPU),
+ VMSTATE_UINT64(env.msr_rtit_output_mask, X86CPU),
+ VMSTATE_UINT64(env.msr_rtit_cr3_match, X86CPU),
+ VMSTATE_UINT64_ARRAY(env.msr_rtit_addrs, X86CPU, MAX_RTIT_ADDRS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
@@ -952,11 +1008,13 @@ VMStateDescription vmstate_x86_cpu = {
&vmstate_avx512,
&vmstate_xss,
&vmstate_tsc_khz,
+ &vmstate_msr_smi_count,
#ifdef TARGET_X86_64
&vmstate_pkru,
#endif
&vmstate_spec_ctrl,
&vmstate_mcg_ext_ctl,
+ &vmstate_msr_intel_pt,
NULL
}
};
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 75429129fd..011419eba2 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -29,7 +29,11 @@
#include "qapi/qmp/qdict.h"
#include "hw/i386/pc.h"
#include "sysemu/kvm.h"
+#include "sysemu/sev.h"
#include "hmp.h"
+#include "qapi/error.h"
+#include "sev_i386.h"
+#include "qapi/qapi-commands-misc.h"
static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
@@ -661,3 +665,65 @@ void hmp_info_io_apic(Monitor *mon, const QDict *qdict)
ioapic_dump_state(mon, qdict);
}
}
+
+SevInfo *qmp_query_sev(Error **errp)
+{
+ SevInfo *info;
+
+ info = sev_get_info();
+ if (!info) {
+ error_setg(errp, "SEV feature is not available");
+ return NULL;
+ }
+
+ return info;
+}
+
+void hmp_info_sev(Monitor *mon, const QDict *qdict)
+{
+ SevInfo *info = sev_get_info();
+
+ if (info && info->enabled) {
+ monitor_printf(mon, "handle: %d\n", info->handle);
+ monitor_printf(mon, "state: %s\n", SevState_str(info->state));
+ monitor_printf(mon, "build: %d\n", info->build_id);
+ monitor_printf(mon, "api version: %d.%d\n",
+ info->api_major, info->api_minor);
+ monitor_printf(mon, "debug: %s\n",
+ info->policy & SEV_POLICY_NODBG ? "off" : "on");
+ monitor_printf(mon, "key-sharing: %s\n",
+ info->policy & SEV_POLICY_NOKS ? "off" : "on");
+ } else {
+ monitor_printf(mon, "SEV is not enabled\n");
+ }
+}
+
+SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp)
+{
+ char *data;
+ SevLaunchMeasureInfo *info;
+
+ data = sev_get_launch_measurement();
+ if (!data) {
+ error_setg(errp, "Measurement is not available");
+ return NULL;
+ }
+
+ info = g_malloc0(sizeof(*info));
+ info->data = data;
+
+ return info;
+}
+
+SevCapability *qmp_query_sev_capabilities(Error **errp)
+{
+ SevCapability *data;
+
+ data = sev_get_capabilities();
+ if (!data) {
+ error_setg(errp, "SEV feature is not available");
+ return NULL;
+ }
+
+ return data;
+}
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
new file mode 100644
index 0000000000..59a003a4eb
--- /dev/null
+++ b/target/i386/sev-stub.c
@@ -0,0 +1,51 @@
+/*
+ * QEMU SEV stub
+ *
+ * Copyright Advanced Micro Devices 2018
+ *
+ * Authors:
+ * Brijesh Singh <brijesh.singh@amd.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sev_i386.h"
+
+SevInfo *sev_get_info(void)
+{
+ return NULL;
+}
+
+bool sev_enabled(void)
+{
+ return false;
+}
+
+uint64_t sev_get_me_mask(void)
+{
+ return ~0;
+}
+
+uint32_t sev_get_cbit_position(void)
+{
+ return 0;
+}
+
+uint32_t sev_get_reduced_phys_bits(void)
+{
+ return 0;
+}
+
+char *sev_get_launch_measurement(void)
+{
+ return NULL;
+}
+
+SevCapability *sev_get_capabilities(void)
+{
+ return NULL;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
new file mode 100644
index 0000000000..019d84cef2
--- /dev/null
+++ b/target/i386/sev.c
@@ -0,0 +1,811 @@
+/*
+ * QEMU SEV support
+ *
+ * Copyright Advanced Micro Devices 2016-2018
+ *
+ * Author:
+ * Brijesh Singh <brijesh.singh@amd.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/kvm.h>
+#include <linux/psp-sev.h>
+
+#include <sys/ioctl.h>
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "qemu/base64.h"
+#include "sysemu/kvm.h"
+#include "sev_i386.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+#include "migration/blocker.h"
+
+#define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
+#define DEFAULT_SEV_DEVICE "/dev/sev"
+
+static SEVState *sev_state;
+static Error *sev_mig_blocker;
+
+static const char *const sev_fw_errlist[] = {
+ "",
+ "Platform state is invalid",
+ "Guest state is invalid",
+ "Platform configuration is invalid",
+ "Buffer too small",
+ "Platform is already owned",
+ "Certificate is invalid",
+ "Policy is not allowed",
+ "Guest is not active",
+ "Invalid address",
+ "Bad signature",
+ "Bad measurement",
+ "Asid is already owned",
+ "Invalid ASID",
+ "WBINVD is required",
+ "DF_FLUSH is required",
+ "Guest handle is invalid",
+ "Invalid command",
+ "Guest is active",
+ "Hardware error",
+ "Hardware unsafe",
+ "Feature not supported",
+ "Invalid parameter"
+};
+
+#define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
+
+static int
+sev_ioctl(int fd, int cmd, void *data, int *error)
+{
+ int r;
+ struct kvm_sev_cmd input;
+
+ memset(&input, 0x0, sizeof(input));
+
+ input.id = cmd;
+ input.sev_fd = fd;
+ input.data = (__u64)(unsigned long)data;
+
+ r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
+
+ if (error) {
+ *error = input.error;
+ }
+
+ return r;
+}
+
+static int
+sev_platform_ioctl(int fd, int cmd, void *data, int *error)
+{
+ int r;
+ struct sev_issue_cmd arg;
+
+ arg.cmd = cmd;
+ arg.data = (unsigned long)data;
+ r = ioctl(fd, SEV_ISSUE_CMD, &arg);
+ if (error) {
+ *error = arg.error;
+ }
+
+ return r;
+}
+
+static const char *
+fw_error_to_str(int code)
+{
+ if (code < 0 || code >= SEV_FW_MAX_ERROR) {
+ return "unknown error";
+ }
+
+ return sev_fw_errlist[code];
+}
+
+static bool
+sev_check_state(SevState state)
+{
+ assert(sev_state);
+ return sev_state->state == state ? true : false;
+}
+
+static void
+sev_set_guest_state(SevState new_state)
+{
+ assert(new_state < SEV_STATE__MAX);
+ assert(sev_state);
+
+ trace_kvm_sev_change_state(SevState_str(sev_state->state),
+ SevState_str(new_state));
+ sev_state->state = new_state;
+}
+
+static void
+sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
+{
+ int r;
+ struct kvm_enc_region range;
+
+ range.addr = (__u64)(unsigned long)host;
+ range.size = size;
+
+ trace_kvm_memcrypt_register_region(host, size);
+ r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
+ if (r) {
+ error_report("%s: failed to register region (%p+%#zx) error '%s'",
+ __func__, host, size, strerror(errno));
+ exit(1);
+ }
+}
+
+static void
+sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
+{
+ int r;
+ struct kvm_enc_region range;
+
+ range.addr = (__u64)(unsigned long)host;
+ range.size = size;
+
+ trace_kvm_memcrypt_unregister_region(host, size);
+ r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
+ if (r) {
+ error_report("%s: failed to unregister region (%p+%#zx)",
+ __func__, host, size);
+ }
+}
+
+static struct RAMBlockNotifier sev_ram_notifier = {
+ .ram_block_added = sev_ram_block_added,
+ .ram_block_removed = sev_ram_block_removed,
+};
+
+static void
+qsev_guest_finalize(Object *obj)
+{
+}
+
+static char *
+qsev_guest_get_session_file(Object *obj, Error **errp)
+{
+ QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
+
+ return s->session_file ? g_strdup(s->session_file) : NULL;
+}
+
+static void
+qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
+{
+ QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
+
+ s->session_file = g_strdup(value);
+}
+
+static char *
+qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
+{
+ QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
+
+ return g_strdup(s->dh_cert_file);
+}
+
+static void
+qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
+{
+ QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
+
+ s->dh_cert_file = g_strdup(value);
+}
+
+static char *
+qsev_guest_get_sev_device(Object *obj, Error **errp)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ return g_strdup(sev->sev_device);
+}
+
+static void
+qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ sev->sev_device = g_strdup(value);
+}
+
+static void
+qsev_guest_class_init(ObjectClass *oc, void *data)
+{
+ object_class_property_add_str(oc, "sev-device",
+ qsev_guest_get_sev_device,
+ qsev_guest_set_sev_device,
+ NULL);
+ object_class_property_set_description(oc, "sev-device",
+ "SEV device to use", NULL);
+ object_class_property_add_str(oc, "dh-cert-file",
+ qsev_guest_get_dh_cert_file,
+ qsev_guest_set_dh_cert_file,
+ NULL);
+ object_class_property_set_description(oc, "dh-cert-file",
+ "guest owners DH certificate (encoded with base64)", NULL);
+ object_class_property_add_str(oc, "session-file",
+ qsev_guest_get_session_file,
+ qsev_guest_set_session_file,
+ NULL);
+ object_class_property_set_description(oc, "session-file",
+ "guest owners session parameters (encoded with base64)", NULL);
+}
+
+static void
+qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, errp);
+ sev->handle = value;
+}
+
+static void
+qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, errp);
+ sev->policy = value;
+}
+
+static void
+qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, errp);
+ sev->cbitpos = value;
+}
+
+static void
+qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+ uint32_t value;
+
+ visit_type_uint32(v, name, &value, errp);
+ sev->reduced_phys_bits = value;
+}
+
+static void
+qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t value;
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ value = sev->policy;
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void
+qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t value;
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ value = sev->handle;
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void
+qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t value;
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ value = sev->cbitpos;
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void
+qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t value;
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ value = sev->reduced_phys_bits;
+ visit_type_uint32(v, name, &value, errp);
+}
+
+static void
+qsev_guest_init(Object *obj)
+{
+ QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+ sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
+ sev->policy = DEFAULT_GUEST_POLICY;
+ object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
+ qsev_guest_set_policy, NULL, NULL, NULL);
+ object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
+ qsev_guest_set_handle, NULL, NULL, NULL);
+ object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
+ qsev_guest_set_cbitpos, NULL, NULL, NULL);
+ object_property_add(obj, "reduced-phys-bits", "uint32",
+ qsev_guest_get_reduced_phys_bits,
+ qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
+}
+
+/* sev guest info */
+static const TypeInfo qsev_guest_info = {
+ .parent = TYPE_OBJECT,
+ .name = TYPE_QSEV_GUEST_INFO,
+ .instance_size = sizeof(QSevGuestInfo),
+ .instance_finalize = qsev_guest_finalize,
+ .class_size = sizeof(QSevGuestInfoClass),
+ .class_init = qsev_guest_class_init,
+ .instance_init = qsev_guest_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { }
+ }
+};
+
+static QSevGuestInfo *
+lookup_sev_guest_info(const char *id)
+{
+ Object *obj;
+ QSevGuestInfo *info;
+
+ obj = object_resolve_path_component(object_get_objects_root(), id);
+ if (!obj) {
+ return NULL;
+ }
+
+ info = (QSevGuestInfo *)
+ object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
+ if (!info) {
+ return NULL;
+ }
+
+ return info;
+}
+
+bool
+sev_enabled(void)
+{
+ return sev_state ? true : false;
+}
+
+uint64_t
+sev_get_me_mask(void)
+{
+ return sev_state ? sev_state->me_mask : ~0;
+}
+
+uint32_t
+sev_get_cbit_position(void)
+{
+ return sev_state ? sev_state->cbitpos : 0;
+}
+
+uint32_t
+sev_get_reduced_phys_bits(void)
+{
+ return sev_state ? sev_state->reduced_phys_bits : 0;
+}
+
+SevInfo *
+sev_get_info(void)
+{
+ SevInfo *info;
+
+ info = g_new0(SevInfo, 1);
+ info->enabled = sev_state ? true : false;
+
+ if (info->enabled) {
+ info->api_major = sev_state->api_major;
+ info->api_minor = sev_state->api_minor;
+ info->build_id = sev_state->build_id;
+ info->policy = sev_state->policy;
+ info->state = sev_state->state;
+ info->handle = sev_state->handle;
+ }
+
+ return info;
+}
+
+static int
+sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
+ size_t *cert_chain_len)
+{
+ guchar *pdh_data, *cert_chain_data;
+ struct sev_user_data_pdh_cert_export export = {};
+ int err, r;
+
+ /* query the certificate length */
+ r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
+ if (r < 0) {
+ if (err != SEV_RET_INVALID_LEN) {
+ error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
+ r, err, fw_error_to_str(err));
+ return 1;
+ }
+ }
+
+ pdh_data = g_new(guchar, export.pdh_cert_len);
+ cert_chain_data = g_new(guchar, export.cert_chain_len);
+ export.pdh_cert_address = (unsigned long)pdh_data;
+ export.cert_chain_address = (unsigned long)cert_chain_data;
+
+ r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
+ if (r < 0) {
+ error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
+ r, err, fw_error_to_str(err));
+ goto e_free;
+ }
+
+ *pdh = pdh_data;
+ *pdh_len = export.pdh_cert_len;
+ *cert_chain = cert_chain_data;
+ *cert_chain_len = export.cert_chain_len;
+ return 0;
+
+e_free:
+ g_free(pdh_data);
+ g_free(cert_chain_data);
+ return 1;
+}
+
+SevCapability *
+sev_get_capabilities(void)
+{
+ SevCapability *cap;
+ guchar *pdh_data, *cert_chain_data;
+ size_t pdh_len = 0, cert_chain_len = 0;
+ uint32_t ebx;
+ int fd;
+
+ fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
+ if (fd < 0) {
+ error_report("%s: Failed to open %s '%s'", __func__,
+ DEFAULT_SEV_DEVICE, strerror(errno));
+ return NULL;
+ }
+
+ if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
+ &cert_chain_data, &cert_chain_len)) {
+ return NULL;
+ }
+
+ cap = g_new0(SevCapability, 1);
+ cap->pdh = g_base64_encode(pdh_data, pdh_len);
+ cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
+
+ host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
+ cap->cbitpos = ebx & 0x3f;
+
+ /*
+ * When SEV feature is enabled, we loose one bit in guest physical
+ * addressing.
+ */
+ cap->reduced_phys_bits = 1;
+
+ g_free(pdh_data);
+ g_free(cert_chain_data);
+
+ close(fd);
+ return cap;
+}
+
+static int
+sev_read_file_base64(const char *filename, guchar **data, gsize *len)
+{
+ gsize sz;
+ gchar *base64;
+ GError *error = NULL;
+
+ if (!g_file_get_contents(filename, &base64, &sz, &error)) {
+ error_report("failed to read '%s' (%s)", filename, error->message);
+ return -1;
+ }
+
+ *data = g_base64_decode(base64, len);
+ return 0;
+}
+
+static int
+sev_launch_start(SEVState *s)
+{
+ gsize sz;
+ int ret = 1;
+ int fw_error;
+ QSevGuestInfo *sev = s->sev_info;
+ struct kvm_sev_launch_start *start;
+ guchar *session = NULL, *dh_cert = NULL;
+
+ start = g_new0(struct kvm_sev_launch_start, 1);
+
+ start->handle = object_property_get_int(OBJECT(sev), "handle",
+ &error_abort);
+ start->policy = object_property_get_int(OBJECT(sev), "policy",
+ &error_abort);
+ if (sev->session_file) {
+ if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
+ return 1;
+ }
+ start->session_uaddr = (unsigned long)session;
+ start->session_len = sz;
+ }
+
+ if (sev->dh_cert_file) {
+ if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
+ return 1;
+ }
+ start->dh_uaddr = (unsigned long)dh_cert;
+ start->dh_len = sz;
+ }
+
+ trace_kvm_sev_launch_start(start->policy, session, dh_cert);
+ ret = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
+ if (ret < 0) {
+ error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
+ return 1;
+ }
+
+ object_property_set_int(OBJECT(sev), start->handle, "handle",
+ &error_abort);
+ sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
+ s->handle = start->handle;
+ s->policy = start->policy;
+
+ g_free(start);
+ g_free(session);
+ g_free(dh_cert);
+
+ return 0;
+}
+
+static int
+sev_launch_update_data(uint8_t *addr, uint64_t len)
+{
+ int ret, fw_error;
+ struct kvm_sev_launch_update_data update;
+
+ if (!addr || !len) {
+ return 1;
+ }
+
+ update.uaddr = (__u64)(unsigned long)addr;
+ update.len = len;
+ trace_kvm_sev_launch_update_data(addr, len);
+ ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
+ &update, &fw_error);
+ if (ret) {
+ error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
+ }
+
+ return ret;
+}
+
+static void
+sev_launch_get_measure(Notifier *notifier, void *unused)
+{
+ int ret, error;
+ guchar *data;
+ SEVState *s = sev_state;
+ struct kvm_sev_launch_measure *measurement;
+
+ if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
+ return;
+ }
+
+ measurement = g_new0(struct kvm_sev_launch_measure, 1);
+
+ /* query the measurement blob length */
+ ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
+ measurement, &error);
+ if (!measurement->len) {
+ error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
+ __func__, ret, error, fw_error_to_str(errno));
+ goto free_measurement;
+ }
+
+ data = g_new0(guchar, measurement->len);
+ measurement->uaddr = (unsigned long)data;
+
+ /* get the measurement blob */
+ ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
+ measurement, &error);
+ if (ret) {
+ error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
+ __func__, ret, error, fw_error_to_str(errno));
+ goto free_data;
+ }
+
+ sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
+
+ /* encode the measurement value and emit the event */
+ s->measurement = g_base64_encode(data, measurement->len);
+ trace_kvm_sev_launch_measurement(s->measurement);
+
+free_data:
+ g_free(data);
+free_measurement:
+ g_free(measurement);
+}
+
+char *
+sev_get_launch_measurement(void)
+{
+ if (sev_state &&
+ sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
+ return g_strdup(sev_state->measurement);
+ }
+
+ return NULL;
+}
+
+static Notifier sev_machine_done_notify = {
+ .notify = sev_launch_get_measure,
+};
+
+static void
+sev_launch_finish(SEVState *s)
+{
+ int ret, error;
+ Error *local_err = NULL;
+
+ trace_kvm_sev_launch_finish();
+ ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
+ if (ret) {
+ error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
+ __func__, ret, error, fw_error_to_str(error));
+ exit(1);
+ }
+
+ sev_set_guest_state(SEV_STATE_RUNNING);
+
+ /* add migration blocker */
+ error_setg(&sev_mig_blocker,
+ "SEV: Migration is not implemented");
+ ret = migrate_add_blocker(sev_mig_blocker, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ error_free(sev_mig_blocker);
+ exit(1);
+ }
+}
+
+static void
+sev_vm_state_change(void *opaque, int running, RunState state)
+{
+ SEVState *s = opaque;
+
+ if (running) {
+ if (!sev_check_state(SEV_STATE_RUNNING)) {
+ sev_launch_finish(s);
+ }
+ }
+}
+
+void *
+sev_guest_init(const char *id)
+{
+ SEVState *s;
+ char *devname;
+ int ret, fw_error;
+ uint32_t ebx;
+ uint32_t host_cbitpos;
+ struct sev_user_data_status status = {};
+
+ s = g_new0(SEVState, 1);
+ s->sev_info = lookup_sev_guest_info(id);
+ if (!s->sev_info) {
+ error_report("%s: '%s' is not a valid '%s' object",
+ __func__, id, TYPE_QSEV_GUEST_INFO);
+ goto err;
+ }
+
+ sev_state = s;
+ s->state = SEV_STATE_UNINIT;
+
+ host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
+ host_cbitpos = ebx & 0x3f;
+
+ s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
+ if (host_cbitpos != s->cbitpos) {
+ error_report("%s: cbitpos check failed, host '%d' requested '%d'",
+ __func__, host_cbitpos, s->cbitpos);
+ goto err;
+ }
+
+ s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
+ "reduced-phys-bits", NULL);
+ if (s->reduced_phys_bits < 1) {
+ error_report("%s: reduced_phys_bits check failed, it should be >=1,"
+ "' requested '%d'", __func__, s->reduced_phys_bits);
+ goto err;
+ }
+
+ s->me_mask = ~(1UL << s->cbitpos);
+
+ devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
+ s->sev_fd = open(devname, O_RDWR);
+ if (s->sev_fd < 0) {
+ error_report("%s: Failed to open %s '%s'", __func__,
+ devname, strerror(errno));
+ goto err;
+ }
+ g_free(devname);
+
+ ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
+ &fw_error);
+ if (ret) {
+ error_report("%s: failed to get platform status ret=%d"
+ "fw_error='%d: %s'", __func__, ret, fw_error,
+ fw_error_to_str(fw_error));
+ goto err;
+ }
+ s->build_id = status.build;
+ s->api_major = status.api_major;
+ s->api_minor = status.api_minor;
+
+ trace_kvm_sev_init();
+ ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
+ if (ret) {
+ error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
+ goto err;
+ }
+
+ ret = sev_launch_start(s);
+ if (ret) {
+ error_report("%s: failed to create encryption context", __func__);
+ goto err;
+ }
+
+ ram_block_notifier_add(&sev_ram_notifier);
+ qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
+ qemu_add_vm_change_state_handler(sev_vm_state_change, s);
+
+ return s;
+err:
+ g_free(sev_state);
+ sev_state = NULL;
+ return NULL;
+}
+
+int
+sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
+{
+ assert(handle);
+
+ /* if SEV is in update state then encrypt the data else do nothing */
+ if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
+ return sev_launch_update_data(ptr, len);
+ }
+
+ return 0;
+}
+
+static void
+sev_register_types(void)
+{
+ type_register_static(&qsev_guest_info);
+}
+
+type_init(sev_register_types);
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
new file mode 100644
index 0000000000..b8622dfb1e
--- /dev/null
+++ b/target/i386/sev_i386.h
@@ -0,0 +1,88 @@
+/*
+ * QEMU Secure Encrypted Virutualization (SEV) support
+ *
+ * Copyright: Advanced Micro Devices, 2016-2018
+ *
+ * Authors:
+ * Brijesh Singh <brijesh.singh@amd.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_SEV_I386_H
+#define QEMU_SEV_I386_H
+
+#include "qom/object.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+#include "sysemu/sev.h"
+#include "qemu/error-report.h"
+#include "qapi/qapi-commands-misc.h"
+
+#define SEV_POLICY_NODBG 0x1
+#define SEV_POLICY_NOKS 0x2
+#define SEV_POLICY_ES 0x4
+#define SEV_POLICY_NOSEND 0x8
+#define SEV_POLICY_DOMAIN 0x10
+#define SEV_POLICY_SEV 0x20
+
+#define TYPE_QSEV_GUEST_INFO "sev-guest"
+#define QSEV_GUEST_INFO(obj) \
+ OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO)
+
+extern bool sev_enabled(void);
+extern uint64_t sev_get_me_mask(void);
+extern SevInfo *sev_get_info(void);
+extern uint32_t sev_get_cbit_position(void);
+extern uint32_t sev_get_reduced_phys_bits(void);
+extern char *sev_get_launch_measurement(void);
+extern SevCapability *sev_get_capabilities(void);
+
+typedef struct QSevGuestInfo QSevGuestInfo;
+typedef struct QSevGuestInfoClass QSevGuestInfoClass;
+
+/**
+ * QSevGuestInfo:
+ *
+ * The QSevGuestInfo object is used for creating a SEV guest.
+ *
+ * # $QEMU \
+ * -object sev-guest,id=sev0 \
+ * -machine ...,memory-encryption=sev0
+ */
+struct QSevGuestInfo {
+ Object parent_obj;
+
+ char *sev_device;
+ uint32_t policy;
+ uint32_t handle;
+ char *dh_cert_file;
+ char *session_file;
+ uint32_t cbitpos;
+ uint32_t reduced_phys_bits;
+};
+
+struct QSevGuestInfoClass {
+ ObjectClass parent_class;
+};
+
+struct SEVState {
+ QSevGuestInfo *sev_info;
+ uint8_t api_major;
+ uint8_t api_minor;
+ uint8_t build_id;
+ uint32_t policy;
+ uint64_t me_mask;
+ uint32_t cbitpos;
+ uint32_t reduced_phys_bits;
+ uint32_t handle;
+ int sev_fd;
+ SevState state;
+ gchar *measurement;
+};
+
+typedef struct SEVState SEVState;
+
+#endif
diff --git a/target/i386/trace-events b/target/i386/trace-events
index 3153fd4454..6a19a69af5 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -5,3 +5,13 @@ kvm_x86_fixup_msi_error(uint32_t gsi) "VT-d failed to remap interrupt for GSI %"
kvm_x86_add_msi_route(int virq) "Adding route entry for virq %d"
kvm_x86_remove_msi_route(int virq) "Removing route entry for virq %d"
kvm_x86_update_msi_routes(int num) "Updated %d MSI routes"
+
+# target/i386/sev.c
+kvm_sev_init(void) ""
+kvm_memcrypt_register_region(void *addr, size_t len) "addr %p len 0x%zu"
+kvm_memcrypt_unregister_region(void *addr, size_t len) "addr %p len 0x%zu"
+kvm_sev_change_state(const char *old, const char *new) "%s -> %s"
+kvm_sev_launch_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p"
+kvm_sev_launch_update_data(void *addr, uint64_t len) "addr %p len 0x%" PRIu64
+kvm_sev_launch_measurement(const char *value) "data %s"
+kvm_sev_launch_finish(void) ""
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 62cbb0dff1..6eeffdf9bb 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -592,3 +592,64 @@ void HELPER(ftentox)(CPUM68KState *env, FPReg *res, FPReg *val)
{
res->d = floatx80_tentox(val->d, &env->fp_status);
}
+
+void HELPER(ftan)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_tan(val->d, &env->fp_status);
+}
+
+void HELPER(fsin)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_sin(val->d, &env->fp_status);
+}
+
+void HELPER(fcos)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_cos(val->d, &env->fp_status);
+}
+
+void HELPER(fsincos)(CPUM68KState *env, FPReg *res0, FPReg *res1, FPReg *val)
+{
+ floatx80 a = val->d;
+ /* If res0 and res1 specify the same floating-point data register,
+ * the sine result is stored in the register, and the cosine
+ * result is discarded.
+ */
+ res1->d = floatx80_cos(a, &env->fp_status);
+ res0->d = floatx80_sin(a, &env->fp_status);
+}
+
+void HELPER(fatan)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_atan(val->d, &env->fp_status);
+}
+
+void HELPER(fasin)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_asin(val->d, &env->fp_status);
+}
+
+void HELPER(facos)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_acos(val->d, &env->fp_status);
+}
+
+void HELPER(fatanh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_atanh(val->d, &env->fp_status);
+}
+
+void HELPER(ftanh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_tanh(val->d, &env->fp_status);
+}
+
+void HELPER(fsinh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_sinh(val->d, &env->fp_status);
+}
+
+void HELPER(fcosh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_cosh(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 9a9734c196..feee7be626 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -75,6 +75,17 @@ DEF_HELPER_3(flog2, void, env, fp, fp)
DEF_HELPER_3(fetox, void, env, fp, fp)
DEF_HELPER_3(ftwotox, void, env, fp, fp)
DEF_HELPER_3(ftentox, void, env, fp, fp)
+DEF_HELPER_3(ftan, void, env, fp, fp)
+DEF_HELPER_3(fsin, void, env, fp, fp)
+DEF_HELPER_3(fcos, void, env, fp, fp)
+DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
+DEF_HELPER_3(fatan, void, env, fp, fp)
+DEF_HELPER_3(fasin, void, env, fp, fp)
+DEF_HELPER_3(facos, void, env, fp, fp)
+DEF_HELPER_3(fatanh, void, env, fp, fp)
+DEF_HELPER_3(ftanh, void, env, fp, fp)
+DEF_HELPER_3(fsinh, void, env, fp, fp)
+DEF_HELPER_3(fcosh, void, env, fp, fp)
DEF_HELPER_3(mac_move, void, env, i32, i32)
DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 4bd5b9e6b7..dffb371c71 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -23,6 +23,10 @@
#include "fpu/softfloat-macros.h"
#include "softfloat_fpsp_tables.h"
+#define pi_exp 0x4000
+#define piby2_exp 0x3FFF
+#define pi_sig LIT64(0xc90fdaa22168c235)
+
static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
{
if (floatx80_is_signaling_nan(a, status)) {
@@ -1266,3 +1270,1636 @@ floatx80 floatx80_tentox(floatx80 a, float_status *status)
return a;
}
}
+
+/*----------------------------------------------------------------------------
+ | Tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_tan(floatx80 a, float_status *status)
+{
+ flag aSign, xSign;
+ int32_t aExp, xExp;
+ uint64_t aSig, xSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact, l, n, j;
+ floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2;
+ float32 twoto63;
+ flag endflag;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ float_raise(float_flag_invalid, status);
+ return floatx80_default_nan(status);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ fp0 = a;
+
+ if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
+ /* 2^(-40) > |X| > 15 PI */
+ if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
+ /* REDUCEX */
+ fp1 = packFloatx80(0, 0, 0);
+ if (compact == 0x7FFEFFFF) {
+ twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
+ LIT64(0xC90FDAA200000000));
+ twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
+ LIT64(0x85A308D300000000));
+ fp0 = floatx80_add(fp0, twopi1, status);
+ fp1 = fp0;
+ fp0 = floatx80_add(fp0, twopi2, status);
+ fp1 = floatx80_sub(fp1, fp0, status);
+ fp1 = floatx80_add(fp1, twopi2, status);
+ }
+ loop:
+ xSign = extractFloatx80Sign(fp0);
+ xExp = extractFloatx80Exp(fp0);
+ xExp -= 0x3FFF;
+ if (xExp <= 28) {
+ l = 0;
+ endflag = 1;
+ } else {
+ l = xExp - 27;
+ endflag = 0;
+ }
+ invtwopi = packFloatx80(0, 0x3FFE - l,
+ LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
+ twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
+ twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
+
+ /* SIGN(INARG)*2^63 IN SGL */
+ twoto63 = packFloat32(xSign, 0xBE, 0);
+
+ fp2 = floatx80_mul(fp0, invtwopi, status);
+ fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
+ status); /* THE FRACT PART OF FP2 IS ROUNDED */
+ fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
+ status); /* FP2 is N */
+ fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
+ fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
+ fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
+ fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
+ fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
+ fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
+ fp3 = fp0; /* FP3 is A */
+ fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
+ fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
+
+ if (endflag > 0) {
+ n = floatx80_to_int32(fp2, status);
+ goto tancont;
+ }
+ fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
+ fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
+ goto loop;
+ } else {
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_move(a, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ } else {
+ fp1 = floatx80_mul(fp0, float64_to_floatx80(
+ make_float64(0x3FE45F306DC9C883), status),
+ status); /* X*2/PI */
+
+ n = floatx80_to_int32(fp1, status);
+ j = 32 + n;
+
+ fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
+ fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
+ status); /* FP0 IS R = (X-Y1)-Y2 */
+
+ tancont:
+ if (n & 1) {
+ /* NODD */
+ fp1 = fp0; /* R */
+ fp0 = floatx80_mul(fp0, fp0, status); /* S = R*R */
+ fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
+ status); /* Q4 */
+ fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
+ status); /* P3 */
+ fp3 = floatx80_mul(fp3, fp0, status); /* SQ4 */
+ fp2 = floatx80_mul(fp2, fp0, status); /* SP3 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBF346F59B39BA65F), status),
+ status); /* Q3+SQ4 */
+ fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
+ fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
+ fp3 = floatx80_mul(fp3, fp0, status); /* S(Q3+SQ4) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* S(P2+SP3) */
+ fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
+ fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
+ fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
+ fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
+ fp3 = floatx80_mul(fp3, fp0, status); /* S(Q2+S(Q3+SQ4)) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* S(P1+S(P2+SP3)) */
+ fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
+ fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* RS(P1+S(P2+SP3)) */
+ fp0 = floatx80_mul(fp0, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
+ fp1 = floatx80_add(fp1, fp2, status); /* R+RS(P1+S(P2+SP3)) */
+ fp0 = floatx80_add(fp0, float32_to_floatx80(
+ make_float32(0x3F800000), status),
+ status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
+
+ xSign = extractFloatx80Sign(fp1);
+ xExp = extractFloatx80Exp(fp1);
+ xSig = extractFloatx80Frac(fp1);
+ xSign ^= 1;
+ fp1 = packFloatx80(xSign, xExp, xSig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_div(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
+ fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
+ status); /* Q4 */
+ fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
+ status); /* P3 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* SQ4 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* SP3 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBF346F59B39BA65F), status),
+ status); /* Q3+SQ4 */
+ fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
+ fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* S(Q3+SQ4) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* S(P2+SP3) */
+ fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
+ fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
+ fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
+ fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
+ fp3 = floatx80_mul(fp3, fp1, status); /* S(Q2+S(Q3+SQ4)) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* S(P1+S(P2+SP3)) */
+ fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
+ fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* RS(P1+S(P2+SP3)) */
+ fp1 = floatx80_mul(fp1, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
+ fp0 = floatx80_add(fp0, fp2, status); /* R+RS(P1+S(P2+SP3)) */
+ fp1 = floatx80_add(fp1, float32_to_floatx80(
+ make_float32(0x3F800000), status),
+ status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_div(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Sine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_sin(floatx80 a, float_status *status)
+{
+ flag aSign, xSign;
+ int32_t aExp, xExp;
+ uint64_t aSig, xSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact, l, n, j;
+ floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
+ float32 posneg1, twoto63;
+ flag adjn, endflag;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ float_raise(float_flag_invalid, status);
+ return floatx80_default_nan(status);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ adjn = 0;
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ fp0 = a;
+
+ if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
+ /* 2^(-40) > |X| > 15 PI */
+ if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
+ /* REDUCEX */
+ fp1 = packFloatx80(0, 0, 0);
+ if (compact == 0x7FFEFFFF) {
+ twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
+ LIT64(0xC90FDAA200000000));
+ twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
+ LIT64(0x85A308D300000000));
+ fp0 = floatx80_add(fp0, twopi1, status);
+ fp1 = fp0;
+ fp0 = floatx80_add(fp0, twopi2, status);
+ fp1 = floatx80_sub(fp1, fp0, status);
+ fp1 = floatx80_add(fp1, twopi2, status);
+ }
+ loop:
+ xSign = extractFloatx80Sign(fp0);
+ xExp = extractFloatx80Exp(fp0);
+ xExp -= 0x3FFF;
+ if (xExp <= 28) {
+ l = 0;
+ endflag = 1;
+ } else {
+ l = xExp - 27;
+ endflag = 0;
+ }
+ invtwopi = packFloatx80(0, 0x3FFE - l,
+ LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
+ twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
+ twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
+
+ /* SIGN(INARG)*2^63 IN SGL */
+ twoto63 = packFloat32(xSign, 0xBE, 0);
+
+ fp2 = floatx80_mul(fp0, invtwopi, status);
+ fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
+ status); /* THE FRACT PART OF FP2 IS ROUNDED */
+ fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
+ status); /* FP2 is N */
+ fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
+ fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
+ fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
+ fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
+ fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
+ fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
+ fp3 = fp0; /* FP3 is A */
+ fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
+ fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
+
+ if (endflag > 0) {
+ n = floatx80_to_int32(fp2, status);
+ goto sincont;
+ }
+ fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
+ fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
+ goto loop;
+ } else {
+ /* SINSM */
+ fp0 = float32_to_floatx80(make_float32(0x3F800000),
+ status); /* 1 */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ if (adjn) {
+ /* COSTINY */
+ a = floatx80_sub(fp0, float32_to_floatx80(
+ make_float32(0x00800000), status), status);
+ } else {
+ /* SINTINY */
+ a = floatx80_move(a, status);
+ }
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ } else {
+ fp1 = floatx80_mul(fp0, float64_to_floatx80(
+ make_float64(0x3FE45F306DC9C883), status),
+ status); /* X*2/PI */
+
+ n = floatx80_to_int32(fp1, status);
+ j = 32 + n;
+
+ fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
+ fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
+ status); /* FP0 IS R = (X-Y1)-Y2 */
+
+ sincont:
+ if ((n + adjn) & 1) {
+ /* COSPOLY */
+ fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+ fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+ fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
+ status); /* B8 */
+ fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
+ status); /* B7 */
+
+ xSign = extractFloatx80Sign(fp0); /* X IS S */
+ xExp = extractFloatx80Exp(fp0);
+ xSig = extractFloatx80Frac(fp0);
+
+ if (((n + adjn) >> 1) & 1) {
+ xSign ^= 1;
+ posneg1 = make_float32(0xBF800000); /* -1 */
+ } else {
+ xSign ^= 0;
+ posneg1 = make_float32(0x3F800000); /* 1 */
+ } /* X IS NOW R'= SGN*R */
+
+ fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3E21EED90612C972), status),
+ status); /* B6+TB8 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBE927E4FB79D9FCF), status),
+ status); /* B5+TB7 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
+ fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3EFA01A01A01D423), status),
+ status); /* B4+T(B6+TB8) */
+ fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
+ fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
+ fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
+ fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
+ fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
+ fp1 = floatx80_add(fp1, float32_to_floatx80(
+ make_float32(0xBF000000), status),
+ status); /* B1+T(B3+T(B5+TB7)) */
+ fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
+ fp0 = floatx80_add(fp0, fp1, status); /* [B1+T(B3+T(B5+TB7))]+
+ * [S(B2+T(B4+T(B6+TB8)))]
+ */
+
+ x = packFloatx80(xSign, xExp, xSig);
+ fp0 = floatx80_mul(fp0, x, status);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ /* SINPOLY */
+ xSign = extractFloatx80Sign(fp0); /* X IS R */
+ xExp = extractFloatx80Exp(fp0);
+ xSig = extractFloatx80Frac(fp0);
+
+ xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
+
+ fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+ fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+ fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
+ status); /* A7 */
+ fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
+ status); /* A6 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBE5AE6452A118AE4), status),
+ status); /* A5+T*A7 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3EC71DE3A5341531), status),
+ status); /* A4+T*A6 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBF2A01A01A018B59), status),
+ status); /* A3+T(A5+TA7) */
+ fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
+ fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
+ fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
+ fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
+ fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
+ fp1 = floatx80_add(fp1, fp2,
+ status); /* [A1+T(A3+T(A5+TA7))]+
+ * [S(A2+T(A4+TA6))]
+ */
+
+ x = packFloatx80(xSign, xExp, xSig);
+ fp0 = floatx80_mul(fp0, x, status); /* R'*S */
+ fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, x, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Cosine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_cos(floatx80 a, float_status *status)
+{
+ flag aSign, xSign;
+ int32_t aExp, xExp;
+ uint64_t aSig, xSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact, l, n, j;
+ floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
+ float32 posneg1, twoto63;
+ flag adjn, endflag;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ float_raise(float_flag_invalid, status);
+ return floatx80_default_nan(status);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(0, one_exp, one_sig);
+ }
+
+ adjn = 1;
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ fp0 = a;
+
+ if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
+ /* 2^(-40) > |X| > 15 PI */
+ if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
+ /* REDUCEX */
+ fp1 = packFloatx80(0, 0, 0);
+ if (compact == 0x7FFEFFFF) {
+ twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
+ LIT64(0xC90FDAA200000000));
+ twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
+ LIT64(0x85A308D300000000));
+ fp0 = floatx80_add(fp0, twopi1, status);
+ fp1 = fp0;
+ fp0 = floatx80_add(fp0, twopi2, status);
+ fp1 = floatx80_sub(fp1, fp0, status);
+ fp1 = floatx80_add(fp1, twopi2, status);
+ }
+ loop:
+ xSign = extractFloatx80Sign(fp0);
+ xExp = extractFloatx80Exp(fp0);
+ xExp -= 0x3FFF;
+ if (xExp <= 28) {
+ l = 0;
+ endflag = 1;
+ } else {
+ l = xExp - 27;
+ endflag = 0;
+ }
+ invtwopi = packFloatx80(0, 0x3FFE - l,
+ LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
+ twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
+ twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
+
+ /* SIGN(INARG)*2^63 IN SGL */
+ twoto63 = packFloat32(xSign, 0xBE, 0);
+
+ fp2 = floatx80_mul(fp0, invtwopi, status);
+ fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
+ status); /* THE FRACT PART OF FP2 IS ROUNDED */
+ fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
+ status); /* FP2 is N */
+ fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
+ fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
+ fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
+ fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
+ fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
+ fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
+ fp3 = fp0; /* FP3 is A */
+ fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
+ fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
+
+ if (endflag > 0) {
+ n = floatx80_to_int32(fp2, status);
+ goto sincont;
+ }
+ fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
+ fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
+ goto loop;
+ } else {
+ /* SINSM */
+ fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ if (adjn) {
+ /* COSTINY */
+ a = floatx80_sub(fp0, float32_to_floatx80(
+ make_float32(0x00800000), status),
+ status);
+ } else {
+ /* SINTINY */
+ a = floatx80_move(a, status);
+ }
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ } else {
+ fp1 = floatx80_mul(fp0, float64_to_floatx80(
+ make_float64(0x3FE45F306DC9C883), status),
+ status); /* X*2/PI */
+
+ n = floatx80_to_int32(fp1, status);
+ j = 32 + n;
+
+ fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
+ fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
+ status); /* FP0 IS R = (X-Y1)-Y2 */
+
+ sincont:
+ if ((n + adjn) & 1) {
+ /* COSPOLY */
+ fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+ fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+ fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
+ status); /* B8 */
+ fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
+ status); /* B7 */
+
+ xSign = extractFloatx80Sign(fp0); /* X IS S */
+ xExp = extractFloatx80Exp(fp0);
+ xSig = extractFloatx80Frac(fp0);
+
+ if (((n + adjn) >> 1) & 1) {
+ xSign ^= 1;
+ posneg1 = make_float32(0xBF800000); /* -1 */
+ } else {
+ xSign ^= 0;
+ posneg1 = make_float32(0x3F800000); /* 1 */
+ } /* X IS NOW R'= SGN*R */
+
+ fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3E21EED90612C972), status),
+ status); /* B6+TB8 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBE927E4FB79D9FCF), status),
+ status); /* B5+TB7 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
+ fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3EFA01A01A01D423), status),
+ status); /* B4+T(B6+TB8) */
+ fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
+ fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
+ fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
+ fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
+ fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
+ fp1 = floatx80_add(fp1, float32_to_floatx80(
+ make_float32(0xBF000000), status),
+ status); /* B1+T(B3+T(B5+TB7)) */
+ fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
+ fp0 = floatx80_add(fp0, fp1, status);
+ /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
+
+ x = packFloatx80(xSign, xExp, xSig);
+ fp0 = floatx80_mul(fp0, x, status);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ /* SINPOLY */
+ xSign = extractFloatx80Sign(fp0); /* X IS R */
+ xExp = extractFloatx80Exp(fp0);
+ xSig = extractFloatx80Frac(fp0);
+
+ xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
+
+ fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+ fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+ fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
+ status); /* A7 */
+ fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
+ status); /* A6 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBE5AE6452A118AE4), status),
+ status); /* A5+T*A7 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3EC71DE3A5341531), status),
+ status); /* A4+T*A6 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
+ fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBF2A01A01A018B59), status),
+ status); /* A3+T(A5+TA7) */
+ fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
+ fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
+ fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
+ fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
+ fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
+ fp1 = floatx80_add(fp1, fp2, status);
+ /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
+
+ x = packFloatx80(xSign, xExp, xSig);
+ fp0 = floatx80_mul(fp0, x, status); /* R'*S */
+ fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, x, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Arc tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_atan(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact, tbl_index;
+ floatx80 fp0, fp1, fp2, fp3, xsave;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ a = packFloatx80(aSign, piby2_exp, pi_sig);
+ float_raise(float_flag_inexact, status);
+ return floatx80_move(a, status);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ if (compact < 0x3FFB8000 || compact > 0x4002FFFF) {
+ /* |X| >= 16 or |X| < 1/16 */
+ if (compact > 0x3FFF8000) { /* |X| >= 16 */
+ if (compact > 0x40638000) { /* |X| > 2^(100) */
+ fp0 = packFloatx80(aSign, piby2_exp, pi_sig);
+ fp1 = packFloatx80(aSign, 0x0001, one_sig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_sub(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ fp0 = a;
+ fp1 = packFloatx80(1, one_exp, one_sig); /* -1 */
+ fp1 = floatx80_div(fp1, fp0, status); /* X' = -1/X */
+ xsave = fp1;
+ fp0 = floatx80_mul(fp1, fp1, status); /* Y = X'*X' */
+ fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
+ fp3 = float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
+ status); /* C5 */
+ fp2 = float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
+ status); /* C4 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* Z*C5 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* Z*C4 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBFC24924827107B8), status),
+ status); /* C3+Z*C5 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3FC999999996263E), status),
+ status); /* C2+Z*C4 */
+ fp1 = floatx80_mul(fp1, fp3, status); /* Z*(C3+Z*C5) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* Y*(C2+Z*C4) */
+ fp1 = floatx80_add(fp1, float64_to_floatx80(
+ make_float64(0xBFD5555555555536), status),
+ status); /* C1+Z*(C3+Z*C5) */
+ fp0 = floatx80_mul(fp0, xsave, status); /* X'*Y */
+ /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
+ fp1 = floatx80_add(fp1, fp2, status);
+ /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
+ fp0 = floatx80_mul(fp0, fp1, status);
+ fp0 = floatx80_add(fp0, xsave, status);
+ fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ } else { /* |X| < 1/16 */
+ if (compact < 0x3FD78000) { /* |X| < 2^(-40) */
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_move(a, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ fp0 = a;
+ xsave = a;
+ fp0 = floatx80_mul(fp0, fp0, status); /* Y = X*X */
+ fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
+ fp2 = float64_to_floatx80(make_float64(0x3FB344447F876989),
+ status); /* B6 */
+ fp3 = float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
+ status); /* B5 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* Z*B6 */
+ fp3 = floatx80_mul(fp3, fp1, status); /* Z*B5 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3FBC71C646940220), status),
+ status); /* B4+Z*B6 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0xBFC24924921872F9),
+ status), status); /* B3+Z*B5 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* Z*(B4+Z*B6) */
+ fp1 = floatx80_mul(fp1, fp3, status); /* Z*(B3+Z*B5) */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3FC9999999998FA9), status),
+ status); /* B2+Z*(B4+Z*B6) */
+ fp1 = floatx80_add(fp1, float64_to_floatx80(
+ make_float64(0xBFD5555555555555), status),
+ status); /* B1+Z*(B3+Z*B5) */
+ fp2 = floatx80_mul(fp2, fp0, status); /* Y*(B2+Z*(B4+Z*B6)) */
+ fp0 = floatx80_mul(fp0, xsave, status); /* X*Y */
+ /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
+ fp1 = floatx80_add(fp1, fp2, status);
+ /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
+ fp0 = floatx80_mul(fp0, fp1, status);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, xsave, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+ } else {
+ aSig &= LIT64(0xF800000000000000);
+ aSig |= LIT64(0x0400000000000000);
+ xsave = packFloatx80(aSign, aExp, aSig); /* F */
+ fp0 = a;
+ fp1 = a; /* X */
+ fp2 = packFloatx80(0, one_exp, one_sig); /* 1 */
+ fp1 = floatx80_mul(fp1, xsave, status); /* X*F */
+ fp0 = floatx80_sub(fp0, xsave, status); /* X-F */
+ fp1 = floatx80_add(fp1, fp2, status); /* 1 + X*F */
+ fp0 = floatx80_div(fp0, fp1, status); /* U = (X-F)/(1+X*F) */
+
+ tbl_index = compact;
+
+ tbl_index &= 0x7FFF0000;
+ tbl_index -= 0x3FFB0000;
+ tbl_index >>= 1;
+ tbl_index += compact & 0x00007800;
+ tbl_index >>= 11;
+
+ fp3 = atan_tbl[tbl_index];
+
+ fp3.high |= aSign ? 0x8000 : 0; /* ATAN(F) */
+
+ fp1 = floatx80_mul(fp0, fp0, status); /* V = U*U */
+ fp2 = float64_to_floatx80(make_float64(0xBFF6687E314987D8),
+ status); /* A3 */
+ fp2 = floatx80_add(fp2, fp1, status); /* A3+V */
+ fp2 = floatx80_mul(fp2, fp1, status); /* V*(A3+V) */
+ fp1 = floatx80_mul(fp1, fp0, status); /* U*V */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x4002AC6934A26DB3), status),
+ status); /* A2+V*(A3+V) */
+ fp1 = floatx80_mul(fp1, float64_to_floatx80(
+ make_float64(0xBFC2476F4E1DA28E), status),
+ status); /* A1+U*V */
+ fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */
+ fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, fp3, status); /* ATAN(X) */
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Arc sine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_asin(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact;
+ floatx80 fp0, fp1, fp2, one;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact >= 0x3FFF8000) { /* |X| >= 1 */
+ if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
+ float_raise(float_flag_inexact, status);
+ a = packFloatx80(aSign, piby2_exp, pi_sig);
+ return floatx80_move(a, status);
+ } else { /* |X| > 1 */
+ float_raise(float_flag_invalid, status);
+ return floatx80_default_nan(status);
+ }
+
+ } /* |X| < 1 */
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ one = packFloatx80(0, one_exp, one_sig);
+ fp0 = a;
+
+ fp1 = floatx80_sub(one, fp0, status); /* 1 - X */
+ fp2 = floatx80_add(one, fp0, status); /* 1 + X */
+ fp1 = floatx80_mul(fp2, fp1, status); /* (1+X)*(1-X) */
+ fp1 = floatx80_sqrt(fp1, status); /* SQRT((1+X)*(1-X)) */
+ fp0 = floatx80_div(fp0, fp1, status); /* X/SQRT((1+X)*(1-X)) */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_atan(fp0, status); /* ATAN(X/SQRT((1+X)*(1-X))) */
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+}
+
+/*----------------------------------------------------------------------------
+ | Arc cosine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_acos(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact;
+ floatx80 fp0, fp1, one;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ if (aExp == 0 && aSig == 0) {
+ float_raise(float_flag_inexact, status);
+ return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
+ piby2_exp, pi_sig, 0, status);
+ }
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact >= 0x3FFF8000) { /* |X| >= 1 */
+ if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
+ if (aSign) { /* X == -1 */
+ a = packFloatx80(0, pi_exp, pi_sig);
+ float_raise(float_flag_inexact, status);
+ return floatx80_move(a, status);
+ } else { /* X == +1 */
+ return packFloatx80(0, 0, 0);
+ }
+ } else { /* |X| > 1 */
+ float_raise(float_flag_invalid, status);
+ return floatx80_default_nan(status);
+ }
+ } /* |X| < 1 */
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ one = packFloatx80(0, one_exp, one_sig);
+ fp0 = a;
+
+ fp1 = floatx80_add(one, fp0, status); /* 1 + X */
+ fp0 = floatx80_sub(one, fp0, status); /* 1 - X */
+ fp0 = floatx80_div(fp0, fp1, status); /* (1-X)/(1+X) */
+ fp0 = floatx80_sqrt(fp0, status); /* SQRT((1-X)/(1+X)) */
+ fp0 = floatx80_atan(fp0, status); /* ATAN(SQRT((1-X)/(1+X))) */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, fp0, status); /* 2 * ATAN(SQRT((1-X)/(1+X))) */
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+}
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic arc tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_atanh(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact;
+ floatx80 fp0, fp1, fp2, one;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact >= 0x3FFF8000) { /* |X| >= 1 */
+ if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
+ float_raise(float_flag_divbyzero, status);
+ return packFloatx80(aSign, floatx80_infinity.high,
+ floatx80_infinity.low);
+ } else { /* |X| > 1 */
+ float_raise(float_flag_invalid, status);
+ return floatx80_default_nan(status);
+ }
+ } /* |X| < 1 */
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ one = packFloatx80(0, one_exp, one_sig);
+ fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */
+ fp0 = packFloatx80(0, aExp, aSig); /* Y = |X| */
+ fp1 = packFloatx80(1, aExp, aSig); /* -Y */
+ fp0 = floatx80_add(fp0, fp0, status); /* 2Y */
+ fp1 = floatx80_add(fp1, one, status); /* 1-Y */
+ fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */
+ fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_mul(fp0, fp2,
+ status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+}
+
+/*----------------------------------------------------------------------------
+ | e to x minus 1
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact, n, j, m, m1;
+ floatx80 fp0, fp1, fp2, fp3, l2, sc, onebysc;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ if (aSign) {
+ return packFloatx80(aSign, one_exp, one_sig);
+ }
+ return packFloatx80(0, floatx80_infinity.high,
+ floatx80_infinity.low);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ if (aExp >= 0x3FFD) { /* |X| >= 1/4 */
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact <= 0x4004C215) { /* |X| <= 70 log2 */
+ fp0 = a;
+ fp1 = a;
+ fp0 = floatx80_mul(fp0, float32_to_floatx80(
+ make_float32(0x42B8AA3B), status),
+ status); /* 64/log2 * X */
+ n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
+ fp0 = int32_to_floatx80(n, status);
+
+ j = n & 0x3F; /* J = N mod 64 */
+ m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
+ if (n < 0 && j) {
+ /* arithmetic right shift is division and
+ * round towards minus infinity
+ */
+ m--;
+ }
+ m1 = -m;
+ /*m += 0x3FFF; // biased exponent of 2^(M) */
+ /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
+
+ fp2 = fp0; /* N */
+ fp0 = floatx80_mul(fp0, float32_to_floatx80(
+ make_float32(0xBC317218), status),
+ status); /* N * L1, L1 = lead(-log2/64) */
+ l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
+ fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
+ fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
+ fp0 = floatx80_add(fp0, fp2, status); /* R */
+
+ fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
+ fp2 = float32_to_floatx80(make_float32(0x3950097B),
+ status); /* A6 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A6 */
+ fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
+ status), fp1, status); /* fp3 is S*A5 */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3F81111111174385), status),
+ status); /* fp2 IS A4+S*A6 */
+ fp3 = floatx80_add(fp3, float64_to_floatx80(
+ make_float64(0x3FA5555555554F5A), status),
+ status); /* fp3 is A3+S*A5 */
+ fp2 = floatx80_mul(fp2, fp1, status); /* fp2 IS S*(A4+S*A6) */
+ fp3 = floatx80_mul(fp3, fp1, status); /* fp3 IS S*(A3+S*A5) */
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3FC5555555555555), status),
+ status); /* fp2 IS A2+S*(A4+S*A6) */
+ fp3 = floatx80_add(fp3, float32_to_floatx80(
+ make_float32(0x3F000000), status),
+ status); /* fp3 IS A1+S*(A3+S*A5) */
+ fp2 = floatx80_mul(fp2, fp1,
+ status); /* fp2 IS S*(A2+S*(A4+S*A6)) */
+ fp1 = floatx80_mul(fp1, fp3,
+ status); /* fp1 IS S*(A1+S*(A3+S*A5)) */
+ fp2 = floatx80_mul(fp2, fp0,
+ status); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
+ fp0 = floatx80_add(fp0, fp1,
+ status); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
+ fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
+
+ fp0 = floatx80_mul(fp0, exp_tbl[j],
+ status); /* 2^(J/64)*(Exp(R)-1) */
+
+ if (m >= 64) {
+ fp1 = float32_to_floatx80(exp_tbl2[j], status);
+ onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
+ fp1 = floatx80_add(fp1, onebysc, status);
+ fp0 = floatx80_add(fp0, fp1, status);
+ fp0 = floatx80_add(fp0, exp_tbl[j], status);
+ } else if (m < -3) {
+ fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
+ status), status);
+ fp0 = floatx80_add(fp0, exp_tbl[j], status);
+ onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
+ fp0 = floatx80_add(fp0, onebysc, status);
+ } else { /* -3 <= m <= 63 */
+ fp1 = exp_tbl[j];
+ fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
+ status), status);
+ onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
+ fp1 = floatx80_add(fp1, onebysc, status);
+ fp0 = floatx80_add(fp0, fp1, status);
+ }
+
+ sc = packFloatx80(0, m + 0x3FFF, one_sig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_mul(fp0, sc, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else { /* |X| > 70 log2 */
+ if (aSign) {
+ fp0 = float32_to_floatx80(make_float32(0xBF800000),
+ status); /* -1 */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, float32_to_floatx80(
+ make_float32(0x00800000), status),
+ status); /* -1 + 2^(-126) */
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ return floatx80_etox(a, status);
+ }
+ }
+ } else { /* |X| < 1/4 */
+ if (aExp >= 0x3FBE) {
+ fp0 = a;
+ fp0 = floatx80_mul(fp0, fp0, status); /* S = X*X */
+ fp1 = float32_to_floatx80(make_float32(0x2F30CAA8),
+ status); /* B12 */
+ fp1 = floatx80_mul(fp1, fp0, status); /* S * B12 */
+ fp2 = float32_to_floatx80(make_float32(0x310F8290),
+ status); /* B11 */
+ fp1 = floatx80_add(fp1, float32_to_floatx80(
+ make_float32(0x32D73220), status),
+ status); /* B10 */
+ fp2 = floatx80_mul(fp2, fp0, status);
+ fp1 = floatx80_mul(fp1, fp0, status);
+ fp2 = floatx80_add(fp2, float32_to_floatx80(
+ make_float32(0x3493F281), status),
+ status); /* B9 */
+ fp1 = floatx80_add(fp1, float64_to_floatx80(
+ make_float64(0x3EC71DE3A5774682), status),
+ status); /* B8 */
+ fp2 = floatx80_mul(fp2, fp0, status);
+ fp1 = floatx80_mul(fp1, fp0, status);
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3EFA01A019D7CB68), status),
+ status); /* B7 */
+ fp1 = floatx80_add(fp1, float64_to_floatx80(
+ make_float64(0x3F2A01A01A019DF3), status),
+ status); /* B6 */
+ fp2 = floatx80_mul(fp2, fp0, status);
+ fp1 = floatx80_mul(fp1, fp0, status);
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3F56C16C16C170E2), status),
+ status); /* B5 */
+ fp1 = floatx80_add(fp1, float64_to_floatx80(
+ make_float64(0x3F81111111111111), status),
+ status); /* B4 */
+ fp2 = floatx80_mul(fp2, fp0, status);
+ fp1 = floatx80_mul(fp1, fp0, status);
+ fp2 = floatx80_add(fp2, float64_to_floatx80(
+ make_float64(0x3FA5555555555555), status),
+ status); /* B3 */
+ fp3 = packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
+ fp1 = floatx80_add(fp1, fp3, status); /* B2 */
+ fp2 = floatx80_mul(fp2, fp0, status);
+ fp1 = floatx80_mul(fp1, fp0, status);
+
+ fp2 = floatx80_mul(fp2, fp0, status);
+ fp1 = floatx80_mul(fp1, a, status);
+
+ fp0 = floatx80_mul(fp0, float32_to_floatx80(
+ make_float32(0x3F000000), status),
+ status); /* S*B1 */
+ fp1 = floatx80_add(fp1, fp2, status); /* Q */
+ fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, a, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else { /* |X| < 2^(-65) */
+ sc = packFloatx80(1, 1, one_sig);
+ fp0 = a;
+
+ if (aExp < 0x0033) { /* |X| < 2^(-16382) */
+ fp0 = floatx80_mul(fp0, float64_to_floatx80(
+ make_float64(0x48B0000000000000), status),
+ status);
+ fp0 = floatx80_add(fp0, sc, status);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_mul(fp0, float64_to_floatx80(
+ make_float64(0x3730000000000000), status),
+ status);
+ } else {
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, sc, status);
+ }
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_tanh(floatx80 a, float_status *status)
+{
+ flag aSign, vSign;
+ int32_t aExp, vExp;
+ uint64_t aSig, vSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact;
+ floatx80 fp0, fp1;
+ uint32_t sign;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ return packFloatx80(aSign, one_exp, one_sig);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
+ /* TANHBORS */
+ if (compact < 0x3FFF8000) {
+ /* TANHSM */
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_move(a, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ if (compact > 0x40048AA1) {
+ /* TANHHUGE */
+ sign = 0x3F800000;
+ sign |= aSign ? 0x80000000 : 0x00000000;
+ fp0 = float32_to_floatx80(make_float32(sign), status);
+ sign &= 0x80000000;
+ sign ^= 0x80800000; /* -SIGN(X)*EPS */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign),
+ status), status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ } else {
+ fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
+ fp0 = floatx80_etox(fp0, status); /* FP0 IS EXP(Y) */
+ fp0 = floatx80_add(fp0, float32_to_floatx80(
+ make_float32(0x3F800000),
+ status), status); /* EXP(Y)+1 */
+ sign = aSign ? 0x80000000 : 0x00000000;
+ fp1 = floatx80_div(float32_to_floatx80(make_float32(
+ sign ^ 0xC0000000), status), fp0,
+ status); /* -SIGN(X)*2 / [EXP(Y)+1] */
+ fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000),
+ status); /* SIGN */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp1, fp0, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+ } else { /* 2**(-40) < |X| < (5/2)LOG2 */
+ fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
+ fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
+ fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x40000000),
+ status),
+ status); /* Z+2 */
+
+ vSign = extractFloatx80Sign(fp1);
+ vExp = extractFloatx80Exp(fp1);
+ vSig = extractFloatx80Frac(fp1);
+
+ fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_div(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic sine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_sinh(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact;
+ floatx80 fp0, fp1, fp2;
+ float32 fact;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ return packFloatx80(aSign, floatx80_infinity.high,
+ floatx80_infinity.low);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact > 0x400CB167) {
+ /* SINHBIG */
+ if (compact > 0x400CB2B3) {
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ return roundAndPackFloatx80(status->floatx80_rounding_precision,
+ aSign, 0x8000, aSig, 0, status);
+ } else {
+ fp0 = floatx80_abs(a); /* Y = |X| */
+ fp0 = floatx80_sub(fp0, float64_to_floatx80(
+ make_float64(0x40C62D38D3D64634), status),
+ status); /* (|X|-16381LOG2_LEAD) */
+ fp0 = floatx80_sub(fp0, float64_to_floatx80(
+ make_float64(0x3D6F90AEB1E75CC7), status),
+ status); /* |X| - 16381 LOG2, ACCURATE */
+ fp0 = floatx80_etox(fp0, status);
+ fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_mul(fp0, fp2, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ } else { /* |X| < 16380 LOG2 */
+ fp0 = floatx80_abs(a); /* Y = |X| */
+ fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
+ fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
+ status), status); /* 1+Z */
+ fp2 = fp0;
+ fp0 = floatx80_div(fp0, fp1, status); /* Z/(1+Z) */
+ fp0 = floatx80_add(fp0, fp2, status);
+
+ fact = packFloat32(aSign, 0x7E, 0);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic cosine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_cosh(floatx80 a, float_status *status)
+{
+ int32_t aExp;
+ uint64_t aSig;
+
+ int8_t user_rnd_mode, user_rnd_prec;
+
+ int32_t compact;
+ floatx80 fp0, fp1;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaNOneArg(a, status);
+ }
+ return packFloatx80(0, floatx80_infinity.high,
+ floatx80_infinity.low);
+ }
+
+ if (aExp == 0 && aSig == 0) {
+ return packFloatx80(0, one_exp, one_sig);
+ }
+
+ user_rnd_mode = status->float_rounding_mode;
+ user_rnd_prec = status->floatx80_rounding_precision;
+ status->float_rounding_mode = float_round_nearest_even;
+ status->floatx80_rounding_precision = 80;
+
+ compact = floatx80_make_compact(aExp, aSig);
+
+ if (compact > 0x400CB167) {
+ if (compact > 0x400CB2B3) {
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+ return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
+ 0x8000, one_sig, 0, status);
+ } else {
+ fp0 = packFloatx80(0, aExp, aSig);
+ fp0 = floatx80_sub(fp0, float64_to_floatx80(
+ make_float64(0x40C62D38D3D64634), status),
+ status);
+ fp0 = floatx80_sub(fp0, float64_to_floatx80(
+ make_float64(0x3D6F90AEB1E75CC7), status),
+ status);
+ fp0 = floatx80_etox(fp0, status);
+ fp1 = packFloatx80(0, 0x7FFB, one_sig);
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_mul(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+ }
+ }
+
+ fp0 = packFloatx80(0, aExp, aSig); /* |X| */
+ fp0 = floatx80_etox(fp0, status); /* EXP(|X|) */
+ fp0 = floatx80_mul(fp0, float32_to_floatx80(make_float32(0x3F000000),
+ status), status); /* (1/2)*EXP(|X|) */
+ fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */
+ fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */
+
+ status->float_rounding_mode = user_rnd_mode;
+ status->floatx80_rounding_precision = user_rnd_prec;
+
+ a = floatx80_add(fp0, fp1, status);
+
+ float_raise(float_flag_inexact, status);
+
+ return a;
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index d28e49fe9f..602661d5a8 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -34,4 +34,15 @@ floatx80 floatx80_log2(floatx80 a, float_status *status);
floatx80 floatx80_etox(floatx80 a, float_status *status);
floatx80 floatx80_twotox(floatx80 a, float_status *status);
floatx80 floatx80_tentox(floatx80 a, float_status *status);
+floatx80 floatx80_tan(floatx80 a, float_status *status);
+floatx80 floatx80_sin(floatx80 a, float_status *status);
+floatx80 floatx80_cos(floatx80 a, float_status *status);
+floatx80 floatx80_atan(floatx80 a, float_status *status);
+floatx80 floatx80_asin(floatx80 a, float_status *status);
+floatx80 floatx80_acos(floatx80 a, float_status *status);
+floatx80 floatx80_atanh(floatx80 a, float_status *status);
+floatx80 floatx80_etoxm1(floatx80 a, float_status *status);
+floatx80 floatx80_tanh(floatx80 a, float_status *status);
+floatx80 floatx80_sinh(floatx80 a, float_status *status);
+floatx80 floatx80_cosh(floatx80 a, float_status *status);
#endif
diff --git a/target/m68k/softfloat_fpsp_tables.h b/target/m68k/softfloat_fpsp_tables.h
index dd76dc0373..3f1419ee6e 100644
--- a/target/m68k/softfloat_fpsp_tables.h
+++ b/target/m68k/softfloat_fpsp_tables.h
@@ -371,4 +371,271 @@ static const uint32_t exp2_tbl2[64] = {
0xBFBDBF4A, 0x3FBEC01A, 0x3FBE8CAC, 0xBFBCBB3F,
0x3FBEF73A, 0xBFB8B795, 0x3FBEF84B, 0xBFBEF581
};
+
+static const floatx80 pi_tbl[65] = {
+ make_floatx80_init(0xC004, 0xC90FDAA22168C235),
+ make_floatx80_init(0xC004, 0xC2C75BCD105D7C23),
+ make_floatx80_init(0xC004, 0xBC7EDCF7FF523611),
+ make_floatx80_init(0xC004, 0xB6365E22EE46F000),
+ make_floatx80_init(0xC004, 0xAFEDDF4DDD3BA9EE),
+ make_floatx80_init(0xC004, 0xA9A56078CC3063DD),
+ make_floatx80_init(0xC004, 0xA35CE1A3BB251DCB),
+ make_floatx80_init(0xC004, 0x9D1462CEAA19D7B9),
+ make_floatx80_init(0xC004, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0xC004, 0x9083652488034B96),
+ make_floatx80_init(0xC004, 0x8A3AE64F76F80584),
+ make_floatx80_init(0xC004, 0x83F2677A65ECBF73),
+ make_floatx80_init(0xC003, 0xFB53D14AA9C2F2C2),
+ make_floatx80_init(0xC003, 0xEEC2D3A087AC669F),
+ make_floatx80_init(0xC003, 0xE231D5F66595DA7B),
+ make_floatx80_init(0xC003, 0xD5A0D84C437F4E58),
+ make_floatx80_init(0xC003, 0xC90FDAA22168C235),
+ make_floatx80_init(0xC003, 0xBC7EDCF7FF523611),
+ make_floatx80_init(0xC003, 0xAFEDDF4DDD3BA9EE),
+ make_floatx80_init(0xC003, 0xA35CE1A3BB251DCB),
+ make_floatx80_init(0xC003, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0xC003, 0x8A3AE64F76F80584),
+ make_floatx80_init(0xC002, 0xFB53D14AA9C2F2C2),
+ make_floatx80_init(0xC002, 0xE231D5F66595DA7B),
+ make_floatx80_init(0xC002, 0xC90FDAA22168C235),
+ make_floatx80_init(0xC002, 0xAFEDDF4DDD3BA9EE),
+ make_floatx80_init(0xC002, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0xC001, 0xFB53D14AA9C2F2C2),
+ make_floatx80_init(0xC001, 0xC90FDAA22168C235),
+ make_floatx80_init(0xC001, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0xC000, 0xC90FDAA22168C235),
+ make_floatx80_init(0xBFFF, 0xC90FDAA22168C235),
+ make_floatx80_init(0x0000, 0x0000000000000000),
+ make_floatx80_init(0x3FFF, 0xC90FDAA22168C235),
+ make_floatx80_init(0x4000, 0xC90FDAA22168C235),
+ make_floatx80_init(0x4001, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0x4001, 0xC90FDAA22168C235),
+ make_floatx80_init(0x4001, 0xFB53D14AA9C2F2C2),
+ make_floatx80_init(0x4002, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0x4002, 0xAFEDDF4DDD3BA9EE),
+ make_floatx80_init(0x4002, 0xC90FDAA22168C235),
+ make_floatx80_init(0x4002, 0xE231D5F66595DA7B),
+ make_floatx80_init(0x4002, 0xFB53D14AA9C2F2C2),
+ make_floatx80_init(0x4003, 0x8A3AE64F76F80584),
+ make_floatx80_init(0x4003, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0x4003, 0xA35CE1A3BB251DCB),
+ make_floatx80_init(0x4003, 0xAFEDDF4DDD3BA9EE),
+ make_floatx80_init(0x4003, 0xBC7EDCF7FF523611),
+ make_floatx80_init(0x4003, 0xC90FDAA22168C235),
+ make_floatx80_init(0x4003, 0xD5A0D84C437F4E58),
+ make_floatx80_init(0x4003, 0xE231D5F66595DA7B),
+ make_floatx80_init(0x4003, 0xEEC2D3A087AC669F),
+ make_floatx80_init(0x4003, 0xFB53D14AA9C2F2C2),
+ make_floatx80_init(0x4004, 0x83F2677A65ECBF73),
+ make_floatx80_init(0x4004, 0x8A3AE64F76F80584),
+ make_floatx80_init(0x4004, 0x9083652488034B96),
+ make_floatx80_init(0x4004, 0x96CBE3F9990E91A8),
+ make_floatx80_init(0x4004, 0x9D1462CEAA19D7B9),
+ make_floatx80_init(0x4004, 0xA35CE1A3BB251DCB),
+ make_floatx80_init(0x4004, 0xA9A56078CC3063DD),
+ make_floatx80_init(0x4004, 0xAFEDDF4DDD3BA9EE),
+ make_floatx80_init(0x4004, 0xB6365E22EE46F000),
+ make_floatx80_init(0x4004, 0xBC7EDCF7FF523611),
+ make_floatx80_init(0x4004, 0xC2C75BCD105D7C23),
+ make_floatx80_init(0x4004, 0xC90FDAA22168C235)
+};
+
+static const float32 pi_tbl2[65] = {
+ const_float32(0x21800000),
+ const_float32(0xA0D00000),
+ const_float32(0xA1E80000),
+ const_float32(0x21480000),
+ const_float32(0xA1200000),
+ const_float32(0x21FC0000),
+ const_float32(0x21100000),
+ const_float32(0xA1580000),
+ const_float32(0x21E00000),
+ const_float32(0x20B00000),
+ const_float32(0xA1880000),
+ const_float32(0x21C40000),
+ const_float32(0x20000000),
+ const_float32(0x21380000),
+ const_float32(0xA1300000),
+ const_float32(0x9FC00000),
+ const_float32(0x21000000),
+ const_float32(0xA1680000),
+ const_float32(0xA0A00000),
+ const_float32(0x20900000),
+ const_float32(0x21600000),
+ const_float32(0xA1080000),
+ const_float32(0x1F800000),
+ const_float32(0xA0B00000),
+ const_float32(0x20800000),
+ const_float32(0xA0200000),
+ const_float32(0x20E00000),
+ const_float32(0x1F000000),
+ const_float32(0x20000000),
+ const_float32(0x20600000),
+ const_float32(0x1F800000),
+ const_float32(0x1F000000),
+ const_float32(0x00000000),
+ const_float32(0x9F000000),
+ const_float32(0x9F800000),
+ const_float32(0xA0600000),
+ const_float32(0xA0000000),
+ const_float32(0x9F000000),
+ const_float32(0xA0E00000),
+ const_float32(0x20200000),
+ const_float32(0xA0800000),
+ const_float32(0x20B00000),
+ const_float32(0x9F800000),
+ const_float32(0x21080000),
+ const_float32(0xA1600000),
+ const_float32(0xA0900000),
+ const_float32(0x20A00000),
+ const_float32(0x21680000),
+ const_float32(0xA1000000),
+ const_float32(0x1FC00000),
+ const_float32(0x21300000),
+ const_float32(0xA1380000),
+ const_float32(0xA0000000),
+ const_float32(0xA1C40000),
+ const_float32(0x21880000),
+ const_float32(0xA0B00000),
+ const_float32(0xA1E00000),
+ const_float32(0x21580000),
+ const_float32(0xA1100000),
+ const_float32(0xA1FC0000),
+ const_float32(0x21200000),
+ const_float32(0xA1480000),
+ const_float32(0x21E80000),
+ const_float32(0x20D00000),
+ const_float32(0xA1800000),
+};
+
+static const floatx80 atan_tbl[128] = {
+ make_floatx80_init(0x3FFB, 0x83D152C5060B7A51),
+ make_floatx80_init(0x3FFB, 0x8BC8544565498B8B),
+ make_floatx80_init(0x3FFB, 0x93BE406017626B0D),
+ make_floatx80_init(0x3FFB, 0x9BB3078D35AEC202),
+ make_floatx80_init(0x3FFB, 0xA3A69A525DDCE7DE),
+ make_floatx80_init(0x3FFB, 0xAB98E94362765619),
+ make_floatx80_init(0x3FFB, 0xB389E502F9C59862),
+ make_floatx80_init(0x3FFB, 0xBB797E436B09E6FB),
+ make_floatx80_init(0x3FFB, 0xC367A5C739E5F446),
+ make_floatx80_init(0x3FFB, 0xCB544C61CFF7D5C6),
+ make_floatx80_init(0x3FFB, 0xD33F62F82488533E),
+ make_floatx80_init(0x3FFB, 0xDB28DA8162404C77),
+ make_floatx80_init(0x3FFB, 0xE310A4078AD34F18),
+ make_floatx80_init(0x3FFB, 0xEAF6B0A8188EE1EB),
+ make_floatx80_init(0x3FFB, 0xF2DAF1949DBE79D5),
+ make_floatx80_init(0x3FFB, 0xFABD581361D47E3E),
+ make_floatx80_init(0x3FFC, 0x8346AC210959ECC4),
+ make_floatx80_init(0x3FFC, 0x8B232A08304282D8),
+ make_floatx80_init(0x3FFC, 0x92FB70B8D29AE2F9),
+ make_floatx80_init(0x3FFC, 0x9ACF476F5CCD1CB4),
+ make_floatx80_init(0x3FFC, 0xA29E76304954F23F),
+ make_floatx80_init(0x3FFC, 0xAA68C5D08AB85230),
+ make_floatx80_init(0x3FFC, 0xB22DFFFD9D539F83),
+ make_floatx80_init(0x3FFC, 0xB9EDEF453E900EA5),
+ make_floatx80_init(0x3FFC, 0xC1A85F1CC75E3EA5),
+ make_floatx80_init(0x3FFC, 0xC95D1BE828138DE6),
+ make_floatx80_init(0x3FFC, 0xD10BF300840D2DE4),
+ make_floatx80_init(0x3FFC, 0xD8B4B2BA6BC05E7A),
+ make_floatx80_init(0x3FFC, 0xE0572A6BB42335F6),
+ make_floatx80_init(0x3FFC, 0xE7F32A70EA9CAA8F),
+ make_floatx80_init(0x3FFC, 0xEF88843264ECEFAA),
+ make_floatx80_init(0x3FFC, 0xF7170A28ECC06666),
+ make_floatx80_init(0x3FFD, 0x812FD288332DAD32),
+ make_floatx80_init(0x3FFD, 0x88A8D1B1218E4D64),
+ make_floatx80_init(0x3FFD, 0x9012AB3F23E4AEE8),
+ make_floatx80_init(0x3FFD, 0x976CC3D411E7F1B9),
+ make_floatx80_init(0x3FFD, 0x9EB689493889A227),
+ make_floatx80_init(0x3FFD, 0xA5EF72C34487361B),
+ make_floatx80_init(0x3FFD, 0xAD1700BAF07A7227),
+ make_floatx80_init(0x3FFD, 0xB42CBCFAFD37EFB7),
+ make_floatx80_init(0x3FFD, 0xBB303A940BA80F89),
+ make_floatx80_init(0x3FFD, 0xC22115C6FCAEBBAF),
+ make_floatx80_init(0x3FFD, 0xC8FEF3E686331221),
+ make_floatx80_init(0x3FFD, 0xCFC98330B4000C70),
+ make_floatx80_init(0x3FFD, 0xD6807AA1102C5BF9),
+ make_floatx80_init(0x3FFD, 0xDD2399BC31252AA3),
+ make_floatx80_init(0x3FFD, 0xE3B2A8556B8FC517),
+ make_floatx80_init(0x3FFD, 0xEA2D764F64315989),
+ make_floatx80_init(0x3FFD, 0xF3BF5BF8BAD1A21D),
+ make_floatx80_init(0x3FFE, 0x801CE39E0D205C9A),
+ make_floatx80_init(0x3FFE, 0x8630A2DADA1ED066),
+ make_floatx80_init(0x3FFE, 0x8C1AD445F3E09B8C),
+ make_floatx80_init(0x3FFE, 0x91DB8F1664F350E2),
+ make_floatx80_init(0x3FFE, 0x97731420365E538C),
+ make_floatx80_init(0x3FFE, 0x9CE1C8E6A0B8CDBA),
+ make_floatx80_init(0x3FFE, 0xA22832DBCADAAE09),
+ make_floatx80_init(0x3FFE, 0xA746F2DDB7602294),
+ make_floatx80_init(0x3FFE, 0xAC3EC0FB997DD6A2),
+ make_floatx80_init(0x3FFE, 0xB110688AEBDC6F6A),
+ make_floatx80_init(0x3FFE, 0xB5BCC49059ECC4B0),
+ make_floatx80_init(0x3FFE, 0xBA44BC7DD470782F),
+ make_floatx80_init(0x3FFE, 0xBEA94144FD049AAC),
+ make_floatx80_init(0x3FFE, 0xC2EB4ABB661628B6),
+ make_floatx80_init(0x3FFE, 0xC70BD54CE602EE14),
+ make_floatx80_init(0x3FFE, 0xCD000549ADEC7159),
+ make_floatx80_init(0x3FFE, 0xD48457D2D8EA4EA3),
+ make_floatx80_init(0x3FFE, 0xDB948DA712DECE3B),
+ make_floatx80_init(0x3FFE, 0xE23855F969E8096A),
+ make_floatx80_init(0x3FFE, 0xE8771129C4353259),
+ make_floatx80_init(0x3FFE, 0xEE57C16E0D379C0D),
+ make_floatx80_init(0x3FFE, 0xF3E10211A87C3779),
+ make_floatx80_init(0x3FFE, 0xF919039D758B8D41),
+ make_floatx80_init(0x3FFE, 0xFE058B8F64935FB3),
+ make_floatx80_init(0x3FFF, 0x8155FB497B685D04),
+ make_floatx80_init(0x3FFF, 0x83889E3549D108E1),
+ make_floatx80_init(0x3FFF, 0x859CFA76511D724B),
+ make_floatx80_init(0x3FFF, 0x87952ECFFF8131E7),
+ make_floatx80_init(0x3FFF, 0x89732FD19557641B),
+ make_floatx80_init(0x3FFF, 0x8B38CAD101932A35),
+ make_floatx80_init(0x3FFF, 0x8CE7A8D8301EE6B5),
+ make_floatx80_init(0x3FFF, 0x8F46A39E2EAE5281),
+ make_floatx80_init(0x3FFF, 0x922DA7D791888487),
+ make_floatx80_init(0x3FFF, 0x94D19FCBDEDF5241),
+ make_floatx80_init(0x3FFF, 0x973AB94419D2A08B),
+ make_floatx80_init(0x3FFF, 0x996FF00E08E10B96),
+ make_floatx80_init(0x3FFF, 0x9B773F9512321DA7),
+ make_floatx80_init(0x3FFF, 0x9D55CC320F935624),
+ make_floatx80_init(0x3FFF, 0x9F100575006CC571),
+ make_floatx80_init(0x3FFF, 0xA0A9C290D97CC06C),
+ make_floatx80_init(0x3FFF, 0xA22659EBEBC0630A),
+ make_floatx80_init(0x3FFF, 0xA388B4AFF6EF0EC9),
+ make_floatx80_init(0x3FFF, 0xA4D35F1061D292C4),
+ make_floatx80_init(0x3FFF, 0xA60895DCFBE3187E),
+ make_floatx80_init(0x3FFF, 0xA72A51DC7367BEAC),
+ make_floatx80_init(0x3FFF, 0xA83A51530956168F),
+ make_floatx80_init(0x3FFF, 0xA93A20077539546E),
+ make_floatx80_init(0x3FFF, 0xAA9E7245023B2605),
+ make_floatx80_init(0x3FFF, 0xAC4C84BA6FE4D58F),
+ make_floatx80_init(0x3FFF, 0xADCE4A4A606B9712),
+ make_floatx80_init(0x3FFF, 0xAF2A2DCD8D263C9C),
+ make_floatx80_init(0x3FFF, 0xB0656F81F22265C7),
+ make_floatx80_init(0x3FFF, 0xB18465150F71496A),
+ make_floatx80_init(0x3FFF, 0xB28AAA156F9ADA35),
+ make_floatx80_init(0x3FFF, 0xB37B44FF3766B895),
+ make_floatx80_init(0x3FFF, 0xB458C3DCE9630433),
+ make_floatx80_init(0x3FFF, 0xB525529D562246BD),
+ make_floatx80_init(0x3FFF, 0xB5E2CCA95F9D88CC),
+ make_floatx80_init(0x3FFF, 0xB692CADA7ACA1ADA),
+ make_floatx80_init(0x3FFF, 0xB736AEA7A6925838),
+ make_floatx80_init(0x3FFF, 0xB7CFAB287E9F7B36),
+ make_floatx80_init(0x3FFF, 0xB85ECC66CB219835),
+ make_floatx80_init(0x3FFF, 0xB8E4FD5A20A593DA),
+ make_floatx80_init(0x3FFF, 0xB99F41F64AFF9BB5),
+ make_floatx80_init(0x3FFF, 0xBA7F1E17842BBE7B),
+ make_floatx80_init(0x3FFF, 0xBB4712857637E17D),
+ make_floatx80_init(0x3FFF, 0xBBFABE8A4788DF6F),
+ make_floatx80_init(0x3FFF, 0xBC9D0FAD2B689D79),
+ make_floatx80_init(0x3FFF, 0xBD306A39471ECD86),
+ make_floatx80_init(0x3FFF, 0xBDB6C731856AF18A),
+ make_floatx80_init(0x3FFF, 0xBE31CAC502E80D70),
+ make_floatx80_init(0x3FFF, 0xBEA2D55CE33194E2),
+ make_floatx80_init(0x3FFF, 0xBF0B10B7C03128F0),
+ make_floatx80_init(0x3FFF, 0xBF6B7A18DACB778D),
+ make_floatx80_init(0x3FFF, 0xBFC4EA4663FA18F6),
+ make_floatx80_init(0x3FFF, 0xC0181BDE8B89A454),
+ make_floatx80_init(0x3FFF, 0xC065B066CFBF6439),
+ make_floatx80_init(0x3FFF, 0xC0AE345F56340AE6),
+ make_floatx80_init(0x3FFF, 0xC0F222919CB9E6A7)
+};
#endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 6d5bde0777..cef6f663ad 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5042,6 +5042,9 @@ DISAS_INSN(fpu)
case 1: /* fint */
gen_helper_firound(cpu_env, cpu_dest, cpu_src);
break;
+ case 2: /* fsinh */
+ gen_helper_fsinh(cpu_env, cpu_dest, cpu_src);
+ break;
case 3: /* fintrz */
gen_helper_fitrunc(cpu_env, cpu_dest, cpu_src);
break;
@@ -5057,6 +5060,24 @@ DISAS_INSN(fpu)
case 0x06: /* flognp1 */
gen_helper_flognp1(cpu_env, cpu_dest, cpu_src);
break;
+ case 0x09: /* ftanh */
+ gen_helper_ftanh(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x0a: /* fatan */
+ gen_helper_fatan(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x0c: /* fasin */
+ gen_helper_fasin(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x0d: /* fatanh */
+ gen_helper_fatanh(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x0e: /* fsin */
+ gen_helper_fsin(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x0f: /* ftan */
+ gen_helper_ftan(cpu_env, cpu_dest, cpu_src);
+ break;
case 0x10: /* fetox */
gen_helper_fetox(cpu_env, cpu_dest, cpu_src);
break;
@@ -5084,6 +5105,9 @@ DISAS_INSN(fpu)
case 0x5c: /* fdabs */
gen_helper_fdabs(cpu_env, cpu_dest, cpu_src);
break;
+ case 0x19: /* fcosh */
+ gen_helper_fcosh(cpu_env, cpu_dest, cpu_src);
+ break;
case 0x1a: /* fneg */
gen_helper_fneg(cpu_env, cpu_dest, cpu_src);
break;
@@ -5093,6 +5117,12 @@ DISAS_INSN(fpu)
case 0x5e: /* fdneg */
gen_helper_fdneg(cpu_env, cpu_dest, cpu_src);
break;
+ case 0x1c: /* facos */
+ gen_helper_facos(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x1d: /* fcos */
+ gen_helper_fcos(cpu_env, cpu_dest, cpu_src);
+ break;
case 0x1e: /* fgetexp */
gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src);
break;
@@ -5150,6 +5180,14 @@ DISAS_INSN(fpu)
case 0x6c: /* fdsub */
gen_helper_fdsub(cpu_env, cpu_dest, cpu_src, cpu_dest);
break;
+ case 0x30: case 0x31: case 0x32:
+ case 0x33: case 0x34: case 0x35:
+ case 0x36: case 0x37: {
+ TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0));
+ gen_helper_fsincos(cpu_env, cpu_dest, cpu_dest2, cpu_src);
+ tcg_temp_free_ptr(cpu_dest2);
+ }
+ break;
case 0x38: /* fcmp */
gen_helper_fcmp(cpu_env, cpu_src, cpu_dest);
return;
diff --git a/tests/.gitignore b/tests/.gitignore
index 18e58b2183..fb62d2299b 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -86,6 +86,7 @@ test-thread-pool
test-throttle
test-timed-average
test-uuid
+test-util-sockets
test-visitor-serialization
test-vmstate
test-write-threshold
diff --git a/tests/Makefile.include b/tests/Makefile.include
index ef9b88c369..42fd426cd0 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -146,6 +146,7 @@ ifneq (,$(findstring qemu-ga,$(TOOLS)))
check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF)
endif
check-unit-y += tests/test-timed-average$(EXESUF)
+check-unit-y += tests/test-util-sockets$(EXESUF)
check-unit-y += tests/test-io-task$(EXESUF)
check-unit-y += tests/test-io-channel-socket$(EXESUF)
check-unit-y += tests/test-io-channel-file$(EXESUF)
@@ -713,9 +714,11 @@ 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/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)
tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \
- tests/io-channel-helpers.o $(test-io-obj-y)
+ tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y)
tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y)
tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y)
tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 994a35a332..a00004319e 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -2,7 +2,7 @@ FROM fedora:27
ENV PACKAGES \
ccache gettext git tar PyYAML sparse flex bison python3 bzip2 hostname \
glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \
- gcc gcc-c++ clang make perl which bc findutils libaio-devel \
+ gcc gcc-c++ llvm clang make perl which bc findutils libaio-devel \
nettle-devel libasan libubsan \
mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config \
mingw32-gtk2 mingw32-gtk3 mingw32-gnutls mingw32-nettle mingw32-libtasn1 \
diff --git a/tests/docker/test-debug b/tests/docker/test-debug
index d020b06917..d3f9f70d01 100755
--- a/tests/docker/test-debug
+++ b/tests/docker/test-debug
@@ -1,6 +1,6 @@
#!/bin/bash -e
#
-# Compile and check with clang & --enable-debug.
+# Compile and check with clang & --enable-debug --enable-sanitizers.
#
# Copyright (c) 2016-2018 Red Hat Inc.
#
@@ -19,8 +19,8 @@ requires clang asan
cd "$BUILD_DIR"
OPTS="--cxx=clang++ --cc=clang --host-cc=clang"
-OPTS="--enable-debug $OPTS"
+OPTS="--enable-debug --enable-sanitizers $OPTS"
build_qemu $OPTS
-make $MAKEFLAGS check
+make $MAKEFLAGS V=1 check
install_qemu
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 22445d9ec2..7470c6b754 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -204,6 +204,11 @@ static bool query_is_blacklisted(const char *cmd)
"query-gic-capabilities", /* arm */
/* Success depends on target-specific build configuration: */
"query-pci", /* CONFIG_PCI */
+ /* Success depends on launching SEV guest */
+ "query-sev-launch-measure",
+ /* Success depends on Host or Hypervisor SEV support */
+ "query-sev",
+ "query-sev-capabilities",
NULL
};
int i;
diff --git a/tests/socket-helpers.c b/tests/socket-helpers.c
new file mode 100644
index 0000000000..8112763f5b
--- /dev/null
+++ b/tests/socket-helpers.c
@@ -0,0 +1,149 @@
+/*
+ * Helper functions for tests using sockets
+ *
+ * Copyright 2015-2018 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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 "qemu/sockets.h"
+#include "socket-helpers.h"
+
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+#ifndef EAI_ADDRFAMILY
+# define EAI_ADDRFAMILY 0
+#endif
+
+int socket_can_bind_connect(const char *hostname)
+{
+ int lfd = -1, cfd = -1, afd = -1;
+ struct addrinfo ai, *res = NULL;
+ struct sockaddr_storage ss;
+ socklen_t sslen = sizeof(ss);
+ int soerr;
+ socklen_t soerrlen = sizeof(soerr);
+ bool check_soerr = false;
+ int rc;
+ int ret = -1;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+ ai.ai_family = AF_UNSPEC;
+ ai.ai_socktype = SOCK_STREAM;
+
+ /* lookup */
+ rc = getaddrinfo(hostname, NULL, &ai, &res);
+ if (rc != 0) {
+ if (rc == EAI_ADDRFAMILY ||
+ rc == EAI_FAMILY) {
+ errno = EADDRNOTAVAIL;
+ } else {
+ errno = EINVAL;
+ }
+ goto cleanup;
+ }
+
+ lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (lfd < 0) {
+ goto cleanup;
+ }
+
+ cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (cfd < 0) {
+ goto cleanup;
+ }
+
+ if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) {
+ goto cleanup;
+ }
+
+ if (listen(lfd, 1) < 0) {
+ goto cleanup;
+ }
+
+ if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) {
+ goto cleanup;
+ }
+
+ qemu_set_nonblock(cfd);
+ if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) {
+ if (errno == EINPROGRESS) {
+ check_soerr = true;
+ } else {
+ goto cleanup;
+ }
+ }
+
+ sslen = sizeof(ss);
+ afd = accept(lfd, (struct sockaddr *)&ss, &sslen);
+ if (afd < 0) {
+ goto cleanup;
+ }
+
+ if (check_soerr) {
+ if (qemu_getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) < 0) {
+ goto cleanup;
+ }
+ if (soerr) {
+ errno = soerr;
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (afd != -1) {
+ close(afd);
+ }
+ if (cfd != -1) {
+ close(cfd);
+ }
+ if (lfd != -1) {
+ close(lfd);
+ }
+ if (res) {
+ freeaddrinfo(res);
+ }
+ return ret;
+}
+
+
+int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
+{
+ *has_ipv4 = *has_ipv6 = false;
+
+ if (socket_can_bind_connect("127.0.0.1") < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ return -1;
+ }
+ } else {
+ *has_ipv4 = true;
+ }
+
+ if (socket_can_bind_connect("::1") < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ return -1;
+ }
+ } else {
+ *has_ipv6 = true;
+ }
+
+ return 0;
+}
diff --git a/tests/socket-helpers.h b/tests/socket-helpers.h
new file mode 100644
index 0000000000..1c07d6d656
--- /dev/null
+++ b/tests/socket-helpers.h
@@ -0,0 +1,42 @@
+/*
+ * Helper functions for tests using sockets
+ *
+ * Copyright 2015-2018 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * @hostname: a DNS name or numeric IP address
+ *
+ * Check whether it is possible to bind & connect to ports
+ * on the DNS name or IP address @hostname. If an IP address
+ * is used, it must not be a wildcard address.
+ *
+ * Returns 0 on success, -1 on error with errno set
+ */
+int socket_can_bind_connect(const char *hostname);
+
+/*
+ * @has_ipv4: set to true on return if IPv4 is available
+ * @has_ipv6: set to true on return if IPv6 is available
+ *
+ * Check whether IPv4 and/or IPv6 are available for use.
+ * On success, @has_ipv4 and @has_ipv6 will be set to
+ * indicate whether the respective protocols are available.
+ *
+ * Returns 0 on success, -1 on fatal error
+ */
+int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6);
diff --git a/tests/test-char.c b/tests/test-char.c
index c731313098..df939cc5c4 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -301,9 +301,8 @@ static int socket_can_read_hello(void *opaque)
return 10;
}
-static void char_socket_test(void)
+static void char_socket_test_common(Chardev *chr)
{
- Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
Chardev *chr_client;
QObject *addr;
QDict *qdict;
@@ -358,6 +357,47 @@ static void char_socket_test(void)
object_unparent(OBJECT(chr));
}
+
+static void char_socket_basic_test(void)
+{
+ Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
+
+ char_socket_test_common(chr);
+}
+
+
+static void char_socket_fdpass_test(void)
+{
+ Chardev *chr;
+ char *optstr;
+ QemuOpts *opts;
+ int fd;
+ SocketAddress *addr = g_new0(SocketAddress, 1);
+
+ addr->type = SOCKET_ADDRESS_TYPE_INET;
+ addr->u.inet.host = g_strdup("127.0.0.1");
+ addr->u.inet.port = g_strdup("0");
+
+ fd = socket_listen(addr, &error_abort);
+ g_assert(fd >= 0);
+
+ qapi_free_SocketAddress(addr);
+
+ optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
+
+ opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
+ optstr, true);
+ g_free(optstr);
+ g_assert_nonnull(opts);
+
+ chr = qemu_chr_new_from_opts(opts, &error_abort);
+
+ qemu_opts_del(opts);
+
+ char_socket_test_common(chr);
+}
+
+
#ifndef _WIN32
static void char_pipe_test(void)
{
@@ -774,7 +814,8 @@ int main(int argc, char **argv)
#ifndef _WIN32
g_test_add_func("/char/file-fifo", char_file_fifo_test);
#endif
- g_test_add_func("/char/socket", char_socket_test);
+ g_test_add_func("/char/socket/basic", char_socket_basic_test);
+ g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
g_test_add_func("/char/udp", char_udp_test);
#ifdef HAVE_CHARDEV_SERIAL
g_test_add_func("/char/serial", char_serial_test);
diff --git a/tests/test-cutils.c b/tests/test-cutils.c
index f64a49b7fb..64a489c2e9 100644
--- a/tests/test-cutils.c
+++ b/tests/test-cutils.c
@@ -223,6 +223,583 @@ static void test_parse_uint_full_correct(void)
g_assert_cmpint(i, ==, 123);
}
+static void test_qemu_strtoi_correct(void)
+{
+ const char *str = "12345 foo";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 12345);
+ g_assert(endptr == str + 5);
+}
+
+static void test_qemu_strtoi_null(void)
+{
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(NULL, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == NULL);
+}
+
+static void test_qemu_strtoi_empty(void)
+{
+ const char *str = "";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtoi_whitespace(void)
+{
+ const char *str = " \t ";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtoi_invalid(void)
+{
+ const char *str = " xxxx \t abc";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtoi_trailing(void)
+{
+ const char *str = "123xxx";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 123);
+ g_assert(endptr == str + 3);
+}
+
+static void test_qemu_strtoi_octal(void)
+{
+ const char *str = "0123";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 8, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0123);
+ g_assert(endptr == str + strlen(str));
+
+ res = 999;
+ endptr = &f;
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoi_decimal(void)
+{
+ const char *str = "0123";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 10, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 123);
+ g_assert(endptr == str + strlen(str));
+
+ str = "123";
+ res = 999;
+ endptr = &f;
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoi_hex(void)
+{
+ const char *str = "0123";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 16, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0x123);
+ g_assert(endptr == str + strlen(str));
+
+ str = "0x123";
+ res = 999;
+ endptr = &f;
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0x123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoi_max(void)
+{
+ char *str = g_strdup_printf("%d", INT_MAX);
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, INT_MAX);
+ g_assert(endptr == str + strlen(str));
+ g_free(str);
+}
+
+static void test_qemu_strtoi_overflow(void)
+{
+ char *str = g_strdup_printf("%lld", (long long)INT_MAX + 1ll);
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert_cmpint(res, ==, INT_MAX);
+ g_assert(endptr == str + strlen(str));
+ g_free(str);
+}
+
+static void test_qemu_strtoi_underflow(void)
+{
+ char *str = g_strdup_printf("%lld", (long long)INT_MIN - 1ll);
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert_cmpint(res, ==, INT_MIN);
+ g_assert(endptr == str + strlen(str));
+ g_free(str);
+}
+
+static void test_qemu_strtoi_negative(void)
+{
+ const char *str = " \t -321";
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, -321);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoi_full_correct(void)
+{
+ const char *str = "123";
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 123);
+}
+
+static void test_qemu_strtoi_full_null(void)
+{
+ char f = 'X';
+ const char *endptr = &f;
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(NULL, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == NULL);
+}
+
+static void test_qemu_strtoi_full_empty(void)
+{
+ const char *str = "";
+ int res = 999L;
+ int err;
+
+ err = qemu_strtoi(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+}
+
+static void test_qemu_strtoi_full_negative(void)
+{
+ const char *str = " \t -321";
+ int res = 999;
+ int err;
+
+ err = qemu_strtoi(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, -321);
+}
+
+static void test_qemu_strtoi_full_trailing(void)
+{
+ const char *str = "123xxx";
+ int res;
+ int err;
+
+ err = qemu_strtoi(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+}
+
+static void test_qemu_strtoi_full_max(void)
+{
+ char *str = g_strdup_printf("%d", INT_MAX);
+ int res;
+ int err;
+
+ err = qemu_strtoi(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, INT_MAX);
+ g_free(str);
+}
+
+static void test_qemu_strtoui_correct(void)
+{
+ const char *str = "12345 foo";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 12345);
+ g_assert(endptr == str + 5);
+}
+
+static void test_qemu_strtoui_null(void)
+{
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(NULL, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == NULL);
+}
+
+static void test_qemu_strtoui_empty(void)
+{
+ const char *str = "";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtoui_whitespace(void)
+{
+ const char *str = " \t ";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtoui_invalid(void)
+{
+ const char *str = " xxxx \t abc";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtoui_trailing(void)
+{
+ const char *str = "123xxx";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 123);
+ g_assert(endptr == str + 3);
+}
+
+static void test_qemu_strtoui_octal(void)
+{
+ const char *str = "0123";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 8, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 0123);
+ g_assert(endptr == str + strlen(str));
+
+ res = 999;
+ endptr = &f;
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 0123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoui_decimal(void)
+{
+ const char *str = "0123";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 10, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 123);
+ g_assert(endptr == str + strlen(str));
+
+ str = "123";
+ res = 999;
+ endptr = &f;
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoui_hex(void)
+{
+ const char *str = "0123";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 16, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmphex(res, ==, 0x123);
+ g_assert(endptr == str + strlen(str));
+
+ str = "0x123";
+ res = 999;
+ endptr = &f;
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmphex(res, ==, 0x123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoui_max(void)
+{
+ char *str = g_strdup_printf("%u", UINT_MAX);
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmphex(res, ==, UINT_MAX);
+ g_assert(endptr == str + strlen(str));
+ g_free(str);
+}
+
+static void test_qemu_strtoui_overflow(void)
+{
+ char *str = g_strdup_printf("%lld", (long long)UINT_MAX + 1ll);
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert_cmphex(res, ==, UINT_MAX);
+ g_assert(endptr == str + strlen(str));
+ g_free(str);
+}
+
+static void test_qemu_strtoui_underflow(void)
+{
+ char *str = g_strdup_printf("%lld", (long long)INT_MIN - 1ll);
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert_cmpuint(res, ==, (unsigned int)-1);
+ g_assert(endptr == str + strlen(str));
+ g_free(str);
+}
+
+static void test_qemu_strtoui_negative(void)
+{
+ const char *str = " \t -321";
+ char f = 'X';
+ const char *endptr = &f;
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, &endptr, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, (unsigned int)-321);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_qemu_strtoui_full_correct(void)
+{
+ const char *str = "123";
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, 123);
+}
+
+static void test_qemu_strtoui_full_null(void)
+{
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(NULL, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+}
+
+static void test_qemu_strtoui_full_empty(void)
+{
+ const char *str = "";
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+}
+static void test_qemu_strtoui_full_negative(void)
+{
+ const char *str = " \t -321";
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, NULL, 0, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpuint(res, ==, (unsigned int)-321);
+}
+
+static void test_qemu_strtoui_full_trailing(void)
+{
+ const char *str = "123xxx";
+ unsigned int res;
+ int err;
+
+ err = qemu_strtoui(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, -EINVAL);
+}
+
+static void test_qemu_strtoui_full_max(void)
+{
+ char *str = g_strdup_printf("%u", UINT_MAX);
+ unsigned int res = 999;
+ int err;
+
+ err = qemu_strtoui(str, NULL, 0, &res);
+
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmphex(res, ==, UINT_MAX);
+ g_free(str);
+}
+
static void test_qemu_strtol_correct(void)
{
const char *str = "12345 foo";
@@ -1612,6 +2189,86 @@ int main(int argc, char **argv)
g_test_add_func("/cutils/parse_uint_full/correct",
test_parse_uint_full_correct);
+ /* qemu_strtoi() tests */
+ g_test_add_func("/cutils/qemu_strtoi/correct",
+ test_qemu_strtoi_correct);
+ g_test_add_func("/cutils/qemu_strtoi/null",
+ test_qemu_strtoi_null);
+ g_test_add_func("/cutils/qemu_strtoi/empty",
+ test_qemu_strtoi_empty);
+ g_test_add_func("/cutils/qemu_strtoi/whitespace",
+ test_qemu_strtoi_whitespace);
+ g_test_add_func("/cutils/qemu_strtoi/invalid",
+ test_qemu_strtoi_invalid);
+ g_test_add_func("/cutils/qemu_strtoi/trailing",
+ test_qemu_strtoi_trailing);
+ g_test_add_func("/cutils/qemu_strtoi/octal",
+ test_qemu_strtoi_octal);
+ g_test_add_func("/cutils/qemu_strtoi/decimal",
+ test_qemu_strtoi_decimal);
+ g_test_add_func("/cutils/qemu_strtoi/hex",
+ test_qemu_strtoi_hex);
+ g_test_add_func("/cutils/qemu_strtoi/max",
+ test_qemu_strtoi_max);
+ g_test_add_func("/cutils/qemu_strtoi/overflow",
+ test_qemu_strtoi_overflow);
+ g_test_add_func("/cutils/qemu_strtoi/underflow",
+ test_qemu_strtoi_underflow);
+ g_test_add_func("/cutils/qemu_strtoi/negative",
+ test_qemu_strtoi_negative);
+ g_test_add_func("/cutils/qemu_strtoi_full/correct",
+ test_qemu_strtoi_full_correct);
+ g_test_add_func("/cutils/qemu_strtoi_full/null",
+ test_qemu_strtoi_full_null);
+ g_test_add_func("/cutils/qemu_strtoi_full/empty",
+ test_qemu_strtoi_full_empty);
+ g_test_add_func("/cutils/qemu_strtoi_full/negative",
+ test_qemu_strtoi_full_negative);
+ g_test_add_func("/cutils/qemu_strtoi_full/trailing",
+ test_qemu_strtoi_full_trailing);
+ g_test_add_func("/cutils/qemu_strtoi_full/max",
+ test_qemu_strtoi_full_max);
+
+ /* qemu_strtoui() tests */
+ g_test_add_func("/cutils/qemu_strtoui/correct",
+ test_qemu_strtoui_correct);
+ g_test_add_func("/cutils/qemu_strtoui/null",
+ test_qemu_strtoui_null);
+ g_test_add_func("/cutils/qemu_strtoui/empty",
+ test_qemu_strtoui_empty);
+ g_test_add_func("/cutils/qemu_strtoui/whitespace",
+ test_qemu_strtoui_whitespace);
+ g_test_add_func("/cutils/qemu_strtoui/invalid",
+ test_qemu_strtoui_invalid);
+ g_test_add_func("/cutils/qemu_strtoui/trailing",
+ test_qemu_strtoui_trailing);
+ g_test_add_func("/cutils/qemu_strtoui/octal",
+ test_qemu_strtoui_octal);
+ g_test_add_func("/cutils/qemu_strtoui/decimal",
+ test_qemu_strtoui_decimal);
+ g_test_add_func("/cutils/qemu_strtoui/hex",
+ test_qemu_strtoui_hex);
+ g_test_add_func("/cutils/qemu_strtoui/max",
+ test_qemu_strtoui_max);
+ g_test_add_func("/cutils/qemu_strtoui/overflow",
+ test_qemu_strtoui_overflow);
+ g_test_add_func("/cutils/qemu_strtoui/underflow",
+ test_qemu_strtoui_underflow);
+ g_test_add_func("/cutils/qemu_strtoui/negative",
+ test_qemu_strtoui_negative);
+ g_test_add_func("/cutils/qemu_strtoui_full/correct",
+ test_qemu_strtoui_full_correct);
+ g_test_add_func("/cutils/qemu_strtoui_full/null",
+ test_qemu_strtoui_full_null);
+ g_test_add_func("/cutils/qemu_strtoui_full/empty",
+ test_qemu_strtoui_full_empty);
+ g_test_add_func("/cutils/qemu_strtoui_full/negative",
+ test_qemu_strtoui_full_negative);
+ g_test_add_func("/cutils/qemu_strtoui_full/trailing",
+ test_qemu_strtoui_full_trailing);
+ g_test_add_func("/cutils/qemu_strtoui_full/max",
+ test_qemu_strtoui_full_max);
+
/* qemu_strtol() tests */
g_test_add_func("/cutils/qemu_strtol/correct",
test_qemu_strtol_correct);
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index b273fd3ba2..0597213f93 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -22,77 +22,9 @@
#include "io/channel-socket.h"
#include "io/channel-util.h"
#include "io-channel-helpers.h"
+#include "socket-helpers.h"
#include "qapi/error.h"
-#ifndef AI_ADDRCONFIG
-# define AI_ADDRCONFIG 0
-#endif
-#ifndef EAI_ADDRFAMILY
-# define EAI_ADDRFAMILY 0
-#endif
-
-static int check_bind(const char *hostname, bool *has_proto)
-{
- int fd = -1;
- struct addrinfo ai, *res = NULL;
- int rc;
- int ret = -1;
-
- memset(&ai, 0, sizeof(ai));
- ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
- ai.ai_family = AF_UNSPEC;
- ai.ai_socktype = SOCK_STREAM;
-
- /* lookup */
- rc = getaddrinfo(hostname, NULL, &ai, &res);
- if (rc != 0) {
- if (rc == EAI_ADDRFAMILY ||
- rc == EAI_FAMILY) {
- *has_proto = false;
- goto done;
- }
- goto cleanup;
- }
-
- fd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd < 0) {
- goto cleanup;
- }
-
- if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
- if (errno == EADDRNOTAVAIL) {
- *has_proto = false;
- goto done;
- }
- goto cleanup;
- }
-
- *has_proto = true;
- done:
- ret = 0;
-
- cleanup:
- if (fd != -1) {
- close(fd);
- }
- if (res) {
- freeaddrinfo(res);
- }
- return ret;
-}
-
-static int check_protocol_support(bool *has_ipv4, bool *has_ipv6)
-{
- if (check_bind("127.0.0.1", has_ipv4) < 0) {
- return -1;
- }
- if (check_bind("::1", has_ipv6) < 0) {
- return -1;
- }
-
- return 0;
-}
-
static void test_io_channel_set_socket_bufs(QIOChannel *src,
QIOChannel *dst)
@@ -566,7 +498,7 @@ int main(int argc, char **argv)
* each protocol to avoid breaking tests on machines
* with either IPv4 or IPv6 disabled.
*/
- if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
+ if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
return 1;
}
diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c
new file mode 100644
index 0000000000..acadd85e8f
--- /dev/null
+++ b/tests/test-util-sockets.c
@@ -0,0 +1,266 @@
+/*
+ * Tests for util/qemu-sockets.c
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/sockets.h"
+#include "qapi/error.h"
+#include "socket-helpers.h"
+#include "monitor/monitor.h"
+
+static void test_fd_is_socket_bad(void)
+{
+ char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX");
+ int fd = mkstemp(tmp);
+ if (fd != 0) {
+ unlink(tmp);
+ }
+ g_free(tmp);
+
+ g_assert(fd >= 0);
+
+ g_assert(!fd_is_socket(fd));
+ close(fd);
+}
+
+static void test_fd_is_socket_good(void)
+{
+ int fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
+
+ g_assert(fd >= 0);
+
+ g_assert(fd_is_socket(fd));
+ close(fd);
+}
+
+static int mon_fd = -1;
+static const char *mon_fdname;
+
+int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
+{
+ g_assert(cur_mon);
+ g_assert(mon == cur_mon);
+ if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) {
+ error_setg(errp, "No fd named %s", fdname);
+ return -1;
+ }
+ return dup(mon_fd);
+}
+
+/* Syms in libqemustub.a are discarded at .o file granularity.
+ * To replace monitor_get_fd() we must ensure everything in
+ * stubs/monitor.c is defined, to make sure monitor.o is discarded
+ * otherwise we get duplicate syms at link time.
+ */
+Monitor *cur_mon;
+void monitor_init(Chardev *chr, int flags) {}
+
+
+static void test_socket_fd_pass_name_good(void)
+{
+ SocketAddress addr;
+ int fd;
+
+ cur_mon = g_malloc(1); /* Fake a monitor */
+ mon_fdname = "myfd";
+ mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0);
+ g_assert_cmpint(mon_fd, >, STDERR_FILENO);
+
+ addr.type = SOCKET_ADDRESS_TYPE_FD;
+ addr.u.fd.str = g_strdup(mon_fdname);
+
+ fd = socket_connect(&addr, &error_abort);
+ g_assert_cmpint(fd, !=, -1);
+ g_assert_cmpint(fd, !=, mon_fd);
+ close(fd);
+
+ fd = socket_listen(&addr, &error_abort);
+ g_assert_cmpint(fd, !=, -1);
+ g_assert_cmpint(fd, !=, mon_fd);
+ close(fd);
+
+ g_free(addr.u.fd.str);
+ mon_fdname = NULL;
+ close(mon_fd);
+ mon_fd = -1;
+ g_free(cur_mon);
+ cur_mon = NULL;
+}
+
+static void test_socket_fd_pass_name_bad(void)
+{
+ SocketAddress addr;
+ Error *err = NULL;
+ int fd;
+
+ cur_mon = g_malloc(1); /* Fake a monitor */
+ mon_fdname = "myfd";
+ mon_fd = dup(STDOUT_FILENO);
+ g_assert_cmpint(mon_fd, >, STDERR_FILENO);
+
+ addr.type = SOCKET_ADDRESS_TYPE_FD;
+ addr.u.fd.str = g_strdup(mon_fdname);
+
+ fd = socket_connect(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ fd = socket_listen(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ g_free(addr.u.fd.str);
+ mon_fdname = NULL;
+ close(mon_fd);
+ mon_fd = -1;
+ g_free(cur_mon);
+ cur_mon = NULL;
+}
+
+static void test_socket_fd_pass_name_nomon(void)
+{
+ SocketAddress addr;
+ Error *err = NULL;
+ int fd;
+
+ g_assert(cur_mon == NULL);
+
+ addr.type = SOCKET_ADDRESS_TYPE_FD;
+ addr.u.fd.str = g_strdup("myfd");
+
+ fd = socket_connect(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ fd = socket_listen(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ g_free(addr.u.fd.str);
+}
+
+
+static void test_socket_fd_pass_num_good(void)
+{
+ SocketAddress addr;
+ int fd, sfd;
+
+ g_assert(cur_mon == NULL);
+ sfd = qemu_socket(AF_INET, SOCK_STREAM, 0);
+ g_assert_cmpint(sfd, >, STDERR_FILENO);
+
+ addr.type = SOCKET_ADDRESS_TYPE_FD;
+ addr.u.fd.str = g_strdup_printf("%d", sfd);
+
+ fd = socket_connect(&addr, &error_abort);
+ g_assert_cmpint(fd, ==, sfd);
+
+ fd = socket_listen(&addr, &error_abort);
+ g_assert_cmpint(fd, ==, sfd);
+
+ g_free(addr.u.fd.str);
+ close(sfd);
+}
+
+static void test_socket_fd_pass_num_bad(void)
+{
+ SocketAddress addr;
+ Error *err = NULL;
+ int fd, sfd;
+
+ g_assert(cur_mon == NULL);
+ sfd = dup(STDOUT_FILENO);
+
+ addr.type = SOCKET_ADDRESS_TYPE_FD;
+ addr.u.fd.str = g_strdup_printf("%d", sfd);
+
+ fd = socket_connect(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ fd = socket_listen(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ g_free(addr.u.fd.str);
+ close(sfd);
+}
+
+static void test_socket_fd_pass_num_nocli(void)
+{
+ SocketAddress addr;
+ Error *err = NULL;
+ int fd;
+
+ cur_mon = g_malloc(1); /* Fake a monitor */
+
+ addr.type = SOCKET_ADDRESS_TYPE_FD;
+ addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO);
+
+ fd = socket_connect(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ fd = socket_listen(&addr, &err);
+ g_assert_cmpint(fd, ==, -1);
+ error_free_or_abort(&err);
+
+ g_free(addr.u.fd.str);
+}
+
+
+int main(int argc, char **argv)
+{
+ bool has_ipv4, has_ipv6;
+
+ socket_init();
+
+ g_test_init(&argc, &argv, NULL);
+
+ /* We're creating actual IPv4/6 sockets, so we should
+ * check if the host running tests actually supports
+ * each protocol to avoid breaking tests on machines
+ * with either IPv4 or IPv6 disabled.
+ */
+ if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
+ return 1;
+ }
+
+ if (has_ipv4) {
+ g_test_add_func("/util/socket/is-socket/bad",
+ test_fd_is_socket_bad);
+ g_test_add_func("/util/socket/is-socket/good",
+ test_fd_is_socket_good);
+ g_test_add_func("/socket/fd-pass/name/good",
+ test_socket_fd_pass_name_good);
+ g_test_add_func("/socket/fd-pass/name/bad",
+ test_socket_fd_pass_name_bad);
+ g_test_add_func("/socket/fd-pass/name/nomon",
+ test_socket_fd_pass_name_nomon);
+ g_test_add_func("/socket/fd-pass/num/good",
+ test_socket_fd_pass_num_good);
+ g_test_add_func("/socket/fd-pass/num/bad",
+ test_socket_fd_pass_num_bad);
+ g_test_add_func("/socket/fd-pass/num/nocli",
+ test_socket_fd_pass_num_nocli);
+ }
+
+ return g_test_run();
+}
diff --git a/trace-events b/trace-events
index 89fcad0fd1..855b0ab240 100644
--- a/trace-events
+++ b/trace-events
@@ -68,9 +68,9 @@ memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned siz
memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
-flatview_new(FlatView *view, MemoryRegion *root) "%p (root %p)"
-flatview_destroy(FlatView *view, MemoryRegion *root) "%p (root %p)"
-flatview_destroy_rcu(FlatView *view, MemoryRegion *root) "%p (root %p)"
+flatview_new(void *view, void *root) "%p (root %p)"
+flatview_destroy(void *view, void *root) "%p (root %p)"
+flatview_destroy_rcu(void *view, void *root) "%p (root %p)"
# gdbstub.c
gdbstub_op_start(const char *device) "Starting gdbstub using device %s"
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index dcd54a5287..cc784346cb 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -38,26 +38,27 @@ common-obj-$(CONFIG_GTK) += gtk.mo
gtk.mo-objs := gtk.o
gtk.mo-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
gtk.mo-libs := $(GTK_LIBS) $(VTE_LIBS)
+ifeq ($(CONFIG_OPENGL),y)
+gtk.mo-objs += gtk-egl.o
+gtk.mo-libs += $(OPENGL_LIBS)
+ifeq ($(CONFIG_GTK_GL),y)
+gtk.mo-objs += gtk-gl-area.o
+endif
+endif
common-obj-$(CONFIG_CURSES) += curses.mo
curses.mo-objs := curses.o
curses.mo-cflags := $(CURSES_CFLAGS)
curses.mo-libs := $(CURSES_LIBS)
-ifeq ($(CONFIG_OPENGL),y)
-common-obj-y += shader.o
-common-obj-y += console-gl.o
-common-obj-y += egl-helpers.o
-common-obj-y += egl-context.o
+common-obj-$(CONFIG_OPENGL) += shader.o
+common-obj-$(CONFIG_OPENGL) += console-gl.o
+common-obj-$(CONFIG_OPENGL) += egl-helpers.o
+common-obj-$(CONFIG_OPENGL) += egl-context.o
common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o
-ifeq ($(CONFIG_GTK_GL),y)
-gtk.mo-objs += gtk-gl-area.o
-else
-gtk.mo-objs += gtk-egl.o
-gtk.mo-libs += $(OPENGL_LIBS)
-endif
-endif
shader.o-libs += $(OPENGL_LIBS)
console-gl.o-libs += $(OPENGL_LIBS)
egl-helpers.o-libs += $(OPENGL_LIBS)
+egl-context.o-libs += $(OPENGL_LIBS)
+egl-headless.o-libs += $(OPENGL_LIBS)
diff --git a/ui/console.c b/ui/console.c
index 6ab4ff3baf..530a491987 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -344,14 +344,28 @@ write_err:
goto out;
}
-void qmp_screendump(const char *filename, Error **errp)
+void qmp_screendump(const char *filename, bool has_device, const char *device,
+ bool has_head, int64_t head, Error **errp)
{
- QemuConsole *con = qemu_console_lookup_by_index(0);
+ QemuConsole *con;
DisplaySurface *surface;
- if (con == NULL) {
- error_setg(errp, "There is no QemuConsole I can screendump from.");
- return;
+ if (has_device) {
+ con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
+ errp);
+ if (!con) {
+ return;
+ }
+ } else {
+ if (has_head) {
+ error_setg(errp, "'head' must be specified together with 'device'");
+ return;
+ }
+ con = qemu_console_lookup_by_index(0);
+ if (!con) {
+ error_setg(errp, "There is no console to take a screendump from");
+ return;
+ }
}
graphic_hw_update(con);
@@ -1039,8 +1053,10 @@ void console_select(unsigned int index)
dcl->ops->dpy_gfx_switch(dcl, s->surface);
}
}
- dpy_gfx_update(s, 0, 0, surface_width(s->surface),
- surface_height(s->surface));
+ if (s->surface) {
+ dpy_gfx_update(s, 0, 0, surface_width(s->surface),
+ surface_height(s->surface));
+ }
}
if (ds->have_text) {
dpy_text_resize(s, s->width, s->height);
@@ -1266,11 +1282,16 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
s->console_type = console_type;
consoles = g_realloc(consoles, sizeof(*consoles) * (nb_consoles+1));
- if (console_type != GRAPHIC_CONSOLE) {
+ if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) {
s->index = nb_consoles;
consoles[nb_consoles++] = s;
} else {
- /* HACK: Put graphical consoles before text consoles. */
+ /*
+ * HACK: Put graphical consoles before text consoles.
+ *
+ * Only do that for coldplugged devices. After initial device
+ * initialization we will not renumber the consoles any more.
+ */
for (i = nb_consoles; i > 0; i--) {
if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
break;
@@ -1370,8 +1391,8 @@ DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
return surface;
}
-static DisplaySurface *qemu_create_message_surface(int w, int h,
- const char *msg)
+DisplaySurface *qemu_create_message_surface(int w, int h,
+ const char *msg)
{
DisplaySurface *surface = qemu_create_displaysurface(w, h);
pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
@@ -1858,21 +1879,61 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
int height = 480;
QemuConsole *s;
DisplayState *ds;
+ DisplaySurface *surface;
ds = get_alloc_displaystate();
- trace_console_gfx_new();
- s = new_console(ds, GRAPHIC_CONSOLE, head);
- s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s);
+ s = qemu_console_lookup_unused();
+ if (s) {
+ trace_console_gfx_reuse(s->index);
+ if (s->surface) {
+ width = surface_width(s->surface);
+ height = surface_height(s->surface);
+ }
+ } else {
+ trace_console_gfx_new();
+ s = new_console(ds, GRAPHIC_CONSOLE, head);
+ s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ dpy_set_ui_info_timer, s);
+ }
graphic_console_set_hwops(s, hw_ops, opaque);
if (dev) {
object_property_set_link(OBJECT(s), OBJECT(dev), "device",
&error_abort);
}
- s->surface = qemu_create_message_surface(width, height, noinit);
+ surface = qemu_create_message_surface(width, height, noinit);
+ dpy_gfx_replace_surface(s, surface);
return s;
}
+static const GraphicHwOps unused_ops = {
+ /* no callbacks */
+};
+
+void graphic_console_close(QemuConsole *con)
+{
+ static const char unplugged[] =
+ "Guest display has been unplugged";
+ DisplaySurface *surface;
+ int width = 640;
+ int height = 480;
+
+ if (con->surface) {
+ width = surface_width(con->surface);
+ height = surface_height(con->surface);
+ }
+
+ trace_console_gfx_close(con->index);
+ object_property_set_link(OBJECT(con), NULL, "device", &error_abort);
+ graphic_console_set_hwops(con, &unused_ops, NULL);
+
+ if (con->gl) {
+ dpy_gl_scanout_disable(con);
+ }
+ surface = qemu_create_message_surface(width, height, unplugged);
+ dpy_gfx_replace_surface(con, surface);
+}
+
QemuConsole *qemu_console_lookup_by_index(unsigned int index)
{
if (index >= nb_consoles) {
@@ -1929,6 +1990,28 @@ QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
return con;
}
+QemuConsole *qemu_console_lookup_unused(void)
+{
+ Object *obj;
+ int i;
+
+ for (i = 0; i < nb_consoles; i++) {
+ if (!consoles[i]) {
+ continue;
+ }
+ if (consoles[i]->hw_ops != &unused_ops) {
+ continue;
+ }
+ obj = object_property_get_link(OBJECT(consoles[i]),
+ "device", &error_abort);
+ if (obj != NULL) {
+ continue;
+ }
+ return consoles[i];
+ }
+ return NULL;
+}
+
bool qemu_console_is_visible(QemuConsole *con)
{
return (con == active_console) || (con->dcls > 0);
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index eb86c26a1d..9390c6762e 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -19,6 +19,7 @@
#include "ui/console.h"
#include "ui/gtk.h"
#include "ui/egl-helpers.h"
+#include "ui/shader.h"
#include "sysemu/sysemu.h"
@@ -194,6 +195,58 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
backing_id, false);
}
+void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+#ifdef CONFIG_OPENGL_DMABUF
+ egl_dmabuf_import_texture(dmabuf);
+ if (!dmabuf->texture) {
+ return;
+ }
+
+ gd_egl_scanout_texture(dcl, dmabuf->texture,
+ false, dmabuf->width, dmabuf->height,
+ 0, 0, dmabuf->width, dmabuf->height);
+#endif
+}
+
+void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf, bool have_hot,
+ uint32_t hot_x, uint32_t hot_y)
+{
+#ifdef CONFIG_OPENGL_DMABUF
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+ if (dmabuf) {
+ egl_dmabuf_import_texture(dmabuf);
+ if (!dmabuf->texture) {
+ return;
+ }
+ egl_fb_setup_for_tex(&vc->gfx.cursor_fb, dmabuf->width, dmabuf->height,
+ dmabuf->texture, false);
+ } else {
+ egl_fb_destroy(&vc->gfx.cursor_fb);
+ }
+#endif
+}
+
+void gd_egl_cursor_position(DisplayChangeListener *dcl,
+ uint32_t pos_x, uint32_t pos_y)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+ vc->gfx.cursor_x = pos_x;
+ vc->gfx.cursor_y = pos_y;
+}
+
+void gd_egl_release_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+#ifdef CONFIG_OPENGL_DMABUF
+ egl_dmabuf_release_texture(dmabuf);
+#endif
+}
+
void gd_egl_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
@@ -214,7 +267,15 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
window = gtk_widget_get_window(vc->gfx.drawing_area);
gdk_drawable_get_size(window, &ww, &wh);
egl_fb_setup_default(&vc->gfx.win_fb, ww, wh);
- egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top);
+ if (vc->gfx.cursor_fb.texture) {
+ egl_texture_blit(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.guest_fb,
+ vc->gfx.y0_top);
+ egl_texture_blend(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.cursor_fb,
+ vc->gfx.y0_top,
+ vc->gfx.cursor_x, vc->gfx.cursor_y);
+ } else {
+ egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top);
+ }
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 563cff32b8..ef5bc42094 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -243,6 +243,8 @@ typedef struct VCChardev {
#define TYPE_CHARDEV_VC "chardev-vc"
#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
+bool gtk_use_gl_area;
+
static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
static void gd_ungrab_pointer(GtkDisplayState *s);
static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
@@ -453,7 +455,7 @@ static void gd_update_full_redraw(VirtualConsole *vc)
int ww, wh;
gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
#if defined(CONFIG_GTK_GL)
- if (vc->gfx.gls) {
+ if (vc->gfx.gls && gtk_use_gl_area) {
gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
return;
}
@@ -725,7 +727,7 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {
.dpy_gl_update = gd_gl_area_scanout_flush,
};
-#else
+#endif /* CONFIG_GTK_GL */
static const DisplayChangeListenerOps dcl_egl_ops = {
.dpy_name = "gtk-egl",
@@ -742,10 +744,13 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
.dpy_gl_ctx_get_current = qemu_egl_get_current_context,
.dpy_gl_scanout_disable = gd_egl_scanout_disable,
.dpy_gl_scanout_texture = gd_egl_scanout_texture,
+ .dpy_gl_scanout_dmabuf = gd_egl_scanout_dmabuf,
+ .dpy_gl_cursor_dmabuf = gd_egl_cursor_dmabuf,
+ .dpy_gl_cursor_position = gd_egl_cursor_position,
+ .dpy_gl_release_dmabuf = gd_egl_release_dmabuf,
.dpy_gl_update = gd_egl_scanout_flush,
};
-#endif /* CONFIG_GTK_GL */
#endif /* CONFIG_OPENGL */
/** QEMU Events **/
@@ -844,13 +849,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
#if defined(CONFIG_OPENGL)
if (vc->gfx.gls) {
-#if defined(CONFIG_GTK_GL)
- /* invoke render callback please */
- return FALSE;
-#else
- gd_egl_draw(vc);
- return TRUE;
-#endif
+ if (gtk_use_gl_area) {
+ /* invoke render callback please */
+ return FALSE;
+ } else {
+ gd_egl_draw(vc);
+ return TRUE;
+ }
}
#endif
@@ -1993,7 +1998,7 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
g_signal_connect(vc->gfx.drawing_area, "draw",
G_CALLBACK(gd_draw_event), vc);
#if defined(CONFIG_GTK_GL)
- if (display_opengl) {
+ if (gtk_use_gl_area) {
/* wire up GtkGlArea events */
g_signal_connect(vc->gfx.drawing_area, "render",
G_CALLBACK(gd_render_event), vc);
@@ -2116,26 +2121,29 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
#if defined(CONFIG_OPENGL)
if (display_opengl) {
#if defined(CONFIG_GTK_GL)
- vc->gfx.drawing_area = gtk_gl_area_new();
- vc->gfx.dcl.ops = &dcl_gl_area_ops;
-#else
- vc->gfx.drawing_area = gtk_drawing_area_new();
- /*
- * gtk_widget_set_double_buffered() was deprecated in 3.14.
- * It is required for opengl rendering on X11 though. A
- * proper replacement (native opengl support) is only
- * available in 3.16+. Silence the warning if possible.
- */
+ if (gtk_use_gl_area) {
+ vc->gfx.drawing_area = gtk_gl_area_new();
+ vc->gfx.dcl.ops = &dcl_gl_area_ops;
+ } else
+#endif /* CONFIG_GTK_GL */
+ {
+ vc->gfx.drawing_area = gtk_drawing_area_new();
+ /*
+ * gtk_widget_set_double_buffered() was deprecated in 3.14.
+ * It is required for opengl rendering on X11 though. A
+ * proper replacement (native opengl support) is only
+ * available in 3.16+. Silence the warning if possible.
+ */
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
- gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
+ gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
#pragma GCC diagnostic pop
#endif
- vc->gfx.dcl.ops = &dcl_egl_ops;
-#endif /* CONFIG_GTK_GL */
+ vc->gfx.dcl.ops = &dcl_egl_ops;
+ }
} else
#endif
{
@@ -2436,11 +2444,15 @@ static void early_gtk_display_init(DisplayOptions *opts)
assert(opts->type == DISPLAY_TYPE_GTK);
if (opts->has_gl && opts->gl) {
#if defined(CONFIG_OPENGL)
-#if defined(CONFIG_GTK_GL)
- gtk_gl_area_init();
-#else
- gtk_egl_init();
+#if defined(CONFIG_GTK_GL) && defined(GDK_WINDOWING_WAYLAND)
+ if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
+ gtk_use_gl_area = true;
+ gtk_gl_area_init();
+ }
#endif
+ {
+ gtk_egl_init();
+ }
#endif
}
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 6e591ab821..3e52abd92d 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -6,6 +6,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "ui/console.h"
+#include "standard-headers/drm/drm_fourcc.h"
PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
{
@@ -88,6 +89,27 @@ pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian)
return 0;
}
+/* Note: drm is little endian, pixman is native endian */
+pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format)
+{
+ static const struct {
+ uint32_t drm_format;
+ pixman_format_code_t pixman;
+ } map[] = {
+ { DRM_FORMAT_RGB888, PIXMAN_LE_r8g8b8 },
+ { DRM_FORMAT_ARGB8888, PIXMAN_LE_a8r8g8b8 },
+ { DRM_FORMAT_XRGB8888, PIXMAN_LE_x8r8g8b8 }
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(map); i++) {
+ if (drm_format == map[i].drm_format) {
+ return map[i].pixman;
+ }
+ }
+ return 0;
+}
+
int qemu_pixman_get_type(int rshift, int gshift, int bshift)
{
int type = PIXMAN_TYPE_OTHER;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 98ccdfb687..fe734821dd 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -26,20 +26,8 @@
#include "ui/spice-display.h"
-static int debug = 0;
bool spice_opengl;
-static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...)
-{
- va_list args;
-
- if (level <= debug) {
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- }
-}
-
int qemu_spice_rect_is_empty(const QXLRect* r)
{
return r->top == r->bottom || r->left == r->right;
@@ -322,8 +310,6 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
{
QXLDevMemSlot memslot;
- dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
-
memset(&memslot, 0, sizeof(memslot));
memslot.slot_group_id = MEMSLOT_GROUP_HOST;
memslot.virt_end = ~0;
@@ -347,10 +333,6 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
ssd->buf = g_malloc(ssd->bufsize);
}
- dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id,
- surface_width(ssd->ds), surface_height(ssd->ds),
- surface_size, ssd->bufsize);
-
surface.format = SPICE_SURFACE_FMT_32_xRGB;
surface.width = surface_width(ssd->ds);
surface.height = surface_height(ssd->ds);
@@ -366,8 +348,6 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
{
- dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
-
qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
}
@@ -389,8 +369,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
{
QXLRect update_area;
- dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__,
- ssd->qxl.id, x, y, w, h);
+ trace_qemu_spice_display_update(ssd->qxl.id, x, y, w, h);
update_area.left = x,
update_area.right = x + w;
update_area.top = y;
@@ -413,8 +392,10 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
surface_height(surface) == pixman_image_get_height(ssd->surface) &&
surface_format(surface) == pixman_image_get_format(ssd->surface)) {
/* no-resize fast path: just swap backing store */
- dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id,
- surface_width(surface), surface_height(surface));
+ trace_qemu_spice_display_surface(ssd->qxl.id,
+ surface_width(surface),
+ surface_height(surface),
+ true);
qemu_mutex_lock(&ssd->lock);
ssd->ds = surface;
pixman_image_unref(ssd->surface);
@@ -427,11 +408,10 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
}
/* full mode switch */
- dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id,
- ssd->surface ? pixman_image_get_width(ssd->surface) : 0,
- ssd->surface ? pixman_image_get_height(ssd->surface) : 0,
- surface ? surface_width(surface) : 0,
- surface ? surface_height(surface) : 0);
+ trace_qemu_spice_display_surface(ssd->qxl.id,
+ surface ? surface_width(surface) : 0,
+ surface ? surface_height(surface) : 0,
+ false);
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
if (ssd->surface) {
@@ -495,7 +475,6 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
{
- dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
graphic_hw_update(ssd->dcl.con);
qemu_mutex_lock(&ssd->lock);
@@ -505,10 +484,10 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
}
qemu_mutex_unlock(&ssd->lock);
+ trace_qemu_spice_display_refresh(ssd->qxl.id, ssd->notify);
if (ssd->notify) {
ssd->notify = 0;
qemu_spice_wakeup(ssd);
- dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id);
}
}
@@ -516,21 +495,17 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
{
- SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
-
- dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
+ /* nothing to do */
}
static void interface_set_compression_level(QXLInstance *sin, int level)
{
- dprint(1, "%s/%d:\n", __func__, sin->id);
/* nothing to do */
}
#if SPICE_NEEDS_SET_MM_TIME
static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
{
- dprint(3, "%s/%d:\n", __func__, sin->id);
/* nothing to do */
}
#endif
@@ -554,8 +529,6 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext)
SimpleSpiceUpdate *update;
int ret = false;
- dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
-
qemu_mutex_lock(&ssd->lock);
update = QTAILQ_FIRST(&ssd->updates);
if (update != NULL) {
@@ -570,7 +543,6 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext)
static int interface_req_cmd_notification(QXLInstance *sin)
{
- dprint(2, "%s/%d:\n", __func__, sin->id);
return 1;
}
@@ -582,7 +554,6 @@ static void interface_release_resource(QXLInstance *sin,
SimpleSpiceCursor *cursor;
QXLCommandExt *ext;
- dprint(2, "%s/%d:\n", __func__, ssd->qxl.id);
ext = (void *)(intptr_t)(rext.info->id);
switch (ext->cmd.type) {
case QXL_CMD_DRAW:
@@ -603,8 +574,6 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext)
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
int ret;
- dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
-
qemu_mutex_lock(&ssd->lock);
if (ssd->ptr_define) {
*ext = ssd->ptr_define->ext;
@@ -623,7 +592,6 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext)
static int interface_req_cursor_notification(QXLInstance *sin)
{
- dprint(2, "%s:\n", __func__);
return 1;
}
@@ -680,7 +648,7 @@ static void interface_set_client_capabilities(QXLInstance *sin,
uint8_t client_present,
uint8_t caps[58])
{
- dprint(3, "%s:\n", __func__);
+ /* nothing to do */
}
static int interface_client_monitors_config(QXLInstance *sin,
@@ -705,9 +673,9 @@ static int interface_client_monitors_config(QXLInstance *sin,
info.width = mc->monitors[head].width;
info.height = mc->monitors[head].height;
}
+
+ trace_qemu_spice_ui_info(ssd->qxl.id, info.width, info.height);
dpy_set_ui_info(ssd->dcl.con, &info);
- dprint(1, "%s/%d: size %dx%d\n", __func__, ssd->qxl.id,
- info.width, info.height);
return 1;
}
@@ -902,9 +870,10 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
return;
}
- dprint(1, "%s: %dx%d (stride %d/%d, fourcc 0x%x)\n", __func__,
- surface_width(ssd->ds), surface_height(ssd->ds),
- surface_stride(ssd->ds), stride, fourcc);
+ trace_qemu_spice_gl_surface(ssd->qxl.id,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ fourcc);
/* note: spice server will close the fd */
spice_qxl_gl_scanout(&ssd->qxl, fd,
@@ -932,7 +901,7 @@ static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- dprint(1, "%s: no framebuffer\n", __func__);
+ trace_qemu_spice_gl_scanout_disable(ssd->qxl.id);
spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false);
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
ssd->have_surface = false;
@@ -957,8 +926,7 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
fprintf(stderr, "%s: failed to get fd for texture\n", __func__);
return;
}
- dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__,
- w, h, stride, fourcc);
+ trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
/* note: spice server will close the fd */
spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
@@ -968,17 +936,133 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
ssd->have_scanout = true;
}
+static void qemu_spice_gl_scanout_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ ssd->guest_dmabuf = dmabuf;
+ ssd->guest_dmabuf_refresh = true;
+
+ ssd->have_surface = false;
+ ssd->have_scanout = true;
+}
+
+static void qemu_spice_gl_cursor_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf, bool have_hot,
+ uint32_t hot_x, uint32_t hot_y)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ ssd->have_hot = have_hot;
+ ssd->hot_x = hot_x;
+ ssd->hot_y = hot_y;
+
+ trace_qemu_spice_gl_cursor(ssd->qxl.id, dmabuf != NULL, have_hot);
+ if (dmabuf) {
+ egl_dmabuf_import_texture(dmabuf);
+ if (!dmabuf->texture) {
+ return;
+ }
+ egl_fb_setup_for_tex(&ssd->cursor_fb, dmabuf->width, dmabuf->height,
+ dmabuf->texture, false);
+ } else {
+ egl_fb_destroy(&ssd->cursor_fb);
+ }
+}
+
+static void qemu_spice_gl_cursor_position(DisplayChangeListener *dcl,
+ uint32_t pos_x, uint32_t pos_y)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ ssd->ptr_x = pos_x;
+ ssd->ptr_y = pos_y;
+}
+
+static void qemu_spice_gl_release_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ if (ssd->guest_dmabuf == dmabuf) {
+ ssd->guest_dmabuf = NULL;
+ ssd->guest_dmabuf_refresh = false;
+ }
+ egl_dmabuf_release_texture(dmabuf);
+}
+
static void qemu_spice_gl_update(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ EGLint stride = 0, fourcc = 0;
+ bool render_cursor = false;
+ bool y_0_top = false; /* FIXME */
uint64_t cookie;
+ int fd;
if (!ssd->have_scanout) {
return;
}
- dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y);
+ if (ssd->cursor_fb.texture) {
+ render_cursor = true;
+ }
+ if (ssd->render_cursor != render_cursor) {
+ ssd->render_cursor = render_cursor;
+ ssd->guest_dmabuf_refresh = true;
+ egl_fb_destroy(&ssd->blit_fb);
+ }
+
+ if (ssd->guest_dmabuf_refresh) {
+ QemuDmaBuf *dmabuf = ssd->guest_dmabuf;
+ if (render_cursor) {
+ egl_dmabuf_import_texture(dmabuf);
+ if (!dmabuf->texture) {
+ return;
+ }
+
+ /* source framebuffer */
+ egl_fb_setup_for_tex(&ssd->guest_fb,
+ dmabuf->width, dmabuf->height,
+ dmabuf->texture, false);
+
+ /* dest framebuffer */
+ if (ssd->blit_fb.width != dmabuf->width ||
+ ssd->blit_fb.height != dmabuf->height) {
+ trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, dmabuf->width,
+ dmabuf->height);
+ egl_fb_destroy(&ssd->blit_fb);
+ egl_fb_setup_new_tex(&ssd->blit_fb,
+ dmabuf->width, dmabuf->height);
+ fd = egl_get_fd_for_texture(ssd->blit_fb.texture,
+ &stride, &fourcc);
+ spice_qxl_gl_scanout(&ssd->qxl, fd,
+ dmabuf->width, dmabuf->height,
+ stride, fourcc, false);
+ }
+ } else {
+ trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id,
+ dmabuf->width, dmabuf->height);
+ /* note: spice server will close the fd, so hand over a dup */
+ spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd),
+ dmabuf->width, dmabuf->height,
+ dmabuf->stride, dmabuf->fourcc, false);
+ }
+ qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height);
+ ssd->guest_dmabuf_refresh = false;
+ }
+
+ if (render_cursor) {
+ egl_texture_blit(ssd->gls, &ssd->blit_fb, &ssd->guest_fb,
+ !y_0_top);
+ egl_texture_blend(ssd->gls, &ssd->blit_fb, &ssd->cursor_fb,
+ !y_0_top, ssd->ptr_x, ssd->ptr_y);
+ glFlush();
+ }
+
+ trace_qemu_spice_gl_update(ssd->qxl.id, w, h, x, y);
qemu_spice_gl_block(ssd, true);
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie);
@@ -1000,6 +1084,10 @@ static const DisplayChangeListenerOps display_listener_gl_ops = {
.dpy_gl_scanout_disable = qemu_spice_gl_scanout_disable,
.dpy_gl_scanout_texture = qemu_spice_gl_scanout_texture,
+ .dpy_gl_scanout_dmabuf = qemu_spice_gl_scanout_dmabuf,
+ .dpy_gl_cursor_dmabuf = qemu_spice_gl_cursor_dmabuf,
+ .dpy_gl_cursor_position = qemu_spice_gl_cursor_position,
+ .dpy_gl_release_dmabuf = qemu_spice_gl_release_dmabuf,
.dpy_gl_update = qemu_spice_gl_update,
};
diff --git a/ui/trace-events b/ui/trace-events
index 861b68a305..eb4bf7f00d 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -2,6 +2,8 @@
# ui/console.c
console_gfx_new(void) ""
+console_gfx_reuse(int index) "%d"
+console_gfx_close(int index) "%d"
console_putchar_csi(int esc_param0, int esc_param1, int ch, int nb_esc_params) "escape sequence CSI%d;%d%c, %d parameters"
console_putchar_unhandled(int ch) "unhandled escape character '%c'"
console_txt_new(int w, int h) "%dx%d"
@@ -75,6 +77,18 @@ qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int asyn
qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d"
qemu_spice_wakeup(uint32_t qid) "%d"
qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d"
+qemu_spice_display_update(int qid, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "%d +%d+%d %dx%d"
+qemu_spice_display_surface(int qid, uint32_t w, uint32_t h, int fast) "%d %dx%d, fast %d"
+qemu_spice_display_refresh(int qid, int notify) "%d notify %d"
+qemu_spice_ui_info(int qid, uint32_t width, uint32_t height) "%d %dx%d"
+
+qemu_spice_gl_surface(int qid, uint32_t w, uint32_t h, uint32_t fourcc) "%d %dx%d, fourcc 0x%x"
+qemu_spice_gl_scanout_disable(int qid) "%d"
+qemu_spice_gl_scanout_texture(int qid, uint32_t w, uint32_t h, uint32_t fourcc) "%d %dx%d, fourcc 0x%x"
+qemu_spice_gl_cursor(int qid, bool enabled, bool hotspot) "%d enabled %d, hotspot %d"
+qemu_spice_gl_forward_dmabuf(int qid, uint32_t width, uint32_t height) "%d %dx%d"
+qemu_spice_gl_render_dmabuf(int qid, uint32_t width, uint32_t height) "%d %dx%d"
+qemu_spice_gl_update(int qid, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "%d +%d+%d %dx%d"
# ui/keymaps.c
keymap_parse(const char *file) "file %s"
diff --git a/ui/vnc.c b/ui/vnc.c
index 13c28cabb0..e164eb798c 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -746,9 +746,19 @@ static void vnc_update_server_surface(VncDisplay *vd)
static void vnc_dpy_switch(DisplayChangeListener *dcl,
DisplaySurface *surface)
{
+ static const char placeholder_msg[] =
+ "Display output is not active.";
+ static DisplaySurface *placeholder;
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
VncState *vs;
+ if (surface == NULL) {
+ if (placeholder == NULL) {
+ placeholder = qemu_create_message_surface(640, 480, placeholder_msg);
+ }
+ surface = placeholder;
+ }
+
vnc_abort_display_jobs(vd);
vd->ds = surface;
diff --git a/util/aio-wait.c b/util/aio-wait.c
index 975afddf4c..b8a8f86dba 100644
--- a/util/aio-wait.c
+++ b/util/aio-wait.c
@@ -34,7 +34,7 @@ static void dummy_bh_cb(void *opaque)
void aio_wait_kick(AioWait *wait)
{
/* The barrier (or an atomic op) is in the caller. */
- if (atomic_read(&wait->need_kick)) {
+ if (atomic_read(&wait->num_waiters)) {
aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
}
}
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
index 926d3402e3..090ba21a13 100644
--- a/util/coroutine-ucontext.c
+++ b/util/coroutine-ucontext.c
@@ -170,7 +170,7 @@ Coroutine *qemu_coroutine_new(void)
}
#ifdef CONFIG_VALGRIND_H
-#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__)
/* Work around an unused variable in the valgrind.h macro... */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
@@ -179,7 +179,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co)
{
VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
}
-#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif
diff --git a/util/cutils.c b/util/cutils.c
index b33ede83d1..0de69e6db4 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -298,6 +298,115 @@ static int check_strtox_error(const char *nptr, char *ep,
}
/**
+ * Convert string @nptr to an integer, and store it in @result.
+ *
+ * This is a wrapper around strtol() that is harder to misuse.
+ * Semantics of @nptr, @endptr, @base match strtol() with differences
+ * noted below.
+ *
+ * @nptr may be null, and no conversion is performed then.
+ *
+ * If no conversion is performed, store @nptr in *@endptr and return
+ * -EINVAL.
+ *
+ * If @endptr is null, and the string isn't fully converted, return
+ * -EINVAL. This is the case when the pointer that would be stored in
+ * a non-null @endptr points to a character other than '\0'.
+ *
+ * If the conversion overflows @result, store INT_MAX in @result,
+ * and return -ERANGE.
+ *
+ * If the conversion underflows @result, store INT_MIN in @result,
+ * and return -ERANGE.
+ *
+ * Else store the converted value in @result, and return zero.
+ */
+int qemu_strtoi(const char *nptr, const char **endptr, int base,
+ int *result)
+{
+ char *ep;
+ long long lresult;
+
+ if (!nptr) {
+ if (endptr) {
+ *endptr = nptr;
+ }
+ return -EINVAL;
+ }
+
+ errno = 0;
+ lresult = strtoll(nptr, &ep, base);
+ if (lresult < INT_MIN) {
+ *result = INT_MIN;
+ errno = ERANGE;
+ } else if (lresult > INT_MAX) {
+ *result = INT_MAX;
+ errno = ERANGE;
+ } else {
+ *result = lresult;
+ }
+ return check_strtox_error(nptr, ep, endptr, errno);
+}
+
+/**
+ * Convert string @nptr to an unsigned integer, and store it in @result.
+ *
+ * This is a wrapper around strtoul() that is harder to misuse.
+ * Semantics of @nptr, @endptr, @base match strtoul() with differences
+ * noted below.
+ *
+ * @nptr may be null, and no conversion is performed then.
+ *
+ * If no conversion is performed, store @nptr in *@endptr and return
+ * -EINVAL.
+ *
+ * If @endptr is null, and the string isn't fully converted, return
+ * -EINVAL. This is the case when the pointer that would be stored in
+ * a non-null @endptr points to a character other than '\0'.
+ *
+ * If the conversion overflows @result, store UINT_MAX in @result,
+ * and return -ERANGE.
+ *
+ * Else store the converted value in @result, and return zero.
+ *
+ * Note that a number with a leading minus sign gets converted without
+ * the minus sign, checked for overflow (see above), then negated (in
+ * @result's type). This is exactly how strtoul() works.
+ */
+int qemu_strtoui(const char *nptr, const char **endptr, int base,
+ unsigned int *result)
+{
+ char *ep;
+ long long lresult;
+
+ if (!nptr) {
+ if (endptr) {
+ *endptr = nptr;
+ }
+ return -EINVAL;
+ }
+
+ errno = 0;
+ lresult = strtoull(nptr, &ep, base);
+
+ /* Windows returns 1 for negative out-of-range values. */
+ if (errno == ERANGE) {
+ *result = -1;
+ } else {
+ if (lresult > UINT_MAX) {
+ *result = UINT_MAX;
+ errno = ERANGE;
+ } else if (lresult < INT_MIN) {
+ *result = UINT_MAX;
+ errno = ERANGE;
+ } else {
+ *result = lresult;
+ }
+ }
+ return check_strtox_error(nptr, ep, endptr, errno);
+}
+
+/**
* Convert string @nptr to a long integer, and store it in @result.
*
* This is a wrapper around strtol() that is harder to misuse.
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 7f13e8a338..8bd8bb64eb 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -91,6 +91,14 @@ NetworkAddressFamily inet_netfamily(int family)
return NETWORK_ADDRESS_FAMILY_UNKNOWN;
}
+bool fd_is_socket(int fd)
+{
+ int optval;
+ socklen_t optlen = sizeof(optval);
+ return !qemu_getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
+}
+
+
/*
* Matrix we're trying to apply
*
@@ -1034,6 +1042,30 @@ fail:
return NULL;
}
+static int socket_get_fd(const char *fdstr, Error **errp)
+{
+ int fd;
+ if (cur_mon) {
+ fd = monitor_get_fd(cur_mon, fdstr, errp);
+ if (fd < 0) {
+ return -1;
+ }
+ } else {
+ if (qemu_strtoi(fdstr, NULL, 10, &fd) < 0) {
+ error_setg_errno(errp, errno,
+ "Unable to parse FD number %s",
+ fdstr);
+ return -1;
+ }
+ }
+ if (!fd_is_socket(fd)) {
+ error_setg(errp, "File descriptor '%s' is not a socket", fdstr);
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
int socket_connect(SocketAddress *addr, Error **errp)
{
int fd;
@@ -1048,7 +1080,7 @@ int socket_connect(SocketAddress *addr, Error **errp)
break;
case SOCKET_ADDRESS_TYPE_FD:
- fd = monitor_get_fd(cur_mon, addr->u.fd.str, errp);
+ fd = socket_get_fd(addr->u.fd.str, errp);
break;
case SOCKET_ADDRESS_TYPE_VSOCK:
@@ -1075,7 +1107,7 @@ int socket_listen(SocketAddress *addr, Error **errp)
break;
case SOCKET_ADDRESS_TYPE_FD:
- fd = monitor_get_fd(cur_mon, addr->u.fd.str, errp);
+ fd = socket_get_fd(addr->u.fd.str, errp);
break;
case SOCKET_ADDRESS_TYPE_VSOCK: