1 Star 0 Fork 38

xisme/qemu-kvm_src-anolis

forked from src-anolis-os/qemu-kvm 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
1069-anolis-csv-i386-add-support-to-migrate-the-outgoing-.patch 14.21 KB
一键复制 编辑 原始数据 按行查看 历史
jiangxin00 提交于 2023-12-08 17:29 +08:00 . Support Hygon CSV3 live migration
From 967c7ad199c55223cc03d0217c6f256d3d418be2 Mon Sep 17 00:00:00 2001
From: jiangxin <jiangxin@hygon.cn>
Date: Fri, 17 Jun 2022 09:37:56 +0800
Subject: [PATCH 1069/1072] anolis: csv/i386: add support to migrate the
outgoing page
The csv_send_encrypt_data() provides the method to encrypt the
guest's private pages during migration. The routine is similar to
CSV2's. Usually, it starts with a SEND_START command to create the
migration context. Then SEND_ENCRYPT_DATA command is performed to
encrypt guest pages. After migration is completed, a SEND_FINISH
command is performed to the firmware.
Change-Id: I6781119890036636d8f5c0a19c6647fa8a33a37d
---
migration/ram.c | 83 ++++++++++++++++++
target/i386/csv.c | 185 +++++++++++++++++++++++++++++++++++++++
target/i386/csv.h | 22 +++++
target/i386/sev.c | 13 ++-
target/i386/sev.h | 1 +
target/i386/trace-events | 1 +
6 files changed, 304 insertions(+), 1 deletion(-)
diff --git a/migration/ram.c b/migration/ram.c
index 1dcd5c8553..c962496684 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -2452,6 +2452,86 @@ ram_save_encrypted_pages_in_batch(RAMState *rs, PageSearchStatus *pss, bool last
}
#endif
+/**
+ * ram_save_csv_pages - send the given csv VM pages to the stream
+ */
+static int ram_save_csv_pages(RAMState *rs, PageSearchStatus *pss,
+ bool last_stage)
+{
+ int ret;
+ int tmppages = 0, pages = 0;
+ RAMBlock *block = pss->block;
+ ram_addr_t offset = 0;
+ hwaddr paddr = RAM_ADDR_INVALID;
+ uint32_t host_len = 0;
+ uint8_t *p;
+ uint64_t bytes_xmit;
+ MachineState *ms = MACHINE(qdev_get_machine());
+ ConfidentialGuestSupportClass *cgs_class =
+ (ConfidentialGuestSupportClass *) object_get_class(OBJECT(ms->cgs));
+ struct ConfidentialGuestMemoryEncryptionOps *ops =
+ cgs_class->memory_encryption_ops;
+
+ if (!csv_enabled())
+ return 0;
+
+ do {
+ /* Check the pages is dirty and if it is send it */
+ if (!migration_bitmap_clear_dirty(rs, block, pss->page)) {
+ pss->page++;
+ continue;
+ }
+
+ ret = kvm_physical_memory_addr_from_host(kvm_state,
+ block->host + (pss->page << TARGET_PAGE_BITS), &paddr);
+ /* Process ROM or MMIO */
+ if (paddr == RAM_ADDR_INVALID || memory_region_is_rom(block->mr))
+ tmppages = ram_save_target_page(rs, pss, last_stage);
+ else {
+ /* Caculate the offset and host virtual address of the page */
+ offset = pss->page << TARGET_PAGE_BITS;
+ p = block->host + offset;
+
+ if (ops->queue_outgoing_page(p, TARGET_PAGE_SIZE, offset))
+ return -1;
+
+ tmppages = 1;
+ host_len += TARGET_PAGE_SIZE;
+ ram_counters.normal++;
+ }
+
+ if (tmppages < 0) {
+ return tmppages;
+ }
+
+ pages += tmppages;
+
+ pss->page++;
+ } while (offset_in_ramblock(block, pss->page << TARGET_PAGE_BITS) &&
+ host_len < CSV3_OUTGOING_PAGE_WINDOW_SIZE);
+
+ /* Check if there are any queued pages */
+ if (host_len != 0) {
+ /* Always set offset as 0 for csv. */
+ ram_counters.transferred +=
+ save_page_header(rs, rs->f, block, 0 | RAM_SAVE_FLAG_ENCRYPTED_DATA);
+
+ qemu_put_be32(rs->f, RAM_SAVE_ENCRYPTED_PAGE);
+ ram_counters.transferred += 4;
+ /* Process the queued pages in batch */
+ ret = ops->save_queued_outgoing_pages(rs->f, &bytes_xmit);
+ if (ret) {
+ return -1;
+ }
+ ram_counters.transferred += bytes_xmit;
+ }
+
+ /* The offset we leave with is the last one we looked at */
+ pss->page--;
+
+ return pages;
+}
+
/**
* ram_save_host_page: save a whole host page
*
@@ -2486,6 +2566,9 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
return 0;
}
+ if (csv_enabled())
+ return ram_save_csv_pages(rs, pss, last_stage);
+
#ifdef CONFIG_HYGON_CSV_MIG_ACCEL
/*
* If command_batch function is enabled and memory encryption is enabled
diff --git a/target/i386/csv.c b/target/i386/csv.c
index 6d05382fb2..c5a2bc9924 100644
--- a/target/i386/csv.c
+++ b/target/i386/csv.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
+#include <linux/psp-sev.h>
#include <linux/kvm.h>
#include "qapi/error.h"
@@ -20,12 +21,30 @@
#include <numaif.h>
#endif
+#include "migration/blocker.h"
+#include "migration/qemu-file.h"
+#include "migration/misc.h"
+#include "monitor/monitor.h"
+#include "sysemu/kvm.h"
+
#include "trace.h"
#include "cpu.h"
#include "sev.h"
#include "csv.h"
#include "exec/address-spaces.h"
+struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops = {
+ .save_setup = sev_save_setup,
+ .save_outgoing_page = NULL,
+ .is_gfn_in_unshared_region = NULL,
+ .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list,
+ .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list,
+ .queue_outgoing_page = csv3_queue_outgoing_page,
+ .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages,
+};
+
+#define CSV_OUTGOING_PAGE_NUM (CSV3_OUTGOING_PAGE_WINDOW_SIZE/TARGET_PAGE_SIZE)
+
CsvGuestState csv_guest = { 0 };
#define GUEST_POLICY_CSV_BIT (1 << 6)
@@ -66,6 +85,7 @@ csv_init(uint32_t policy, int fd, void *state, struct sev_ops *ops)
csv_guest.fw_error_to_str = ops->fw_error_to_str;
QTAILQ_INIT(&csv_guest.dma_map_regions_list);
qemu_mutex_init(&csv_guest.dma_map_regions_list_mutex);
+ csv_guest.sev_send_start = ops->sev_send_start;
}
return 0;
}
@@ -297,3 +317,168 @@ end:
qemu_mutex_unlock(&s->dma_map_regions_list_mutex);
return;
}
+
+static inline hwaddr csv_hva_to_gfn(uint8_t *ptr)
+{
+ ram_addr_t offset = RAM_ADDR_INVALID;
+
+ kvm_physical_memory_addr_from_host(kvm_state, ptr, &offset);
+
+ return offset >> TARGET_PAGE_BITS;
+}
+
+static int
+csv_send_start(QEMUFile *f, uint64_t *bytes_sent)
+{
+ if (csv_guest.sev_send_start)
+ return csv_guest.sev_send_start(f, bytes_sent);
+ else
+ return -1;
+}
+
+static int
+csv_send_get_packet_len(int *fw_err)
+{
+ int ret;
+ struct kvm_csv_send_encrypt_data update = {0};
+
+ update.hdr_len = 0;
+ update.trans_len = 0;
+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, fw_err);
+ if (*fw_err != SEV_RET_INVALID_LEN) {
+ error_report("%s: failed to get session length ret=%d fw_error=%d '%s'",
+ __func__, ret, *fw_err, fw_error_to_str(*fw_err));
+ ret = 0;
+ goto err;
+ }
+
+ if (update.hdr_len <= INT_MAX)
+ ret = update.hdr_len;
+ else
+ ret = 0;
+
+err:
+ return ret;
+}
+
+static int
+csv_send_encrypt_data(CsvGuestState *s, QEMUFile *f, uint8_t *ptr, uint32_t size,
+ uint64_t *bytes_sent)
+{
+ int ret, fw_error = 0;
+ guchar *trans;
+ uint32_t guest_addr_entry_num;
+ uint32_t i;
+ struct kvm_csv_send_encrypt_data update = { };
+
+ /*
+ * If this is first call then query the packet header bytes and allocate
+ * the packet buffer.
+ */
+ if (!s->send_packet_hdr) {
+ s->send_packet_hdr_len = csv_send_get_packet_len(&fw_error);
+ if (s->send_packet_hdr_len < 1) {
+ error_report("%s: SEND_UPDATE fw_error=%d '%s'",
+ __func__, fw_error, fw_error_to_str(fw_error));
+ return 1;
+ }
+
+ s->send_packet_hdr = g_new(gchar, s->send_packet_hdr_len);
+ }
+
+ if (!s->guest_addr_len || !s->guest_addr_data) {
+ error_report("%s: invalid host address or size", __func__);
+ return 1;
+ } else {
+ guest_addr_entry_num = s->guest_addr_len / sizeof(struct guest_addr_entry);
+ }
+
+ /* allocate transport buffer */
+ trans = g_new(guchar, guest_addr_entry_num * TARGET_PAGE_SIZE);
+
+ update.hdr_uaddr = (uintptr_t)s->send_packet_hdr;
+ update.hdr_len = s->send_packet_hdr_len;
+ update.guest_addr_data = (uintptr_t)s->guest_addr_data;
+ update.guest_addr_len = s->guest_addr_len;
+ update.trans_uaddr = (uintptr_t)trans;
+ update.trans_len = guest_addr_entry_num * TARGET_PAGE_SIZE;
+
+ trace_kvm_csv_send_encrypt_data(trans, update.trans_len);
+
+ ret = csv_ioctl(KVM_CSV_SEND_ENCRYPT_DATA, &update, &fw_error);
+ if (ret) {
+ error_report("%s: SEND_ENCRYPT_DATA ret=%d fw_error=%d '%s'",
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
+ goto err;
+ }
+
+ for (i = 0; i < guest_addr_entry_num; i++) {
+ if (s->guest_addr_data[i].share)
+ memcpy(trans + i * TARGET_PAGE_SIZE, (guchar *)s->guest_hva_data[i].hva,
+ TARGET_PAGE_SIZE);
+ }
+
+ qemu_put_be32(f, update.hdr_len);
+ qemu_put_buffer(f, (uint8_t *)update.hdr_uaddr, update.hdr_len);
+ *bytes_sent = 4 + update.hdr_len;
+
+ qemu_put_be32(f, update.guest_addr_len);
+ qemu_put_buffer(f, (uint8_t *)update.guest_addr_data, update.guest_addr_len);
+ *bytes_sent = 4 + update.guest_addr_len;
+
+ qemu_put_be32(f, update.trans_len);
+ qemu_put_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len);
+ *bytes_sent += (4 + update.trans_len);
+
+err:
+ s->guest_addr_len = 0;
+ g_free(trans);
+ return ret;
+}
+
+int
+csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr)
+{
+ CsvGuestState *s = &csv_guest;
+ uint32_t i = 0;
+
+ (void) addr;
+
+ if (!s->guest_addr_data) {
+ s->guest_hva_data = g_new0(struct guest_hva_entry, CSV_OUTGOING_PAGE_NUM);
+ s->guest_addr_data = g_new0(struct guest_addr_entry, CSV_OUTGOING_PAGE_NUM);
+ s->guest_addr_len = 0;
+ }
+
+ if (s->guest_addr_len >= sizeof(struct guest_addr_entry) * CSV_OUTGOING_PAGE_NUM) {
+ error_report("Failed to queue outgoing page");
+ return 1;
+ }
+
+ i = s->guest_addr_len / sizeof(struct guest_addr_entry);
+ s->guest_hva_data[i].hva = (uintptr_t)ptr;
+ s->guest_addr_data[i].share = 0;
+ s->guest_addr_data[i].reserved = 0;
+ s->guest_addr_data[i].gfn = csv_hva_to_gfn(ptr);
+ s->guest_addr_len += sizeof(struct guest_addr_entry);
+
+ return 0;
+}
+
+int
+csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent)
+{
+ CsvGuestState *s = &csv_guest;
+
+ /*
+ * 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) &&
+ csv_send_start(f, bytes_sent)) {
+ error_report("Failed to create outgoing context");
+ return 1;
+ }
+
+ return csv_send_encrypt_data(s, f, NULL, 0, bytes_sent);
+}
diff --git a/target/i386/csv.h b/target/i386/csv.h
index 6412c0c70b..273d69d12c 100644
--- a/target/i386/csv.h
+++ b/target/i386/csv.h
@@ -62,6 +62,18 @@ struct dma_map_region {
QTAILQ_ENTRY(dma_map_region) list;
};
+#define CSV3_OUTGOING_PAGE_WINDOW_SIZE (512 * TARGET_PAGE_SIZE)
+
+struct guest_addr_entry {
+ uint64_t share: 1;
+ uint64_t reserved: 11;
+ uint64_t gfn: 52;
+};
+
+struct guest_hva_entry {
+ uint64_t hva;
+};
+
struct CsvGuestState {
uint32_t policy;
int sev_fd;
@@ -70,6 +82,13 @@ struct CsvGuestState {
const char *(*fw_error_to_str)(int code);
QTAILQ_HEAD(, dma_map_region) dma_map_regions_list;
QemuMutex dma_map_regions_list_mutex;
+ gchar *send_packet_hdr;
+ size_t send_packet_hdr_len;
+ struct guest_hva_entry *guest_hva_data;
+ struct guest_addr_entry *guest_addr_data;
+ size_t guest_addr_len;
+
+ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent);
};
typedef struct CsvGuestState CsvGuestState;
@@ -77,10 +96,13 @@ 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);
+extern struct ConfidentialGuestMemoryEncryptionOps csv_memory_encryption_ops;
int csv_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp);
int csv_shared_region_dma_map(uint64_t start, uint64_t end);
void csv_shared_region_dma_unmap(uint64_t start, uint64_t end);
+int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr);
+int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent);
#endif
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 26b6e84d3f..31af1ecdf3 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1173,7 +1173,10 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
qemu_add_vm_change_state_handler(sev_vm_state_change, sev);
add_migration_state_change_notifier(&sev_migration_state_notify);
- cgs_class->memory_encryption_ops = &sev_memory_encryption_ops;
+ if (csv_enabled())
+ cgs_class->memory_encryption_ops = &csv_memory_encryption_ops;
+ else
+ cgs_class->memory_encryption_ops = &sev_memory_encryption_ops;
QTAILQ_INIT(&sev->shared_regions_list);
/* Determine whether support MSR_AMD64_SEV_ES_GHCB */
@@ -2552,9 +2555,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
return ret;
}
+static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent)
+{
+ SevGuestState *s = sev_guest;
+
+ return sev_send_start(s, f, bytes_sent);
+}
+
struct sev_ops sev_ops = {
.sev_ioctl = sev_ioctl,
.fw_error_to_str = fw_error_to_str,
+ .sev_send_start = _sev_send_start,
};
static void
diff --git a/target/i386/sev.h b/target/i386/sev.h
index 8b38567c3d..6d1a918413 100644
--- a/target/i386/sev.h
+++ b/target/i386/sev.h
@@ -89,6 +89,7 @@ int csv_load_incoming_cpu_state(QEMUFile *f);
struct sev_ops {
int (*sev_ioctl)(int fd, int cmd, void *data, int *error);
const char *(*fw_error_to_str)(int code);
+ int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent);
};
#endif
diff --git a/target/i386/trace-events b/target/i386/trace-events
index 60a4609c0f..8db3e36385 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -22,3 +22,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int
# csv.c
kvm_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"
--
2.17.1
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/xisme/qemu-kvm_src-anolis.git
git@gitee.com:xisme/qemu-kvm_src-anolis.git
xisme
qemu-kvm_src-anolis
qemu-kvm_src-anolis
vtkm_support_csv

搜索帮助

371d5123 14472233 46e8bd33 14472233