aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-10-05 11:29:42 -0700
committerRichard Henderson <richard.henderson@linaro.org>2021-10-05 11:29:42 -0700
commit08a9b68dc033c9826da89f84202e547beadd92f0 (patch)
treeaafcb717250d0cb0648e4d8fee8fe8c6b3489c5b /target
parent9618c5badaa8eed25259cf095ff880efb939fbe7 (diff)
parentbb647c49b8f1f986d8171dd61db65e8a8d255be0 (diff)
downloadqemu-08a9b68dc033c9826da89f84202e547beadd92f0.zip
qemu-08a9b68dc033c9826da89f84202e547beadd92f0.tar.gz
qemu-08a9b68dc033c9826da89f84202e547beadd92f0.tar.bz2
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* Meson version update * fix search path when configuring with --cpu * support for measured SEV boot with -kernel (Dov) * fix missing BQL locks (Emanuele) * retrieve applesmc key from the host (Pedro) * KVM PV feature documentation (Vitaly) # gpg: Signature made Tue 05 Oct 2021 04:13:00 AM PDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] * remotes/bonzini/tags/for-upstream: meson: show library versions in the summary target/xtensa: list cores in a text file hexagon: use env keyword argument to pass PYTHONPATH meson: switch minimum meson version to 0.58.2, minimum recommended to 0.59.2 meson: bump submodule to 0.59.2 migration: add missing qemu_mutex_lock_iothread in migration_completion migration: block-dirty-bitmap: add missing qemu_mutex_lock_iothread configure, meson: move CPU_CFLAGS out of QEMU_CFLAGS hw/misc: applesmc: use host osk as default on macs x86/sev: generate SEV kernel loader hashes in x86_load_linux sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot i386: docs: Briefly describe KVM PV features Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/hexagon/meson.build3
-rw-r--r--target/i386/sev-stub.c5
-rw-r--r--target/i386/sev.c137
-rw-r--r--target/i386/sev_i386.h12
-rw-r--r--target/xtensa/cores.list9
-rwxr-xr-xtarget/xtensa/import_core.sh3
-rw-r--r--target/xtensa/meson.build4
7 files changed, 170 insertions, 3 deletions
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 6fd9360..c6d858f 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -156,7 +156,8 @@ dectree_generated = custom_target(
'dectree_generated.h.inc',
output: 'dectree_generated.h.inc',
depends: [iset_py],
- command: ['env', 'PYTHONPATH=' + meson.current_build_dir(), files('dectree.py'), '@OUTPUT@'],
+ env: {'PYTHONPATH': meson.current_build_dir()},
+ command: [python, files('dectree.py'), '@OUTPUT@'],
)
hexagon_ss.add(dectree_generated)
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 0227cb5..d8e6583 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -81,3 +81,8 @@ sev_get_attestation_report(const char *mnonce, Error **errp)
error_setg(errp, "SEV is not available in this QEMU");
return NULL;
}
+
+bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+{
+ g_assert_not_reached();
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index fa72104..bcd9260 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -23,6 +23,7 @@
#include "qemu/base64.h"
#include "qemu/module.h"
#include "qemu/uuid.h"
+#include "crypto/hash.h"
#include "sysemu/kvm.h"
#include "sev_i386.h"
#include "sysemu/sysemu.h"
@@ -83,6 +84,32 @@ typedef struct __attribute__((__packed__)) SevInfoBlock {
uint32_t reset_addr;
} SevInfoBlock;
+#define SEV_HASH_TABLE_RV_GUID "7255371f-3a3b-4b04-927b-1da6efa8d454"
+typedef struct QEMU_PACKED SevHashTableDescriptor {
+ /* SEV hash table area guest address */
+ uint32_t base;
+ /* SEV hash table area size (in bytes) */
+ uint32_t size;
+} SevHashTableDescriptor;
+
+/* hard code sha256 digest size */
+#define HASH_SIZE 32
+
+typedef struct QEMU_PACKED SevHashTableEntry {
+ QemuUUID guid;
+ uint16_t len;
+ uint8_t hash[HASH_SIZE];
+} SevHashTableEntry;
+
+typedef struct QEMU_PACKED SevHashTable {
+ QemuUUID guid;
+ uint16_t len;
+ SevHashTableEntry cmdline;
+ SevHashTableEntry initrd;
+ SevHashTableEntry kernel;
+ uint8_t padding[];
+} SevHashTable;
+
static SevGuestState *sev_guest;
static Error *sev_mig_blocker;
@@ -1071,6 +1098,116 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
return 0;
}
+static const QemuUUID sev_hash_table_header_guid = {
+ .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93,
+ 0xd4, 0x11, 0xfd, 0x21)
+};
+
+static const QemuUUID sev_kernel_entry_guid = {
+ .data = UUID_LE(0x4de79437, 0xabd2, 0x427f, 0xb8, 0x35, 0xd5, 0xb1,
+ 0x72, 0xd2, 0x04, 0x5b)
+};
+static const QemuUUID sev_initrd_entry_guid = {
+ .data = UUID_LE(0x44baf731, 0x3a2f, 0x4bd7, 0x9a, 0xf1, 0x41, 0xe2,
+ 0x91, 0x69, 0x78, 0x1d)
+};
+static const QemuUUID sev_cmdline_entry_guid = {
+ .data = UUID_LE(0x97d02dd8, 0xbd20, 0x4c94, 0xaa, 0x78, 0xe7, 0x71,
+ 0x4d, 0x36, 0xab, 0x2a)
+};
+
+/*
+ * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
+ * which is included in SEV's initial memory measurement.
+ */
+bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
+{
+ uint8_t *data;
+ SevHashTableDescriptor *area;
+ SevHashTable *ht;
+ uint8_t cmdline_hash[HASH_SIZE];
+ uint8_t initrd_hash[HASH_SIZE];
+ uint8_t kernel_hash[HASH_SIZE];
+ uint8_t *hashp;
+ size_t hash_len = HASH_SIZE;
+ int aligned_len;
+
+ if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
+ error_setg(errp, "SEV: kernel specified but OVMF has no hash table guid");
+ return false;
+ }
+ area = (SevHashTableDescriptor *)data;
+
+ /*
+ * Calculate hash of kernel command-line with the terminating null byte. If
+ * the user doesn't supply a command-line via -append, the 1-byte "\0" will
+ * be used.
+ */
+ hashp = cmdline_hash;
+ if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->cmdline_data,
+ ctx->cmdline_size, &hashp, &hash_len, errp) < 0) {
+ return false;
+ }
+ assert(hash_len == HASH_SIZE);
+
+ /*
+ * Calculate hash of initrd. If the user doesn't supply an initrd via
+ * -initrd, an empty buffer will be used (ctx->initrd_size == 0).
+ */
+ hashp = initrd_hash;
+ if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->initrd_data,
+ ctx->initrd_size, &hashp, &hash_len, errp) < 0) {
+ return false;
+ }
+ assert(hash_len == HASH_SIZE);
+
+ /* Calculate hash of the kernel */
+ hashp = kernel_hash;
+ struct iovec iov[2] = {
+ { .iov_base = ctx->setup_data, .iov_len = ctx->setup_size },
+ { .iov_base = ctx->kernel_data, .iov_len = ctx->kernel_size }
+ };
+ if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, iov, ARRAY_SIZE(iov),
+ &hashp, &hash_len, errp) < 0) {
+ return false;
+ }
+ assert(hash_len == HASH_SIZE);
+
+ /*
+ * Populate the hashes table in the guest's memory at the OVMF-designated
+ * area for the SEV hashes table
+ */
+ ht = qemu_map_ram_ptr(NULL, area->base);
+
+ ht->guid = sev_hash_table_header_guid;
+ ht->len = sizeof(*ht);
+
+ ht->cmdline.guid = sev_cmdline_entry_guid;
+ ht->cmdline.len = sizeof(ht->cmdline);
+ memcpy(ht->cmdline.hash, cmdline_hash, sizeof(ht->cmdline.hash));
+
+ ht->initrd.guid = sev_initrd_entry_guid;
+ ht->initrd.len = sizeof(ht->initrd);
+ memcpy(ht->initrd.hash, initrd_hash, sizeof(ht->initrd.hash));
+
+ ht->kernel.guid = sev_kernel_entry_guid;
+ ht->kernel.len = sizeof(ht->kernel);
+ memcpy(ht->kernel.hash, kernel_hash, sizeof(ht->kernel.hash));
+
+ /* When calling sev_encrypt_flash, the length has to be 16 byte aligned */
+ aligned_len = ROUND_UP(ht->len, 16);
+ if (aligned_len != ht->len) {
+ /* zero the excess data so the measurement can be reliably calculated */
+ memset(ht->padding, 0, aligned_len - ht->len);
+ }
+
+ if (sev_encrypt_flash((uint8_t *)ht, aligned_len, errp) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
static void
sev_register_types(void)
{
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index ae6d840..2afe108 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -28,6 +28,17 @@
#define SEV_POLICY_DOMAIN 0x10
#define SEV_POLICY_SEV 0x20
+typedef struct SevKernelLoaderContext {
+ char *setup_data;
+ size_t setup_size;
+ char *kernel_data;
+ size_t kernel_size;
+ char *initrd_data;
+ size_t initrd_size;
+ char *cmdline_data;
+ size_t cmdline_size;
+} SevKernelLoaderContext;
+
extern bool sev_es_enabled(void);
extern uint64_t sev_get_me_mask(void);
extern SevInfo *sev_get_info(void);
@@ -37,5 +48,6 @@ extern char *sev_get_launch_measurement(void);
extern SevCapability *sev_get_capabilities(Error **errp);
extern SevAttestationReport *
sev_get_attestation_report(const char *mnonce, Error **errp);
+extern bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp);
#endif
diff --git a/target/xtensa/cores.list b/target/xtensa/cores.list
new file mode 100644
index 0000000..5772a00
--- /dev/null
+++ b/target/xtensa/cores.list
@@ -0,0 +1,9 @@
+core-dc232b.c
+core-dc233c.c
+core-de212.c
+core-de233_fpu.c
+core-dsp3400.c
+core-fsf.c
+core-sample_controller.c
+core-test_kc705_be.c
+core-test_mmuhifi_c3.c
diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh
index 396b264..df66d09 100755
--- a/target/xtensa/import_core.sh
+++ b/target/xtensa/import_core.sh
@@ -66,3 +66,6 @@ static XtensaConfig $NAME __attribute__((unused)) = {
REGISTER_CORE($NAME)
EOF
+
+grep -qxf core-${NAME}.c "$BASE"/cores.list || \
+ echo core-${NAME}.c >> "$BASE"/cores.list
diff --git a/target/xtensa/meson.build b/target/xtensa/meson.build
index 7c4efa6..20bbf9b 100644
--- a/target/xtensa/meson.build
+++ b/target/xtensa/meson.build
@@ -1,7 +1,7 @@
xtensa_ss = ss.source_set()
-xtensa_cores = run_command('sh', '-c', 'cd $MESON_SOURCE_ROOT/$MESON_SUBDIR ; ls -1 core-*.c')
-xtensa_ss.add(files(xtensa_cores.stdout().strip().split('\n')))
+xtensa_cores = fs.read('cores.list')
+xtensa_ss.add(files(xtensa_cores.strip().split('\n')))
xtensa_ss.add(files(
'cpu.c',