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 387c0a142df..a2ac0ae33e3 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 c3c070de6f0..453d220226b 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) -- Gitee 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 3875127a375..dca6b484767 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 96ca055270b..cf2c0c1a312 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 0e48982964d..f00385d809c 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 86f46d30c2c..03537a57284 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 cecc3d035d8..469349420ca 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; -- Gitee 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 84aad306dc7..ed00786f425 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 dca6b484767..02bba131e6c 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 cf2c0c1a312..66d734f94c2 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 f00385d809c..770ea7d5bfb 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 03537a57284..485534d2d69 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 47ab390de69..0610d5ea8fd 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) "" -- Gitee 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 a06b2998d68..07d91ee716d 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; } -- Gitee 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 07d91ee716d..94d3c1853b6 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, -- Gitee