aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--accel/kvm/kvm-all.c38
-rw-r--r--accel/kvm/sev-stub.c10
-rw-r--r--accel/stubs/kvm-stub.c10
-rw-r--r--backends/confidential-guest-support.c33
-rw-r--r--backends/meson.build1
-rwxr-xr-xconfigure6
-rw-r--r--docs/amd-memory-encryption.txt2
-rw-r--r--docs/confidential-guest-support.txt49
-rw-r--r--docs/papr-pef.txt30
-rw-r--r--docs/system/arm/versatile.rst34
-rw-r--r--docs/system/arm/vexpress.rst28
-rw-r--r--docs/system/s390x/protvirt.rst19
-rw-r--r--gdbstub.c17
-rw-r--r--hw/core/machine.c63
-rw-r--r--hw/i386/pc_sysfw.c17
-rw-r--r--hw/ppc/meson.build1
-rw-r--r--hw/ppc/pef.c140
-rw-r--r--hw/ppc/spapr.c8
-rw-r--r--hw/s390x/pv.c62
-rw-r--r--hw/s390x/s390-virtio-ccw.c3
-rw-r--r--include/exec/confidential-guest-support.h62
-rw-r--r--include/hw/boards.h2
-rw-r--r--include/hw/ppc/pef.h17
-rw-r--r--include/hw/s390x/pv.h17
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/qom/object.h3
-rw-r--r--include/sysemu/kvm.h16
-rw-r--r--include/sysemu/sev.h4
-rw-r--r--qom/object.c4
-rw-r--r--scripts/mtest2make.py1
-rw-r--r--scripts/qapi/commands.py62
-rw-r--r--scripts/qapi/events.py16
-rw-r--r--scripts/qapi/gen.py94
-rw-r--r--scripts/qapi/main.py2
-rw-r--r--scripts/qapi/mypy.ini1
-rw-r--r--scripts/qapi/schema.py42
-rw-r--r--scripts/qapi/types.py4
-rw-r--r--scripts/qapi/visit.py6
-rw-r--r--softmmu/rtc.c3
-rw-r--r--softmmu/vl.c27
-rw-r--r--target/i386/kvm/kvm.c20
-rw-r--r--target/i386/sev-stub.c5
-rw-r--r--target/i386/sev.c95
-rw-r--r--target/ppc/kvm.c18
-rw-r--r--target/ppc/kvm_ppc.h6
-rw-r--r--tests/Makefile.include12
-rw-r--r--tests/acceptance/replay_kernel.py2
-rw-r--r--tests/docker/Makefile.include26
-rwxr-xr-xtests/docker/docker.py23
-rw-r--r--tests/docker/dockerfiles/empty.docker8
-rw-r--r--tests/qapi-schema/comments.out2
-rw-r--r--tests/qapi-schema/doc-good.out2
-rw-r--r--tests/qapi-schema/empty.out2
-rw-r--r--tests/qapi-schema/event-case.out2
-rw-r--r--tests/qapi-schema/include-repetition.out2
-rw-r--r--tests/qapi-schema/include-simple.out2
-rw-r--r--tests/qapi-schema/indented-expr.out2
-rw-r--r--tests/qapi-schema/qapi-schema-test.out2
-rw-r--r--tests/tcg/Makefile.qemu4
-rw-r--r--tests/tcg/multiarch/Makefile.target5
61 files changed, 875 insertions, 322 deletions
diff --git a/Makefile b/Makefile
index b0dff73904..d7fb6b270e 100644
--- a/Makefile
+++ b/Makefile
@@ -305,7 +305,7 @@ endif
@echo 'Test targets:'
$(call print-help,check,Run all tests (check-help for details))
$(call print-help,bench,Run all benchmarks)
- $(call print-help,docker,Help about targets running tests inside containers)
+ $(call print-help,docker-help,Help about targets running tests inside containers)
$(call print-help,vm-help,Help about targets running tests inside VM)
@echo ''
@echo 'Documentation targets:'
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 5164d838b9..e72a19aaf8 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -123,10 +123,6 @@ struct KVMState
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);
-
/* For "info mtree -f" to tell if an MR is registered in KVM */
int nr_as;
struct KVMAs {
@@ -225,26 +221,6 @@ 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;
-}
-
/* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{
@@ -2204,20 +2180,6 @@ 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
index 4f97452585..9587d1b2a3 100644
--- a/accel/kvm/sev-stub.c
+++ b/accel/kvm/sev-stub.c
@@ -15,12 +15,8 @@
#include "qemu-common.h"
#include "sysemu/sev.h"
-int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
+int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
{
- abort();
-}
-
-void *sev_guest_init(const char *id)
-{
- return NULL;
+ /* If we get here, cgs must be some non-SEV thing */
+ return 0;
}
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 680e099463..0f17acfac0 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -81,16 +81,6 @@ 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/backends/confidential-guest-support.c b/backends/confidential-guest-support.c
new file mode 100644
index 0000000000..052fde8db0
--- /dev/null
+++ b/backends/confidential-guest-support.c
@@ -0,0 +1,33 @@
+/*
+ * QEMU Confidential Guest support
+ *
+ * Copyright Red Hat.
+ *
+ * Authors:
+ * David Gibson <david@gibson.dropbear.id.au>
+ *
+ * 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 "exec/confidential-guest-support.h"
+
+OBJECT_DEFINE_ABSTRACT_TYPE(ConfidentialGuestSupport,
+ confidential_guest_support,
+ CONFIDENTIAL_GUEST_SUPPORT,
+ OBJECT)
+
+static void confidential_guest_support_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void confidential_guest_support_init(Object *obj)
+{
+}
+
+static void confidential_guest_support_finalize(Object *obj)
+{
+}
diff --git a/backends/meson.build b/backends/meson.build
index 484456ece7..d4221831fc 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -6,6 +6,7 @@ softmmu_ss.add([files(
'rng-builtin.c',
'rng-egd.c',
'rng.c',
+ 'confidential-guest-support.c',
), numa])
softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('rng-random.c'))
diff --git a/configure b/configure
index a34f91171d..57813eba7b 100755
--- a/configure
+++ b/configure
@@ -198,8 +198,8 @@ has() {
}
version_ge () {
- local_ver1=`echo $1 | tr . ' '`
- local_ver2=`echo $2 | tr . ' '`
+ local_ver1=$(expr "$1" : '\([0-9.]*\)' | tr . ' ')
+ local_ver2=$(echo "$2" | tr . ' ')
while true; do
set x $local_ver1
local_first=${2-0}
@@ -6115,7 +6115,7 @@ fi
if test -n "$gdb_bin"; then
gdb_version=$($gdb_bin --version | head -n 1)
- if version_ge ${gdb_version##* } 8.3.1; then
+ if version_ge ${gdb_version##* } 9.1; then
echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
fi
fi
diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
index 80b8eb00e9..145896aec7 100644
--- a/docs/amd-memory-encryption.txt
+++ b/docs/amd-memory-encryption.txt
@@ -73,7 +73,7 @@ complete flow chart.
To launch a SEV guest
# ${QEMU} \
- -machine ...,memory-encryption=sev0 \
+ -machine ...,confidential-guest-support=sev0 \
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
Debugging
diff --git a/docs/confidential-guest-support.txt b/docs/confidential-guest-support.txt
new file mode 100644
index 0000000000..71d07ba57a
--- /dev/null
+++ b/docs/confidential-guest-support.txt
@@ -0,0 +1,49 @@
+Confidential Guest Support
+==========================
+
+Traditionally, hypervisors such as QEMU have complete access to a
+guest's memory and other state, meaning that a compromised hypervisor
+can compromise any of its guests. A number of platforms have added
+mechanisms in hardware and/or firmware which give guests at least some
+protection from a compromised hypervisor. This is obviously
+especially desirable for public cloud environments.
+
+These mechanisms have different names and different modes of
+operation, but are often referred to as Secure Guests or Confidential
+Guests. We use the term "Confidential Guest Support" to distinguish
+this from other aspects of guest security (such as security against
+attacks from other guests, or from network sources).
+
+Running a Confidential Guest
+----------------------------
+
+To run a confidential guest you need to add two command line parameters:
+
+1. Use "-object" to create a "confidential guest support" object. The
+ type and parameters will vary with the specific mechanism to be
+ used
+2. Set the "confidential-guest-support" machine parameter to the ID of
+ the object from (1).
+
+Example (for AMD SEV)::
+
+ qemu-system-x86_64 \
+ <other parameters> \
+ -machine ...,confidential-guest-support=sev0 \
+ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
+
+Supported mechanisms
+--------------------
+
+Currently supported confidential guest mechanisms are:
+
+AMD Secure Encrypted Virtualization (SEV)
+ docs/amd-memory-encryption.txt
+
+POWER Protected Execution Facility (PEF)
+ docs/papr-pef.txt
+
+s390x Protected Virtualization (PV)
+ docs/system/s390x/protvirt.rst
+
+Other mechanisms may be supported in future.
diff --git a/docs/papr-pef.txt b/docs/papr-pef.txt
new file mode 100644
index 0000000000..72550e9bf8
--- /dev/null
+++ b/docs/papr-pef.txt
@@ -0,0 +1,30 @@
+POWER (PAPR) Protected Execution Facility (PEF)
+===============================================
+
+Protected Execution Facility (PEF), also known as Secure Guest support
+is a feature found on IBM POWER9 and POWER10 processors.
+
+If a suitable firmware including an Ultravisor is installed, it adds
+an extra memory protection mode to the CPU. The ultravisor manages a
+pool of secure memory which cannot be accessed by the hypervisor.
+
+When this feature is enabled in QEMU, a guest can use ultracalls to
+enter "secure mode". This transfers most of its memory to secure
+memory, where it cannot be eavesdropped by a compromised hypervisor.
+
+Launching
+---------
+
+To launch a guest which will be permitted to enter PEF secure mode:
+
+# ${QEMU} \
+ -object pef-guest,id=pef0 \
+ -machine confidential-guest-support=pef0 \
+ ...
+
+Live Migration
+----------------
+
+Live migration is not yet implemented for PEF guests. For
+consistency, we currently prevent migration if the PEF feature is
+enabled, whether or not the guest has actually entered secure mode.
diff --git a/docs/system/arm/versatile.rst b/docs/system/arm/versatile.rst
index 51221c30a4..2ae792bac3 100644
--- a/docs/system/arm/versatile.rst
+++ b/docs/system/arm/versatile.rst
@@ -27,3 +27,37 @@ The Arm Versatile baseboard is emulated with the following devices:
devices.
- PL181 MultiMedia Card Interface with SD card.
+
+Booting a Linux kernel
+----------------------
+
+Building a current Linux kernel with ``versatile_defconfig`` should be
+enough to get something running. Nowadays an out-of-tree build is
+recommended (and also useful if you build a lot of different targets).
+In the following example $BLD points to the build directory and $SRC
+points to the root of the Linux source tree. You can drop $SRC if you
+are running from there.
+
+.. code-block:: bash
+
+ $ make O=$BLD -C $SRC ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- versatile_defconfig
+ $ make O=$BLD -C $SRC ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
+
+You may want to enable some additional modules if you want to boot
+something from the SCSI interface::
+
+ CONFIG_PCI=y
+ CONFIG_PCI_VERSATILE=y
+ CONFIG_SCSI=y
+ CONFIG_SCSI_SYM53C8XX_2=y
+
+You can then boot with a command line like:
+
+.. code-block:: bash
+
+ $ qemu-system-arm -machine type=versatilepb \
+ -serial mon:stdio \
+ -drive if=scsi,driver=file,filename=debian-buster-armel-rootfs.ext4 \
+ -kernel zImage \
+ -dtb versatile-pb.dtb \
+ -append "console=ttyAMA0 ro root=/dev/sda"
diff --git a/docs/system/arm/vexpress.rst b/docs/system/arm/vexpress.rst
index 7f1bcbef07..3e3839e923 100644
--- a/docs/system/arm/vexpress.rst
+++ b/docs/system/arm/vexpress.rst
@@ -58,3 +58,31 @@ Other differences between the hardware and the QEMU model:
``vexpress-a15``, and have IRQs from 40 upwards. If a dtb is
provided on the command line then QEMU will edit it to include
suitable entries describing these transports for the guest.
+
+Booting a Linux kernel
+----------------------
+
+Building a current Linux kernel with ``multi_v7_defconfig`` should be
+enough to get something running. Nowadays an out-of-tree build is
+recommended (and also useful if you build a lot of different targets).
+In the following example $BLD points to the build directory and $SRC
+points to the root of the Linux source tree. You can drop $SRC if you
+are running from there.
+
+.. code-block:: bash
+
+ $ make O=$BLD -C $SRC ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- multi_v7_defconfig
+ $ make O=$BLD -C $SRC ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
+
+By default you will want to boot your rootfs off the sdcard interface.
+Your rootfs will need to be padded to the right size. With a suitable
+DTB you could also add devices to the virtio-mmio bus.
+
+.. code-block:: bash
+
+ $ qemu-system-arm -cpu cortex-a15 -smp 4 -m 4096 \
+ -machine type=vexpress-a15 -serial mon:stdio \
+ -drive if=sd,driver=file,filename=armel-rootfs.ext4 \
+ -kernel zImage \
+ -dtb vexpress-v2p-ca15-tc1.dtb \
+ -append "console=ttyAMA0 root=/dev/mmcblk0 ro"
diff --git a/docs/system/s390x/protvirt.rst b/docs/system/s390x/protvirt.rst
index 712974ad87..0f481043d9 100644
--- a/docs/system/s390x/protvirt.rst
+++ b/docs/system/s390x/protvirt.rst
@@ -22,15 +22,22 @@ If those requirements are met, the capability `KVM_CAP_S390_PROTECTED`
will indicate that KVM can support PVMs on that LPAR.
-QEMU Settings
--------------
+Running a Protected Virtual Machine
+-----------------------------------
-To indicate to the VM that it can transition into protected mode, the
+To run a PVM you will need to select a CPU model which includes the
`Unpack facility` (stfle bit 161 represented by the feature
-`unpack`/`S390_FEAT_UNPACK`) needs to be part of the cpu model of
-the VM.
+`unpack`/`S390_FEAT_UNPACK`), and add these options to the command line::
+
+ -object s390-pv-guest,id=pv0 \
+ -machine confidential-guest-support=pv0
+
+Adding these options will:
+
+* Ensure the `unpack` facility is available
+* Enable the IOMMU by default for all I/O devices
+* Initialize the PV mechanism
-All I/O devices need to use the IOMMU.
Passthrough (vfio) devices are currently not supported.
Host huge page backings are not supported. However guests can use huge
diff --git a/gdbstub.c b/gdbstub.c
index c7ca7e9f88..759bb00bcf 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2245,7 +2245,6 @@ static void handle_query_xfer_auxv(GdbCmdContext *gdb_ctx, void *user_ctx)
{
TaskState *ts;
unsigned long offset, len, saved_auxv, auxv_len;
- const char *mem;
if (gdb_ctx->num_params < 2) {
put_packet("E22");
@@ -2257,8 +2256,8 @@ static void handle_query_xfer_auxv(GdbCmdContext *gdb_ctx, void *user_ctx)
ts = gdbserver_state.c_cpu->opaque;
saved_auxv = ts->info->saved_auxv;
auxv_len = ts->info->auxv_len;
- mem = (const char *)(saved_auxv + offset);
- if (offset > auxv_len) {
+
+ if (offset >= auxv_len) {
put_packet("E00");
return;
}
@@ -2269,12 +2268,20 @@ static void handle_query_xfer_auxv(GdbCmdContext *gdb_ctx, void *user_ctx)
if (len < auxv_len - offset) {
g_string_assign(gdbserver_state.str_buf, "m");
- memtox(gdbserver_state.str_buf, mem, len);
} else {
g_string_assign(gdbserver_state.str_buf, "l");
- memtox(gdbserver_state.str_buf, mem, auxv_len - offset);
+ len = auxv_len - offset;
+ }
+
+ g_byte_array_set_size(gdbserver_state.mem_buf, len);
+ if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset,
+ gdbserver_state.mem_buf->data, len, false)) {
+ put_packet("E14");
+ return;
}
+ memtox(gdbserver_state.str_buf,
+ (const char *)gdbserver_state.mem_buf->data, len);
put_packet_binary(gdbserver_state.str_buf->str,
gdbserver_state.str_buf->len, true);
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 5d6163ab70..970046f438 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -32,6 +32,9 @@
#include "hw/mem/nvdimm.h"
#include "migration/global_state.h"
#include "migration/vmstate.h"
+#include "exec/confidential-guest-support.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-pci.h"
GlobalProperty hw_compat_5_2[] = {};
const size_t hw_compat_5_2_len = G_N_ELEMENTS(hw_compat_5_2);
@@ -427,24 +430,37 @@ static char *machine_get_memory_encryption(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
- return g_strdup(ms->memory_encryption);
+ if (ms->cgs) {
+ return g_strdup(object_get_canonical_path_component(OBJECT(ms->cgs)));
+ }
+
+ return NULL;
}
static void machine_set_memory_encryption(Object *obj, const char *value,
Error **errp)
{
- MachineState *ms = MACHINE(obj);
+ Object *cgs =
+ object_resolve_path_component(object_get_objects_root(), value);
+
+ if (!cgs) {
+ error_setg(errp, "No such memory encryption object '%s'", value);
+ return;
+ }
- g_free(ms->memory_encryption);
- ms->memory_encryption = g_strdup(value);
+ object_property_set_link(obj, "confidential-guest-support", cgs, errp);
+}
+static void machine_check_confidential_guest_support(const Object *obj,
+ const char *name,
+ Object *new_target,
+ Error **errp)
+{
/*
- * With memory encryption, the host can't see the real contents of RAM,
- * so there's no point in it trying to merge areas.
+ * So far the only constraint is that the target has the
+ * TYPE_CONFIDENTIAL_GUEST_SUPPORT interface, and that's checked
+ * by the QOM core
*/
- if (value) {
- machine_set_mem_merge(obj, false, errp);
- }
}
static bool machine_get_nvdimm(Object *obj, Error **errp)
@@ -844,6 +860,15 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "suppress-vmdesc",
"Set on to disable self-describing migration");
+ object_class_property_add_link(oc, "confidential-guest-support",
+ TYPE_CONFIDENTIAL_GUEST_SUPPORT,
+ offsetof(MachineState, cgs),
+ machine_check_confidential_guest_support,
+ OBJ_PROP_LINK_STRONG);
+ object_class_property_set_description(oc, "confidential-guest-support",
+ "Set confidential guest scheme to support");
+
+ /* For compatibility */
object_class_property_add_str(oc, "memory-encryption",
machine_get_memory_encryption, machine_set_memory_encryption);
object_class_property_set_description(oc, "memory-encryption",
@@ -1166,6 +1191,26 @@ void machine_run_board_init(MachineState *machine)
cc->deprecation_note);
}
+ if (machine->cgs) {
+ /*
+ * With confidential guests, the host can't see the real
+ * contents of RAM, so there's no point in it trying to merge
+ * areas.
+ */
+ machine_set_mem_merge(OBJECT(machine), false, &error_abort);
+
+ /*
+ * Virtio devices can't count on directly accessing guest
+ * memory, so they need iommu_platform=on to use normal DMA
+ * mechanisms. That requires also disabling legacy virtio
+ * support for those virtio pci devices which allow it.
+ */
+ object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy",
+ "on", true);
+ object_register_sugar_prop(TYPE_VIRTIO_DEVICE, "iommu_platform",
+ "on", false);
+ }
+
machine_class->init(machine);
phase_advance(PHASE_MACHINE_INITIALIZED);
}
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 92e90ff013..11172214f1 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -38,6 +38,7 @@
#include "sysemu/sysemu.h"
#include "hw/block/flash.h"
#include "sysemu/kvm.h"
+#include "sysemu/sev.h"
#define FLASH_SECTOR_SIZE 4096
@@ -147,7 +148,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
PFlashCFI01 *system_flash;
MemoryRegion *flash_mem;
void *flash_ptr;
- int ret, flash_size;
+ int flash_size;
assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
@@ -191,16 +192,10 @@ static void pc_system_flash_map(PCMachineState *pcms,
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);
- }
- }
+ /* Encrypt the pflash boot ROM, if necessary */
+ flash_ptr = memory_region_get_ram_ptr(flash_mem);
+ flash_size = memory_region_size(flash_mem);
+ sev_encrypt_flash(flash_ptr, flash_size, &error_fatal);
}
}
}
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index ffa2ec37fa..218631c883 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -27,6 +27,7 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files(
'spapr_nvdimm.c',
'spapr_rtas_ddw.c',
'spapr_numa.c',
+ 'pef.c',
))
ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c'))
ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_LINUX'], if_true: files(
diff --git a/hw/ppc/pef.c b/hw/ppc/pef.c
new file mode 100644
index 0000000000..573be3ed79
--- /dev/null
+++ b/hw/ppc/pef.c
@@ -0,0 +1,140 @@
+/*
+ * PEF (Protected Execution Facility) for POWER support
+ *
+ * Copyright Red Hat.
+ *
+ * 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 "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "sysemu/kvm.h"
+#include "migration/blocker.h"
+#include "exec/confidential-guest-support.h"
+#include "hw/ppc/pef.h"
+
+#define TYPE_PEF_GUEST "pef-guest"
+OBJECT_DECLARE_SIMPLE_TYPE(PefGuest, PEF_GUEST)
+
+typedef struct PefGuest PefGuest;
+typedef struct PefGuestClass PefGuestClass;
+
+struct PefGuestClass {
+ ConfidentialGuestSupportClass parent_class;
+};
+
+/**
+ * PefGuest:
+ *
+ * The PefGuest object is used for creating and managing a PEF
+ * guest.
+ *
+ * # $QEMU \
+ * -object pef-guest,id=pef0 \
+ * -machine ...,confidential-guest-support=pef0
+ */
+struct PefGuest {
+ ConfidentialGuestSupport parent_obj;
+};
+
+static int kvmppc_svm_init(Error **errp)
+{
+#ifdef CONFIG_KVM
+ static Error *pef_mig_blocker;
+
+ if (!kvm_check_extension(kvm_state, KVM_CAP_PPC_SECURE_GUEST)) {
+ error_setg(errp,
+ "KVM implementation does not support Secure VMs (is an ultravisor running?)");
+ return -1;
+ } else {
+ int ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_SECURE_GUEST, 0, 1);
+
+ if (ret < 0) {
+ error_setg(errp,
+ "Error enabling PEF with KVM");
+ return -1;
+ }
+ }
+
+ /* add migration blocker */
+ error_setg(&pef_mig_blocker, "PEF: Migration is not implemented");
+ /* NB: This can fail if --only-migratable is used */
+ migrate_add_blocker(pef_mig_blocker, &error_fatal);
+
+ return 0;
+#else
+ g_assert_not_reached();
+#endif
+}
+
+/*
+ * Don't set error if KVM_PPC_SVM_OFF ioctl is invoked on kernels
+ * that don't support this ioctl.
+ */
+static int kvmppc_svm_off(Error **errp)
+{
+#ifdef CONFIG_KVM
+ int rc;
+
+ rc = kvm_vm_ioctl(KVM_STATE(current_accel()), KVM_PPC_SVM_OFF);
+ if (rc && rc != -ENOTTY) {
+ error_setg_errno(errp, -rc, "KVM_PPC_SVM_OFF ioctl failed");
+ return rc;
+ }
+ return 0;
+#else
+ g_assert_not_reached();
+#endif
+}
+
+int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ if (!object_dynamic_cast(OBJECT(cgs), TYPE_PEF_GUEST)) {
+ return 0;
+ }
+
+ if (!kvm_enabled()) {
+ error_setg(errp, "PEF requires KVM");
+ return -1;
+ }
+
+ return kvmppc_svm_init(errp);
+}
+
+int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ if (!object_dynamic_cast(OBJECT(cgs), TYPE_PEF_GUEST)) {
+ return 0;
+ }
+
+ /*
+ * If we don't have KVM we should never have been able to
+ * initialize PEF, so we should never get this far
+ */
+ assert(kvm_enabled());
+
+ return kvmppc_svm_off(errp);
+}
+
+OBJECT_DEFINE_TYPE_WITH_INTERFACES(PefGuest,
+ pef_guest,
+ PEF_GUEST,
+ CONFIDENTIAL_GUEST_SUPPORT,
+ { TYPE_USER_CREATABLE },
+ { NULL })
+
+static void pef_guest_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void pef_guest_init(Object *obj)
+{
+}
+
+static void pef_guest_finalize(Object *obj)
+{
+}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 6c47466fc2..612356e9ec 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -83,6 +83,7 @@
#include "hw/ppc/spapr_tpm_proxy.h"
#include "hw/ppc/spapr_nvdimm.h"
#include "hw/ppc/spapr_numa.h"
+#include "hw/ppc/pef.h"
#include "monitor/monitor.h"
@@ -1574,7 +1575,7 @@ static void spapr_machine_reset(MachineState *machine)
void *fdt;
int rc;
- kvmppc_svm_off(&error_fatal);
+ pef_kvm_reset(machine->cgs, &error_fatal);
spapr_caps_apply(spapr);
first_ppc_cpu = POWERPC_CPU(first_cpu);
@@ -2658,6 +2659,11 @@ static void spapr_machine_init(MachineState *machine)
char *filename;
Error *resize_hpt_err = NULL;
+ /*
+ * if Secure VM (PEF) support is configured, then initialize it
+ */
+ pef_kvm_init(machine->cgs, &error_fatal);
+
msi_nonbroken = true;
QLIST_INIT(&spapr->phbs);
diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
index ab3a2482aa..93eccfc05d 100644
--- a/hw/s390x/pv.c
+++ b/hw/s390x/pv.c
@@ -14,8 +14,11 @@
#include <linux/kvm.h>
#include "cpu.h"
+#include "qapi/error.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
+#include "qom/object_interfaces.h"
+#include "exec/confidential-guest-support.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/pv.h"
@@ -111,3 +114,62 @@ void s390_pv_inject_reset_error(CPUState *cs)
/* Report that we are unable to enter protected mode */
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
}
+
+#define TYPE_S390_PV_GUEST "s390-pv-guest"
+OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST)
+
+/**
+ * S390PVGuest:
+ *
+ * The S390PVGuest object is basically a dummy used to tell the
+ * confidential guest support system to use s390's PV mechanism.
+ *
+ * # $QEMU \
+ * -object s390-pv-guest,id=pv0 \
+ * -machine ...,confidential-guest-support=pv0
+ */
+struct S390PVGuest {
+ ConfidentialGuestSupport parent_obj;
+};
+
+typedef struct S390PVGuestClass S390PVGuestClass;
+
+struct S390PVGuestClass {
+ ConfidentialGuestSupportClass parent_class;
+};
+
+int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) {
+ return 0;
+ }
+
+ if (!s390_has_feat(S390_FEAT_UNPACK)) {
+ error_setg(errp,
+ "CPU model does not support Protected Virtualization");
+ return -1;
+ }
+
+ cgs->ready = true;
+
+ return 0;
+}
+
+OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest,
+ s390_pv_guest,
+ S390_PV_GUEST,
+ CONFIDENTIAL_GUEST_SUPPORT,
+ { TYPE_USER_CREATABLE },
+ { NULL })
+
+static void s390_pv_guest_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void s390_pv_guest_init(Object *obj)
+{
+}
+
+static void s390_pv_guest_finalize(Object *obj)
+{
+}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index a2d9a79c84..2972b607f3 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -250,6 +250,9 @@ static void ccw_init(MachineState *machine)
/* init CPUs (incl. CPU model) early so s390_has_feature() works */
s390_init_cpus(machine);
+ /* Need CPU model to be determined before we can set up PV */
+ s390_pv_init(machine->cgs, &error_fatal);
+
s390_flic_init();
/* init the SIGP facility */
diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h
new file mode 100644
index 0000000000..ba2dd4b5df
--- /dev/null
+++ b/include/exec/confidential-guest-support.h
@@ -0,0 +1,62 @@
+/*
+ * QEMU Confidential Guest support
+ * This interface describes the common pieces between various
+ * schemes for protecting guest memory or other state against a
+ * compromised hypervisor. This includes memory encryption (AMD's
+ * SEV and Intel's MKTME) or special protection modes (PEF on POWER,
+ * or PV on s390x).
+ *
+ * Copyright Red Hat.
+ *
+ * Authors:
+ * David Gibson <david@gibson.dropbear.id.au>
+ *
+ * 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_CONFIDENTIAL_GUEST_SUPPORT_H
+#define QEMU_CONFIDENTIAL_GUEST_SUPPORT_H
+
+#ifndef CONFIG_USER_ONLY
+
+#include "qom/object.h"
+
+#define TYPE_CONFIDENTIAL_GUEST_SUPPORT "confidential-guest-support"
+OBJECT_DECLARE_SIMPLE_TYPE(ConfidentialGuestSupport, CONFIDENTIAL_GUEST_SUPPORT)
+
+struct ConfidentialGuestSupport {
+ Object parent;
+
+ /*
+ * ready: flag set by CGS initialization code once it's ready to
+ * start executing instructions in a potentially-secure
+ * guest
+ *
+ * The definition here is a bit fuzzy, because this is essentially
+ * part of a self-sanity-check, rather than a strict mechanism.
+ *
+ * It's not feasible to have a single point in the common machine
+ * init path to configure confidential guest support, because
+ * different mechanisms have different interdependencies requiring
+ * initialization in different places, often in arch or machine
+ * type specific code. It's also usually not possible to check
+ * for invalid configurations until that initialization code.
+ * That means it would be very easy to have a bug allowing CGS
+ * init to be bypassed entirely in certain configurations.
+ *
+ * Silently ignoring a requested security feature would be bad, so
+ * to avoid that we check late in init that this 'ready' flag is
+ * set if CGS was requested. If the CGS init hasn't happened, and
+ * so 'ready' is not set, we'll abort.
+ */
+ bool ready;
+};
+
+typedef struct ConfidentialGuestSupportClass {
+ ObjectClass parent;
+} ConfidentialGuestSupportClass;
+
+#endif /* !CONFIG_USER_ONLY */
+
+#endif /* QEMU_CONFIDENTIAL_GUEST_SUPPORT_H */
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 85af4faf76..a46dfe5d1a 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -270,7 +270,7 @@ struct MachineState {
bool iommu;
bool suppress_vmdesc;
bool enable_graphics;
- char *memory_encryption;
+ ConfidentialGuestSupport *cgs;
char *ram_memdev_id;
/*
* convenience alias to ram_memdev_id backend memory region
diff --git a/include/hw/ppc/pef.h b/include/hw/ppc/pef.h
new file mode 100644
index 0000000000..707dbe524c
--- /dev/null
+++ b/include/hw/ppc/pef.h
@@ -0,0 +1,17 @@
+/*
+ * PEF (Protected Execution Facility) for POWER support
+ *
+ * Copyright Red Hat.
+ *
+ * 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 HW_PPC_PEF_H
+#define HW_PPC_PEF_H
+
+int pef_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
+int pef_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp);
+
+#endif /* HW_PPC_PEF_H */
diff --git a/include/hw/s390x/pv.h b/include/hw/s390x/pv.h
index aee758bc2d..1f1f545bfc 100644
--- a/include/hw/s390x/pv.h
+++ b/include/hw/s390x/pv.h
@@ -12,6 +12,9 @@
#ifndef HW_S390_PV_H
#define HW_S390_PV_H
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
#ifdef CONFIG_KVM
#include "cpu.h"
#include "hw/s390x/s390-virtio-ccw.h"
@@ -55,4 +58,18 @@ static inline void s390_pv_unshare(void) {}
static inline void s390_pv_inject_reset_error(CPUState *cs) {};
#endif /* CONFIG_KVM */
+int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
+static inline int s390_pv_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ if (!cgs) {
+ return 0;
+ }
+ if (kvm_enabled()) {
+ return s390_pv_kvm_init(cgs, errp);
+ }
+
+ error_setg(errp, "Protected Virtualization requires KVM");
+ return -1;
+}
+
#endif /* HW_S390_PV_H */
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 68deb74ef6..dc39b05c30 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -37,6 +37,7 @@ typedef struct Chardev Chardev;
typedef struct Clock Clock;
typedef struct CompatProperty CompatProperty;
typedef struct CoMutex CoMutex;
+typedef struct ConfidentialGuestSupport ConfidentialGuestSupport;
typedef struct CPUAddressSpace CPUAddressSpace;
typedef struct CPUState CPUState;
typedef struct DeviceListener DeviceListener;
diff --git a/include/qom/object.h b/include/qom/object.h
index d378f13a11..6721cd312e 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -638,7 +638,8 @@ bool object_apply_global_props(Object *obj, const GPtrArray *props,
Error **errp);
void object_set_machine_compat_props(GPtrArray *compat_props);
void object_set_accelerator_compat_props(GPtrArray *compat_props);
-void object_register_sugar_prop(const char *driver, const char *prop, const char *value);
+void object_register_sugar_prop(const char *driver, const char *prop,
+ const char *value, bool optional);
void object_apply_compat_props(Object *obj);
/**
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 739682f3c3..c5546bdecc 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -233,22 +233,6 @@ int kvm_has_intx_set_mask(void);
*/
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
index 7ab6e3e31d..5c5a13c6ca 100644
--- a/include/sysemu/sev.h
+++ b/include/sysemu/sev.h
@@ -16,8 +16,8 @@
#include "sysemu/kvm.h"
-void *sev_guest_init(const char *id);
-int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
+int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);
+int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp);
int sev_inject_launch_secret(const char *hdr, const char *secret,
uint64_t gpa, Error **errp);
#endif
diff --git a/qom/object.c b/qom/object.c
index 2fa0119647..491823db4a 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -442,7 +442,8 @@ static GPtrArray *object_compat_props[3];
* other than "-global". These are generally used for syntactic
* sugar and legacy command line options.
*/
-void object_register_sugar_prop(const char *driver, const char *prop, const char *value)
+void object_register_sugar_prop(const char *driver, const char *prop,
+ const char *value, bool optional)
{
GlobalProperty *g;
if (!object_compat_props[2]) {
@@ -452,6 +453,7 @@ void object_register_sugar_prop(const char *driver, const char *prop, const char
g->driver = g_strdup(driver);
g->property = g_strdup(prop);
g->value = g_strdup(value);
+ g->optional = optional;
g_ptr_array_add(object_compat_props[2], g);
}
diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py
index 25ee6887cf..cbbcba100d 100644
--- a/scripts/mtest2make.py
+++ b/scripts/mtest2make.py
@@ -110,6 +110,7 @@ def emit_suite(name, suite, prefix):
print('ifneq ($(filter %s %s, $(MAKECMDGOALS)),)' % (target, prefix))
print('.tests += $(.test.$(SPEED).%s)' % (target, ))
print('endif')
+ print('all-%s-targets += %s' % (prefix, target))
targets = {t['id']: [os.path.relpath(f) for f in t['filename']]
for t in introspect['targets']}
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 50978090b4..54af519f44 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -23,7 +23,6 @@ from typing import (
from .common import c_name, mcgen
from .gen import (
QAPIGenC,
- QAPIGenCCode,
QAPISchemaModularCVisitor,
build_params,
ifcontext,
@@ -126,6 +125,9 @@ def gen_marshal(name: str,
boxed: bool,
ret_type: Optional[QAPISchemaType]) -> str:
have_args = boxed or (arg_type and not arg_type.is_empty())
+ if have_args:
+ assert arg_type is not None
+ arg_type_c_name = arg_type.c_name()
ret = mcgen('''
@@ -147,7 +149,7 @@ def gen_marshal(name: str,
ret += mcgen('''
%(c_name)s arg = {0};
''',
- c_name=arg_type.c_name())
+ c_name=arg_type_c_name)
ret += mcgen('''
@@ -163,7 +165,7 @@ def gen_marshal(name: str,
ok = visit_check_struct(v, errp);
}
''',
- c_arg_type=arg_type.c_name())
+ c_arg_type=arg_type_c_name)
else:
ret += mcgen('''
ok = visit_check_struct(v, errp);
@@ -193,7 +195,7 @@ out:
ret += mcgen('''
visit_type_%(c_arg_type)s_members(v, &arg, NULL);
''',
- c_arg_type=arg_type.c_name())
+ c_arg_type=arg_type_c_name)
ret += mcgen('''
visit_end_struct(v, NULL);
@@ -234,28 +236,11 @@ def gen_register_command(name: str,
return ret
-def gen_registry(registry: str, prefix: str) -> str:
- ret = mcgen('''
-
-void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
-{
- QTAILQ_INIT(cmds);
-
-''',
- c_prefix=c_name(prefix, protect=False))
- ret += registry
- ret += mcgen('''
-}
-''')
- return ret
-
-
class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
def __init__(self, prefix: str):
super().__init__(
prefix, 'qapi-commands',
' * Schema-defined QAPI/QMP commands', None, __doc__)
- self._regy = QAPIGenCCode(None)
self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
def _begin_user_module(self, name: str) -> None:
@@ -282,25 +267,36 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
''',
types=types))
- def visit_end(self) -> None:
- self._add_system_module('init', ' * QAPI Commands initialization')
+ def visit_begin(self, schema: QAPISchema) -> None:
+ self._add_module('./init', ' * QAPI Commands initialization')
self._genh.add(mcgen('''
#include "qapi/qmp/dispatch.h"
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
''',
c_prefix=c_name(self._prefix, protect=False)))
- self._genc.preamble_add(mcgen('''
+ self._genc.add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqapi-commands.h"
#include "%(prefix)sqapi-init-commands.h"
+
+void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
+{
+ QTAILQ_INIT(cmds);
+
''',
- prefix=self._prefix))
- self._genc.add(gen_registry(self._regy.get_content(), self._prefix))
+ prefix=self._prefix,
+ c_prefix=c_name(self._prefix, protect=False)))
+
+ def visit_end(self) -> None:
+ with self._temp_module('./init'):
+ self._genc.add(mcgen('''
+}
+'''))
def visit_command(self,
name: str,
- info: QAPISourceInfo,
+ info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
arg_type: Optional[QAPISchemaObjectType],
@@ -321,15 +317,17 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
if ret_type and ret_type not in self._visited_ret_types[self._genc]:
self._visited_ret_types[self._genc].add(ret_type)
with ifcontext(ret_type.ifcond,
- self._genh, self._genc, self._regy):
+ self._genh, self._genc):
self._genc.add(gen_marshal_output(ret_type))
- with ifcontext(ifcond, self._genh, self._genc, self._regy):
+ with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
self._genh.add(gen_marshal_decl(name))
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
- self._regy.add(gen_register_command(name, success_response,
- allow_oob, allow_preconfig,
- coroutine))
+ with self._temp_module('./init'):
+ with ifcontext(ifcond, self._genh, self._genc):
+ self._genc.add(gen_register_command(name, success_response,
+ allow_oob, allow_preconfig,
+ coroutine))
def gen_commands(schema: QAPISchema,
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index 599f3d1f56..8c57deb2b8 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -12,7 +12,7 @@ This work is licensed under the terms of the GNU GPL, version 2.
See the COPYING file in the top-level directory.
"""
-from typing import List
+from typing import List, Optional
from .common import c_enum_const, c_name, mcgen
from .gen import QAPISchemaModularCVisitor, build_params, ifcontext
@@ -27,7 +27,7 @@ from .types import gen_enum, gen_enum_lookup
def build_event_send_proto(name: str,
- arg_type: QAPISchemaObjectType,
+ arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> str:
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
'c_name': c_name(name.lower()),
@@ -35,7 +35,7 @@ def build_event_send_proto(name: str,
def gen_event_send_decl(name: str,
- arg_type: QAPISchemaObjectType,
+ arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> str:
return mcgen('''
@@ -78,7 +78,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str:
def gen_event_send(name: str,
- arg_type: QAPISchemaObjectType,
+ arg_type: Optional[QAPISchemaObjectType],
boxed: bool,
event_enum_name: str,
event_emit: str) -> str:
@@ -99,6 +99,7 @@ def gen_event_send(name: str,
proto=build_event_send_proto(name, arg_type, boxed))
if have_args:
+ assert arg_type is not None
ret += mcgen('''
QObject *obj;
Visitor *v;
@@ -114,6 +115,7 @@ def gen_event_send(name: str,
name=name)
if have_args:
+ assert arg_type is not None
ret += mcgen('''
v = qobject_output_visitor_new(&obj);
''')
@@ -189,7 +191,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
types=types))
def visit_end(self) -> None:
- self._add_system_module('emit', ' * QAPI Events emission')
+ self._add_module('./emit', ' * QAPI Events emission')
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqapi-emit-events.h"
@@ -211,10 +213,10 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
def visit_event(self,
name: str,
- info: QAPISourceInfo,
+ info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
- arg_type: QAPISchemaObjectType,
+ arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> None:
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
index b40f18eee3..63549cc8d4 100644
--- a/scripts/qapi/gen.py
+++ b/scripts/qapi/gen.py
@@ -31,12 +31,16 @@ from .common import (
guardstart,
mcgen,
)
-from .schema import QAPISchemaObjectType, QAPISchemaVisitor
+from .schema import (
+ QAPISchemaModule,
+ QAPISchemaObjectType,
+ QAPISchemaVisitor,
+)
from .source import QAPISourceInfo
class QAPIGen:
- def __init__(self, fname: Optional[str]):
+ def __init__(self, fname: str):
self.fname = fname
self._preamble = ''
self._body = ''
@@ -121,7 +125,7 @@ def build_params(arg_type: Optional[QAPISchemaObjectType],
class QAPIGenCCode(QAPIGen):
- def __init__(self, fname: Optional[str]):
+ def __init__(self, fname: str):
super().__init__(fname)
self._start_if: Optional[Tuple[List[str], str, str]] = None
@@ -130,15 +134,12 @@ class QAPIGenCCode(QAPIGen):
self._start_if = (ifcond, self._body, self._preamble)
def end_if(self) -> None:
- assert self._start_if
- self._wrap_ifcond()
- self._start_if = None
-
- def _wrap_ifcond(self) -> None:
+ assert self._start_if is not None
self._body = _wrap_ifcond(self._start_if[0],
self._start_if[1], self._body)
self._preamble = _wrap_ifcond(self._start_if[0],
self._start_if[2], self._preamble)
+ self._start_if = None
def get_content(self) -> str:
assert self._start_if is None
@@ -243,85 +244,88 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
self._user_blurb = user_blurb
self._builtin_blurb = builtin_blurb
self._pydoc = pydoc
- self._genc: Optional[QAPIGenC] = None
- self._genh: Optional[QAPIGenH] = None
- self._module: Dict[Optional[str], Tuple[QAPIGenC, QAPIGenH]] = {}
+ self._current_module: Optional[str] = None
+ self._module: Dict[str, Tuple[QAPIGenC, QAPIGenH]] = {}
self._main_module: Optional[str] = None
- @staticmethod
- def _is_user_module(name: Optional[str]) -> bool:
- return bool(name and not name.startswith('./'))
+ @property
+ def _genc(self) -> QAPIGenC:
+ assert self._current_module is not None
+ return self._module[self._current_module][0]
- @staticmethod
- def _is_builtin_module(name: Optional[str]) -> bool:
- return not name
+ @property
+ def _genh(self) -> QAPIGenH:
+ assert self._current_module is not None
+ return self._module[self._current_module][1]
- def _module_dirname(self, name: Optional[str]) -> str:
- if self._is_user_module(name):
+ @staticmethod
+ def _module_dirname(name: str) -> str:
+ if QAPISchemaModule.is_user_module(name):
return os.path.dirname(name)
return ''
- def _module_basename(self, what: str, name: Optional[str]) -> str:
- ret = '' if self._is_builtin_module(name) else self._prefix
- if self._is_user_module(name):
+ def _module_basename(self, what: str, name: str) -> str:
+ ret = '' if QAPISchemaModule.is_builtin_module(name) else self._prefix
+ if QAPISchemaModule.is_user_module(name):
basename = os.path.basename(name)
ret += what
if name != self._main_module:
ret += '-' + os.path.splitext(basename)[0]
else:
- name = name[2:] if name else 'builtin'
- ret += re.sub(r'-', '-' + name + '-', what)
+ assert QAPISchemaModule.is_system_module(name)
+ ret += re.sub(r'-', '-' + name[2:] + '-', what)
return ret
- def _module_filename(self, what: str, name: Optional[str]) -> str:
+ def _module_filename(self, what: str, name: str) -> str:
return os.path.join(self._module_dirname(name),
self._module_basename(what, name))
- def _add_module(self, name: Optional[str], blurb: str) -> None:
+ def _add_module(self, name: str, blurb: str) -> None:
+ if QAPISchemaModule.is_user_module(name):
+ if self._main_module is None:
+ self._main_module = name
basename = self._module_filename(self._what, name)
genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
self._module[name] = (genc, genh)
- self._genc, self._genh = self._module[name]
-
- def _add_user_module(self, name: str, blurb: str) -> None:
- assert self._is_user_module(name)
- if self._main_module is None:
- self._main_module = name
- self._add_module(name, blurb)
+ self._current_module = name
- def _add_system_module(self, name: Optional[str], blurb: str) -> None:
- self._add_module(name and './' + name, blurb)
+ @contextmanager
+ def _temp_module(self, name: str) -> Iterator[None]:
+ old_module = self._current_module
+ self._current_module = name
+ yield
+ self._current_module = old_module
def write(self, output_dir: str, opt_builtins: bool = False) -> None:
for name in self._module:
- if self._is_builtin_module(name) and not opt_builtins:
+ if QAPISchemaModule.is_builtin_module(name) and not opt_builtins:
continue
(genc, genh) = self._module[name]
genc.write(output_dir)
genh.write(output_dir)
- def _begin_system_module(self, name: None) -> None:
+ def _begin_builtin_module(self) -> None:
pass
def _begin_user_module(self, name: str) -> None:
pass
- def visit_module(self, name: Optional[str]) -> None:
- if name is None:
+ def visit_module(self, name: str) -> None:
+ if QAPISchemaModule.is_builtin_module(name):
if self._builtin_blurb:
- self._add_system_module(None, self._builtin_blurb)
- self._begin_system_module(name)
+ self._add_module(name, self._builtin_blurb)
+ self._begin_builtin_module()
else:
# The built-in module has not been created. No code may
# be generated.
- self._genc = None
- self._genh = None
+ self._current_module = None
else:
- self._add_user_module(name, self._user_blurb)
+ assert QAPISchemaModule.is_user_module(name)
+ self._add_module(name, self._user_blurb)
self._begin_user_module(name)
- def visit_include(self, name: str, info: QAPISourceInfo) -> None:
+ def visit_include(self, name: str, info: Optional[QAPISourceInfo]) -> None:
relname = os.path.relpath(self._module_filename(self._what, name),
os.path.dirname(self._genh.fname))
self._genh.preamble_add(mcgen('''
diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
index 42517210b8..703e7ed1ed 100644
--- a/scripts/qapi/main.py
+++ b/scripts/qapi/main.py
@@ -23,6 +23,8 @@ from .visit import gen_visit
def invalid_prefix_char(prefix: str) -> Optional[str]:
match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', prefix)
+ # match cannot be None, but mypy cannot infer that.
+ assert match is not None
if match.end() != len(prefix):
return prefix[match.end()]
return None
diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini
index 74fc6c8215..04bd5db527 100644
--- a/scripts/qapi/mypy.ini
+++ b/scripts/qapi/mypy.ini
@@ -1,6 +1,5 @@
[mypy]
strict = True
-strict_optional = False
disallow_untyped_calls = False
python_version = 3.6
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 720449feee..353e8020a2 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -68,7 +68,8 @@ class QAPISchemaEntity:
def _set_module(self, schema, info):
assert self._checked
- self._module = schema.module_by_fname(info and info.fname)
+ fname = info.fname if info else QAPISchemaModule.BUILTIN_MODULE_NAME
+ self._module = schema.module_by_fname(fname)
self._module.add_entity(self)
def set_module(self, schema):
@@ -137,10 +138,40 @@ class QAPISchemaVisitor:
class QAPISchemaModule:
+
+ BUILTIN_MODULE_NAME = './builtin'
+
def __init__(self, name):
self.name = name
self._entity_list = []
+ @staticmethod
+ def is_system_module(name: str) -> bool:
+ """
+ System modules are internally defined modules.
+
+ Their names start with the "./" prefix.
+ """
+ return name.startswith('./')
+
+ @classmethod
+ def is_user_module(cls, name: str) -> bool:
+ """
+ User modules are those defined by the user in qapi JSON files.
+
+ They do not start with the "./" prefix.
+ """
+ return not cls.is_system_module(name)
+
+ @classmethod
+ def is_builtin_module(cls, name: str) -> bool:
+ """
+ The built-in module is a single System module for the built-in types.
+
+ It is always "./builtin".
+ """
+ return name == cls.BUILTIN_MODULE_NAME
+
def add_entity(self, ent):
self._entity_list.append(ent)
@@ -825,7 +856,7 @@ class QAPISchema:
self._entity_dict = {}
self._module_dict = OrderedDict()
self._schema_dir = os.path.dirname(fname)
- self._make_module(None) # built-ins
+ self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
self._make_module(fname)
self._predefining = True
self._def_predefineds()
@@ -870,9 +901,9 @@ class QAPISchema:
info, "%s uses unknown type '%s'" % (what, name))
return typ
- def _module_name(self, fname):
- if fname is None:
- return None
+ def _module_name(self, fname: str) -> str:
+ if QAPISchemaModule.is_system_module(fname):
+ return fname
return os.path.relpath(fname, self._schema_dir)
def _make_module(self, fname):
@@ -883,7 +914,6 @@ class QAPISchema:
def module_by_fname(self, fname):
name = self._module_name(fname)
- assert name in self._module_dict
return self._module_dict[name]
def _def_include(self, expr, info, doc):
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 2b4916cdaa..2bdd626847 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -271,7 +271,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
prefix, 'qapi-types', ' * Schema-defined QAPI types',
' * Built-in QAPI types', __doc__)
- def _begin_system_module(self, name: None) -> None:
+ def _begin_builtin_module(self) -> None:
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
@@ -350,7 +350,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
def visit_alternate_type(self,
name: str,
- info: QAPISourceInfo,
+ info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 339f152152..22e62df901 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -305,7 +305,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
prefix, 'qapi-visit', ' * Schema-defined QAPI visitors',
' * Built-in QAPI visitors', __doc__)
- def _begin_system_module(self, name: None) -> None:
+ def _begin_builtin_module(self) -> None:
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/error.h"
@@ -336,7 +336,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
def visit_enum_type(self,
name: str,
- info: QAPISourceInfo,
+ info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
members: List[QAPISchemaEnumMember],
@@ -378,7 +378,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
def visit_alternate_type(self,
name: str,
- info: QAPISourceInfo,
+ info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:
diff --git a/softmmu/rtc.c b/softmmu/rtc.c
index e1e15ef613..5632684fc9 100644
--- a/softmmu/rtc.c
+++ b/softmmu/rtc.c
@@ -179,7 +179,8 @@ void configure_rtc(QemuOpts *opts)
if (!strcmp(value, "slew")) {
object_register_sugar_prop("mc146818rtc",
"lost_tick_policy",
- "slew");
+ "slew",
+ false);
} else if (!strcmp(value, "none")) {
/* discard is default */
} else {
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 58ed9be92f..b219ce1f35 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -101,6 +101,7 @@
#include "qemu/plugin.h"
#include "qemu/queue.h"
#include "sysemu/arch_init.h"
+#include "exec/confidential-guest-support.h"
#include "ui/qemu-spice.h"
#include "qapi/string-input-visitor.h"
@@ -1663,16 +1664,20 @@ static int machine_set_property(void *opaque,
return 0;
}
if (g_str_equal(qom_name, "igd-passthru")) {
- object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), qom_name, value);
+ object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), qom_name, value,
+ false);
return 0;
}
if (g_str_equal(qom_name, "kvm-shadow-mem")) {
- object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value);
+ object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value,
+ false);
return 0;
}
if (g_str_equal(qom_name, "kernel-irqchip")) {
- object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value);
- object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), qom_name, value);
+ object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value,
+ false);
+ object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), qom_name, value,
+ false);
return 0;
}
@@ -2298,9 +2303,10 @@ static void qemu_process_sugar_options(void)
val = g_strdup_printf("%d",
(uint32_t) qemu_opt_get_number(qemu_find_opts_singleton("smp-opts"), "cpus", 1));
- object_register_sugar_prop("memory-backend", "prealloc-threads", val);
+ object_register_sugar_prop("memory-backend", "prealloc-threads", val,
+ false);
g_free(val);
- object_register_sugar_prop("memory-backend", "prealloc", "on");
+ object_register_sugar_prop("memory-backend", "prealloc", "on", false);
}
if (watchdog) {
@@ -2493,6 +2499,8 @@ static void qemu_create_cli_devices(void)
static void qemu_machine_creation_done(void)
{
+ MachineState *machine = MACHINE(qdev_get_machine());
+
/* Did we create any drives that we failed to create a device for? */
drive_check_orphaned();
@@ -2512,6 +2520,13 @@ static void qemu_machine_creation_done(void)
qdev_machine_creation_done();
+ if (machine->cgs) {
+ /*
+ * Verify that Confidential Guest Support has actually been initialized
+ */
+ assert(machine->cgs->ready);
+ }
+
if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
exit(1);
}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 6dc1ee052d..4788139128 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -42,6 +42,7 @@
#include "hw/i386/intel_iommu.h"
#include "hw/i386/x86-iommu.h"
#include "hw/i386/e820_memory_layout.h"
+#include "sysemu/sev.h"
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
@@ -2135,6 +2136,25 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
uint64_t shadow_mem;
int ret;
struct utsname utsname;
+ Error *local_err = NULL;
+
+ /*
+ * Initialize SEV context, if required
+ *
+ * If no memory encryption is requested (ms->cgs == NULL) this is
+ * a no-op.
+ *
+ * It's also a no-op if a non-SEV confidential guest support
+ * mechanism is selected. SEV is the only mechanism available to
+ * select on x86 at present, so this doesn't arise, but if new
+ * mechanisms are supported in future (e.g. TDX), they'll need
+ * their own initialization either here or elsewhere.
+ */
+ ret = sev_kvm_init(ms->cgs, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return ret;
+ }
if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
error_report("kvm: KVM_CAP_IRQ_ROUTING not supported by KVM");
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index c1fecc2101..1ac1fd5b94 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -54,3 +54,8 @@ int sev_inject_launch_secret(const char *hdr, const char *secret,
{
return 1;
}
+
+int sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
+{
+ return 0;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 1546606811..11c9a3cc21 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -31,6 +31,7 @@
#include "qom/object.h"
#include "exec/address-spaces.h"
#include "monitor/monitor.h"
+#include "exec/confidential-guest-support.h"
#define TYPE_SEV_GUEST "sev-guest"
OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
@@ -47,7 +48,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
* -machine ...,memory-encryption=sev0
*/
struct SevGuestState {
- Object parent_obj;
+ ConfidentialGuestSupport parent_obj;
/* configuration parameters */
char *sev_device;
@@ -322,7 +323,7 @@ sev_guest_instance_init(Object *obj)
/* sev guest info */
static const TypeInfo sev_guest_info = {
- .parent = TYPE_OBJECT,
+ .parent = TYPE_CONFIDENTIAL_GUEST_SUPPORT,
.name = TYPE_SEV_GUEST,
.instance_size = sizeof(SevGuestState),
.instance_finalize = sev_guest_finalize,
@@ -334,26 +335,6 @@ static const TypeInfo sev_guest_info = {
}
};
-static SevGuestState *
-lookup_sev_guest_info(const char *id)
-{
- Object *obj;
- SevGuestState *info;
-
- obj = object_resolve_path_component(object_get_objects_root(), id);
- if (!obj) {
- return NULL;
- }
-
- info = (SevGuestState *)
- object_dynamic_cast(obj, TYPE_SEV_GUEST);
- if (!info) {
- return NULL;
- }
-
- return info;
-}
-
bool
sev_enabled(void)
{
@@ -681,27 +662,24 @@ sev_vm_state_change(void *opaque, int running, RunState state)
}
}
-void *
-sev_guest_init(const char *id)
+int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
{
- SevGuestState *sev;
+ SevGuestState *sev
+ = (SevGuestState *)object_dynamic_cast(OBJECT(cgs), TYPE_SEV_GUEST);
char *devname;
int ret, fw_error;
uint32_t ebx;
uint32_t host_cbitpos;
struct sev_user_data_status status = {};
+ if (!sev) {
+ return 0;
+ }
+
ret = ram_block_discard_disable(true);
if (ret) {
error_report("%s: cannot disable RAM discard", __func__);
- return NULL;
- }
-
- sev = lookup_sev_guest_info(id);
- if (!sev) {
- error_report("%s: '%s' is not a valid '%s' object",
- __func__, id, TYPE_SEV_GUEST);
- goto err;
+ return -1;
}
sev_guest = sev;
@@ -711,14 +689,14 @@ sev_guest_init(const char *id)
host_cbitpos = ebx & 0x3f;
if (host_cbitpos != sev->cbitpos) {
- error_report("%s: cbitpos check failed, host '%d' requested '%d'",
- __func__, host_cbitpos, sev->cbitpos);
+ error_setg(errp, "%s: cbitpos check failed, host '%d' requested '%d'",
+ __func__, host_cbitpos, sev->cbitpos);
goto err;
}
if (sev->reduced_phys_bits < 1) {
- error_report("%s: reduced_phys_bits check failed, it should be >=1,"
- " requested '%d'", __func__, sev->reduced_phys_bits);
+ error_setg(errp, "%s: reduced_phys_bits check failed, it should be >=1,"
+ " requested '%d'", __func__, sev->reduced_phys_bits);
goto err;
}
@@ -727,20 +705,19 @@ sev_guest_init(const char *id)
devname = object_property_get_str(OBJECT(sev), "sev-device", NULL);
sev->sev_fd = open(devname, O_RDWR);
if (sev->sev_fd < 0) {
- error_report("%s: Failed to open %s '%s'", __func__,
- devname, strerror(errno));
- }
- g_free(devname);
- if (sev->sev_fd < 0) {
+ error_setg(errp, "%s: Failed to open %s '%s'", __func__,
+ devname, strerror(errno));
+ g_free(devname);
goto err;
}
+ g_free(devname);
ret = sev_platform_ioctl(sev->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));
+ error_setg(errp, "%s: failed to get platform status ret=%d "
+ "fw_error='%d: %s'", __func__, ret, fw_error,
+ fw_error_to_str(fw_error));
goto err;
}
sev->build_id = status.build;
@@ -750,14 +727,14 @@ sev_guest_init(const char *id)
trace_kvm_sev_init();
ret = sev_ioctl(sev->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));
+ error_setg(errp, "%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(sev);
if (ret) {
- error_report("%s: failed to create encryption context", __func__);
+ error_setg(errp, "%s: failed to create encryption context", __func__);
goto err;
}
@@ -765,23 +742,29 @@ sev_guest_init(const char *id)
qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
qemu_add_vm_change_state_handler(sev_vm_state_change, sev);
- return sev;
+ cgs->ready = true;
+
+ return 0;
err:
sev_guest = NULL;
ram_block_discard_disable(false);
- return NULL;
+ return -1;
}
int
-sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
+sev_encrypt_flash(uint8_t *ptr, uint64_t len, Error **errp)
{
- SevGuestState *sev = handle;
-
- assert(sev);
+ if (!sev_guest) {
+ return 0;
+ }
/* if SEV is in update state then encrypt the data else do nothing */
- if (sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) {
- return sev_launch_update_data(sev, ptr, len);
+ if (sev_check_state(sev_guest, SEV_STATE_LAUNCH_UPDATE)) {
+ int ret = sev_launch_update_data(sev_guest, ptr, len);
+ if (ret < 0) {
+ error_setg(errp, "failed to encrypt pflash rom");
+ return ret;
+ }
}
return 0;
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index daf690a678..0c5056dd5b 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2929,21 +2929,3 @@ void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &tb_offset);
}
}
-
-/*
- * Don't set error if KVM_PPC_SVM_OFF ioctl is invoked on kernels
- * that don't support this ioctl.
- */
-void kvmppc_svm_off(Error **errp)
-{
- int rc;
-
- if (!kvm_enabled()) {
- return;
- }
-
- rc = kvm_vm_ioctl(KVM_STATE(current_accel()), KVM_PPC_SVM_OFF);
- if (rc && rc != -ENOTTY) {
- error_setg_errno(errp, -rc, "KVM_PPC_SVM_OFF ioctl failed");
- }
-}
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 73ce2bc951..989f61ace0 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -39,7 +39,6 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
bool radix, bool gtse,
uint64_t proc_tbl);
-void kvmppc_svm_off(Error **errp);
#ifndef CONFIG_USER_ONLY
bool kvmppc_spapr_use_multitce(void);
int kvmppc_spapr_enable_inkernel_multitce(void);
@@ -216,11 +215,6 @@ static inline target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
return 0;
}
-static inline void kvmppc_svm_off(Error **errp)
-{
- return;
-}
-
static inline void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu,
unsigned int online)
{
diff --git a/tests/Makefile.include b/tests/Makefile.include
index ceaf3f0d6e..d34254fb29 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -12,7 +12,7 @@ check-help:
@echo " $(MAKE) check-speed Run qobject speed tests"
@echo " $(MAKE) check-qapi-schema Run QAPI schema tests"
@echo " $(MAKE) check-block Run block tests"
-ifeq ($(CONFIG_TCG),y)
+ifneq ($(filter $(all-check-targets), check-softfloat),)
@echo " $(MAKE) check-tcg Run TCG tests"
@echo " $(MAKE) check-softfloat Run FPU emulation tests"
endif
@@ -40,11 +40,13 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
SPEED = quick
-# Per guest TCG tests
+# Build up our target list from the filtered list of ninja targets
+TARGETS=$(patsubst libqemu-%.fa, %, $(filter libqemu-%.fa, $(ninja-targets)))
-BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TARGET_DIRS))
-CLEAN_TCG_TARGET_RULES=$(patsubst %,clean-tcg-tests-%, $(TARGET_DIRS))
-RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TARGET_DIRS))
+# Per guest TCG tests
+BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TARGETS))
+CLEAN_TCG_TARGET_RULES=$(patsubst %,clean-tcg-tests-%, $(TARGETS))
+RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TARGETS))
# Probe for the Docker Builds needed for each build
$(foreach PROBE_TARGET,$(TARGET_DIRS), \
diff --git a/tests/acceptance/replay_kernel.py b/tests/acceptance/replay_kernel.py
index 772633b01d..c1cb862468 100644
--- a/tests/acceptance/replay_kernel.py
+++ b/tests/acceptance/replay_kernel.py
@@ -31,7 +31,7 @@ class ReplayKernelBase(LinuxKernelTest):
terminates.
"""
- timeout = 90
+ timeout = 120
KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
def run_vm(self, kernel_path, kernel_command_line, console_pattern,
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 0779dab5b9..93b29ad823 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -1,6 +1,6 @@
# Makefile for Docker tests
-.PHONY: docker docker-test docker-clean docker-image docker-qemu-src
+.PHONY: docker docker-help docker-test docker-clean docker-image docker-qemu-src
NULL :=
SPACE := $(NULL) #
@@ -11,7 +11,7 @@ HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m))
DOCKER_SUFFIX := .docker
DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles
# we don't run tests on intermediate images (used as base by another image)
-DOCKER_PARTIAL_IMAGES := debian10 debian11 debian-bootstrap
+DOCKER_PARTIAL_IMAGES := debian10 debian11 debian-bootstrap empty
DOCKER_IMAGES := $(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker))))
DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES))
# Use a global constant ccache directory to speed up repetitive builds
@@ -92,6 +92,24 @@ docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker
{ echo "You will need to build $(EXECUTABLE)"; exit 1;},\
"CHECK", "debian-$* exists"))
+# These are test targets
+USER_TCG_TARGETS=$(patsubst %-linux-user,qemu-%,$(filter %-linux-user,$(TARGET_DIRS)))
+EXEC_COPY_TESTS=$(patsubst %,docker-exec-copy-test-%, $(USER_TCG_TARGETS))
+
+$(EXEC_COPY_TESTS): docker-exec-copy-test-%: $(DOCKER_FILES_DIR)/empty.docker
+ $(call quiet-command, \
+ $(DOCKER_SCRIPT) build -t qemu/exec-copy-test-$* -f $< \
+ $(if $V,,--quiet) --no-cache \
+ --include-executable=$* \
+ --skip-binfmt, \
+ "TEST","copy $* to container")
+ $(call quiet-command, \
+ $(DOCKER_SCRIPT) run qemu/exec-copy-test-$* \
+ /$* -version > tests/docker-exec-copy-test-$*.out, \
+ "TEST","check $* works in container")
+
+docker-exec-copy-test: $(EXEC_COPY_TESTS)
+
endif
# Enforce dependencies for composite images
@@ -209,7 +227,7 @@ endif
@echo ' before running the command.'
@echo ' NETWORK=1 Enable virtual network interface with default backend.'
@echo ' NETWORK=$$BACKEND Enable virtual network interface with $$BACKEND.'
- @echo ' NOUSER Define to disable adding current user to containers passwd.'
+ @echo ' NOUSER=1 Define to disable adding current user to containers passwd.'
@echo ' NOCACHE=1 Ignore cache when build images.'
@echo ' EXECUTABLE=<path> Include executable in image.'
@echo ' EXTRA_FILES="<path> [... <path>]"'
@@ -218,6 +236,8 @@ endif
@echo ' Specify which container engine to run.'
@echo ' REGISTRY=url Cache builds from registry (default:$(DOCKER_REGISTRY))'
+docker-help: docker
+
# This rule if for directly running against an arbitrary docker target.
# It is called by the expanded docker targets (e.g. make
# docker-test-foo@bar) which will do additional verification.
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index 884dfeb29c..d28df4c140 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -93,7 +93,7 @@ def _guess_engine_command():
commands_txt)
-def _copy_with_mkdir(src, root_dir, sub_path='.'):
+def _copy_with_mkdir(src, root_dir, sub_path='.', name=None):
"""Copy src into root_dir, creating sub_path as needed."""
dest_dir = os.path.normpath("%s/%s" % (root_dir, sub_path))
try:
@@ -102,8 +102,13 @@ def _copy_with_mkdir(src, root_dir, sub_path='.'):
# we can safely ignore already created directories
pass
- dest_file = "%s/%s" % (dest_dir, os.path.basename(src))
- copy(src, dest_file)
+ dest_file = "%s/%s" % (dest_dir, name if name else os.path.basename(src))
+
+ try:
+ copy(src, dest_file)
+ except FileNotFoundError:
+ print("Couldn't copy %s to %s" % (src, dest_file))
+ pass
def _get_so_libs(executable):
@@ -120,7 +125,7 @@ def _get_so_libs(executable):
search = ldd_re.search(line)
if search:
try:
- libs.append(s.group(1))
+ libs.append(search.group(1))
except IndexError:
pass
except subprocess.CalledProcessError:
@@ -150,8 +155,9 @@ def _copy_binary_with_libs(src, bin_dest, dest_dir):
if libs:
for l in libs:
so_path = os.path.dirname(l)
+ name = os.path.basename(l)
real_l = os.path.realpath(l)
- _copy_with_mkdir(real_l, dest_dir, so_path)
+ _copy_with_mkdir(real_l, dest_dir, so_path, name)
def _check_binfmt_misc(executable):
@@ -432,6 +438,9 @@ class BuildCommand(SubCommand):
help="""Specify a binary that will be copied to the
container together with all its dependent
libraries""")
+ parser.add_argument("--skip-binfmt",
+ action="store_true",
+ help="""Skip binfmt entry check (used for testing)""")
parser.add_argument("--extra-files", nargs='*',
help="""Specify files that will be copied in the
Docker image, fulfilling the ADD directive from the
@@ -460,7 +469,9 @@ class BuildCommand(SubCommand):
docker_dir = tempfile.mkdtemp(prefix="docker_build")
# Validate binfmt_misc will work
- if args.include_executable:
+ if args.skip_binfmt:
+ qpath = args.include_executable
+ elif args.include_executable:
qpath, enabled = _check_binfmt_misc(args.include_executable)
if not enabled:
return 1
diff --git a/tests/docker/dockerfiles/empty.docker b/tests/docker/dockerfiles/empty.docker
new file mode 100644
index 0000000000..9ba980f1a8
--- /dev/null
+++ b/tests/docker/dockerfiles/empty.docker
@@ -0,0 +1,8 @@
+#
+# Empty Dockerfile
+#
+
+FROM scratch
+
+# Add everything from the context into the container
+ADD . /
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 273f0f54e1..ce4f6a4f0f 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 419284dae2..715b0bbc1a 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 69666c39ad..3feb3f69d3 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 42ae519656..9ae44052ac 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 0b654ddebb..16dbd9b819 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 061f81e509..48e923bfbc 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 04356775cd..6a30ded3fa 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 8868ca0dca..3b1387d9f1 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,4 +1,4 @@
-module None
+module ./builtin
object q_empty
enum QType
prefix QTYPE
diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu
index c096c611a2..a56564660c 100644
--- a/tests/tcg/Makefile.qemu
+++ b/tests/tcg/Makefile.qemu
@@ -90,11 +90,11 @@ run-guest-tests: guest-tests
else
guest-tests:
- $(call quiet-command, /bin/true, "BUILD", \
+ $(call quiet-command, true, "BUILD", \
"$(TARGET) guest-tests SKIPPED")
run-guest-tests:
- $(call quiet-command, /bin/true, "RUN", \
+ $(call quiet-command, true, "RUN", \
"tests for $(TARGET) SKIPPED")
endif
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index 1dd0f64d23..abbdb2e126 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -63,8 +63,11 @@ run-gdbstub-qxfer-auxv-read: sha1
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
"basic gdbstub qXfer:auxv:read support")
-EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read
+else
+run-gdbstub-%:
+ $(call skip-test, "gdbstub test $*", "need working gdb")
endif
+EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read
# Update TESTS