From 9514a8d6fbd7d0f44664d14c929dc6906010a0f0 Mon Sep 17 00:00:00 2001 From: Xuchun Shang Date: Thu, 9 Jan 2025 14:02:27 +0800 Subject: [PATCH] [Feature] Sync Patch form source repo to #IBGPVM Pick the CSV patch from source repo. Signed-off-by: Xuchun Shang --- ...i386-csv-guest-Introduce-secret-head.patch | 220 +++++++++ ...Support-to-get-and-enable-extensions.patch | 111 +++++ ...Request-to-set-private-memory-of-CSV.patch | 422 ++++++++++++++++++ ...Support-load-kernel-hashes-for-CSV3-.patch | 40 ++ ...Support-inject-secret-for-CSV3-guest.patch | 43 ++ ...citly-using-KVM_CAP_HYGON_COCO_EXT_C.patch | 73 +++ ...Return-0-if-sev_send_get_packet_len-.patch | 71 +++ ...The-CSV2-guest-running-on-the-recipi.patch | 95 ++++ ...etwork-stall-at-the-host-side-waitin.patch | 339 ++++++++++++++ qemu-kvm.spec | 23 +- 10 files changed, 1436 insertions(+), 1 deletion(-) create mode 100644 1120-qapi-qom-target-i386-csv-guest-Introduce-secret-head.patch create mode 100644 1121-target-i386-kvm-Support-to-get-and-enable-extensions.patch create mode 100644 1122-target-i386-csv-Request-to-set-private-memory-of-CSV.patch create mode 100644 1123-target-i386-csv-Support-load-kernel-hashes-for-CSV3-.patch create mode 100644 1124-target-i386-csv-Support-inject-secret-for-CSV3-guest.patch create mode 100644 1125-i386-Avoid-explicitly-using-KVM_CAP_HYGON_COCO_EXT_C.patch create mode 100644 1126-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch create mode 100644 1127-target-i386-csv-The-CSV2-guest-running-on-the-recipi.patch create mode 100644 1128-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch diff --git a/1120-qapi-qom-target-i386-csv-guest-Introduce-secret-head.patch b/1120-qapi-qom-target-i386-csv-guest-Introduce-secret-head.patch new file mode 100644 index 0000000..70e4710 --- /dev/null +++ b/1120-qapi-qom-target-i386-csv-guest-Introduce-secret-head.patch @@ -0,0 +1,220 @@ +From 8134a9109a3dde612795059b7ae125f931b88e78 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Fri, 2 Aug 2024 01:35:25 +0800 +Subject: [PATCH 1/5] qapi/qom,target/i386: csv-guest: Introduce + secret-header-file=str and secret-file=str options + +This feature only applied to Hygon CSV. + +User can utilize the hag to generate secret header file and secret file, +and inject these data to guest encrypted secret area automatically. + +Signed-off-by: hanliyang +--- + qapi/qom.json | 9 ++++- + qemu-options.hx | 8 +++- + target/i386/sev.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 115 insertions(+), 2 deletions(-) + +diff --git a/qapi/qom.json b/qapi/qom.json +index 387c0a142d..a2ac0ae33e 100644 +--- a/qapi/qom.json ++++ b/qapi/qom.json +@@ -775,6 +775,11 @@ + # + # @user-id: the user id of the guest owner, only support on Hygon CPUs + # ++# @secret-header-file: the header file of guest owner's secret, only ++# support on Hygon CPUs (since 6.2) ++# @secret-file: the file guest owner's secret, only support on Hygon ++# CPUs (since 6.2) ++# + # Since: 2.12 + ## + { 'struct': 'SevGuestProperties', +@@ -786,7 +791,9 @@ + '*cbitpos': 'uint32', + 'reduced-phys-bits': 'uint32', + '*kernel-hashes': 'bool', +- '*user-id': 'str' } } ++ '*user-id': 'str', ++ '*secret-header-file': 'str', ++ '*secret-file': 'str' } } + + ## + # @ObjectType: +diff --git a/qemu-options.hx b/qemu-options.hx +index c3c070de6f..453d220226 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -5189,7 +5189,7 @@ SRST + -object secret,id=sec0,keyid=secmaster0,format=base64,\\ + data=$SECRET,iv=$(user_id = g_strdup(value); + } + ++static char * ++sev_guest_get_secret_header_file(Object *obj, Error **errp) ++{ ++ SevGuestState *s = SEV_GUEST(obj); ++ ++ return g_strdup(s->secret_header_file); ++} ++ ++static void ++sev_guest_set_secret_header_file(Object *obj, const char *value, Error **errp) ++{ ++ SevGuestState *s = SEV_GUEST(obj); ++ ++ s->secret_header_file = g_strdup(value); ++} ++ ++static char * ++sev_guest_get_secret_file(Object *obj, Error **errp) ++{ ++ SevGuestState *s = SEV_GUEST(obj); ++ ++ return g_strdup(s->secret_file); ++} ++ ++static void ++sev_guest_set_secret_file(Object *obj, const char *value, Error **errp) ++{ ++ SevGuestState *s = SEV_GUEST(obj); ++ ++ s->secret_file = g_strdup(value); ++} ++ + static char * + sev_guest_get_sev_device(Object *obj, Error **errp) + { +@@ -458,6 +492,16 @@ sev_guest_class_init(ObjectClass *oc, void *data) + sev_guest_set_user_id); + object_class_property_set_description(oc, "user-id", + "user id of the guest owner"); ++ object_class_property_add_str(oc, "secret-header-file", ++ sev_guest_get_secret_header_file, ++ sev_guest_set_secret_header_file); ++ object_class_property_set_description(oc, "secret-header-file", ++ "header file of the guest owner's secret"); ++ object_class_property_add_str(oc, "secret-file", ++ sev_guest_get_secret_file, ++ sev_guest_set_secret_file); ++ object_class_property_set_description(oc, "secret-file", ++ "file of the guest owner's secret"); + } + + static void +@@ -836,6 +880,9 @@ sev_launch_update_vmsa(SevGuestState *sev) + return ret; + } + ++static int ++csv_load_launch_secret(const char *secret_header_file, const char *secret_file); ++ + static void + sev_launch_get_measure(Notifier *notifier, void *unused) + { +@@ -885,6 +932,15 @@ sev_launch_get_measure(Notifier *notifier, void *unused) + /* encode the measurement value and emit the event */ + sev->measurement = g_base64_encode(data, measurement.len); + trace_kvm_sev_launch_measurement(sev->measurement); ++ ++ /* Hygon CSV will auto load guest owner's secret */ ++ if (is_hygon_cpu()) { ++ if (sev->secret_header_file && ++ strlen(sev->secret_header_file) && ++ sev->secret_file && ++ strlen(sev->secret_file)) ++ csv_load_launch_secret(sev->secret_header_file, sev->secret_file); ++ } + } + + static char *sev_get_launch_measurement(void) +@@ -2479,6 +2535,50 @@ int csv_load_incoming_cpu_state(QEMUFile *f) + return ret; + } + ++static int ++csv_load_launch_secret(const char *secret_header_file, const char *secret_file) ++{ ++ gsize secret_header_size, secret_size; ++ gchar *secret_header = NULL, *secret = NULL; ++ uint8_t *data; ++ struct sev_secret_area *area; ++ uint64_t gpa; ++ GError *error = NULL; ++ Error *local_err = NULL; ++ int ret = 0; ++ ++ if (!g_file_get_contents(secret_header_file, ++ &secret_header, ++ &secret_header_size, &error)) { ++ error_report("CSV: Failed to read '%s' (%s)", ++ secret_header_file, error->message); ++ g_error_free(error); ++ return -1; ++ } ++ ++ if (!g_file_get_contents(secret_file, &secret, &secret_size, &error)) { ++ error_report("CSV: Failed to read '%s' (%s)", secret_file, error->message); ++ g_error_free(error); ++ return -1; ++ } ++ ++ if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, &data, NULL)) { ++ error_report("CSV: no secret area found in OVMF, gpa must be" ++ " specified."); ++ return -1; ++ } ++ area = (struct sev_secret_area *)data; ++ gpa = area->base; ++ ++ ret = sev_inject_launch_secret((char *)secret_header, ++ (char *)secret, gpa, &local_err); ++ ++ if (local_err) { ++ error_report_err(local_err); ++ } ++ return ret; ++} ++ + static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +-- +2.39.3 + diff --git a/1121-target-i386-kvm-Support-to-get-and-enable-extensions.patch b/1121-target-i386-kvm-Support-to-get-and-enable-extensions.patch new file mode 100644 index 0000000..7c71a62 --- /dev/null +++ b/1121-target-i386-kvm-Support-to-get-and-enable-extensions.patch @@ -0,0 +1,111 @@ +From 576b6a5d6f90b7628b2ce977bb77f3589f8636c5 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sat, 28 Sep 2024 14:46:28 +0800 +Subject: [PATCH 2/5] target/i386: kvm: Support to get and enable extensions + for Hygon CoCo guest + +To enable advanced Hygon CoCo features, we should detect these features +during the initialization of VMs in the KVM accelerator. It is +suggested to enable these features if they are detected, allowing the +guest VM to run with additional functionalities. + +Signed-off-by: hanliyang +--- + linux-headers/linux/kvm.h | 7 +++++++ + target/i386/csv-sysemu-stub.c | 3 +++ + target/i386/csv.c | 3 +++ + target/i386/csv.h | 3 +++ + target/i386/kvm/kvm.c | 17 +++++++++++++++++ + 5 files changed, 33 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 3875127a37..dca6b48476 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1155,6 +1155,13 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_S390_ZPCI_OP 221 + #define KVM_CAP_S390_CPU_TOPOLOGY 222 + #define KVM_CAP_SEV_ES_GHCB 500 ++#define KVM_CAP_HYGON_COCO_EXT 501 ++/* support userspace to request firmware to build CSV3 guest's memory space */ ++#define KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM (1 << 0) ++/* support request to update CSV3 guest's memory region multiple times */ ++#define KVM_CAP_HYGON_COCO_EXT_CSV3_MULT_LUP_DATA (1 << 1) ++/* support request to inject secret to CSV3 guest */ ++#define KVM_CAP_HYGON_COCO_EXT_CSV3_INJ_SECRET (1 << 2) + + #define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) + +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 96ca055270..cf2c0c1a31 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -15,6 +15,9 @@ + #include "sev.h" + #include "csv.h" + ++uint32_t kvm_hygon_coco_ext; ++uint32_t kvm_hygon_coco_ext_inuse; ++ + int csv_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 0e48982964..f00385d809 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -33,6 +33,9 @@ + #include "csv.h" + #include "exec/address-spaces.h" + ++uint32_t kvm_hygon_coco_ext; ++uint32_t kvm_hygon_coco_ext_inuse; ++ + struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = { + .save_setup = sev_save_setup, + .save_outgoing_page = NULL, +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 86f46d30c2..03537a5728 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -67,6 +67,9 @@ struct dma_map_region { + + #define CSV3_OUTGOING_PAGE_WINDOW_SIZE (512 * TARGET_PAGE_SIZE) + ++extern uint32_t kvm_hygon_coco_ext; ++extern uint32_t kvm_hygon_coco_ext_inuse; ++ + struct guest_addr_entry { + uint64_t share: 1; + uint64_t reserved: 11; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index cecc3d035d..469349420c 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -2455,6 +2455,23 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + } + } + ++ if (is_hygon_cpu()) { ++ /* check and enable Hygon coco extensions */ ++ kvm_hygon_coco_ext = (uint32_t)kvm_vm_check_extension(s, ++ KVM_CAP_HYGON_COCO_EXT); ++ if (kvm_hygon_coco_ext) { ++ ret = kvm_vm_enable_cap(s, KVM_CAP_HYGON_COCO_EXT, 0, ++ (uint64_t)kvm_hygon_coco_ext); ++ if (ret == -EINVAL) { ++ error_report("kvm: Failed to enable KVM_CAP_HYGON_COCO_EXT cap: %s", ++ strerror(-ret)); ++ kvm_hygon_coco_ext_inuse = 0; ++ } else { ++ kvm_hygon_coco_ext_inuse = (uint32_t)ret; ++ } ++ } ++ } ++ + ret = kvm_get_supported_msrs(s); + if (ret < 0) { + return ret; +-- +2.39.3 + diff --git a/1122-target-i386-csv-Request-to-set-private-memory-of-CSV.patch b/1122-target-i386-csv-Request-to-set-private-memory-of-CSV.patch new file mode 100644 index 0000000..4ac1977 --- /dev/null +++ b/1122-target-i386-csv-Request-to-set-private-memory-of-CSV.patch @@ -0,0 +1,422 @@ +From 08495c0e6f4bb1951d1e20b18483b353c81a4f37 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sat, 28 Sep 2024 17:37:17 +0800 +Subject: [PATCH 3/5] target/i386: csv: Request to set private memory of CSV3 + guest if the extension is enabled + +If Qemu negotiates with Linux KVM to enable the +KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM capability, then Qemu should +explicitly request the issuance of the CSV3_CMD_SET_GUEST_PRIVATE_MEMORY +command. + +Signed-off-by: hanliyang +--- + hw/i386/pc_sysfw.c | 7 +++- + linux-headers/linux/kvm.h | 58 ++++++++++++++------------- + target/i386/csv-sysemu-stub.c | 5 +++ + target/i386/csv.c | 75 ++++++++++++++++++++++------------- + target/i386/csv.h | 2 + + target/i386/trace-events | 11 ++--- + 6 files changed, 96 insertions(+), 62 deletions(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index 84aad306dc..ed00786f42 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -209,9 +209,12 @@ static void pc_system_flash_map(PCMachineState *pcms, + exit(1); + } + +- if (csv_enabled()) ++ if (csv_enabled()) { ++ if (kvm_hygon_coco_ext_inuse & KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM) ++ csv3_set_guest_private_memory(&error_fatal); ++ + csv_load_data(flash_mem->addr, flash_ptr, flash_size, &error_fatal); +- else ++ } else + sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); + } + } +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index dca6b48476..02bba131e6 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1950,43 +1950,34 @@ struct kvm_sev_receive_update_vmsa { + __u32 trans_len; + }; + +-/* CSV command */ +-enum csv_cmd_id { +- KVM_CSV_NR_MIN = 0xc0, ++/* CSV3 command */ ++enum csv3_cmd_id { ++ KVM_CSV3_NR_MIN = 0xc0, + +- KVM_CSV_INIT = KVM_CSV_NR_MIN, +- KVM_CSV_LAUNCH_ENCRYPT_DATA, +- KVM_CSV_LAUNCH_ENCRYPT_VMCB, +- KVM_CSV_SEND_ENCRYPT_DATA, +- KVM_CSV_SEND_ENCRYPT_CONTEXT, +- KVM_CSV_RECEIVE_ENCRYPT_DATA, +- KVM_CSV_RECEIVE_ENCRYPT_CONTEXT, ++ 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_CSV_NR_MAX, ++ KVM_CSV3_SET_GUEST_PRIVATE_MEMORY = 0xc8, ++ ++ KVM_CSV3_NR_MAX, + }; + +-struct kvm_csv_launch_encrypt_data { ++struct kvm_csv3_launch_encrypt_data { + __u64 gpa; + __u64 uaddr; + __u32 len; + }; + +-struct kvm_csv_init_data { ++struct kvm_csv3_init_data { + __u64 nodemask; + }; + +-struct kvm_csv_batch_list_node { +- __u64 cmd_data_addr; +- __u64 addr; +- __u64 next_cmd_addr; +-}; +- +-struct kvm_csv_command_batch { +- __u32 command_id; +- __u64 csv_batch_list_uaddr; +-}; +- +-struct kvm_csv_send_encrypt_data { ++struct kvm_csv3_send_encrypt_data { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 guest_addr_data; +@@ -1995,14 +1986,14 @@ struct kvm_csv_send_encrypt_data { + __u32 trans_len; + }; + +-struct kvm_csv_send_encrypt_context { ++struct kvm_csv3_send_encrypt_context { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 trans_uaddr; + __u32 trans_len; + }; + +-struct kvm_csv_receive_encrypt_data { ++struct kvm_csv3_receive_encrypt_data { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 guest_addr_data; +@@ -2011,13 +2002,24 @@ struct kvm_csv_receive_encrypt_data { + __u32 trans_len; + }; + +-struct kvm_csv_receive_encrypt_context { ++struct kvm_csv3_receive_encrypt_context { + __u64 hdr_uaddr; + __u32 hdr_len; + __u64 trans_uaddr; + __u32 trans_len; + }; + ++struct kvm_csv_batch_list_node { ++ __u64 cmd_data_addr; ++ __u64 addr; ++ __u64 next_cmd_addr; ++}; ++ ++struct kvm_csv_command_batch { ++ __u32 command_id; ++ __u64 csv_batch_list_uaddr; ++}; ++ + struct kvm_csv_init { + __u64 userid_addr; + __u32 len; +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index cf2c0c1a31..66d734f94c 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -42,3 +42,8 @@ void csv_shared_region_dma_unmap(uint64_t start, uint64_t end) + { + + } ++ ++int csv3_set_guest_private_memory(Error **errp) ++{ ++ g_assert_not_reached(); ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index f00385d809..770ea7d5bf 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -60,7 +60,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + { + int fw_error; + int ret; +- struct kvm_csv_init_data data = { 0 }; ++ struct kvm_csv3_init_data data = { 0 }; + + #ifdef CONFIG_NUMA + int mode; +@@ -77,7 +77,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + + csv_guest.policy = policy; + if (csv_enabled()) { +- ret = ops->sev_ioctl(fd, KVM_CSV_INIT, &data, &fw_error); ++ ret = ops->sev_ioctl(fd, KVM_CSV3_INIT, &data, &fw_error); + if (ret) { + csv_guest.policy = 0; + error_report("%s: Fail to initialize ret=%d fw_error=%d '%s'", +@@ -107,13 +107,13 @@ csv_enabled(void) + } + + static bool +-csv_check_state(SevState state) ++csv3_check_state(SevState state) + { + return *((SevState *)csv_guest.state) == state ? true : false; + } + + static int +-csv_ioctl(int cmd, void *data, int *error) ++csv3_ioctl(int cmd, void *data, int *error) + { + if (csv_guest.sev_ioctl) + return csv_guest.sev_ioctl(csv_guest.sev_fd, cmd, data, error); +@@ -134,7 +134,7 @@ static int + csv_launch_encrypt_data(uint64_t gpa, uint8_t *addr, uint64_t len) + { + int ret, fw_error; +- struct kvm_csv_launch_encrypt_data update; ++ struct kvm_csv3_launch_encrypt_data update; + + if (!addr || !len) { + return 1; +@@ -143,8 +143,8 @@ csv_launch_encrypt_data(uint64_t gpa, uint8_t *addr, uint64_t len) + update.gpa = (__u64)gpa; + update.uaddr = (__u64)(unsigned long)addr; + update.len = len; +- trace_kvm_csv_launch_encrypt_data(gpa, addr, len); +- ret = csv_ioctl(KVM_CSV_LAUNCH_ENCRYPT_DATA, &update, &fw_error); ++ 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: CSV LAUNCH_ENCRYPT_DATA ret=%d fw_error=%d '%s'", + __func__, ret, fw_error, fw_error_to_str(fw_error)); +@@ -164,7 +164,7 @@ csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + } + + /* if CSV is in update state then load the data to secure memory */ +- if (csv_check_state(SEV_STATE_LAUNCH_UPDATE)) { ++ if (csv3_check_state(SEV_STATE_LAUNCH_UPDATE)) { + ret = csv_launch_encrypt_data(gpa, ptr, len); + if (ret) + error_setg(errp, "%s: CSV fail to encrypt data", __func__); +@@ -183,7 +183,7 @@ csv_launch_encrypt_vmcb(void) + return -1; + } + +- ret = csv_ioctl(KVM_CSV_LAUNCH_ENCRYPT_VMCB, NULL, &fw_error); ++ ret = csv3_ioctl(KVM_CSV3_LAUNCH_ENCRYPT_VMCB, NULL, &fw_error); + if (ret) { + error_report("%s: CSV LAUNCH_ENCRYPT_VMCB ret=%d fw_error=%d '%s'", + __func__, ret, fw_error, fw_error_to_str(fw_error)); +@@ -347,11 +347,11 @@ static int + csv_send_get_packet_len(int *fw_err) + { + int ret; +- struct kvm_csv_send_encrypt_data update = {0}; ++ struct kvm_csv3_send_encrypt_data update = {0}; + + update.hdr_len = 0; + update.trans_len = 0; +- ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, fw_err); ++ 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)); +@@ -376,7 +376,7 @@ csv_send_encrypt_data(CsvGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size + guchar *trans; + uint32_t guest_addr_entry_num; + uint32_t i; +- struct kvm_csv_send_encrypt_data update = { }; ++ struct kvm_csv3_send_encrypt_data update = { }; + + /* + * If this is first call then query the packet header bytes and allocate +@@ -410,9 +410,9 @@ csv_send_encrypt_data(CsvGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size + update.trans_uaddr = (uintptr_t)trans; + update.trans_len = guest_addr_entry_num * TARGET_PAGE_SIZE; + +- trace_kvm_csv_send_encrypt_data(trans, update.trans_len); ++ trace_kvm_csv3_send_encrypt_data(trans, update.trans_len); + +- ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, &fw_error); ++ 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)); +@@ -481,7 +481,7 @@ csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) + * If this is a first buffer then create outgoing encryption context + * and write our PDH, policy and session data. + */ +- if (!csv_check_state(SEV_STATE_SEND_UPDATE) && ++ if (!csv3_check_state(SEV_STATE_SEND_UPDATE) && + csv_send_start(f, bytes_sent)) { + error_report("Failed to create outgoing context"); + return 1; +@@ -505,7 +505,7 @@ static int csv_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) + uint32_t i, guest_addr_entry_num; + gchar *hdr = NULL, *trans = NULL; + struct guest_addr_entry *guest_addr_data; +- struct kvm_csv_receive_encrypt_data update = {}; ++ struct kvm_csv3_receive_encrypt_data update = {}; + void *hva = NULL; + MemoryRegion *mr = NULL; + +@@ -543,9 +543,9 @@ static int csv_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) + } + } + +- trace_kvm_csv_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); ++ trace_kvm_csv3_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); + +- ret = csv_ioctl(KVM_CSV_RECEIVE_ENCRYPT_DATA, &update, &fw_error); ++ 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)); +@@ -565,7 +565,7 @@ 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 (!csv_check_state(SEV_STATE_RECEIVE_UPDATE) && ++ if (!csv3_check_state(SEV_STATE_RECEIVE_UPDATE) && + csv_receive_start(f)) { + return 1; + } +@@ -577,9 +577,9 @@ static int + csv_send_get_context_len(int *fw_err, int *context_len, int *hdr_len) + { + int ret = 0; +- struct kvm_csv_send_encrypt_context update = {}; ++ struct kvm_csv3_send_encrypt_context update = {}; + +- ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_CONTEXT, &update, fw_err); ++ 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)); +@@ -604,7 +604,7 @@ csv_send_encrypt_context(CsvGuestState *s, QEMUFile *f) + int hdr_len = 0; + guchar *trans; + guchar *hdr; +- struct kvm_csv_send_encrypt_context update = { }; ++ struct kvm_csv3_send_encrypt_context update = { }; + + ret = csv_send_get_context_len(&fw_error, &context_len, &hdr_len); + if (context_len < 1 || hdr_len < 1) { +@@ -622,9 +622,9 @@ csv_send_encrypt_context(CsvGuestState *s, QEMUFile *f) + update.trans_uaddr = (uintptr_t)trans; + update.trans_len = context_len; + +- trace_kvm_csv_send_encrypt_context(trans, update.trans_len); ++ trace_kvm_csv3_send_encrypt_context(trans, update.trans_len); + +- ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_CONTEXT, &update, &fw_error); ++ 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)); +@@ -648,7 +648,7 @@ csv_receive_encrypt_context(CsvGuestState *s, QEMUFile *f) + { + int ret = 1, fw_error = 0; + gchar *hdr = NULL, *trans = NULL; +- struct kvm_csv_receive_encrypt_context update = {}; ++ struct kvm_csv3_receive_encrypt_context update = {}; + + /* get packet header */ + update.hdr_len = qemu_get_be32(f); +@@ -664,9 +664,9 @@ csv_receive_encrypt_context(CsvGuestState *s, QEMUFile *f) + update.trans_uaddr = (uintptr_t)trans; + qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); + +- trace_kvm_csv_receive_encrypt_context(trans, update.trans_len, hdr, update.hdr_len); ++ trace_kvm_csv3_receive_encrypt_context(trans, update.trans_len, hdr, update.hdr_len); + +- ret = csv_ioctl(KVM_CSV_RECEIVE_ENCRYPT_CONTEXT, &update, &fw_error); ++ 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)); +@@ -694,3 +694,24 @@ int csv3_load_incoming_context(QEMUFile *f) + /* receive csv context. */ + return csv_receive_encrypt_context(s, f); + } ++ ++int csv3_set_guest_private_memory(Error **errp) ++{ ++ int fw_error; ++ int ret = 0; ++ ++ if (!csv_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)) { ++ trace_kvm_csv3_set_guest_private_memory(); ++ ret = csv3_ioctl(KVM_CSV3_SET_GUEST_PRIVATE_MEMORY, NULL, &fw_error); ++ if (ret) ++ error_setg(errp, "%s: CSV3 fail set private memory", __func__); ++ } ++ ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 03537a5728..485534d2d6 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -115,4 +115,6 @@ 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_set_guest_private_memory(Error **errp); ++ + #endif +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 47ab390de6..0610d5ea8f 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -21,8 +21,9 @@ kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len + 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_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 +-kvm_csv_send_encrypt_data(void *dst, int len) "trans %p len %d" +-kvm_csv_send_encrypt_context(void *dst, int len) "trans %p len %d" +-kvm_csv_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" +-kvm_csv_receive_encrypt_context(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" ++kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIx64 ++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" ++kvm_csv3_set_guest_private_memory(void) "" +-- +2.39.3 + diff --git a/1123-target-i386-csv-Support-load-kernel-hashes-for-CSV3-.patch b/1123-target-i386-csv-Support-load-kernel-hashes-for-CSV3-.patch new file mode 100644 index 0000000..b49a3dd --- /dev/null +++ b/1123-target-i386-csv-Support-load-kernel-hashes-for-CSV3-.patch @@ -0,0 +1,40 @@ +From 2aeb25e51ec21196f9e94af602e5d2cef0caed28 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sat, 28 Sep 2024 17:55:13 +0800 +Subject: [PATCH 4/5] target/i386: csv: Support load kernel hashes for CSV3 + guest only if the extension is enabled + +The CSV3 guest can only update kernel hashes when the +KVM_CAP_HYGON_COCO_EXT_CSV3_MULT_LUP_DATA capability is enabled. + +Signed-off-by: hanliyang +--- + target/i386/sev.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index a06b2998d6..07d91ee716 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -2701,7 +2701,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) + /* zero the excess data so the measurement can be reliably calculated */ + memset(padded_ht->padding, 0, sizeof(padded_ht->padding)); + +- if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht), errp) < 0) { ++ if (csv_enabled()) { ++ if (kvm_hygon_coco_ext_inuse & KVM_CAP_HYGON_COCO_EXT_CSV3_MULT_LUP_DATA) { ++ if (csv_load_data(area->base, (uint8_t *)padded_ht, ++ sizeof(*padded_ht), errp) < 0) { ++ ret = false; ++ } ++ } else { ++ error_report("%s: CSV3 load kernel hashes unsupported!", __func__); ++ ret = false; ++ } ++ } else if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht), errp) < 0) { + ret = false; + } + +-- +2.39.3 + diff --git a/1124-target-i386-csv-Support-inject-secret-for-CSV3-guest.patch b/1124-target-i386-csv-Support-inject-secret-for-CSV3-guest.patch new file mode 100644 index 0000000..fc7774d --- /dev/null +++ b/1124-target-i386-csv-Support-inject-secret-for-CSV3-guest.patch @@ -0,0 +1,43 @@ +From 6972f7a24c0a8bb7ef84b65032164971451a7255 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sun, 29 Sep 2024 15:03:47 +0800 +Subject: [PATCH 5/5] target/i386: csv: Support inject secret for CSV3 guest + only if the extension is enabled + +The CSV3 guest can only inject secrets when the +KVM_CAP_HYGON_COCO_EXT_CSV3_INJ_SECRET capability is enabled. + +Additionally, if the guest is a CSV3 guest, the guest_uaddr field of the +KVM ioctl's input should be set to the value of the GPA. + +Signed-off-by: hanliyang +--- + target/i386/sev.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 07d91ee716..94d3c1853b 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1373,7 +1373,17 @@ int sev_inject_launch_secret(const char *packet_hdr, const char *secret, + input.trans_uaddr = (uint64_t)(unsigned long)data; + input.trans_len = data_sz; + +- input.guest_uaddr = (uint64_t)(unsigned long)hva; ++ /* For Hygon CSV3 guest, the guest_uaddr should be the gpa */ ++ if (csv_enabled()) { ++ if (kvm_hygon_coco_ext_inuse & KVM_CAP_HYGON_COCO_EXT_CSV3_INJ_SECRET) { ++ input.guest_uaddr = gpa; ++ } else { ++ error_setg(errp, "CSV3 inject secret unsupported!"); ++ return 1; ++ } ++ } else { ++ input.guest_uaddr = (uint64_t)(unsigned long)hva; ++ } + input.guest_len = data_sz; + + trace_kvm_sev_launch_secret(gpa, input.guest_uaddr, +-- +2.39.3 + diff --git a/1125-i386-Avoid-explicitly-using-KVM_CAP_HYGON_COCO_EXT_C.patch b/1125-i386-Avoid-explicitly-using-KVM_CAP_HYGON_COCO_EXT_C.patch new file mode 100644 index 0000000..f4b1fc6 --- /dev/null +++ b/1125-i386-Avoid-explicitly-using-KVM_CAP_HYGON_COCO_EXT_C.patch @@ -0,0 +1,73 @@ +From edd31dc98e89167490ecbfc708680b2f25e8b63d Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Tue, 31 Dec 2024 13:33:20 +0800 +Subject: [PATCH 1/4] i386: Avoid explicitly using + KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM in hw/i386/pc_sysfw.c + +Additionally, add 1 space to make the log format for the trace event +kvm_csv3_launch_encrypt_datas more user-friendly. + +Fixes: 08495c0e6f ("target/i386: csv: Request to set private memory of CSV3 guest if the extension is enabled") +Signed-off-by: hanliyang +--- + hw/i386/pc_sysfw.c | 2 +- + include/sysemu/kvm.h | 9 +++++++++ + target/i386/trace-events | 2 +- + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index ed00786f42..c18a0c6236 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -210,7 +210,7 @@ static void pc_system_flash_map(PCMachineState *pcms, + } + + if (csv_enabled()) { +- if (kvm_hygon_coco_ext_inuse & KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM) ++ if (kvm_csv3_should_set_priv_mem()) + csv3_set_guest_private_memory(&error_fatal); + + csv_load_data(flash_mem->addr, flash_ptr, flash_size, &error_fatal); +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 9f8099f487..f050dfa1f7 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -168,6 +168,14 @@ extern bool kvm_has_msr_ghcb; + */ + #define kvm_msi_devid_required() (kvm_msi_use_devid) + ++/** ++ * kvm_csv3_should_set_priv_mem: ++ * Returns: true if we should explicitly request ++ * KVM_CSV3_SET_GUEST_PRIVATE_MEMORY. ++ */ ++#define kvm_csv3_should_set_priv_mem() \ ++ (kvm_hygon_coco_ext_inuse & KVM_CAP_HYGON_COCO_EXT_CSV3_SET_PRIV_MEM) ++ + #else + + #define kvm_enabled() (0) +@@ -185,6 +193,7 @@ extern bool kvm_has_msr_ghcb; + #define kvm_direct_msi_enabled() (false) + #define kvm_ioeventfd_any_length_enabled() (false) + #define kvm_msi_devid_required() (false) ++#define kvm_csv3_should_set_priv_mem() (false) + + #endif /* CONFIG_KVM_IS_POSSIBLE */ + +diff --git a/target/i386/trace-events b/target/i386/trace-events +index 0610d5ea8f..5d4a709a39 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -21,7 +21,7 @@ kvm_sev_send_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *dst, int len + 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%" PRIx64 ++kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 " addr %p len 0x%" PRIx64 + 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.39.3 + diff --git a/1126-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch b/1126-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch new file mode 100644 index 0000000..d0aa531 --- /dev/null +++ b/1126-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch @@ -0,0 +1,71 @@ +From bff3b691404354de6a03ac496026320d8da39ffc Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Fri, 3 Jan 2025 16:28:18 +0800 +Subject: [PATCH 2/4] target/i386: sev: Return 0 if sev_send_get_packet_len() + fails + +The send_packet_hdr_len of struct SEVState is of type size_t +which is an unsigned class type. If the send_packet_hdr_len +is assigned as -1, then it will be a huge number and the QEMU +process will crash when allocating packet buffer with the +huge size. + +For example, the following code could cause crash described +above. + + ``` + static int + sev_send_update_data(SEVState *s, QEMUFile *f, uint8_t *ptr, uint32_t size, + uint64_t *bytes_sent) + { + + ...... + + if (!s->send_packet_hdr) { + s->send_packet_hdr_len = sev_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); + } + + ...... + + } + ``` + +[ hly: Also return 0 if sev_send_vmsa_get_packet_len() fails. ] + +Signed-off-by: hanliyang +--- + target/i386/sev.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 94d3c1853b..484e6e7509 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1643,7 +1643,7 @@ sev_send_get_packet_len(int *fw_err) + ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_DATA, + &update, fw_err); + if (*fw_err != SEV_RET_INVALID_LEN) { +- ret = -1; ++ ret = 0; + error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", + __func__, ret, *fw_err, fw_error_to_str(*fw_err)); + goto err; +@@ -2370,7 +2370,7 @@ sev_send_vmsa_get_packet_len(int *fw_err) + ret = sev_ioctl(sev_guest->sev_fd, KVM_SEV_SEND_UPDATE_VMSA, + &update, fw_err); + if (*fw_err != SEV_RET_INVALID_LEN) { +- ret = -1; ++ ret = 0; + error_report("%s: failed to get session length ret=%d fw_error=%d '%s'", + __func__, ret, *fw_err, fw_error_to_str(*fw_err)); + goto err; +-- +2.39.3 + diff --git a/1127-target-i386-csv-The-CSV2-guest-running-on-the-recipi.patch b/1127-target-i386-csv-The-CSV2-guest-running-on-the-recipi.patch new file mode 100644 index 0000000..9ba5f03 --- /dev/null +++ b/1127-target-i386-csv-The-CSV2-guest-running-on-the-recipi.patch @@ -0,0 +1,95 @@ +From 4b103bfc7b873bc070a6d714341f6b25b2d251c1 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Fri, 26 Apr 2024 21:17:35 +0800 +Subject: [PATCH 3/4] target/i386/csv: The CSV2 guest running on the recipient + side is not resettable + +Currently, both CSV2 guest running on the recipient side and CSV3 +guest are not resettable. Provide a new global variable +kvm_csv_reset_inhibit to indicate the resettable state if the VM +is using CSV technologies. + +Signed-off-by: hanliyang +--- + target/i386/csv.c | 2 ++ + target/i386/csv.h | 2 ++ + target/i386/kvm/kvm.c | 4 +++- + target/i386/kvm/sev-stub.c | 2 ++ + target/i386/sev.c | 3 +++ + 5 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 770ea7d5bf..12e2cc16be 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -93,6 +93,8 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex); + csv_guest.sev_send_start = ops->sev_send_start; + csv_guest.sev_receive_start = ops->sev_receive_start; ++ ++ kvm_csv_reset_inhibit = true; + } + return 0; + } +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 485534d2d6..cc02ba83a4 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -18,6 +18,8 @@ + #include "qemu/thread.h" + #include "qemu/queue.h" + ++extern bool kvm_csv_reset_inhibit; ++ + #ifdef CONFIG_SEV + + #include "cpu.h" +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 469349420c..a14debcfc2 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -5383,7 +5383,9 @@ bool kvm_has_waitpkg(void) + + bool kvm_arch_cpu_check_are_resettable(void) + { +- return !(sev_es_enabled() && !is_hygon_cpu()) && !csv_enabled(); ++ if (is_hygon_cpu()) ++ return !kvm_csv_reset_inhibit; ++ return !sev_es_enabled(); + } + + #define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 +diff --git a/target/i386/kvm/sev-stub.c b/target/i386/kvm/sev-stub.c +index 6080c007a2..0651502f1c 100644 +--- a/target/i386/kvm/sev-stub.c ++++ b/target/i386/kvm/sev-stub.c +@@ -20,3 +20,5 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + /* If we get here, cgs must be some non-SEV thing */ + return 0; + } ++ ++bool kvm_csv_reset_inhibit; +diff --git a/target/i386/sev.c b/target/i386/sev.c +index 484e6e7509..3f25d2b6d7 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -219,6 +219,7 @@ static struct ConfidentialGuestMemoryEncryptionOps sev_memory_encryption_ops = { + }; + + bool kvm_has_msr_ghcb; ++bool kvm_csv_reset_inhibit; + + static int + sev_ioctl(int fd, int cmd, void *data, int *error) +@@ -1275,6 +1276,8 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + error_setg(errp, "%s: failed to create encryption context", __func__); + goto err; + } ++ } else if (is_hygon_cpu() && sev_es_enabled()) { ++ kvm_csv_reset_inhibit = true; + } + + /* CSV guest needs no notifier to reg/unreg memory */ +-- +2.39.3 + diff --git a/1128-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch b/1128-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch new file mode 100644 index 0000000..f1cdd06 --- /dev/null +++ b/1128-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch @@ -0,0 +1,339 @@ +From 833c21b48d30780fc36fb3f886b06cc5c51d1600 Mon Sep 17 00:00:00 2001 +From: thomas +Date: Fri, 12 Jul 2024 11:10:53 +0800 +Subject: [PATCH 4/4] virtio-net: Fix network stall at the host side waiting + for kick + +commit f937309fbdbb48c354220a3e7110c202ae4aa7fa upstream. + +Patch 06b12970174 ("virtio-net: fix network stall under load") +added double-check to test whether the available buffer size +can satisfy the request or not, in case the guest has added +some buffers to the avail ring simultaneously after the first +check. It will be lucky if the available buffer size becomes +okay after the double-check, then the host can send the packet +to the guest. If the buffer size still can't satisfy the request, +even if the guest has added some buffers, viritio-net would +stall at the host side forever. + +The patch enables notification and checks whether the guest has +added some buffers since last check of available buffers when +the available buffers are insufficient. If no buffer is added, +return false, else recheck the available buffers in the loop. +If the available buffers are sufficient, disable notification +and return true. + +Changes: +1. Change the return type of virtqueue_get_avail_bytes() from void + to int, it returns an opaque that represents the shadow_avail_idx + of the virtqueue on success, else -1 on error. +2. Add a new API: virtio_queue_enable_notification_and_check(), + it takes an opaque as input arg which is returned from + virtqueue_get_avail_bytes(). It enables notification firstly, + then checks whether the guest has added some buffers since + last check of available buffers or not by virtio_queue_poll(), + return ture if yes. + +The patch also reverts patch "06b12970174". + +The case below can reproduce the stall. + + Guest 0 + +--------+ + | iperf | + ---------------> | server | + Host | +--------+ + +--------+ | ... + | iperf |---- + | client |---- Guest n + +--------+ | +--------+ + | | iperf | + ---------------> | server | + +--------+ + +Boot many guests from qemu with virtio network: + qemu ... -netdev tap,id=net_x \ + -device virtio-net-pci-non-transitional,\ + iommu_platform=on,mac=xx:xx:xx:xx:xx:xx,netdev=net_x + +Each guest acts as iperf server with commands below: + iperf3 -s -D -i 10 -p 8001 + iperf3 -s -D -i 10 -p 8002 + +The host as iperf client: + iperf3 -c guest_IP -p 8001 -i 30 -w 256k -P 20 -t 40000 + iperf3 -c guest_IP -p 8002 -i 30 -w 256k -P 20 -t 40000 + +After some time, the host loses connection to the guest, +the guest can send packet to the host, but can't receive +packet from the host. + +It's more likely to happen if SWIOTLB is enabled in the guest, +allocating and freeing bounce buffer takes some CPU ticks, +copying from/to bounce buffer takes more CPU ticks, compared +with that there is no bounce buffer in the guest. +Once the rate of producing packets from the host approximates +the rate of receiveing packets in the guest, the guest would +loop in NAPI. + + receive packets --- + | | + v | + free buf virtnet_poll + | | + v | + add buf to avail ring --- + | + | need kick the host? + | NAPI continues + v + receive packets --- + | | + v | + free buf virtnet_poll + | | + v | + add buf to avail ring --- + | + v + ... ... + +On the other hand, the host fetches free buf from avail +ring, if the buf in the avail ring is not enough, the +host notifies the guest the event by writing the avail +idx read from avail ring to the event idx of used ring, +then the host goes to sleep, waiting for the kick signal +from the guest. + +Once the guest finds the host is waiting for kick singal +(in virtqueue_kick_prepare_split()), it kicks the host. + +The host may stall forever at the sequences below: + + Host Guest + ------------ ----------- + fetch buf, send packet receive packet --- + ... ... | + fetch buf, send packet add buf | + ... add buf virtnet_poll + buf not enough avail idx-> add buf | + read avail idx add buf | + add buf --- + receive packet --- + write event idx ... | + wait for kick add buf virtnet_poll + ... | + --- + no more packet, exit NAPI + +In the first loop of NAPI above, indicated in the range of +virtnet_poll above, the host is sending packets while the +guest is receiving packets and adding buffers. + step 1: The buf is not enough, for example, a big packet + needs 5 buf, but the available buf count is 3. + The host read current avail idx. + step 2: The guest adds some buf, then checks whether the + host is waiting for kick signal, not at this time. + The used ring is not empty, the guest continues + the second loop of NAPI. + step 3: The host writes the avail idx read from avail + ring to used ring as event idx via + virtio_queue_set_notification(q->rx_vq, 1). + step 4: At the end of the second loop of NAPI, recheck + whether kick is needed, as the event idx in the + used ring written by the host is beyound the + range of kick condition, the guest will not + send kick signal to the host. + +Fixes: 06b12970174 ("virtio-net: fix network stall under load") +Cc: qemu-stable@nongnu.org +Signed-off-by: Wencheng Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +--- + hw/net/virtio-net.c | 28 ++++++++++------- + hw/virtio/virtio.c | 64 +++++++++++++++++++++++++++++++++++--- + include/hw/virtio/virtio.h | 19 +++++++++-- + 3 files changed, 92 insertions(+), 19 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 7d459726d4..09b76676dd 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1518,24 +1518,28 @@ static bool virtio_net_can_receive(NetClientState *nc) + + static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) + { ++ int opaque; ++ unsigned int in_bytes; + VirtIONet *n = q->n; +- if (virtio_queue_empty(q->rx_vq) || +- (n->mergeable_rx_bufs && +- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { +- virtio_queue_set_notification(q->rx_vq, 1); +- +- /* To avoid a race condition where the guest has made some buffers +- * available after the above check but before notification was +- * enabled, check for available buffers again. +- */ +- if (virtio_queue_empty(q->rx_vq) || +- (n->mergeable_rx_bufs && +- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { ++ ++ while (virtio_queue_empty(q->rx_vq) || n->mergeable_rx_bufs) { ++ opaque = virtqueue_get_avail_bytes(q->rx_vq, &in_bytes, NULL, ++ bufsize, 0); ++ /* Buffer is enough, disable notifiaction */ ++ if (bufsize <= in_bytes) { ++ break; ++ } ++ ++ if (virtio_queue_enable_notification_and_check(q->rx_vq, opaque)) { ++ /* Guest has added some buffers, try again */ ++ continue; ++ } else { + return 0; + } + } + + virtio_queue_set_notification(q->rx_vq, 0); ++ + return 1; + } + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index ea7c079fb0..2971d271ff 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -660,6 +660,60 @@ int virtio_queue_empty(VirtQueue *vq) + } + } + ++static bool virtio_queue_split_poll(VirtQueue *vq, unsigned shadow_idx) ++{ ++ if (unlikely(!vq->vring.avail)) { ++ return false; ++ } ++ ++ return (uint16_t)shadow_idx != vring_avail_idx(vq); ++} ++ ++static bool virtio_queue_packed_poll(VirtQueue *vq, unsigned shadow_idx) ++{ ++ VRingPackedDesc desc; ++ VRingMemoryRegionCaches *caches; ++ ++ if (unlikely(!vq->vring.desc)) { ++ return false; ++ } ++ ++ caches = vring_get_region_caches(vq); ++ if (!caches) { ++ return false; ++ } ++ ++ vring_packed_desc_read(vq->vdev, &desc, &caches->desc, ++ shadow_idx, true); ++ ++ return is_desc_avail(desc.flags, vq->shadow_avail_wrap_counter); ++} ++ ++static bool virtio_queue_poll(VirtQueue *vq, unsigned shadow_idx) ++{ ++ if (virtio_device_disabled(vq->vdev)) { ++ return false; ++ } ++ ++ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) { ++ return virtio_queue_packed_poll(vq, shadow_idx); ++ } else { ++ return virtio_queue_split_poll(vq, shadow_idx); ++ } ++} ++ ++bool virtio_queue_enable_notification_and_check(VirtQueue *vq, ++ int opaque) ++{ ++ virtio_queue_set_notification(vq, 1); ++ ++ if (opaque >= 0) { ++ return virtio_queue_poll(vq, (unsigned)opaque); ++ } else { ++ return false; ++ } ++} ++ + static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len) + { +@@ -1226,9 +1280,9 @@ err: + goto done; + } + +-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, +- unsigned int *out_bytes, +- unsigned max_in_bytes, unsigned max_out_bytes) ++int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, ++ unsigned int *out_bytes, unsigned max_in_bytes, ++ unsigned max_out_bytes) + { + uint16_t desc_size; + VRingMemoryRegionCaches *caches; +@@ -1261,7 +1315,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + caches); + } + +- return; ++ return (int)vq->shadow_avail_idx; + err: + if (in_bytes) { + *in_bytes = 0; +@@ -1269,6 +1323,8 @@ err: + if (out_bytes) { + *out_bytes = 0; + } ++ ++ return -1; + } + + int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 8bab9cfb75..0d4299b87b 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -203,9 +203,13 @@ void qemu_put_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, + VirtQueueElement *elem); + int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, + unsigned int out_bytes); +-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, +- unsigned int *out_bytes, +- unsigned max_in_bytes, unsigned max_out_bytes); ++/** ++ * Return <0 on error or an opaque >=0 to pass to ++ * virtio_queue_enable_notification_and_check on success. ++ */ ++int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, ++ unsigned int *out_bytes, unsigned max_in_bytes, ++ unsigned max_out_bytes); + + void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq); + void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); +@@ -232,6 +236,15 @@ int virtio_queue_ready(VirtQueue *vq); + + int virtio_queue_empty(VirtQueue *vq); + ++/** ++ * Enable notification and check whether guest has added some ++ * buffers since last call to virtqueue_get_avail_bytes. ++ * ++ * @opaque: value returned from virtqueue_get_avail_bytes ++ */ ++bool virtio_queue_enable_notification_and_check(VirtQueue *vq, ++ int opaque); ++ + /* Host binding interface. */ + + uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr); +-- +2.39.3 + diff --git a/qemu-kvm.spec b/qemu-kvm.spec index f0f10d2..755f58a 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.1 +%define anolis_release .0.3 %global SLOF_gittagdate 20191022 %global SLOF_gittagcommit 899d9883 @@ -1025,6 +1025,15 @@ Patch1116: 1116-i386-cpu-Mask-with-XCR0-XSS-mask-for-FEAT_XSAVE_XCR0.patch Patch1117: 1117-i386-cpuid-Decrease-cpuid_i-when-skipping-CPUID-leaf.patch Patch1118: 1118-i386-cpuid-Move-leaf-7-to-correct-group.patch Patch1119: 1119-target-i386-Introduce-Icelake-Server-v7-to-enable-TS.patch +Patch1120: 1120-qapi-qom-target-i386-csv-guest-Introduce-secret-head.patch +Patch1121: 1121-target-i386-kvm-Support-to-get-and-enable-extensions.patch +Patch1122: 1122-target-i386-csv-Request-to-set-private-memory-of-CSV.patch +Patch1123: 1123-target-i386-csv-Support-load-kernel-hashes-for-CSV3-.patch +Patch1124: 1124-target-i386-csv-Support-inject-secret-for-CSV3-guest.patch +Patch1125: 1125-i386-Avoid-explicitly-using-KVM_CAP_HYGON_COCO_EXT_C.patch +Patch1126: 1126-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch +Patch1127: 1127-target-i386-csv-The-CSV2-guest-running-on-the-recipi.patch +Patch1128: 1128-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch BuildRequires: wget BuildRequires: rpm-build @@ -2263,6 +2272,18 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %endif %changelog +* Thu Jan 09 2025 Xuchun Shang - 6.2.0-53.0.1.3 +- Sync Patch from source repo +- 1120-qapi-qom-target-i386-csv-guest-Introduce-secret-head.patch +- 1121-target-i386-kvm-Support-to-get-and-enable-extensions.patch +- 1122-target-i386-csv-Request-to-set-private-memory-of-CSV.patch +- 1123-target-i386-csv-Support-load-kernel-hashes-for-CSV3-.patch +- 1124-target-i386-csv-Support-inject-secret-for-CSV3-guest.patch +- 1125-i386-Avoid-explicitly-using-KVM_CAP_HYGON_COCO_EXT_C.patch +- 1126-target-i386-sev-Return-0-if-sev_send_get_packet_len-.patch +- 1127-target-i386-csv-The-CSV2-guest-running-on-the-recipi.patch +- 1128-virtio-net-Fix-network-stall-at-the-host-side-waitin.patch + * Fri Nov 08 2024 Jacob Wang - 6.2.0-53.0.1.2 - Adjust limit for virtiofsd minor version - Add loongarch supporti (lixianglai@loongson.cn) -- Gitee