From ab43ef19179fa5d2ee85aba91008c5984755dbd1 Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 14 Sep 2023 13:59:45 +0800 Subject: [PATCH] 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 --- 0001-anolis-csv-i386-add-CSV-context.patch | 205 ++++++++++++++++++ ...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 | 44 ++++ ...-vga-force-full-update-for-CSV-guest.patch | 47 ++++ qemu-kvm.spec | 23 +- 9 files changed, 869 insertions(+), 1 deletion(-) create mode 100644 0001-anolis-csv-i386-add-CSV-context.patch create mode 100644 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch create mode 100644 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch create mode 100644 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch create mode 100644 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch create mode 100644 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch create mode 100644 0007-anolis-target-i386-csv-load-initial-image-to-private.patch create mode 100644 0008-anolis-vga-force-full-update-for-CSV-guest.patch diff --git a/0001-anolis-csv-i386-add-CSV-context.patch b/0001-anolis-csv-i386-add-CSV-context.patch new file mode 100644 index 0000000..89e3d49 --- /dev/null +++ b/0001-anolis-csv-i386-add-CSV-context.patch @@ -0,0 +1,205 @@ +From fda324e163898d543e215cfec1aa3d26ba816426 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 14:57:28 +0800 +Subject: [PATCH 1/8] 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. + +Change-Id: I02b48c779dd25ddda4546fe3e28c1fe0c8c2e4c6 +Signed-off-by: Xin Jiang +--- + configs/devices/i386-softmmu/default.mak | 1 + + .../x86_64-softmmu/x86_64-rh-devices.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 + + 7 files changed, 110 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/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak +index 31ce08edab..ee1df7aa52 100644 +--- a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak ++++ b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak +@@ -102,3 +102,4 @@ CONFIG_TPM_TIS_ISA=y + CONFIG_TPM_EMULATOR=y + CONFIG_TPM_PASSTHROUGH=y + CONFIG_SGX=y ++CONFIG_CSV=y +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/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch b/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch new file mode 100644 index 0000000..a62796a --- /dev/null +++ b/0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch @@ -0,0 +1,204 @@ +From 3239acc6c33806fac55fc08d7e5a81ef9ce85e23 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 11:07:41 +0800 +Subject: [PATCH 2/8] 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: Ia4201dc90c250c23658e1cf5e19b528df9075330 +--- + 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 bcaf66cc4d..b15b8f5550 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1808,6 +1808,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 025ff7a6f8..023532f4ec 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: + * +@@ -952,6 +955,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, &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__); +@@ -1332,6 +1344,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 83e82aa42c..1c97bff99e 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/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch b/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch new file mode 100644 index 0000000..ba1f14a --- /dev/null +++ b/0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch @@ -0,0 +1,164 @@ +From 6dcfcd61e610da4e8d7dcfb6c3eefd7fc8a67c45 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 09:59:16 +0800 +Subject: [PATCH 3/8] 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: I6d4bea4969a0afa87fb8f2e52fb7ab02ec0db2ed +--- + 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 b15b8f5550..53f9202ffb 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1813,6 +1813,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/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch b/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch new file mode 100644 index 0000000..1ea643b --- /dev/null +++ b/0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch @@ -0,0 +1,107 @@ +From 630d76cc15bd98669162f785861cdd81f2ee8f01 Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:25:05 +0800 +Subject: [PATCH 4/8] 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: I821bc8ab726f1bd22df36c163196951504eaa8da +--- + 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 53f9202ffb..c6cd3a619a 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1814,6 +1814,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..7dc5c75366 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 023532f4ec..73a794ef74 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -770,8 +770,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/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch b/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch new file mode 100644 index 0000000..d82d10e --- /dev/null +++ b/0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch @@ -0,0 +1,41 @@ +From 501e16b4b4cf5a302363c1ae55fb4fb8e68beb8d Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Tue, 24 Aug 2021 17:31:28 +0800 +Subject: [PATCH 5/8] 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: Ifdd2a20f7cb4a079ba918928f012e5f64f7059e6 +--- + target/i386/cpu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index aa9e636800..970d9bf184 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -27,6 +27,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" +@@ -5769,6 +5770,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/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch b/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch new file mode 100644 index 0000000..af4851e --- /dev/null +++ b/0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch @@ -0,0 +1,35 @@ +From e25884e4e0ee839b591836ae33681ac9a52883ce Mon Sep 17 00:00:00 2001 +From: jiangxin +Date: Wed, 25 Aug 2021 12:36:00 +0800 +Subject: [PATCH 6/8] 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: I10d5b5ee8dbc3a1bf9ed1935c006c61a094f1e8d +--- + 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 73a794ef74..36669bbdf4 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -973,7 +973,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/0007-anolis-target-i386-csv-load-initial-image-to-private.patch b/0007-anolis-target-i386-csv-load-initial-image-to-private.patch new file mode 100644 index 0000000..a40bcfe --- /dev/null +++ b/0007-anolis-target-i386-csv-load-initial-image-to-private.patch @@ -0,0 +1,44 @@ +From 2df9c321195bd47485867e1d821913f1f3c21fc2 Mon Sep 17 00:00:00 2001 +From: Xin Jiang +Date: Fri, 25 Aug 2023 14:51:16 +0800 +Subject: [PATCH 7/8] 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: I708e7521bfe079216c0e0aea619a9c6bb1d7af04 +--- + hw/i386/pc_sysfw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index c8b17af953..84aad306dc 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -38,6 +38,7 @@ + #include "hw/block/flash.h" + #include "sysemu/kvm.h" + #include "sev.h" ++#include "csv.h" + + #define FLASH_SECTOR_SIZE 4096 + +@@ -208,7 +209,10 @@ static void pc_system_flash_map(PCMachineState *pcms, + exit(1); + } + +- sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); ++ if (csv_enabled()) ++ csv_load_data(flash_mem->addr, flash_ptr, flash_size, &error_fatal); ++ else ++ sev_encrypt_flash(flash_ptr, flash_size, &error_fatal); + } + } + } +-- +2.17.1 + diff --git a/0008-anolis-vga-force-full-update-for-CSV-guest.patch b/0008-anolis-vga-force-full-update-for-CSV-guest.patch new file mode 100644 index 0000000..40842ec --- /dev/null +++ b/0008-anolis-vga-force-full-update-for-CSV-guest.patch @@ -0,0 +1,47 @@ +From 42d8658a8868721a0c4fb08295a8957e9fdc96c6 Mon Sep 17 00:00:00 2001 +From: Xin Jiang +Date: Thu, 13 Jul 2023 09:35:10 +0800 +Subject: [PATCH 8/8] 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: I51ff00440483011fb9088a75005644beb378f8dd +--- + hw/display/vga.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 9d1f66af40..be4282a2f5 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -36,6 +36,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 + +@@ -1779,6 +1782,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-kvm.spec b/qemu-kvm.spec index 433dd59..072824c 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -1,4 +1,4 @@ -%define anolis_release .0.2 +%define anolis_release .0.3 %global SLOF_gittagdate 20191022 %global SLOF_gittagcommit 899d9883 @@ -697,6 +697,16 @@ Patch1028: Fixed-the-issue-where-qemu-specifies-the-boot-order.patch # https://github.com/qemu/qemu/commit/10be627d2b5ec2d6b3dce045144aa739eef678b4 Patch1029: 1029-anolis-qemu-fix-CVE-2023-3354.patch +# CSV3 feature on Hygon hardware +Patch1030: 0001-anolis-csv-i386-add-CSV-context.patch +Patch1031: 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch +Patch1032: 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch +Patch1033: 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch +Patch1034: 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch +Patch1035: 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch +Patch1036: 0007-anolis-target-i386-csv-load-initial-image-to-private.patch +Patch1037: 0008-anolis-vga-force-full-update-for-CSV-guest.patch + BuildRequires: wget BuildRequires: rpm-build BuildRequires: ninja-build @@ -1934,6 +1944,17 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %endif %changelog +* Thu Sep 14 2023 Xin Jiang - 6.2.0-33.0.3 +- 0001-anolis-csv-i386-add-CSV-context.patch +- 0002-anolis-csv-i386-add-command-to-initialize-CSV-contex.patch +- 0003-anolis-csv-i386-add-command-to-load-data-to-guest-me.patch +- 0004-anolis-csv-i386-add-command-to-load-vmcb-to-guest-me.patch +- 0005-anolis-cpu-i386-populate-CPUID-0x8000_001F-when-CSV-.patch +- 0006-anolis-csv-i386-CSV-guest-do-not-need-register-unreg.patch +- 0007-anolis-target-i386-csv-load-initial-image-to-private.patch +- 0008-anolis-vga-force-full-update-for-CSV-guest.patch + (Hygon CSV3 feature) + * Thu Aug 24 2023 lixianglai - 6.2.0-33.0.2 - loongarch: Fixed the issue where qemu specifies the boot order - Fix CVE-2023-3354 (Liwei Ge ) -- Gitee