208 lines
7.1 KiB
Diff
208 lines
7.1 KiB
Diff
|
|
From b2091d245563f4bd2974c8d8e6ef186de614f8e2 Mon Sep 17 00:00:00 2001
|
||
|
|
From: fangbaoshun <fangbaoshun@hygon.cn>
|
||
|
|
Date: Mon, 2 Aug 2021 11:41:58 +0800
|
||
|
|
Subject: [PATCH] target/i386: csv: add support to encrypt the outgoing pages
|
||
|
|
in the list queued before.
|
||
|
|
|
||
|
|
The csv_save_queued_outgoing_pages() provide the implementation to encrypt
|
||
|
|
the guest private pages during transmission. The routines uses SEND_START
|
||
|
|
command to create the outgoing encryption context on the first call then
|
||
|
|
uses COMMAND_BATCH command to send the SEND_UPDATE_DATA commands queued
|
||
|
|
in the list to encrypt the data before writing it to the socket. While
|
||
|
|
encrypting the data SEND_UPDATE_DATA produces some metadata (e.g MAC, IV).
|
||
|
|
The metadata is also sent to the target machine. After migration is completed,
|
||
|
|
we issue the SEND_FINISH command to transition the SEV guest state from sending
|
||
|
|
to unrunnable state.
|
||
|
|
|
||
|
|
Signed-off-by: hanliyang <hanliyang@hygon.cn>
|
||
|
|
---
|
||
|
|
include/exec/confidential-guest-support.h | 4 ++
|
||
|
|
linux-headers/linux/kvm.h | 8 +++
|
||
|
|
target/i386/csv.h | 1 +
|
||
|
|
target/i386/sev.c | 88 +++++++++++++++++++++++
|
||
|
|
target/i386/sev.h | 3 +
|
||
|
|
5 files changed, 104 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/include/exec/confidential-guest-support.h b/include/exec/confidential-guest-support.h
|
||
|
|
index 8949568acc..c84f8c1efc 100644
|
||
|
|
--- a/include/exec/confidential-guest-support.h
|
||
|
|
+++ b/include/exec/confidential-guest-support.h
|
||
|
|
@@ -80,6 +80,10 @@ struct ConfidentialGuestMemoryEncryptionOps {
|
||
|
|
|
||
|
|
/* Queue the encrypted page and metadata associated with it into a list */
|
||
|
|
int (*queue_outgoing_page)(uint8_t *ptr, uint32_t size, uint64_t addr);
|
||
|
|
+
|
||
|
|
+ /* Write the list queued with encrypted pages and metadata associated
|
||
|
|
+ * with them */
|
||
|
|
+ int (*save_queued_outgoing_pages)(QEMUFile *f, uint64_t *bytes_sent);
|
||
|
|
};
|
||
|
|
|
||
|
|
typedef struct ConfidentialGuestSupportClass {
|
||
|
|
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
|
||
|
|
index ca78fdc8b6..fcd09126a1 100644
|
||
|
|
--- a/linux-headers/linux/kvm.h
|
||
|
|
+++ b/linux-headers/linux/kvm.h
|
||
|
|
@@ -1971,6 +1971,9 @@ enum sev_cmd_id {
|
||
|
|
/* Guest Migration Extension */
|
||
|
|
KVM_SEV_SEND_CANCEL,
|
||
|
|
|
||
|
|
+ /* Hygon CSV batch command */
|
||
|
|
+ KVM_CSV_COMMAND_BATCH = 0x18,
|
||
|
|
+
|
||
|
|
KVM_SEV_NR_MAX,
|
||
|
|
};
|
||
|
|
|
||
|
|
@@ -2073,6 +2076,11 @@ struct kvm_csv_batch_list_node {
|
||
|
|
__u64 next_cmd_addr;
|
||
|
|
};
|
||
|
|
|
||
|
|
+struct kvm_csv_command_batch {
|
||
|
|
+ __u32 command_id;
|
||
|
|
+ __u64 csv_batch_list_uaddr;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
|
||
|
|
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
|
||
|
|
#define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
|
||
|
|
diff --git a/target/i386/csv.h b/target/i386/csv.h
|
||
|
|
index 4c1ef20029..2a3a3119d9 100644
|
||
|
|
--- a/target/i386/csv.h
|
||
|
|
+++ b/target/i386/csv.h
|
||
|
|
@@ -54,5 +54,6 @@ struct CsvBatchCmdList {
|
||
|
|
};
|
||
|
|
|
||
|
|
int csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr);
|
||
|
|
+int csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent);
|
||
|
|
|
||
|
|
#endif
|
||
|
|
diff --git a/target/i386/sev.c b/target/i386/sev.c
|
||
|
|
index 7dd35d64ee..1e2bbafe36 100644
|
||
|
|
--- a/target/i386/sev.c
|
||
|
|
+++ b/target/i386/sev.c
|
||
|
|
@@ -191,6 +191,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = {
|
||
|
|
.save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list,
|
||
|
|
.load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list,
|
||
|
|
.queue_outgoing_page = csv_queue_outgoing_page,
|
||
|
|
+ .save_queued_outgoing_pages = csv_save_queued_outgoing_pages,
|
||
|
|
};
|
||
|
|
|
||
|
|
static int
|
||
|
|
@@ -2012,6 +2013,69 @@ err:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int
|
||
|
|
+csv_command_batch(uint32_t cmd_id, uint64_t head_uaddr, int *fw_err)
|
||
|
|
+{
|
||
|
|
+ int ret;
|
||
|
|
+ struct kvm_csv_command_batch command_batch = { };
|
||
|
|
+
|
||
|
|
+ command_batch.command_id = cmd_id;
|
||
|
|
+ command_batch.csv_batch_list_uaddr = head_uaddr;
|
||
|
|
+
|
||
|
|
+ ret = sev_ioctl(sev_guest->sev_fd, KVM_CSV_COMMAND_BATCH,
|
||
|
|
+ &command_batch, fw_err);
|
||
|
|
+ if (ret) {
|
||
|
|
+ error_report("%s: COMMAND_BATCH ret=%d fw_err=%d '%s'",
|
||
|
|
+ __func__, ret, *fw_err, fw_error_to_str(*fw_err));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+csv_send_update_data_batch(SevGuestState *s, QEMUFile *f, uint64_t *bytes_sent)
|
||
|
|
+{
|
||
|
|
+ int ret, fw_error = 0;
|
||
|
|
+ struct kvm_sev_send_update_data *update;
|
||
|
|
+ struct kvm_csv_batch_list_node *node;
|
||
|
|
+
|
||
|
|
+ ret = csv_command_batch(KVM_SEV_SEND_UPDATE_DATA,
|
||
|
|
+ (uint64_t)s->csv_batch_cmd_list->head, &fw_error);
|
||
|
|
+ if (ret) {
|
||
|
|
+ error_report("%s: csv_command_batch ret=%d fw_error=%d '%s'",
|
||
|
|
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
|
||
|
|
+ goto err;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (node = s->csv_batch_cmd_list->head;
|
||
|
|
+ node != NULL;
|
||
|
|
+ node = (struct kvm_csv_batch_list_node *)node->next_cmd_addr) {
|
||
|
|
+ if (node != s->csv_batch_cmd_list->head) {
|
||
|
|
+ /* head's page header is saved before send_update_data */
|
||
|
|
+ qemu_put_be64(f, node->addr);
|
||
|
|
+ *bytes_sent += 8;
|
||
|
|
+ if (node->next_cmd_addr != 0)
|
||
|
|
+ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH);
|
||
|
|
+ else
|
||
|
|
+ qemu_put_be32(f, RAM_SAVE_ENCRYPTED_PAGE_BATCH_END);
|
||
|
|
+ *bytes_sent += 4;
|
||
|
|
+ }
|
||
|
|
+ update = (struct kvm_sev_send_update_data *)node->cmd_data_addr;
|
||
|
|
+ qemu_put_be32(f, update->hdr_len);
|
||
|
|
+ qemu_put_buffer(f, (uint8_t *)update->hdr_uaddr, update->hdr_len);
|
||
|
|
+ *bytes_sent += (4 + update->hdr_len);
|
||
|
|
+
|
||
|
|
+ qemu_put_be32(f, update->trans_len);
|
||
|
|
+ qemu_put_buffer(f, (uint8_t *)update->trans_uaddr, update->trans_len);
|
||
|
|
+ *bytes_sent += (4 + update->trans_len);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+err:
|
||
|
|
+ csv_batch_cmd_list_destroy(s->csv_batch_cmd_list);
|
||
|
|
+ s->csv_batch_cmd_list = NULL;
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
int
|
||
|
|
csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr)
|
||
|
|
{
|
||
|
|
@@ -2026,6 +2090,30 @@ csv_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr)
|
||
|
|
return csv_send_queue_data(s, ptr, sz, addr);
|
||
|
|
}
|
||
|
|
|
||
|
|
+int
|
||
|
|
+csv_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent)
|
||
|
|
+{
|
||
|
|
+ SevGuestState *s = sev_guest;
|
||
|
|
+
|
||
|
|
+ /* Only support for HYGON CSV */
|
||
|
|
+ if (!is_hygon_cpu()) {
|
||
|
|
+ error_report("Only support transfer queued pages for HYGON CSV");
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * If this is a first buffer then create outgoing encryption context
|
||
|
|
+ * and write our PDH, policy and session data.
|
||
|
|
+ */
|
||
|
|
+ if (!sev_check_state(s, SEV_STATE_SEND_UPDATE) &&
|
||
|
|
+ sev_send_start(s, f, bytes_sent)) {
|
||
|
|
+ error_report("Failed to create outgoing context");
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return csv_send_update_data_batch(s, f, bytes_sent);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static const QemuUUID sev_hash_table_header_guid = {
|
||
|
|
.data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93,
|
||
|
|
0xd4, 0x11, 0xfd, 0x21)
|
||
|
|
diff --git a/target/i386/sev.h b/target/i386/sev.h
|
||
|
|
index 84e3bdf2df..f7886116e7 100644
|
||
|
|
--- a/target/i386/sev.h
|
||
|
|
+++ b/target/i386/sev.h
|
||
|
|
@@ -41,6 +41,9 @@ typedef struct SevKernelLoaderContext {
|
||
|
|
#define RAM_SAVE_ENCRYPTED_PAGE 0x1
|
||
|
|
#define RAM_SAVE_SHARED_REGIONS_LIST 0x2
|
||
|
|
|
||
|
|
+#define RAM_SAVE_ENCRYPTED_PAGE_BATCH 0x4
|
||
|
|
+#define RAM_SAVE_ENCRYPTED_PAGE_BATCH_END 0x5
|
||
|
|
+
|
||
|
|
#ifdef CONFIG_SEV
|
||
|
|
bool sev_enabled(void);
|
||
|
|
bool sev_es_enabled(void);
|
||
|
|
--
|
||
|
|
2.41.0.windows.1
|
||
|
|
|