diff --git a/1033-target-i386-csv-Add-CSV3-context.patch b/1033-target-i386-csv-Add-CSV3-context.patch new file mode 100644 index 0000000000000000000000000000000000000000..880f4c2ae67e91fd79f489d0395fcb22cb098d94 --- /dev/null +++ b/1033-target-i386-csv-Add-CSV3-context.patch @@ -0,0 +1,86 @@ +From d9da5a2694de340197ff8e51080f112af8bfff5c Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 14:57:28 +0800 +Subject: [PATCH 01/14] target/i386: csv: Add CSV3 context + +CSV/CSV2/CSV3 are the secure virtualization features on Hygon CPUs. +The CSV and CSV2 are compatible with the AMD SEV and SEV-ES, +respectively. From CSV3, we introduced more secure features to +protect the guest, users can bit 6 of the guest policy to run a +CSV3 guest. + +Add the context and the build option. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + target/i386/csv.c | 11 +++++++++++ + target/i386/csv.h | 18 ++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 88fb05ac3..9a1de04db 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -18,3 +18,14 @@ + #include "csv.h" + + bool csv_kvm_cpu_reset_inhibit; ++ ++Csv3GuestState csv3_guest = { 0 }; ++ ++bool ++csv3_enabled(void) ++{ ++ if (!is_hygon_cpu()) ++ return false; ++ ++ return sev_es_enabled() && (csv3_guest.policy & GUEST_POLICY_CSV3_BIT); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index ac4bb5bee..7852fb8dc 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -14,6 +14,8 @@ + #ifndef I386_CSV_H + #define I386_CSV_H + ++#include "qapi/qapi-commands-misc-target.h" ++ + #ifdef CONFIG_CSV + + #include "cpu.h" +@@ -38,9 +40,12 @@ static bool __attribute__((unused)) is_hygon_cpu(void) + return false; + } + ++bool csv3_enabled(void); ++ + #else + + #define is_hygon_cpu() (false) ++#define csv3_enabled() (false) + + #endif + +@@ -64,4 +69,17 @@ int csv_load_queued_incoming_pages(QEMUFile *f); + int csv_save_outgoing_cpu_state(QEMUFile *f, uint64_t *bytes_sent); + int csv_load_incoming_cpu_state(QEMUFile *f); + ++/* CSV3 */ ++#define GUEST_POLICY_CSV3_BIT (1 << 6) ++ ++struct Csv3GuestState { ++ uint32_t policy; ++ int sev_fd; ++ void *state; ++}; ++ ++typedef struct Csv3GuestState Csv3GuestState; ++ ++extern struct Csv3GuestState csv3_guest; ++ + #endif +-- +2.31.1 + diff --git a/1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch b/1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e8bf484b787141d2bef77700214dca9bf158ec5 --- /dev/null +++ b/1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch @@ -0,0 +1,202 @@ +From ab6316e662eac3bd66085d50d33153d8205b2334 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 11:07:41 +0800 +Subject: [PATCH 02/14] target/i386: csv: Add command to initialize CSV3 + context + +When CSV3 is enabled, KVM_CSV3_INIT command is used to initialize +the platform, which is implemented by reusing the SEV API framework +and extending the functionality. + +The KVM_CSV3_INIT command should be performed earlier than +any other command. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 11 +++++++++ + target/i386/csv-sysemu-stub.c | 5 ++++ + target/i386/csv.c | 45 +++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 4 ++++ + target/i386/sev.c | 17 +++++++++++++ + target/i386/sev.h | 7 ++++++ + 6 files changed, 89 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 372d0bd14..d976908bc 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2060,6 +2060,17 @@ struct kvm_csv_command_batch { + __u64 csv_batch_list_uaddr; + }; + ++/* CSV3 command */ ++enum csv3_cmd_id { ++ KVM_CSV3_NR_MIN = 0xc0, ++ ++ KVM_CSV3_INIT = KVM_CSV3_NR_MIN, ++}; ++ ++struct kvm_csv3_init_data { ++ __u64 nodemask; ++}; ++ + #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-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 5874e4cc1..72f0f5c77 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -14,3 +14,8 @@ + #include "qemu/osdep.h" + #include "sev.h" + #include "csv.h" ++ ++int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) ++{ ++ return 0; ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 9a1de04db..f02aadb54 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -12,6 +12,13 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/error-report.h" ++ ++#include ++ ++#ifdef CONFIG_NUMA ++#include ++#endif + + #include "cpu.h" + #include "sev.h" +@@ -21,6 +28,44 @@ bool csv_kvm_cpu_reset_inhibit; + + Csv3GuestState csv3_guest = { 0 }; + ++int ++csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) ++{ ++ int fw_error; ++ int ret; ++ struct kvm_csv3_init_data data = { 0 }; ++ ++#ifdef CONFIG_NUMA ++ int mode; ++ unsigned long nodemask; ++ ++ /* Set flags as 0 to retrieve the default NUMA policy. */ ++ ret = get_mempolicy(&mode, &nodemask, sizeof(nodemask) * 8, NULL, 0); ++ if (ret == 0 && (mode == MPOL_BIND)) ++ data.nodemask = nodemask; ++#endif ++ ++ if (!ops || !ops->sev_ioctl || !ops->fw_error_to_str) ++ return -1; ++ ++ csv3_guest.policy = policy; ++ if (csv3_enabled()) { ++ ret = ops->sev_ioctl(fd, KVM_CSV3_INIT, &data, &fw_error); ++ if (ret) { ++ csv3_guest.policy = 0; ++ error_report("%s: Fail to initialize ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, ops->fw_error_to_str(fw_error)); ++ return -1; ++ } ++ ++ csv3_guest.sev_fd = fd; ++ csv3_guest.state = state; ++ csv3_guest.sev_ioctl = ops->sev_ioctl; ++ csv3_guest.fw_error_to_str = ops->fw_error_to_str; ++ } ++ return 0; ++} ++ + bool + csv3_enabled(void) + { +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 7852fb8dc..cf125fe0f 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -15,6 +15,7 @@ + #define I386_CSV_H + + #include "qapi/qapi-commands-misc-target.h" ++#include "sev.h" + + #ifdef CONFIG_CSV + +@@ -76,10 +77,13 @@ struct Csv3GuestState { + uint32_t policy; + int sev_fd; + void *state; ++ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); ++ const char *(*fw_error_to_str)(int code); + }; + + typedef struct Csv3GuestState Csv3GuestState; + + extern struct Csv3GuestState csv3_guest; ++extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 3406861f6..50f3429a4 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1180,6 +1180,18 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + goto err; + } + ++ /* Support CSV3 */ ++ if (!ret && cmd == KVM_SEV_ES_INIT) { ++ ret = csv3_init(sev_guest->policy, sev->sev_fd, (void *)&sev->state, &sev_ops); ++ if (ret) { ++ error_setg(errp, "%s: failed to init csv3 context", __func__); ++ goto err; ++ } ++ /* The CSV3 guest is not resettable */ ++ if (csv3_enabled()) ++ csv_kvm_cpu_reset_inhibit = true; ++ } ++ + /* + * The LAUNCH context is used for new guest, if its an incoming guest + * then RECEIVE context will be created after the connection is established. +@@ -2589,6 +2601,11 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) + return ret; + } + ++struct sev_ops sev_ops = { ++ .sev_ioctl = sev_ioctl, ++ .fw_error_to_str = fw_error_to_str, ++}; ++ + static void + sev_register_types(void) + { +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 0bfe3879e..e91431e0f 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -80,4 +80,11 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + + extern bool sev_kvm_has_msr_ghcb; + ++struct sev_ops { ++ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); ++ const char *(*fw_error_to_str)(int code); ++}; ++ ++extern struct sev_ops sev_ops; ++ + #endif +-- +2.31.1 + diff --git a/1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch b/1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch new file mode 100644 index 0000000000000000000000000000000000000000..ca4a3aeb051b4b6fe237c11937bdf201f02a1c45 --- /dev/null +++ b/1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch @@ -0,0 +1,166 @@ +From 39ab65c4235b733a1a4e0147be3f81881fb1c551 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 09:59:16 +0800 +Subject: [PATCH 03/14] target/i386: csv: Add command to load data to CSV3 + guest memory + +The KVM_CSV3_LAUNCH_ENCRYPT_DATA command is used to load data to an +encrypted guest memory in an isolated memory region that guest owns. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 7 ++++ + target/i386/csv-sysemu-stub.c | 5 +++ + target/i386/csv.c | 69 +++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 2 + + target/i386/trace-events | 3 ++ + 5 files changed, 86 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index d976908bc..fa7b41581 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2065,6 +2065,13 @@ enum csv3_cmd_id { + KVM_CSV3_NR_MIN = 0xc0, + + KVM_CSV3_INIT = KVM_CSV3_NR_MIN, ++ KVM_CSV3_LAUNCH_ENCRYPT_DATA, ++}; ++ ++struct kvm_csv3_launch_encrypt_data { ++ __u64 gpa; ++ __u64 uaddr; ++ __u32 len; + }; + + struct kvm_csv3_init_data { +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 72f0f5c77..b0ccbd2f1 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -19,3 +19,8 @@ int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + { + return 0; + } ++ ++int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) ++{ ++ g_assert_not_reached(); ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index f02aadb54..0e3f4478a 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -13,6 +13,7 @@ + + #include "qemu/osdep.h" + #include "qemu/error-report.h" ++#include "qapi/error.h" + + #include + +@@ -20,6 +21,7 @@ + #include + #endif + ++#include "trace.h" + #include "cpu.h" + #include "sev.h" + #include "csv.h" +@@ -74,3 +76,70 @@ csv3_enabled(void) + + return sev_es_enabled() && (csv3_guest.policy & GUEST_POLICY_CSV3_BIT); + } ++ ++static bool ++csv3_check_state(SevState state) ++{ ++ return *((SevState *)csv3_guest.state) == state ? true : false; ++} ++ ++static int ++csv3_ioctl(int cmd, void *data, int *error) ++{ ++ if (csv3_guest.sev_ioctl) ++ return csv3_guest.sev_ioctl(csv3_guest.sev_fd, cmd, data, error); ++ else ++ return -1; ++} ++ ++static const char * ++fw_error_to_str(int code) ++{ ++ if (csv3_guest.fw_error_to_str) ++ return csv3_guest.fw_error_to_str(code); ++ else ++ return NULL; ++} ++ ++static int ++csv3_launch_encrypt_data(uint64_t gpa, uint8_t *addr, uint64_t len) ++{ ++ int ret, fw_error; ++ struct kvm_csv3_launch_encrypt_data update; ++ ++ if (!addr || !len) { ++ return 1; ++ } ++ ++ update.gpa = (__u64)gpa; ++ update.uaddr = (__u64)(unsigned long)addr; ++ update.len = len; ++ trace_kvm_csv3_launch_encrypt_data(gpa, addr, len); ++ ret = csv3_ioctl(KVM_CSV3_LAUNCH_ENCRYPT_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("%s: CSV3 LAUNCH_ENCRYPT_DATA ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ } ++ ++ return ret; ++} ++ ++int ++csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) ++{ ++ int ret = 0; ++ ++ if (!csv3_enabled()) { ++ error_setg(errp, "%s: CSV3 is not enabled", __func__); ++ return -1; ++ } ++ ++ /* if CSV3 is in update state then load the data to secure memory */ ++ if (csv3_check_state(SEV_STATE_LAUNCH_UPDATE)) { ++ ret = csv3_launch_encrypt_data(gpa, ptr, len); ++ if (ret) ++ error_setg(errp, "%s: CSV3 fail to encrypt data", __func__); ++ } ++ ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index cf125fe0f..928774f59 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -86,4 +86,6 @@ typedef struct Csv3GuestState Csv3GuestState; + extern struct Csv3GuestState csv3_guest; + extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + ++int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); ++ + #endif +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 87b765c73..e07061bf3 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -19,3 +19,6 @@ kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_le + kvm_sev_receive_finish(void) "" + kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len) "cpu_id %d cpu_index %d trans %p len %d" + kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int len, void *hdr, int hdr_len) "cpu_id %d cpu_index %d trans %p len %d hdr %p hdr_len %d" ++ ++# csv.c ++kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 +-- +2.31.1 + diff --git a/1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch b/1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch new file mode 100644 index 0000000000000000000000000000000000000000..febed2638d656f38345b4065cd187e20464167c3 --- /dev/null +++ b/1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch @@ -0,0 +1,108 @@ +From dad06ad8bf5f8ba7842f92f0a92346697740557a Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:25:05 +0800 +Subject: [PATCH 04/14] target/i386: csv: Add command to load vmcb to CSV3 + guest memory + +The KVM_CSV3_LAUNCH_ENCRYPT_VMCB command is used to load and encrypt +the initial VMCB data to secure memory in an isolated region that +guest owns. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 1 + + target/i386/csv-sysemu-stub.c | 5 +++++ + target/i386/csv.c | 21 +++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/sev.c | 8 ++++++-- + 5 files changed, 34 insertions(+), 2 deletions(-) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index fa7b41581..061b2e7f0 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2066,6 +2066,7 @@ enum csv3_cmd_id { + + KVM_CSV3_INIT = KVM_CSV3_NR_MIN, + KVM_CSV3_LAUNCH_ENCRYPT_DATA, ++ KVM_CSV3_LAUNCH_ENCRYPT_VMCB, + }; + + struct kvm_csv3_launch_encrypt_data { +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index b0ccbd2f1..23d885f0f 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -24,3 +24,8 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + { + g_assert_not_reached(); + } ++ ++int csv3_launch_encrypt_vmcb(void) ++{ ++ g_assert_not_reached(); ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 0e3f4478a..f423b898f 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -143,3 +143,24 @@ csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + + return ret; + } ++ ++int ++csv3_launch_encrypt_vmcb(void) ++{ ++ int ret, fw_error; ++ ++ if (!csv3_enabled()) { ++ error_report("%s: CSV3 is not enabled",__func__); ++ return -1; ++ } ++ ++ ret = csv3_ioctl(KVM_CSV3_LAUNCH_ENCRYPT_VMCB, NULL, &fw_error); ++ if (ret) { ++ error_report("%s: CSV3 LAUNCH_ENCRYPT_VMCB ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++err: ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 928774f59..6444d54ef 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -85,6 +85,7 @@ typedef struct Csv3GuestState Csv3GuestState; + + extern struct Csv3GuestState csv3_guest; + extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); ++extern int csv3_launch_encrypt_vmcb(void); + + int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 50f3429a4..b77572f0b 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -857,8 +857,12 @@ sev_launch_get_measure(Notifier *notifier, void *unused) + } + + if (sev_es_enabled()) { +- /* measure all the VM save areas before getting launch_measure */ +- ret = sev_launch_update_vmsa(sev); ++ if (csv3_enabled()) { ++ ret = csv3_launch_encrypt_vmcb(); ++ } else { ++ /* measure all the VM save areas before getting launch_measure */ ++ ret = sev_launch_update_vmsa(sev); ++ } + if (ret) { + exit(1); + } +-- +2.31.1 + diff --git a/1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch b/1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch new file mode 100644 index 0000000000000000000000000000000000000000..56c39136d3c4176f76d679c94c6bb8dc322c90f5 --- /dev/null +++ b/1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch @@ -0,0 +1,41 @@ +From 94786f0f3fb14205852f0c7ad8c3b4b8fb0ff4fa Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 17:31:28 +0800 +Subject: [PATCH 05/14] target/i386: cpu: Populate CPUID 0x8000_001F when CSV3 + is active + +On Hygon platform, bit 30 of EAX indicates whether +this feature is supported in hardware. + +When CSV3 is active, CPUID 0x8000_001F provides +information for it. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + target/i386/cpu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index a66e5a357..c01943ee6 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -29,6 +29,7 @@ + #include "hvf/hvf-i386.h" + #include "kvm/kvm_i386.h" + #include "sev.h" ++#include "csv.h" + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "qapi/qapi-visit-machine.h" +@@ -6660,6 +6661,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (sev_enabled()) { + *eax = 0x2; + *eax |= sev_es_enabled() ? 0x8 : 0; ++ *eax |= csv3_enabled() ? 0x40000000 : 0; /* bit 30 for CSV3 */ + *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ + *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ + } +-- +2.31.1 + diff --git a/1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch b/1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a1939c91b1acd7d049d1d9840538033612145ea --- /dev/null +++ b/1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch @@ -0,0 +1,35 @@ +From 1ac5b6d0bef3090fea6fbcc0435cb4215bdf0129 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:36:00 +0800 +Subject: [PATCH 06/14] target/i386: csv: Do not register/unregister guest + secure memory for CSV3 guest + +CSV3's guest memory is allocated by firmware in secure processor +from dedicated memory reserved upon system boot up, consequently +it is not necessary to add notifier to pin/unpin memory. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + target/i386/sev.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index b77572f0b..eb1026b57 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1217,7 +1217,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + } + } + +- ram_block_notifier_add(&sev_ram_notifier); ++ /* CSV3 guest do not need notifier to reg/unreg memory */ ++ if (!csv3_enabled()) { ++ 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, sev); + migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); +-- +2.31.1 + diff --git a/1039-target-i386-csv-Load-initial-image-to-private-memory.patch b/1039-target-i386-csv-Load-initial-image-to-private-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..8a22f5dda7204c6cc28b36d4eb6cb529d39eb371 --- /dev/null +++ b/1039-target-i386-csv-Load-initial-image-to-private-memory.patch @@ -0,0 +1,52 @@ +From 1234dd2391d79ba6a2db3fe82a22822ef7ad9e02 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 14:29:40 +0800 +Subject: [PATCH 07/14] target/i386: csv: Load initial image to private memory + for CSV3 guest + +The initial image of CSV3 guest should be loaded into private memory +before boot the guest. + +Add APIs to implement the image load. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + hw/i386/pc_sysfw.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index c8d9e71b8..2bbcbb8d3 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -37,6 +37,7 @@ + #include "hw/block/flash.h" + #include "sysemu/kvm.h" + #include "sev.h" ++#include "csv.h" + + #define FLASH_SECTOR_SIZE 4096 + +@@ -263,7 +264,18 @@ void x86_firmware_configure(void *ptr, int size) + error_report("failed to locate and/or save reset vector"); + exit(1); + } ++ if (csv3_enabled()) { ++ ram_addr_t offset = 0; ++ MemoryRegion *mr; + +- sev_encrypt_flash(ptr, size, &error_fatal); ++ mr = memory_region_from_host(ptr, &offset); ++ if (!mr) { ++ error_report("failed to get memory region of flash"); ++ exit(1); ++ } ++ csv3_load_data(mr->addr + offset, ptr, size, &error_fatal); ++ } else { ++ sev_encrypt_flash(ptr, size, &error_fatal); ++ } + } + } +-- +2.31.1 + diff --git a/1040-vga-Force-full-update-for-CSV3-guest.patch b/1040-vga-Force-full-update-for-CSV3-guest.patch new file mode 100644 index 0000000000000000000000000000000000000000..49c2b26480652c46dcdbc41ed463a9ffebcbb729 --- /dev/null +++ b/1040-vga-Force-full-update-for-CSV3-guest.patch @@ -0,0 +1,128 @@ +From ef998e2666f941ca94f8b5383d574bb886dcf81a Mon Sep 17 00:00:00 2001 +From: Xin Jiang +Date: Thu, 13 Jul 2023 09:35:10 +0800 +Subject: [PATCH 08/14] vga: Force full update for CSV3 guest + +As CSV3's NPT(nested page table) is managed by firmware, VMM is hard +to track the dirty pages of vga buffer. Although VMM could perform +a command to firmware to update read/write attribute of vga buffer +in NPT, it costs more time due to communication between VMM and +firmware. So the simplest method is to fully update vga buffer +always. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + accel/kvm/kvm-all.c | 1 + + accel/stubs/kvm-stub.c | 1 + + hw/display/vga.c | 7 +++++++ + include/sysemu/kvm.h | 8 ++++++++ + target/i386/csv.c | 3 +++ + 5 files changed, 20 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index e5ed69c33..25d23bba2 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -98,6 +98,7 @@ bool kvm_allowed; + bool kvm_readonly_mem_allowed; + bool kvm_vm_attributes_allowed; + bool kvm_msi_use_devid; ++bool kvm_csv3_allowed; + bool kvm_has_guest_debug; + static int kvm_sstep_flags; + static bool kvm_immediate_exit; +diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c +index 1b37d9a30..45b23f61c 100644 +--- a/accel/stubs/kvm-stub.c ++++ b/accel/stubs/kvm-stub.c +@@ -24,6 +24,7 @@ bool kvm_gsi_direct_mapping; + bool kvm_allowed; + bool kvm_readonly_mem_allowed; + bool kvm_msi_use_devid; ++bool kvm_csv3_allowed; + + void kvm_flush_coalesced_mmio_buffer(void) + { +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 37557c344..d70226a89 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -39,6 +39,8 @@ + #include "migration/vmstate.h" + #include "trace.h" + ++#include "sysemu/kvm.h" ++ + //#define DEBUG_VGA_MEM + //#define DEBUG_VGA_REG + +@@ -1783,6 +1785,11 @@ static void vga_update_display(void *opaque) + s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + full_update = 1; + } ++ ++ /* Force to full update in CSV guest. */ ++ if (kvm_csv3_enabled()) ++ full_update = 1; ++ + switch(graphic_mode) { + case GMODE_TEXT: + vga_draw_text(s, full_update); +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index d61487816..1e15cfe9d 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -42,6 +42,7 @@ extern bool kvm_gsi_routing_allowed; + extern bool kvm_gsi_direct_mapping; + extern bool kvm_readonly_mem_allowed; + extern bool kvm_msi_use_devid; ++extern bool kvm_csv3_allowed; + + #define kvm_enabled() (kvm_allowed) + /** +@@ -143,6 +144,12 @@ extern bool kvm_msi_use_devid; + */ + #define kvm_msi_devid_required() (kvm_msi_use_devid) + ++/** ++ * kvm_csv3_enabled: ++ * Returns: true if CSV3 feature is used for the VM. ++ */ ++#define kvm_csv3_enabled() (kvm_csv3_allowed) ++ + #else + + #define kvm_enabled() (0) +@@ -157,6 +164,7 @@ extern bool kvm_msi_use_devid; + #define kvm_gsi_direct_mapping() (false) + #define kvm_readonly_mem_enabled() (false) + #define kvm_msi_devid_required() (false) ++#define kvm_csv3_enabled() (false) + + #endif /* CONFIG_KVM_IS_POSSIBLE */ + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index f423b898f..70900be86 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -14,6 +14,7 @@ + #include "qemu/osdep.h" + #include "qemu/error-report.h" + #include "qapi/error.h" ++#include "sysemu/kvm.h" + + #include + +@@ -60,6 +61,8 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + return -1; + } + ++ kvm_csv3_allowed = true; ++ + csv3_guest.sev_fd = fd; + csv3_guest.state = state; + csv3_guest.sev_ioctl = ops->sev_ioctl; +-- +2.31.1 + diff --git a/1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch b/1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef0d64cc1e007491b82af65e2b74ad28f91d7f39 --- /dev/null +++ b/1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch @@ -0,0 +1,397 @@ +From 0d2dbd4d687ce23342fc072c1d5a64c28f3580c7 Mon Sep 17 00:00:00 2001 +From: liuyafei +Date: Mon, 22 May 2023 20:37:40 +0800 +Subject: [PATCH 09/14] vfio: Only map shared region for CSV3 virtual machine + +qemu vfio listener map/unmap all of the virtual machine's memory. +It does not work for CSV3 virtual machine, as only shared memory +should be accessed by device. + +Signed-off-by: liuyafei +Signed-off-by: hanliyang +--- + hw/vfio/container.c | 46 +++++++++++- + include/exec/memory.h | 11 +++ + system/memory.c | 18 +++++ + target/i386/csv-sysemu-stub.c | 10 +++ + target/i386/csv.c | 134 ++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 12 +++ + target/i386/kvm/kvm.c | 2 + + 7 files changed, 230 insertions(+), 3 deletions(-) + +diff --git a/hw/vfio/container.c b/hw/vfio/container.c +index 242010036..ce075f37d 100644 +--- a/hw/vfio/container.c ++++ b/hw/vfio/container.c +@@ -30,6 +30,7 @@ + #include "qemu/error-report.h" + #include "qemu/range.h" + #include "sysemu/reset.h" ++#include "sysemu/kvm.h" + #include "trace.h" + #include "qapi/error.h" + #include "migration/migration.h" +@@ -468,6 +469,32 @@ static void vfio_free_container(VFIOContainer *container) + g_free(container); + } + ++static SharedRegionListener *g_shl; ++ ++static void shared_memory_listener_register(MemoryListener *listener, ++ AddressSpace *as) ++{ ++ SharedRegionListener *shl; ++ ++ shl = g_new0(SharedRegionListener, 1); ++ ++ shl->listener = listener; ++ shl->as = as; ++ ++ shared_region_register_listener(shl); ++ g_shl = shl; ++} ++ ++static void shared_memory_listener_unregister(void) ++{ ++ SharedRegionListener *shl = g_shl; ++ ++ shared_region_unregister_listener(shl); ++ ++ g_free(shl); ++ g_shl = NULL; ++} ++ + static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + Error **errp) + { +@@ -613,7 +640,12 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + + container->listener = vfio_memory_listener; + +- memory_listener_register(&container->listener, container->space->as); ++ if (kvm_csv3_enabled()) { ++ shared_memory_listener_register(&container->listener, ++ container->space->as); ++ } else { ++ memory_listener_register(&container->listener, container->space->as); ++ } + + if (container->error) { + ret = -1; +@@ -629,7 +661,11 @@ listener_release_exit: + QLIST_REMOVE(group, container_next); + QLIST_REMOVE(container, next); + vfio_kvm_device_del_group(group); +- memory_listener_unregister(&container->listener); ++ if (kvm_csv3_enabled()) { ++ shared_memory_listener_unregister(); ++ } else { ++ memory_listener_unregister(&container->listener); ++ } + if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU || + container->iommu_type == VFIO_SPAPR_TCE_IOMMU) { + vfio_spapr_container_deinit(container); +@@ -663,7 +699,11 @@ static void vfio_disconnect_container(VFIOGroup *group) + * group. + */ + if (QLIST_EMPTY(&container->group_list)) { +- memory_listener_unregister(&container->listener); ++ if (kvm_csv3_enabled()) { ++ shared_memory_listener_unregister(); ++ } else { ++ memory_listener_unregister(&container->listener); ++ } + if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU || + container->iommu_type == VFIO_SPAPR_TCE_IOMMU) { + vfio_spapr_container_deinit(container); +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 831f7c996..3e65d8d9f 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -775,6 +775,17 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only, + bool *mr_has_discard_manager); + ++typedef struct SharedRegionListener SharedRegionListener; ++struct SharedRegionListener { ++ MemoryListener *listener; ++ AddressSpace *as; ++ QTAILQ_ENTRY(SharedRegionListener) next; ++}; ++ ++void shared_region_register_listener(SharedRegionListener *shl); ++void shared_region_unregister_listener(SharedRegionListener *shl); ++void *shared_region_listeners_get(void); ++ + typedef struct CoalescedMemoryRange CoalescedMemoryRange; + typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; + +diff --git a/system/memory.c b/system/memory.c +index 798b6c0a1..2ffb878eb 100644 +--- a/system/memory.c ++++ b/system/memory.c +@@ -48,6 +48,9 @@ static QTAILQ_HEAD(, MemoryListener) memory_listeners + static QTAILQ_HEAD(, AddressSpace) address_spaces + = QTAILQ_HEAD_INITIALIZER(address_spaces); + ++static QTAILQ_HEAD(, SharedRegionListener) shared_region_listeners ++ = QTAILQ_HEAD_INITIALIZER(shared_region_listeners); ++ + static GHashTable *flat_views; + + typedef struct AddrRange AddrRange; +@@ -2226,6 +2229,21 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + return true; + } + ++void shared_region_register_listener(SharedRegionListener *shl) ++{ ++ QTAILQ_INSERT_TAIL(&shared_region_listeners, shl, next); ++} ++ ++void shared_region_unregister_listener(SharedRegionListener *shl) ++{ ++ QTAILQ_REMOVE(&shared_region_listeners, shl, next); ++} ++ ++void *shared_region_listeners_get(void) ++{ ++ return &shared_region_listeners; ++} ++ + void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) + { + uint8_t mask = 1 << client; +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 23d885f0f..db22c299a 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -29,3 +29,13 @@ int csv3_launch_encrypt_vmcb(void) + { + g_assert_not_reached(); + } ++ ++int csv3_shared_region_dma_map(uint64_t start, uint64_t end) ++{ ++ return 0; ++} ++ ++void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end) ++{ ++ ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 70900be86..5823c8994 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -15,6 +15,7 @@ + #include "qemu/error-report.h" + #include "qapi/error.h" + #include "sysemu/kvm.h" ++#include "exec/address-spaces.h" + + #include + +@@ -67,6 +68,8 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + csv3_guest.state = state; + csv3_guest.sev_ioctl = ops->sev_ioctl; + csv3_guest.fw_error_to_str = ops->fw_error_to_str; ++ QTAILQ_INIT(&csv3_guest.dma_map_regions_list); ++ qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); + } + return 0; + } +@@ -167,3 +170,134 @@ csv3_launch_encrypt_vmcb(void) + err: + return ret; + } ++ ++int csv3_shared_region_dma_map(uint64_t start, uint64_t end) ++{ ++ MemoryRegionSection section; ++ AddressSpace *as; ++ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; ++ SharedRegionListener *shl; ++ MemoryListener *listener; ++ uint64_t size; ++ Csv3GuestState *s = &csv3_guest; ++ struct dma_map_region *region, *pos; ++ int ret = 0; ++ ++ if (!csv3_enabled()) ++ return 0; ++ ++ if (end <= start) ++ return 0; ++ ++ shared_region_listeners = shared_region_listeners_get(); ++ if (QTAILQ_EMPTY(shared_region_listeners)) ++ return 0; ++ ++ size = end - start; ++ ++ qemu_mutex_lock(&s->dma_map_regions_list_mutex); ++ QTAILQ_FOREACH(pos, &s->dma_map_regions_list, list) { ++ if (start >= (pos->start + pos->size)) { ++ continue; ++ } else if ((start + size) <= pos->start) { ++ break; ++ } else { ++ goto end; ++ } ++ } ++ QTAILQ_FOREACH(shl, shared_region_listeners, next) { ++ listener = shl->listener; ++ as = shl->as; ++ section = memory_region_find(as->root, start, size); ++ if (!section.mr) { ++ goto end; ++ } ++ ++ if (!memory_region_is_ram(section.mr)) { ++ memory_region_unref(section.mr); ++ goto end; ++ } ++ ++ if (listener->region_add) { ++ listener->region_add(listener, §ion); ++ } ++ memory_region_unref(section.mr); ++ } ++ ++ region = g_malloc0(sizeof(*region)); ++ if (!region) { ++ ret = -1; ++ goto end; ++ } ++ region->start = start; ++ region->size = size; ++ ++ if (pos) { ++ QTAILQ_INSERT_BEFORE(pos, region, list); ++ } else { ++ QTAILQ_INSERT_TAIL(&s->dma_map_regions_list, region, list); ++ } ++ ++end: ++ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); ++ return ret; ++} ++ ++void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end) ++{ ++ MemoryRegionSection section; ++ AddressSpace *as; ++ QTAILQ_HEAD(, SharedRegionListener) *shared_region_listeners; ++ SharedRegionListener *shl; ++ MemoryListener *listener; ++ uint64_t size; ++ Csv3GuestState *s = &csv3_guest; ++ struct dma_map_region *pos, *next_pos; ++ ++ if (!csv3_enabled()) ++ return; ++ ++ if (end <= start) ++ return; ++ ++ shared_region_listeners = shared_region_listeners_get(); ++ if (QTAILQ_EMPTY(shared_region_listeners)) ++ return; ++ ++ size = end - start; ++ ++ qemu_mutex_lock(&s->dma_map_regions_list_mutex); ++ QTAILQ_FOREACH_SAFE(pos, &s->dma_map_regions_list, list, next_pos) { ++ uint64_t l, r; ++ uint64_t curr_end = pos->start + pos->size; ++ ++ l = MAX(start, pos->start); ++ r = MIN(start + size, pos->start + pos->size); ++ if (l < r) { ++ if ((start <= pos->start) && (start + size >= pos->start + pos->size)) { ++ QTAILQ_FOREACH(shl, shared_region_listeners, next) { ++ listener = shl->listener; ++ as = shl->as; ++ section = memory_region_find(as->root, pos->start, pos->size); ++ if (!section.mr) { ++ goto end; ++ } ++ if (listener->region_del) { ++ listener->region_del(listener, §ion); ++ } ++ memory_region_unref(section.mr); ++ } ++ ++ QTAILQ_REMOVE(&s->dma_map_regions_list, pos, list); ++ g_free(pos); ++ } ++ break; ++ } ++ if ((start + size) <= curr_end) { ++ break; ++ } ++ } ++end: ++ qemu_mutex_unlock(&s->dma_map_regions_list_mutex); ++ return; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 6444d54ef..0c402cefd 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -15,6 +15,8 @@ + #define I386_CSV_H + + #include "qapi/qapi-commands-misc-target.h" ++#include "qemu/thread.h" ++#include "qemu/queue.h" + #include "sev.h" + + #ifdef CONFIG_CSV +@@ -73,12 +75,19 @@ int csv_load_incoming_cpu_state(QEMUFile *f); + /* CSV3 */ + #define GUEST_POLICY_CSV3_BIT (1 << 6) + ++struct dma_map_region { ++ uint64_t start, size; ++ QTAILQ_ENTRY(dma_map_region) list; ++}; ++ + struct Csv3GuestState { + uint32_t policy; + int sev_fd; + void *state; + int (*sev_ioctl)(int fd, int cmd, void *data, int *error); + const char *(*fw_error_to_str)(int code); ++ QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; ++ QemuMutex dma_map_regions_list_mutex; + }; + + typedef struct Csv3GuestState Csv3GuestState; +@@ -89,4 +98,7 @@ extern int csv3_launch_encrypt_vmcb(void); + + int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + ++int csv3_shared_region_dma_map(uint64_t start, uint64_t end); ++void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++ + #endif +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 2866a6d0e..925f4f804 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -5026,8 +5026,10 @@ static int kvm_handle_exit_hypercall(X86CPU *cpu, struct kvm_run *run) + + if (enc) { + sev_remove_shared_regions_list(gfn_start, gfn_end); ++ csv3_shared_region_dma_unmap(gpa, gfn_end << TARGET_PAGE_BITS); + } else { + sev_add_shared_regions_list(gfn_start, gfn_end); ++ csv3_shared_region_dma_map(gpa, gfn_end << TARGET_PAGE_BITS); + } + } + return 0; +-- +2.31.1 + diff --git a/1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch b/1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch new file mode 100644 index 0000000000000000000000000000000000000000..ee137076f3888a9332d71ba8536b322bcf05a4a0 --- /dev/null +++ b/1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch @@ -0,0 +1,79 @@ +From 9a1d0fdf779053eba4ba380adeef54d126b87b7b Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:25:19 +0800 +Subject: [PATCH 10/14] linux-headers: update kernel headers to include CSV3 + migration cmds + +Four new migration commands are added to support CSV3 migration. + +KVM_CSV3_SEND_ENCRYPT_DATA/KVM_CSV3_RECEIVE_ENCRYPT_DATA cmds are +used to migrate guest's pages. + +KVM_CSV3_SEND_ENCRYPT_CONTEXT/KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT cmds +are used to migration guest's runtime context. + +Signed-off-by: Xin Jiang +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 061b2e7f0..6edf0b33a 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -2067,6 +2067,12 @@ enum csv3_cmd_id { + KVM_CSV3_INIT = KVM_CSV3_NR_MIN, + KVM_CSV3_LAUNCH_ENCRYPT_DATA, + KVM_CSV3_LAUNCH_ENCRYPT_VMCB, ++ KVM_CSV3_SEND_ENCRYPT_DATA, ++ KVM_CSV3_SEND_ENCRYPT_CONTEXT, ++ KVM_CSV3_RECEIVE_ENCRYPT_DATA, ++ KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT, ++ ++ KVM_CSV3_NR_MAX, + }; + + struct kvm_csv3_launch_encrypt_data { +@@ -2079,6 +2085,38 @@ struct kvm_csv3_init_data { + __u64 nodemask; + }; + ++struct kvm_csv3_send_encrypt_data { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 guest_addr_data; ++ __u32 guest_addr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_csv3_send_encrypt_context { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_csv3_receive_encrypt_data { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 guest_addr_data; ++ __u32 guest_addr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_csv3_receive_encrypt_context { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ + #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) +-- +2.31.1 + diff --git a/1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch b/1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..079568af057072be1c64ac30714e732fc18394df --- /dev/null +++ b/1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch @@ -0,0 +1,454 @@ +From 161f1fdbd8cc76f8859a0f1d92dd3a179cd426e5 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:37:56 +0800 +Subject: [PATCH 11/14] target/i386: csv: Add support to migrate the outgoing + page for CSV3 guest + +The csv3_send_encrypt_data() provides the method to encrypt the +guest's private pages during migration. The routine is similar to +CSV2's. Usually, it starts with a SEND_START command to create the +migration context. Then SEND_ENCRYPT_DATA command is performed to +encrypt guest pages. After migration is completed, a SEND_FINISH +command is performed to the firmware. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + migration/ram.c | 87 ++++++++++++++++++ + target/i386/csv.c | 184 +++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 22 +++++ + target/i386/sev.c | 14 ++- + target/i386/sev.h | 1 + + target/i386/trace-events | 1 + + 6 files changed, 308 insertions(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 198b06000..71353bc90 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2478,6 +2478,90 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss) + } + #endif + ++/** ++ * ram_save_csv3_pages - send the given csv3 VM pages to the stream ++ */ ++static int ram_save_csv3_pages(RAMState *rs, PageSearchStatus *pss) ++{ ++ bool page_dirty; ++ int ret; ++ int tmppages, pages = 0; ++ uint8_t *p; ++ uint32_t host_len = 0; ++ uint64_t bytes_xmit = 0; ++ RAMBlock *block = pss->block; ++ ram_addr_t offset = 0; ++ hwaddr paddr = RAM_ADDR_INVALID; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ ConfidentialGuestSupportClass *cgs_class = ++ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs)); ++ struct ConfidentialGuestMemoryEncryptionOps *ops = ++ cgs_class->memory_encryption_ops; ++ ++ if (!kvm_csv3_enabled()) ++ return 0; ++ ++ do { ++ page_dirty = migration_bitmap_clear_dirty(rs, block, pss->page); ++ ++ /* Check the pages is dirty and if it is send it */ ++ if (page_dirty) { ++ ret = kvm_physical_memory_addr_from_host(kvm_state, ++ block->host + (pss->page << TARGET_PAGE_BITS), &paddr); ++ /* Process ROM or MMIO */ ++ if (paddr == RAM_ADDR_INVALID || ++ memory_region_is_rom(block->mr)) { ++ tmppages = migration_ops->ram_save_target_page(rs, pss); ++ } else { ++ /* Caculate the offset and host virtual address of the page */ ++ offset = pss->page << TARGET_PAGE_BITS; ++ p = block->host + offset; ++ ++ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset)) ++ return -1; ++ ++ tmppages = 1; ++ host_len += TARGET_PAGE_SIZE; ++ ++ stat64_add(&mig_stats.normal_pages, 1); ++ } ++ } else { ++ tmppages = 0; ++ } ++ ++ if (tmppages >= 0) { ++ pages += tmppages; ++ } else { ++ return tmppages; ++ } ++ ++ pss_find_next_dirty(pss); ++ } while (offset_in_ramblock(block, ++ ((ram_addr_t)pss->page) << TARGET_PAGE_BITS) && ++ host_len < CSV3_OUTGOING_PAGE_WINDOW_SIZE); ++ ++ /* Check if there are any queued pages */ ++ if (host_len != 0) { ++ /* Always set offset as 0 for csv3. */ ++ ram_transferred_add(save_page_header(pss, pss->pss_channel, ++ block, 0 | RAM_SAVE_FLAG_ENCRYPTED_DATA)); ++ ++ qemu_put_be32(pss->pss_channel, RAM_SAVE_ENCRYPTED_PAGE); ++ ram_transferred_add(4); ++ /* Process the queued pages in batch */ ++ ret = ops->save_queued_outgoing_pages(pss->pss_channel, &bytes_xmit); ++ if (ret) { ++ return -1; ++ } ++ ram_transferred_add(bytes_xmit); ++ } ++ ++ /* The offset we leave with is the last one we looked at */ ++ pss->page--; ++ ++ return pages; ++} ++ + /** + * ram_save_host_page: save a whole host page + * +@@ -2513,6 +2597,9 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) + return 0; + } + ++ if (kvm_csv3_enabled()) ++ return ram_save_csv3_pages(rs, pss); ++ + #ifdef CONFIG_HYGON_CSV_MIG_ACCEL + /* + * If command_batch function is enabled and memory encryption is enabled +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 5823c8994..ffa5a73a7 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -16,8 +16,13 @@ + #include "qapi/error.h" + #include "sysemu/kvm.h" + #include "exec/address-spaces.h" ++#include "migration/blocker.h" ++#include "migration/qemu-file.h" ++#include "migration/misc.h" ++#include "monitor/monitor.h" + + #include ++#include + + #ifdef CONFIG_NUMA + #include +@@ -30,6 +35,19 @@ + + bool csv_kvm_cpu_reset_inhibit; + ++struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { ++ .save_setup = sev_save_setup, ++ .save_outgoing_page = NULL, ++ .is_gfn_in_unshared_region = NULL, ++ .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 = csv3_queue_outgoing_page, ++ .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, ++}; ++ ++#define CSV3_OUTGOING_PAGE_NUM \ ++ (CSV3_OUTGOING_PAGE_WINDOW_SIZE / TARGET_PAGE_SIZE) ++ + Csv3GuestState csv3_guest = { 0 }; + + int +@@ -70,6 +88,7 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + csv3_guest.fw_error_to_str = ops->fw_error_to_str; + QTAILQ_INIT(&csv3_guest.dma_map_regions_list); + qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); ++ csv3_guest.sev_send_start = ops->sev_send_start; + } + return 0; + } +@@ -301,3 +320,168 @@ end: + qemu_mutex_unlock(&s->dma_map_regions_list_mutex); + return; + } ++ ++static inline hwaddr csv3_hva_to_gfn(uint8_t *ptr) ++{ ++ ram_addr_t offset = RAM_ADDR_INVALID; ++ ++ kvm_physical_memory_addr_from_host(kvm_state, ptr, &offset); ++ ++ return offset >> TARGET_PAGE_BITS; ++} ++ ++static int ++csv3_send_start(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ if (csv3_guest.sev_send_start) ++ return csv3_guest.sev_send_start(f, bytes_sent); ++ else ++ return -1; ++} ++ ++static int ++csv3_send_get_packet_len(int *fw_err) ++{ ++ int ret; ++ struct kvm_csv3_send_encrypt_data update = {0}; ++ ++ update.hdr_len = 0; ++ update.trans_len = 0; ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_DATA, &update, fw_err); ++ if (*fw_err != SEV_RET_INVALID_LEN) { ++ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ ret = 0; ++ goto err; ++ } ++ ++ if (update.hdr_len <= INT_MAX) ++ ret = update.hdr_len; ++ else ++ ret = 0; ++ ++err: ++ return ret; ++} ++ ++static int ++csv3_send_encrypt_data(Csv3GuestState *s, QEMUFile *f, ++ uint8_t *ptr, uint32_t size, uint64_t *bytes_sent) ++{ ++ int ret, fw_error = 0; ++ guchar *trans; ++ uint32_t guest_addr_entry_num; ++ uint32_t i; ++ struct kvm_csv3_send_encrypt_data update = { }; ++ ++ /* ++ * If this is first call then query the packet header bytes and allocate ++ * the packet buffer. ++ */ ++ if (!s->send_packet_hdr) { ++ s->send_packet_hdr_len = csv3_send_get_packet_len(&fw_error); ++ if (s->send_packet_hdr_len < 1) { ++ error_report("%s: SEND_UPDATE fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ ++ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len); ++ } ++ ++ if (!s->guest_addr_len || !s->guest_addr_data) { ++ error_report("%s: invalid host address or size", __func__); ++ return 1; ++ } else { ++ guest_addr_entry_num = s->guest_addr_len / sizeof(struct guest_addr_entry); ++ } ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, guest_addr_entry_num * TARGET_PAGE_SIZE); ++ ++ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr; ++ update.hdr_len = s->send_packet_hdr_len; ++ update.guest_addr_data = (uintptr_t)s->guest_addr_data; ++ update.guest_addr_len = s->guest_addr_len; ++ update.trans_uaddr = (uintptr_t)trans; ++ update.trans_len = guest_addr_entry_num * TARGET_PAGE_SIZE; ++ ++ trace_kvm_csv3_send_encrypt_data(trans, update.trans_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("%s: SEND_ENCRYPT_DATA ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ for (i = 0; i < guest_addr_entry_num; i++) { ++ if (s->guest_addr_data[i].share) ++ memcpy(trans + i * TARGET_PAGE_SIZE, (guchar *)s->guest_hva_data[i].hva, ++ TARGET_PAGE_SIZE); ++ } ++ ++ 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.guest_addr_len); ++ qemu_put_buffer(f, (uint8_t *)update.guest_addr_data, update.guest_addr_len); ++ *bytes_sent += 4 + update.guest_addr_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: ++ s->guest_addr_len = 0; ++ g_free(trans); ++ return ret; ++} ++ ++int ++csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ uint32_t i = 0; ++ ++ (void) addr; ++ ++ if (!s->guest_addr_data) { ++ s->guest_hva_data = g_new0(struct guest_hva_entry, CSV3_OUTGOING_PAGE_NUM); ++ s->guest_addr_data = g_new0(struct guest_addr_entry, CSV3_OUTGOING_PAGE_NUM); ++ s->guest_addr_len = 0; ++ } ++ ++ if (s->guest_addr_len >= sizeof(struct guest_addr_entry) * CSV3_OUTGOING_PAGE_NUM) { ++ error_report("Failed to queue outgoing page"); ++ return 1; ++ } ++ ++ i = s->guest_addr_len / sizeof(struct guest_addr_entry); ++ s->guest_hva_data[i].hva = (uintptr_t)ptr; ++ s->guest_addr_data[i].share = 0; ++ s->guest_addr_data[i].reserved = 0; ++ s->guest_addr_data[i].gfn = csv3_hva_to_gfn(ptr); ++ s->guest_addr_len += sizeof(struct guest_addr_entry); ++ ++ return 0; ++} ++ ++int ++csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ ++ /* ++ * If this is a first buffer then create outgoing encryption context ++ * and write our PDH, policy and session data. ++ */ ++ if (!csv3_check_state(SEV_STATE_SEND_UPDATE) && ++ csv3_send_start(f, bytes_sent)) { ++ error_report("Failed to create outgoing context"); ++ return 1; ++ } ++ ++ return csv3_send_encrypt_data(s, f, NULL, 0, bytes_sent); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 0c402cefd..e808bea61 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -80,6 +80,18 @@ struct dma_map_region { + QTAILQ_ENTRY(dma_map_region) list; + }; + ++#define CSV3_OUTGOING_PAGE_WINDOW_SIZE (512 * TARGET_PAGE_SIZE) ++ ++struct guest_addr_entry { ++ uint64_t share: 1; ++ uint64_t reserved: 11; ++ uint64_t gfn: 52; ++}; ++ ++struct guest_hva_entry { ++ uint64_t hva; ++}; ++ + struct Csv3GuestState { + uint32_t policy; + int sev_fd; +@@ -88,11 +100,19 @@ struct Csv3GuestState { + const char *(*fw_error_to_str)(int code); + QTAILQ_HEAD(, dma_map_region) dma_map_regions_list; + QemuMutex dma_map_regions_list_mutex; ++ gchar *send_packet_hdr; ++ size_t send_packet_hdr_len; ++ struct guest_hva_entry *guest_hva_data; ++ struct guest_addr_entry *guest_addr_data; ++ size_t guest_addr_len; ++ ++ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); + }; + + typedef struct Csv3GuestState Csv3GuestState; + + extern struct Csv3GuestState csv3_guest; ++extern struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops; + extern int csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + extern int csv3_launch_encrypt_vmcb(void); + +@@ -100,5 +120,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); ++int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + + #endif +diff --git a/target/i386/sev.c b/target/i386/sev.c +index eb1026b57..465b62cb7 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1225,7 +1225,11 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + qemu_add_vm_change_state_handler(sev_vm_state_change, sev); + migration_add_notifier(&sev_migration_state, sev_migration_state_notifier); + +- cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; ++ if (csv3_enabled()) { ++ cgs_class->memory_encryption_ops = &csv3_memory_encryption_ops; ++ } else { ++ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops; ++ } + QTAILQ_INIT(&sev->shared_regions_list); + + /* Determine whether support MSR_AMD64_SEV_ES_GHCB */ +@@ -2608,9 +2612,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) + return ret; + } + ++static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ SevGuestState *s = sev_guest; ++ ++ return sev_send_start(s, f, bytes_sent); ++} ++ + struct sev_ops sev_ops = { + .sev_ioctl = sev_ioctl, + .fw_error_to_str = fw_error_to_str, ++ .sev_send_start = _sev_send_start, + }; + + static void +diff --git a/target/i386/sev.h b/target/i386/sev.h +index e91431e0f..8ccef22a9 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -83,6 +83,7 @@ extern bool sev_kvm_has_msr_ghcb; + struct sev_ops { + int (*sev_ioctl)(int fd, int cmd, void *data, int *error); + const char *(*fw_error_to_str)(int code); ++ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); + }; + + extern struct sev_ops sev_ops; +diff --git a/target/i386/trace-events b/target/i386/trace-events +index e07061bf3..6ebb644cb 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -22,3 +22,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int + + # csv.c + kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 ++kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" +-- +2.31.1 + diff --git a/1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch b/1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch new file mode 100644 index 0000000000000000000000000000000000000000..306d8e2f46f9b2b16910ef92340333ee98ef108d --- /dev/null +++ b/1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch @@ -0,0 +1,205 @@ +From e1ed25546ed0c9b1ae43c99131ef7910db6d03eb Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:45:45 +0800 +Subject: [PATCH 12/14] target/i386: csv: Add support to migrate the incoming + page for CSV3 guest + +The csv3_receive_encrypt_data() provides the method to read incoming +guest private pages from socket and load them into guest memory. +The routine is similar to CSV2's. Usually, it starts with a RECEIVE +START command to create the migration context. Then RECEIVE ENCRYPT +DATA command is performed to let the firmware load incoming pages +into guest memory. After migration is completed, a RECEIVE FINISH +command is performed to the firmware. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 2 + + target/i386/sev.c | 8 ++++ + target/i386/sev.h | 1 + + target/i386/trace-events | 1 + + 5 files changed, 99 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index ffa5a73a7..81407e3c2 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -38,11 +38,14 @@ bool csv_kvm_cpu_reset_inhibit; + struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = NULL, ++ .load_incoming_page = csv3_load_incoming_page, + .is_gfn_in_unshared_region = NULL, + .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 = csv3_queue_outgoing_page, + .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, ++ .queue_incoming_page = NULL, ++ .load_queued_incoming_pages = NULL, + }; + + #define CSV3_OUTGOING_PAGE_NUM \ +@@ -89,6 +92,7 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + QTAILQ_INIT(&csv3_guest.dma_map_regions_list); + qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); + csv3_guest.sev_send_start = ops->sev_send_start; ++ csv3_guest.sev_receive_start = ops->sev_receive_start; + } + return 0; + } +@@ -485,3 +489,86 @@ csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) + + return csv3_send_encrypt_data(s, f, NULL, 0, bytes_sent); + } ++ ++static int ++csv3_receive_start(QEMUFile *f) ++{ ++ if (csv3_guest.sev_receive_start) ++ return csv3_guest.sev_receive_start(f); ++ else ++ return -1; ++} ++ ++static int csv3_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) ++{ ++ int ret = 1, fw_error = 0; ++ uint32_t i, guest_addr_entry_num; ++ gchar *hdr = NULL, *trans = NULL; ++ struct guest_addr_entry *guest_addr_data; ++ struct kvm_csv3_receive_encrypt_data update = {}; ++ void *hva = NULL; ++ MemoryRegion *mr = NULL; ++ ++ /* get packet header */ ++ update.hdr_len = qemu_get_be32(f); ++ ++ hdr = g_new(gchar, update.hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); ++ update.hdr_uaddr = (uintptr_t)hdr; ++ ++ /* get guest addr data */ ++ update.guest_addr_len = qemu_get_be32(f); ++ ++ guest_addr_data = (struct guest_addr_entry *)g_new(gchar, update.guest_addr_len); ++ qemu_get_buffer(f, (uint8_t *)guest_addr_data, update.guest_addr_len); ++ update.guest_addr_data = (uintptr_t)guest_addr_data; ++ ++ /* get transport buffer */ ++ update.trans_len = qemu_get_be32(f); ++ ++ trans = g_new(gchar, update.trans_len); ++ update.trans_uaddr = (uintptr_t)trans; ++ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ ++ /* update share memory. */ ++ guest_addr_entry_num = update.guest_addr_len / sizeof(struct guest_addr_entry); ++ for (i = 0; i < guest_addr_entry_num; i++) { ++ if (guest_addr_data[i].share) { ++ hva = gpa2hva(&mr, ++ ((uint64_t)guest_addr_data[i].gfn << TARGET_PAGE_BITS), ++ TARGET_PAGE_SIZE, ++ NULL); ++ if (hva) ++ memcpy(hva, trans + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); ++ } ++ } ++ ++ trace_kvm_csv3_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_RECEIVE_ENCRYPT_DATA, &update, &fw_error); ++ if (ret) { ++ error_report("Error RECEIVE_ENCRYPT_DATA ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++err: ++ g_free(trans); ++ g_free(guest_addr_data); ++ g_free(hdr); ++ return ret; ++} ++ ++int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) ++{ ++ /* ++ * If this is first buffer and SEV is not in recieiving state then ++ * use RECEIVE_START command to create a encryption context. ++ */ ++ if (!csv3_check_state(SEV_STATE_RECEIVE_UPDATE) && ++ csv3_receive_start(f)) { ++ return 1; ++ } ++ ++ return csv3_receive_encrypt_data(f, ptr); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index e808bea61..b0adae0a8 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -107,6 +107,7 @@ struct Csv3GuestState { + size_t guest_addr_len; + + int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); ++ int (*sev_receive_start)(QEMUFile *f); + }; + + typedef struct Csv3GuestState Csv3GuestState; +@@ -120,6 +121,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); ++int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 465b62cb7..337f54415 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -2619,10 +2619,18 @@ static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) + return sev_send_start(s, f, bytes_sent); + } + ++static int _sev_receive_start(QEMUFile *f) ++{ ++ SevGuestState *s = sev_guest; ++ ++ return sev_receive_start(s, f); ++} ++ + struct sev_ops sev_ops = { + .sev_ioctl = sev_ioctl, + .fw_error_to_str = fw_error_to_str, + .sev_send_start = _sev_send_start, ++ .sev_receive_start = _sev_receive_start, + }; + + static void +diff --git a/target/i386/sev.h b/target/i386/sev.h +index 8ccef22a9..647b426b1 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -84,6 +84,7 @@ struct sev_ops { + int (*sev_ioctl)(int fd, int cmd, void *data, int *error); + const char *(*fw_error_to_str)(int code); + int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); ++ int (*sev_receive_start)(QEMUFile *f); + }; + + extern struct sev_ops sev_ops; +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 6ebb644cb..9609fe3d5 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -23,3 +23,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int + # csv.c + kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 + kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" ++kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-- +2.31.1 + diff --git a/1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch b/1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch new file mode 100644 index 0000000000000000000000000000000000000000..3bfdb71f8568c772cf2ae359833a750abb1b9d5b --- /dev/null +++ b/1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch @@ -0,0 +1,139 @@ +From 434ad630110cd376ea184a11572ec72961e679a4 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 09:52:31 +0800 +Subject: [PATCH 13/14] target/i386: csv: Add support to migrate the outgoing + context for CSV3 guest + +CSV3 needs to migrate guest cpu's context pages. Prior to migration +of the context, it should query transfer buffer length and header +data length by SEND ENCRYPT CONTEXT command. New migration flag +RAM_SAVE_ENCRYPTED_CSV3_CONTEXT is defined for CSV3. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + target/i386/csv.c | 81 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/trace-events | 1 + + 3 files changed, 83 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 81407e3c2..1560db680 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -46,6 +46,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { + .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, + .queue_incoming_page = NULL, + .load_queued_incoming_pages = NULL, ++ .save_outgoing_cpu_state = csv3_save_outgoing_context, + }; + + #define CSV3_OUTGOING_PAGE_NUM \ +@@ -572,3 +573,83 @@ int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) + + return csv3_receive_encrypt_data(f, ptr); + } ++ ++static int ++csv3_send_get_context_len(int *fw_err, int *context_len, int *hdr_len) ++{ ++ int ret = 0; ++ struct kvm_csv3_send_encrypt_context update = { 0 }; ++ ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_CONTEXT, &update, fw_err); ++ if (*fw_err != SEV_RET_INVALID_LEN) { ++ error_report("%s: failed to get context length ret=%d fw_error=%d '%s'", ++ __func__, ret, *fw_err, fw_error_to_str(*fw_err)); ++ ret = -1; ++ goto err; ++ } ++ ++ if (update.trans_len <= INT_MAX && update.hdr_len <= INT_MAX) { ++ *context_len = update.trans_len; ++ *hdr_len = update.hdr_len; ++ } ++ ret = 0; ++err: ++ return ret; ++} ++ ++static int ++csv3_send_encrypt_context(Csv3GuestState *s, QEMUFile *f, uint64_t *bytes_sent) ++{ ++ int ret, fw_error = 0; ++ int context_len = 0; ++ int hdr_len = 0; ++ guchar *trans; ++ guchar *hdr; ++ struct kvm_csv3_send_encrypt_context update = { }; ++ ++ ret = csv3_send_get_context_len(&fw_error, &context_len, &hdr_len); ++ if (context_len < 1 || hdr_len < 1) { ++ error_report("%s: fail to get context length fw_error=%d '%s'", ++ __func__, fw_error, fw_error_to_str(fw_error)); ++ return 1; ++ } ++ ++ /* allocate transport buffer */ ++ trans = g_new(guchar, context_len); ++ hdr = g_new(guchar, hdr_len); ++ ++ update.hdr_uaddr = (uintptr_t)hdr; ++ update.hdr_len = hdr_len; ++ update.trans_uaddr = (uintptr_t)trans; ++ update.trans_len = context_len; ++ ++ trace_kvm_csv3_send_encrypt_context(trans, update.trans_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_SEND_ENCRYPT_CONTEXT, &update, &fw_error); ++ if (ret) { ++ error_report("%s: SEND_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", ++ __func__, ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++ 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: ++ g_free(trans); ++ g_free(hdr); ++ return ret; ++} ++ ++int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ ++ /* send csv3 context. */ ++ return csv3_send_encrypt_context(s, f, bytes_sent); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index b0adae0a8..e9b8e00c9 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -124,5 +124,6 @@ void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); + int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); ++int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent); + + #endif +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 9609fe3d5..31a2418bb 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -23,4 +23,5 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int + # csv.c + kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 + kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" ++kvm_csv3_send_encrypt_context(void *dst, int len) "trans %p len %d" + kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-- +2.31.1 + diff --git a/1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch b/1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch new file mode 100644 index 0000000000000000000000000000000000000000..f23e7401b31d99cbca69df0fd0df989fda0ce554 --- /dev/null +++ b/1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch @@ -0,0 +1,110 @@ +From e944da634c51c78e5fad793096c9ceba04ba3f19 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Fri, 17 Jun 2022 10:00:46 +0800 +Subject: [PATCH 14/14] target/i386: csv: Add support to migrate the incoming + context for CSV3 guest + +The csv3_load_incoming_context() provides the method to read incoming +guest's context from socket. It loads them into guest private memory. +This is the last step during migration and RECEIVE FINISH command is +performed by then to complete the whole migration. + +Signed-off-by: Jiang Xin +Signed-off-by: hanliyang +--- + target/i386/csv.c | 45 ++++++++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 1 + + target/i386/trace-events | 1 + + 3 files changed, 47 insertions(+) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 1560db680..0593f9b19 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -47,6 +47,7 @@ struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { + .queue_incoming_page = NULL, + .load_queued_incoming_pages = NULL, + .save_outgoing_cpu_state = csv3_save_outgoing_context, ++ .load_incoming_cpu_state = csv3_load_incoming_context, + }; + + #define CSV3_OUTGOING_PAGE_NUM \ +@@ -646,6 +647,42 @@ err: + return ret; + } + ++static int ++csv3_receive_encrypt_context(Csv3GuestState *s, QEMUFile *f) ++{ ++ int ret = 1, fw_error = 0; ++ gchar *hdr = NULL, *trans = NULL; ++ struct kvm_csv3_receive_encrypt_context update = {}; ++ ++ /* get packet header */ ++ update.hdr_len = qemu_get_be32(f); ++ ++ hdr = g_new(gchar, update.hdr_len); ++ qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); ++ update.hdr_uaddr = (uintptr_t)hdr; ++ ++ /* get transport buffer */ ++ update.trans_len = qemu_get_be32(f); ++ ++ trans = g_new(gchar, update.trans_len); ++ update.trans_uaddr = (uintptr_t)trans; ++ qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); ++ ++ trace_kvm_csv3_receive_encrypt_context(trans, update.trans_len, hdr, update.hdr_len); ++ ++ ret = csv3_ioctl(KVM_CSV3_RECEIVE_ENCRYPT_CONTEXT, &update, &fw_error); ++ if (ret) { ++ error_report("Error RECEIVE_ENCRYPT_CONTEXT ret=%d fw_error=%d '%s'", ++ ret, fw_error, fw_error_to_str(fw_error)); ++ goto err; ++ } ++ ++err: ++ g_free(trans); ++ g_free(hdr); ++ return ret; ++} ++ + int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent) + { + Csv3GuestState *s = &csv3_guest; +@@ -653,3 +690,11 @@ int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent) + /* send csv3 context. */ + return csv3_send_encrypt_context(s, f, bytes_sent); + } ++ ++int csv3_load_incoming_context(QEMUFile *f) ++{ ++ Csv3GuestState *s = &csv3_guest; ++ ++ /* receive csv3 context. */ ++ return csv3_receive_encrypt_context(s, f); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index e9b8e00c9..bbe372498 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -122,6 +122,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); + int csv3_shared_region_dma_map(uint64_t start, uint64_t end); + void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); + int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); ++int csv3_load_incoming_context(QEMUFile *f); + int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); + int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); + int csv3_save_outgoing_context(QEMUFile *f, uint64_t *bytes_sent); +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 31a2418bb..515441c4f 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -25,3 +25,4 @@ kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" P + kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" + kvm_csv3_send_encrypt_context(void *dst, int len) "trans %p len %d" + kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" ++kvm_csv3_receive_encrypt_context(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-- +2.31.1 + diff --git a/qemu.spec b/qemu.spec index efe077f0d2ead1026c7cc6346ac6df1fdef42330..af6eefdcabb3d573e07f3cf1c62945870179134a 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,4 +1,4 @@ -%define anolis_release 9 +%define anolis_release 10 %bcond_with check @@ -333,6 +333,20 @@ Patch1029: 1029-target-i386-csv-Add-support-for-migrate-VMSA-for-CSV.patch Patch1030: 1030-target-i386-get-set-migrate-GHCB-state.patch Patch1031: 1031-target-i386-kvm-Fix-the-resettable-info-when-emulate.patch Patch1032: 1032-kvm-Add-support-for-CSV2-reboot.patch +Patch1033: 1033-target-i386-csv-Add-CSV3-context.patch +Patch1034: 1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch +Patch1035: 1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch +Patch1036: 1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch +Patch1037: 1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch +Patch1038: 1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch +Patch1039: 1039-target-i386-csv-Load-initial-image-to-private-memory.patch +Patch1040: 1040-vga-Force-full-update-for-CSV3-guest.patch +Patch1041: 1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch +Patch1042: 1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch +Patch1043: 1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +Patch1044: 1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch +Patch1045: 1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +Patch1046: 1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch ExclusiveArch: x86_64 aarch64 loongarch64 @@ -1892,6 +1906,23 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog +* Thu Apr 11 2024 Liyang Han - 2:8.2.0-10 +- Patch1033: 1033-target-i386-csv-Add-CSV3-context.patch +- Patch1034: 1034-target-i386-csv-Add-command-to-initialize-CSV3-conte.patch +- Patch1035: 1035-target-i386-csv-Add-command-to-load-data-to-CSV3-gue.patch +- Patch1036: 1036-target-i386-csv-Add-command-to-load-vmcb-to-CSV3-gue.patch +- Patch1037: 1037-target-i386-cpu-Populate-CPUID-0x8000_001F-when-CSV3.patch +- Patch1038: 1038-target-i386-csv-Do-not-register-unregister-guest-sec.patch +- Patch1039: 1039-target-i386-csv-Load-initial-image-to-private-memory.patch +- Patch1040: 1040-vga-Force-full-update-for-CSV3-guest.patch +- Patch1041: 1041-vfio-Only-map-shared-region-for-CSV3-virtual-machine.patch +- Patch1042: 1042-linux-headers-update-kernel-headers-to-include-CSV3-.patch +- Patch1043: 1043-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +- Patch1044: 1044-target-i386-csv-Add-support-to-migrate-the-incoming-.patch +- Patch1045: 1045-target-i386-csv-Add-support-to-migrate-the-outgoing-.patch +- Patch1046: 1046-target-i386-csv-Add-support-to-migrate-the-incoming-.patch + (Support boot CSV3 guest, CSV3 live migration) + * Thu Apr 11 2024 Liyang Han - 2:8.2.0-9 - Patch1005: 1005-doc-update-AMD-SEV-to-include-Live-migration-flow.patch - Patch1006: 1006-migration.json-add-AMD-SEV-specific-migration-parame.patch