From bdc479ca044c60e1de79d61fff3d891f62ebc05a Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Mon, 21 Aug 2023 16:48:12 +0800 Subject: [PATCH] fixed 88da33c from https://gitee.com/hanliyang/src-anolis-os.qemu/pulls/4 Support Hygon CSV3 feature CSV3 feature integrates secure processor, memory encryption and memory isolation to provide the ability to protect guest's private data. The CSV guest's context like CPU registers, control block and nested page table is accessed only by the guest itself and the secure processor. Neither other guests nor the host can tamper with the guest's context. Signed-off-by: Xin Jiang --- 0002-anolis-csv-i386-add-CSV-context.patch | 195 +++++++++++++++++ ...add-command-to-initialize-CSV-contex.patch | 204 ++++++++++++++++++ ...add-command-to-load-data-to-guest-me.patch | 164 ++++++++++++++ ...add-command-to-load-vmcb-to-guest-me.patch | 107 +++++++++ ...populate-CPUID-0x8000_001F-when-CSV-.patch | 41 ++++ ...CSV-guest-do-not-need-register-unreg.patch | 35 +++ ...86-csv-load-initial-image-to-private.patch | 51 +++++ ...-vga-force-full-update-for-CSV-guest.patch | 47 ++++ qemu.spec | 21 +- 9 files changed, 864 insertions(+), 1 deletion(-) create mode 100644 0002-anolis-csv-i386-add-CSV-context.patch create mode 100644 0003-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch create mode 100644 0004-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch create mode 100644 0005-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch create mode 100644 0006-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch create mode 100644 0007-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch create mode 100644 0008-anolis-target-i386-csv-load-initial-image-to-private.patch create mode 100644 0009-anolis-vga-force-full-update-for-CSV-guest.patch diff --git a/0002-anolis-csv-i386-add-CSV-context.patch b/0002-anolis-csv-i386-add-CSV-context.patch new file mode 100644 index 0000000..72cb6ae --- /dev/null +++ b/0002-anolis-csv-i386-add-CSV-context.patch @@ -0,0 +1,195 @@ +From 0080a84a9fe46aea59773975d9aebbc18a6cb210 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 14:57:28 +0800 +Subject: [PATCH 2/9] anolis: csv/i386: add CSV context + +CSV is the secure virtualization feature on Hygon CPU. +It is compatible with the AMD SEV/SEV-ES and extends out +specific funtionality by setting bit 6 of guest policy. + +Add the context and the build option. + +Signed-off-by: Xin Jiang +Change-Id: I5dba29a487e3a763c832ac30cef5c7fe63eac26a +--- + configs/devices/i386-softmmu/default.mak | 1 + + hw/i386/Kconfig | 5 +++ + target/i386/csv-sysemu-stub.c | 16 ++++++++ + target/i386/csv.c | 51 ++++++++++++++++++++++++ + target/i386/csv.h | 35 ++++++++++++++++ + target/i386/meson.build | 1 + + 6 files changed, 109 insertions(+) + create mode 100644 target/i386/csv-sysemu-stub.c + create mode 100644 target/i386/csv.c + create mode 100644 target/i386/csv.h + +diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak +index 598c6646df..db83ffcab9 100644 +--- a/configs/devices/i386-softmmu/default.mak ++++ b/configs/devices/i386-softmmu/default.mak +@@ -23,6 +23,7 @@ + #CONFIG_TPM_TIS_ISA=n + #CONFIG_VTD=n + #CONFIG_SGX=n ++#CONFIG_CSV=n + + # Boards: + # +diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig +index d22ac4a4b9..ed35d762b3 100644 +--- a/hw/i386/Kconfig ++++ b/hw/i386/Kconfig +@@ -10,6 +10,10 @@ config SGX + bool + depends on KVM + ++config CSV ++ bool ++ depends on SEV ++ + config PC + bool + imply APPLESMC +@@ -26,6 +30,7 @@ config PC + imply QXL + imply SEV + imply SGX ++ imply CSV + imply SGA + imply TEST_DEVICES + imply TPM_CRB +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +new file mode 100644 +index 0000000000..a89b2600e7 +--- /dev/null ++++ b/target/i386/csv-sysemu-stub.c +@@ -0,0 +1,16 @@ ++/* ++ * QEMU CSV support ++ * ++ * Copyright: Hygon Info Technologies Ltd. 2022 ++ * ++ * Author: ++ * Jiang Xin ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "sev.h" ++#include "csv.h" +diff --git a/target/i386/csv.c b/target/i386/csv.c +new file mode 100644 +index 0000000000..aac825d3f9 +--- /dev/null ++++ b/target/i386/csv.c +@@ -0,0 +1,51 @@ ++/* ++ * QEMU CSV support ++ * ++ * Copyright: Hygon Info Technologies Ltd. 2022 ++ * ++ * Author: ++ * Jiang Xin ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++ ++#include "cpu.h" ++#include "sev.h" ++#include "csv.h" ++ ++CsvGuestState csv_guest = { 0 }; ++ ++#define CPUID_VENDOR_HYGON_EBX 0x6f677948 /* "Hygo" */ ++#define CPUID_VENDOR_HYGON_ECX 0x656e6975 /* "uine" */ ++#define CPUID_VENDOR_HYGON_EDX 0x6e65476e /* "nGen" */ ++ ++#define GUEST_POLICY_CSV_BIT (1 << 6) ++ ++static bool is_hygon_cpu(void) ++{ ++ uint32_t ebx = 0; ++ uint32_t ecx = 0; ++ uint32_t edx = 0; ++ ++ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); ++ ++ if (ebx == CPUID_VENDOR_HYGON_EBX && ++ ecx == CPUID_VENDOR_HYGON_ECX && ++ edx == CPUID_VENDOR_HYGON_EDX) ++ return true; ++ else ++ return false; ++} ++ ++bool ++csv_enabled(void) ++{ ++ if (!is_hygon_cpu()) ++ return false; ++ ++ return sev_es_enabled() && (csv_guest.policy & GUEST_POLICY_CSV_BIT); ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +new file mode 100644 +index 0000000000..057d37d975 +--- /dev/null ++++ b/target/i386/csv.h +@@ -0,0 +1,35 @@ ++/* ++ * QEMU CSV support ++ * ++ * Copyright: Hygon Info Technologies Ltd. 2022 ++ * ++ * Author: ++ * Jiang Xin ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#ifndef QEMU_CSV_H ++#define QEMU_CSV_H ++ ++#include "qapi/qapi-commands-misc-target.h" ++ ++#ifdef CONFIG_CSV ++bool csv_enabled(void); ++#else ++#define csv_enabled() 0 ++#endif ++ ++struct CsvGuestState { ++ uint32_t policy; ++ int sev_fd; ++ void *state; ++}; ++ ++typedef struct CsvGuestState CsvGuestState; ++ ++extern struct CsvGuestState csv_guest; ++ ++#endif +diff --git a/target/i386/meson.build b/target/i386/meson.build +index ae38dc9563..361dea9290 100644 +--- a/target/i386/meson.build ++++ b/target/i386/meson.build +@@ -21,6 +21,7 @@ i386_softmmu_ss.add(files( + 'cpu-sysemu.c', + )) + i386_softmmu_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-sysemu-stub.c')) ++i386_softmmu_ss.add(when: 'CONFIG_CSV', if_true: files('csv.c'), if_false: files('csv-sysemu-stub.c')) + + i386_user_ss = ss.source_set() + +-- +2.17.1 + diff --git a/0003-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch b/0003-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch new file mode 100644 index 0000000..d4144f7 --- /dev/null +++ b/0003-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch @@ -0,0 +1,204 @@ +From e9343731c5de9052c0ea8faaec4f04e1bf23c7b6 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 11:07:41 +0800 +Subject: [PATCH 3/9] anolis: csv/i386: add command to initialize CSV context + +When CSV is enabled, KVM_CSV_INIT command is used to initialize +the platform, which is implemented by reusing the SEV API +framework and extending the functionality. + +The KVM_CSV_INIT command should be performed earlier than +any other command. + +Signed-off-by: Xin Jiang +Change-Id: I20573286b621c38432384c1d6e198fc85d88f38e +--- + linux-headers/linux/kvm.h | 11 +++++++++ + target/i386/csv-sysemu-stub.c | 5 ++++ + target/i386/csv.c | 44 +++++++++++++++++++++++++++++++++++ + target/i386/csv.h | 3 +++ + target/i386/sev.c | 17 ++++++++++++++ + target/i386/sev.h | 5 ++++ + 6 files changed, 85 insertions(+) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index ebdafa576d..a67173cef0 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1983,6 +1983,17 @@ struct kvm_sev_receive_update_data { + __u32 trans_len; + }; + ++/* CSV command */ ++enum csv_cmd_id { ++ KVM_CSV_NR_MIN = 0xc0, ++ ++ KVM_CSV_INIT = KVM_CSV_NR_MIN, ++}; ++ ++struct kvm_csv_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 a89b2600e7..dbd710dc6f 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 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 aac825d3f9..c11f59f30c 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -13,6 +13,12 @@ + + #include "qemu/osdep.h" + ++#include ++ ++#ifdef CONFIG_NUMA ++#include ++#endif ++ + #include "cpu.h" + #include "sev.h" + #include "csv.h" +@@ -41,6 +47,44 @@ static bool is_hygon_cpu(void) + return false; + } + ++int ++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 }; ++ ++#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; ++ ++ csv_guest.policy = policy; ++ if (csv_enabled()) { ++ ret = ops->sev_ioctl(fd, KVM_CSV_INIT, &data, &fw_error); ++ if (ret) { ++ csv_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; ++ } ++ ++ csv_guest.sev_fd = fd; ++ csv_guest.state = state; ++ csv_guest.sev_ioctl = ops->sev_ioctl; ++ csv_guest.fw_error_to_str = ops->fw_error_to_str; ++ } ++ return 0; ++} ++ + bool + csv_enabled(void) + { +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 057d37d975..886dbb2613 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -26,10 +26,13 @@ struct CsvGuestState { + 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 CsvGuestState CsvGuestState; + + extern struct CsvGuestState csv_guest; ++extern int csv_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 32f7dbac4e..20507da004 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -26,6 +26,7 @@ + #include "crypto/hash.h" + #include "sysemu/kvm.h" + #include "sev.h" ++#include "csv.h" + #include "sysemu/sysemu.h" + #include "sysemu/runstate.h" + #include "trace.h" +@@ -43,6 +44,8 @@ + OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST) + + ++extern struct sev_ops sev_ops; ++ + /** + * SevGuestState: + * +@@ -992,6 +995,15 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + goto err; + } + ++ /* Support CSV */ ++ if (!ret && cmd == KVM_SEV_ES_INIT) { ++ ret = csv_init(sev_guest->policy, sev->sev_fd, (void *)&sev->state, &sev_ops); ++ if (ret) { ++ error_setg(errp, "%s: failed to init csv context", __func__); ++ goto err; ++ } ++ } ++ + ret = sev_launch_start(sev); + if (ret) { + error_setg(errp, "%s: failed to create encryption context", __func__); +@@ -1372,6 +1384,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 7b1528248a..0a82f97f35 100644 +--- a/target/i386/sev.h ++++ b/target/i386/sev.h +@@ -59,4 +59,9 @@ void sev_es_set_reset_vector(CPUState *cpu); + + int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp); + ++struct sev_ops { ++ int (*sev_ioctl)(int fd, int cmd, void *data, int *error); ++ const char *(*fw_error_to_str)(int code); ++}; ++ + #endif +-- +2.17.1 + diff --git a/0004-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch b/0004-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch new file mode 100644 index 0000000..4b11faa --- /dev/null +++ b/0004-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch @@ -0,0 +1,164 @@ +From 13d1098ac04a90ed183877133a30b791bd00b56d Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 09:59:16 +0800 +Subject: [PATCH 4/9] anolis: csv/i386: add command to load data to guest + memory + +The KVM_CSV_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 +Change-Id: Ibebef9ad29a411d93936b373b3b2e874e56e40f4 +--- + 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 a67173cef0..456aed121f 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1988,6 +1988,13 @@ enum csv_cmd_id { + KVM_CSV_NR_MIN = 0xc0, + + KVM_CSV_INIT = KVM_CSV_NR_MIN, ++ KVM_CSV_LAUNCH_ENCRYPT_DATA, ++}; ++ ++struct kvm_csv_launch_encrypt_data { ++ __u64 gpa; ++ __u64 uaddr; ++ __u32 len; + }; + + struct kvm_csv_init_data { +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index dbd710dc6f..236a6909d2 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -19,3 +19,8 @@ int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) + { + return 0; + } ++ ++int csv_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 c11f59f30c..3b3dff5174 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -14,11 +14,13 @@ + #include "qemu/osdep.h" + + #include ++#include "qapi/error.h" + + #ifdef CONFIG_NUMA + #include + #endif + ++#include "trace.h" + #include "cpu.h" + #include "sev.h" + #include "csv.h" +@@ -93,3 +95,70 @@ csv_enabled(void) + + return sev_es_enabled() && (csv_guest.policy & GUEST_POLICY_CSV_BIT); + } ++ ++static bool ++csv_check_state(SevState state) ++{ ++ return *((SevState *)csv_guest.state) == state ? true : false; ++} ++ ++static int ++csv_ioctl(int cmd, void *data, int *error) ++{ ++ if (csv_guest.sev_ioctl) ++ return csv_guest.sev_ioctl(csv_guest.sev_fd, cmd, data, error); ++ else ++ return -1; ++} ++ ++static const char * ++fw_error_to_str(int code) ++{ ++ if (csv_guest.fw_error_to_str) ++ return csv_guest.fw_error_to_str(code); ++ else ++ return NULL; ++} ++ ++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; ++ ++ if (!addr || !len) { ++ return 1; ++ } ++ ++ 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); ++ 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)); ++ } ++ ++ return ret; ++} ++ ++int ++csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) ++{ ++ int ret = 0; ++ ++ if (!csv_enabled()) { ++ error_setg(errp, "%s: CSV is not enabled", __func__); ++ return -1; ++ } ++ ++ /* if CSV is in update state then load the data to secure memory */ ++ if (csv_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__); ++ } ++ ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 886dbb2613..6f7b112d96 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -35,4 +35,6 @@ typedef struct CsvGuestState CsvGuestState; + extern struct CsvGuestState csv_guest; + extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); + ++int csv_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 2cd8726eeb..b7da9bd748 100644 +--- a/target/i386/trace-events ++++ b/target/i386/trace-events +@@ -11,3 +11,6 @@ kvm_sev_launch_measurement(const char *value) "data %s" + kvm_sev_launch_finish(void) "" + kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa 0x%" PRIx64 " hva 0x%" PRIx64 " data 0x%" PRIx64 " len %d" + kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s" ++ ++# csv.c ++kvm_csv_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIu64 +-- +2.17.1 + diff --git a/0005-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch b/0005-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch new file mode 100644 index 0000000..843943c --- /dev/null +++ b/0005-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch @@ -0,0 +1,107 @@ +From 0c10f36276fef9f5983dc4b503aff6abf6af5961 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:25:05 +0800 +Subject: [PATCH 5/9] anolis: csv/i386: add command to load vmcb to guest + memory + +The KVM_CSV_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 +Change-Id: I9dacc9e6b1b73c168b28a88b96c298bba4baa1ee +--- + 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 | 7 +++++-- + 5 files changed, 33 insertions(+), 2 deletions(-) + +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index 456aed121f..e5b45c384d 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1989,6 +1989,7 @@ enum csv_cmd_id { + + KVM_CSV_INIT = KVM_CSV_NR_MIN, + KVM_CSV_LAUNCH_ENCRYPT_DATA, ++ KVM_CSV_LAUNCH_ENCRYPT_VMCB, + }; + + struct kvm_csv_launch_encrypt_data { +diff --git a/target/i386/csv-sysemu-stub.c b/target/i386/csv-sysemu-stub.c +index 236a6909d2..a5ce986e3c 100644 +--- a/target/i386/csv-sysemu-stub.c ++++ b/target/i386/csv-sysemu-stub.c +@@ -24,3 +24,8 @@ int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + { + g_assert_not_reached(); + } ++ ++int csv_launch_encrypt_vmcb(void) ++{ ++ g_assert_not_reached(); ++} +diff --git a/target/i386/csv.c b/target/i386/csv.c +index 3b3dff5174..d166d3775e 100644 +--- a/target/i386/csv.c ++++ b/target/i386/csv.c +@@ -162,3 +162,24 @@ csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp) + + return ret; + } ++ ++int ++csv_launch_encrypt_vmcb(void) ++{ ++ int ret, fw_error; ++ ++ if (!csv_enabled()) { ++ error_report("%s: CSV is not enabled",__func__); ++ return -1; ++ } ++ ++ ret = csv_ioctl(KVM_CSV_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)); ++ goto err; ++ } ++ ++err: ++ return ret; ++} +diff --git a/target/i386/csv.h b/target/i386/csv.h +index 6f7b112d96..640eafd45b 100644 +--- a/target/i386/csv.h ++++ b/target/i386/csv.h +@@ -34,6 +34,7 @@ typedef struct CsvGuestState CsvGuestState; + + extern struct CsvGuestState csv_guest; + extern int csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops); ++extern int csv_launch_encrypt_vmcb(void); + + int csv_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 20507da004..efbe48fc30 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -810,8 +810,11 @@ 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 (csv_enabled()) ++ ret = csv_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.17.1 + diff --git a/0006-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch b/0006-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch new file mode 100644 index 0000000..82b079f --- /dev/null +++ b/0006-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch @@ -0,0 +1,41 @@ +From 2ab84ef10562be99e01e2407daaef8bdaf2a89e8 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 17:31:28 +0800 +Subject: [PATCH 6/9] anolis: cpu/i386: populate CPUID 0x8000_001F when CSV is + active + +On Hygon platform, bit 30 of EAX indicates whether +this feature is supported in hardware. + +When CSV is active, CPUID 0x8000_001F provides +information for it. + +Signed-off-by: Xin Jiang +Change-Id: I19322a73d0df091c0bbb4ca2a3cc5f4225cc2c9f +--- + target/i386/cpu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 0f71ff9fea..f8e7498971 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -28,6 +28,7 @@ + #include "sysemu/hvf.h" + #include "kvm/kvm_i386.h" + #include "sev.h" ++#include "csv.h" + #include "qapi/error.h" + #include "qapi/qapi-visit-machine.h" + #include "qapi/qmp/qerror.h" +@@ -5853,6 +5854,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 |= csv_enabled() ? 0x40000000 : 0; /* bit 30 for CSV */ + *ebx = sev_get_cbit_position(); + *ebx |= sev_get_reduced_phys_bits() << 6; + } +-- +2.17.1 + diff --git a/0007-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch b/0007-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch new file mode 100644 index 0000000..76da826 --- /dev/null +++ b/0007-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch @@ -0,0 +1,35 @@ +From 98df47b94deeee784e36f6084b2ac8c18b4d51f1 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:36:00 +0800 +Subject: [PATCH 7/9] anolis: csv/i386: CSV guest do not need + register/unregister guest secure memory + +CSV 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 +Change-Id: Idfe109b3925971ed71116bed2975133255ba11cc +--- + 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 efbe48fc30..6a672c4398 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -1013,7 +1013,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) + goto err; + } + +- ram_block_notifier_add(&sev_ram_notifier); ++ /* CSV guest needs no notifier to reg/unreg memory */ ++ if (!csv_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); + +-- +2.17.1 + diff --git a/0008-anolis-target-i386-csv-load-initial-image-to-private.patch b/0008-anolis-target-i386-csv-load-initial-image-to-private.patch new file mode 100644 index 0000000..da2e880 --- /dev/null +++ b/0008-anolis-target-i386-csv-load-initial-image-to-private.patch @@ -0,0 +1,51 @@ +From 2d31ae0925df36b3a17031bb43d267fb675b4733 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 14:29:40 +0800 +Subject: [PATCH 8/9] anolis: target/i386: csv: load initial image to private + memory + +The initial image of CSV guest should be loaded into private memory +before guest boot. + +Add APIs to implement the image load. + +Signed-off-by: Xin Jiang +Change-Id: I8bd63bd788098c97260c255db1a689751b40dc45 +--- + hw/i386/pc_sysfw.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index c8d9e71b88..d7d5e94da7 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,17 @@ void x86_firmware_configure(void *ptr, int size) + error_report("failed to locate and/or save reset vector"); + exit(1); + } ++ if (csv_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); ++ } ++ csv_load_data(mr->addr + offset, ptr, size, &error_fatal); ++ } else ++ sev_encrypt_flash(ptr, size, &error_fatal); + } + } +-- +2.17.1 + diff --git a/0009-anolis-vga-force-full-update-for-CSV-guest.patch b/0009-anolis-vga-force-full-update-for-CSV-guest.patch new file mode 100644 index 0000000..bb5b122 --- /dev/null +++ b/0009-anolis-vga-force-full-update-for-CSV-guest.patch @@ -0,0 +1,47 @@ +From 91a0ddd8f13f02a1250ba9e15db72be0f1fc7c9e Mon Sep 17 00:00:00 2001 +From: Xin Jiang +Date: Thu, 13 Jul 2023 09:35:10 +0800 +Subject: [PATCH 9/9] anolis: vga: force full update for CSV guest + +As CSV'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 +Change-Id: I093cebad952157aa38edf43fcf861926f7204dd6 +--- + hw/display/vga.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 0cb26a791b..1b5bd5f363 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -37,6 +37,9 @@ + #include "migration/vmstate.h" + #include "trace.h" + ++#include "target/i386/sev.h" ++#include "target/i386/csv.h" ++ + //#define DEBUG_VGA_MEM + //#define DEBUG_VGA_REG + +@@ -1781,6 +1784,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 (csv_enabled()) ++ full_update = 1; ++ + switch(graphic_mode) { + case GMODE_TEXT: + vga_draw_text(s, full_update); +-- +2.17.1 + diff --git a/qemu.spec b/qemu.spec index 282afcb..d01eeb3 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,4 +1,4 @@ -%define anolis_release 1 +%define anolis_release 2 %bcond_with check @@ -264,6 +264,14 @@ Source31: kvm-x86.conf Source36: README.tests Patch0001: 0001-sgx-stub-fix.patch +Patch0002: 0002-anolis-csv-i386-add-CSV-context.patch +Patch0003: 0003-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch +Patch0004: 0004-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch +Patch0005: 0005-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch +Patch0006: 0006-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch +Patch0007: 0007-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch +Patch0008: 0008-anolis-target-i386-csv-load-initial-image-to-private.patch +Patch0009: 0009-anolis-vga-force-full-update-for-CSV-guest.patch BuildRequires: meson >= %{meson_version} BuildRequires: zlib-devel @@ -1830,6 +1838,17 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog +* Tue Oct 17 2023 Xin Jiang - 15:7.2.6-2 +- Patch0002: 0002-anolis-csv-i386-add-CSV-context.patch +- Patch0003: 0003-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch +- Patch0004: 0004-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch +- Patch0005: 0005-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch +- Patch0006: 0006-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch +- Patch0007: 0007-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch +- Patch0008: 0008-anolis-target-i386-csv-load-initial-image-to-private.patch +- Patch0009: 0009-anolis-vga-force-full-update-for-CSV-guest.patch + (Support Hygon CSV3 feature) + * Mon Oct 16 2023 Funda Wang - 15:7.2.6-1 - New version 7.2.6 -- Gitee