From 1a651b41c3a4b0e050334b2b94f6115220533bc8 Mon Sep 17 00:00:00 2001 From: panhengchang Date: Sun, 1 Feb 2026 21:00:01 +0800 Subject: [PATCH 1/2] support host mig agent --- arch/arm64/include/asm/kvm_tmi.h | 7 +- arch/arm64/include/asm/kvm_tmm.h | 67 ++++- arch/arm64/kernel/virtcca_cvm_guest.c | 21 +- arch/arm64/kvm/tmi.c | 14 + arch/arm64/kvm/virtcca_cvm.c | 358 +++++++++++++++++++++++++- arch/arm64/kvm/virtcca_mig.c | 14 +- arch/arm64/kvm/virtcca_mig.h | 6 - 7 files changed, 454 insertions(+), 33 deletions(-) diff --git a/arch/arm64/include/asm/kvm_tmi.h b/arch/arm64/include/asm/kvm_tmi.h index 7abf21f86301..c09fd62281b3 100644 --- a/arch/arm64/include/asm/kvm_tmi.h +++ b/arch/arm64/include/asm/kvm_tmi.h @@ -348,7 +348,9 @@ typedef enum tmi_tmm_mig_data_fid_e{ typedef enum tmi_tmm_mig_attestation_fid_e{ TMI_TMM_MIG_BIND_CLEAN, - TMI_TMM_MIG_BIND_PEEK + TMI_TMM_MIG_BIND_PEEK, + TMI_TMM_MIG_INTEGRITY_CHECKSUM_INIT, + TMI_TMM_MIG_INTEGRITY_CHECKSUM_LOOP } tmi_tmm_mig_attestation_fid_t; #define TMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16) @@ -534,6 +536,9 @@ u64 tmi_update_cvm_info(uint64_t rd, uint64_t cvm_update_info_addr); void virtcca_set_tmm_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot); struct arm_smccc_res tmi_export_pause(uint64_t rd); +u64 tmi_mig_integrity_checksum_loop(uint64_t rd, uint64_t thread_id); +u64 tmi_mig_integrity_checksum_init(unsigned long dst_rd, unsigned long queue_pa); + /* enable the migcvm ctl */ int kvm_migcvm_ioctl(struct kvm *kvm, unsigned long arg); struct arm_smccc_res tmi_mem_region_protect(u64 rd, u64 start, u64 end); diff --git a/arch/arm64/include/asm/kvm_tmm.h b/arch/arm64/include/asm/kvm_tmm.h index 9abcefd31114..fac3ebabd40a 100644 --- a/arch/arm64/include/asm/kvm_tmm.h +++ b/arch/arm64/include/asm/kvm_tmm.h @@ -46,14 +46,20 @@ struct tmi_cvm_params { u32 migration_migvm_cap; /* the type of CVM (support migration) */ }; +#define CVM_NAME_LEN 64 +#define CVM_MIG_IP_LEN 16 +#define CVM_MIG_SYNC_NUM_MAX 1 + /* the guest cvm and migcvm both use this structure */ #define KVM_CVM_MIGVM_VERSION 0 struct mig_cvm { /* used by guest cvm */ - uint8_t version; /* kvm version of migcvm*/ uint64_t migvm_cid; /* vsock cid of migvm */ + uint8_t version; /* kvm version of migcvm*/ uint16_t dst_port; /* port of destination cvm */ - char dst_ip[16]; /* ip of destination cvm */ + char dst_ip[CVM_MIG_IP_LEN]; /* ip of destination cvm */ + uint8_t is_migcvm; /* indicates whether the device is a migcvm. */ + char reserved[4]; }; struct cvm { @@ -126,6 +132,53 @@ struct virtcca_cvm_tec { #define CVM_RW_32_BIT 0x20 #define CVM_RW_64_BIT 0x40 +struct virtcca_tmi_cmd { + __u32 id; + __u32 flags; + __u64 data; + __u64 ret_val; +}; + +/* Mark verifier status to indicate mig agent to update migration info */ +enum virtcca_mig_verifier_status { + VIRTCCA_MIG_NEW = 0, + VIRTCCA_MIG_UPDATED, + VIRTCCA_MIG_NOTIFIED, + + VIRTCCA_MIG_STATUS_MAX, +}; + +/* info to agent */ +struct virtcca_mig_agent_notify_info { + char name[CVM_NAME_LEN]; + char dst_ip[CVM_MIG_IP_LEN]; + uint64_t rd; + uint16_t dst_port; + uint16_t cvm_vmid; + uint16_t is_src; +}; + +struct virtcca_mig_verifier { + char name[CVM_NAME_LEN]; + char dst_ip[CVM_MIG_IP_LEN]; + uint64_t rd; + uint16_t dst_port; + uint16_t cvm_vmid; + uint16_t is_src; + uint16_t status; + struct list_head list; +}; + +/* info from qemu */ +struct virtcca_mig_dst_host_info { + char name[CVM_NAME_LEN]; + char dst_ip[CVM_MIG_IP_LEN]; + uint16_t dst_port; + uint8_t is_src; + uint8_t migcvm_enabled; + uint8_t version; +}; + struct cvm_ttt_addr { struct list_head list; u64 addr; @@ -155,6 +208,13 @@ int kvm_cvm_map_ipa_mmio(struct kvm *kvm, phys_addr_t ipa_base, bool is_in_virtcca_ram_range(struct kvm *kvm, uint64_t iova); bool is_virtcca_iova_need_vfio_dma(struct kvm *kvm, uint64_t iova); +int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_info *dst_host_info); +int virtcca_mig_verify_delete(struct kvm *kvm); + +int virtcca_mig_get_notify(struct virtcca_tmi_cmd *cmd); +int virtcca_get_dstvm_rd(struct virtcca_tmi_cmd *cmd); +int virtcca_migvm_mem_checksum_loop(struct virtcca_tmi_cmd *cmd); + #define CVM_TTT_BLOCK_LEVEL 2 #define CVM_TTT_MAX_LEVEL 3 @@ -185,8 +245,7 @@ static inline unsigned long cvm_ttt_level_mapsize(int level) enum kvm_cvm_cmd_id { /* virtcca MIG migcvm commands. */ KVM_CVM_MIGCVM_SET_CID = 0, - KVM_CVM_MIGCVM_ATTEST, - KVM_CVM_MIGCVM_ATTEST_DST, + KVM_CVM_MIG_NOTIFY, KVM_CVM_GET_BIND_STATUS, KVM_CVM_MIG_EXPORT_ABORT, /* virtcca MIG stream commands. */ diff --git a/arch/arm64/kernel/virtcca_cvm_guest.c b/arch/arm64/kernel/virtcca_cvm_guest.c index 324278ecaf99..c62bbdacd4e7 100644 --- a/arch/arm64/kernel/virtcca_cvm_guest.c +++ b/arch/arm64/kernel/virtcca_cvm_guest.c @@ -16,6 +16,7 @@ #include #include #include +#include #define CVM_PTE_NS_BIT 5 #define CVM_PTE_NS_MASK (1 << CVM_PTE_NS_BIT) @@ -264,6 +265,7 @@ static struct driver_data *driver_data_ptr = NULL; static struct mig_queue_device *migvm_queue_dev_create(unsigned long rd) { + uint64_t ret = 0; struct mig_queue_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; @@ -288,12 +290,19 @@ static struct mig_queue_device *migvm_queue_dev_create(unsigned long rd) dev->queue_addr.recv_buf_ipa = page_to_phys(dev->recv_page); memset(page_address(dev->recv_page), 0, QUEUE_SIZE); - if (tsi_mig_integrity_checksum_init(rd, virt_to_phys((void *)&dev->queue_addr))) { - __free_page(dev->send_page); - __free_page(dev->recv_page); - kfree(dev); - return NULL; - } + if (is_virtcca_cvm_world()) { + ret = tsi_mig_integrity_checksum_init(rd, virt_to_phys((void *)&dev->queue_addr)); + } else { + ret = tmi_mig_integrity_checksum_init(rd, virt_to_phys((void *)&dev->queue_addr)); + } + + if (ret) { + pr_err("Failed to init integrity checksum, ret = 0x%lx", ret); + __free_page(dev->send_page); + __free_page(dev->recv_page); + kfree(dev); + return NULL; + } dev->rd = rd; return dev; diff --git a/arch/arm64/kvm/tmi.c b/arch/arm64/kvm/tmi.c index efd71ba376de..67413e4d3fef 100644 --- a/arch/arm64/kvm/tmi.c +++ b/arch/arm64/kvm/tmi.c @@ -567,4 +567,18 @@ struct arm_smccc_res tmi_bind_peek(uint64_t rd) struct arm_smccc_res res; arm_smccc_1_1_smc(TMI_TMM_MIG_ATTESTATION, TMI_TMM_MIG_BIND_PEEK, rd, &res); return res; +} + +u64 tmi_mig_integrity_checksum_init(unsigned long dst_rd, unsigned long queue_pa) +{ + struct arm_smccc_res res; + arm_smccc_1_1_smc(TMI_TMM_MIG_ATTESTATION, TMI_TMM_MIG_INTEGRITY_CHECKSUM_INIT, dst_rd, queue_pa, &res); + return res.a1; +} + +u64 tmi_mig_integrity_checksum_loop(uint64_t rd, uint64_t thread_id) +{ + struct arm_smccc_res res; + arm_smccc_1_1_smc(TMI_TMM_MIG_ATTESTATION, TMI_TMM_MIG_INTEGRITY_CHECKSUM_LOOP, rd, thread_id, &res); + return res.a1; } \ No newline at end of file diff --git a/arch/arm64/kvm/virtcca_cvm.c b/arch/arm64/kvm/virtcca_cvm.c index 5bc7758537e6..b73ea61b44dc 100644 --- a/arch/arm64/kvm/virtcca_cvm.c +++ b/arch/arm64/kvm/virtcca_cvm.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include "virtcca_mig.h" @@ -25,11 +27,14 @@ static DEFINE_SPINLOCK(cvm_vmid_lock); static unsigned long *cvm_vmid_bitmap; DECLARE_STATIC_KEY_FALSE(virtcca_cvm_is_enable); static bool virtcca_vtimer_adjust; +static int virtcca_migcvm_enabled = 0; #define SIMD_PAGE_SIZE 0x3000 #define UEFI_MAX_SIZE 0x8000000 #define UEFI_DTB_START 0x40000000 #define DTB_MAX_SIZE 0x200000 +static int virtcca_mig_notify(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd); + bool is_virtcca_available(void) { return static_key_enabled(&virtcca_cvm_is_enable); @@ -201,12 +206,22 @@ int kvm_arm_create_cvm(struct kvm *kvm) pr_warn("warning : Migration Capability is not set\n"); } - if(cvm->params->migration_migvm_cap) { + if (cvm->params->migration_migvm_cap) { + if (virtcca_migcvm_enabled) { + pr_err("Mig-CVM is already exist\n"); + ret = -EFAULT; + goto out; + } + + virtcca_migcvm_enabled = 1; + cvm->mig_cvm_info = kzalloc(sizeof(struct mig_cvm), GFP_KERNEL_ACCOUNT); if (!cvm->mig_cvm_info) { - return -ENOMEM; + ret = -ENOMEM; + goto out; } - pr_warn("Info : This CVM is Mig-CVM\n"); + pr_info("Info : This CVM is Mig-CVM\n"); + cvm->mig_cvm_info->is_migcvm = 1; } WRITE_ONCE(cvm->state, CVM_STATE_NEW); @@ -246,6 +261,10 @@ void kvm_destroy_cvm(struct kvm *kvm) } if (cvm->mig_cvm_info) { + if (cvm->mig_cvm_info->is_migcvm) { + virtcca_migcvm_enabled = 0; + pr_info("Mig-CVM destroyed!\n"); + } kfree(cvm->mig_cvm_info); } @@ -259,8 +278,6 @@ void kvm_destroy_cvm(struct kvm *kvm) #endif cvm_vmid = cvm->cvm_vmid; - kfree(cvm->params); - cvm->params = NULL; if (virtcca_cvm_state(kvm) == CVM_STATE_NONE) return; @@ -287,6 +304,7 @@ void kvm_destroy_cvm(struct kvm *kvm) if (!tmi_cvm_destroy(cvm->rd)) kvm_info("KVM has destroyed cVM: %d\n", cvm->cvm_vmid); + virtcca_mig_verify_delete(kvm); cvm_vmid_release(cvm_vmid); cvm->is_mapped = false; kfree(cvm); @@ -1073,11 +1091,8 @@ int kvm_migcvm_ioctl(struct kvm *kvm, unsigned long arg) case KVM_CVM_MIGCVM_SET_CID: ret = virtcca_save_migvm_cid(kvm, &cvm_cmd); break; - case KVM_CVM_MIGCVM_ATTEST: - ret = virtcca_migvm_agent_ratstls(kvm, &cvm_cmd); - break; - case KVM_CVM_MIGCVM_ATTEST_DST: - ret = virtcca_migvm_agent_ratstls_dst(kvm, &cvm_cmd); + case KVM_CVM_MIG_NOTIFY: + ret = virtcca_mig_notify(kvm, &cvm_cmd); break; case KVM_CVM_GET_BIND_STATUS: ret = virtcca_get_bind_info(kvm, &cvm_cmd); @@ -1579,4 +1594,327 @@ int virtcca_cvm_arm_smmu_domain_set_kvm(void *group) (void *)NULL, cvm_arm_smmu_domain_set_kvm); return ret; } + +static LIST_HEAD(virtcca_mig_verifier_list); +static DEFINE_MUTEX(verifier_list_mutex); + +int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_info *dst_host_info) +{ + struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; + struct virtcca_mig_verifier *verifier = NULL; + int ret = 0; + + mutex_lock(&verifier_list_mutex); + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (verifier->cvm_vmid == cvm->cvm_vmid) { + if (dst_host_info->is_src) { + strncpy(verifier->dst_ip, dst_host_info->dst_ip, sizeof(verifier->dst_ip) - 1); + verifier->dst_ip[sizeof(verifier->dst_ip) - 1] = '\0'; + verifier->dst_port = dst_host_info->dst_port; + } + + verifier->status = VIRTCCA_MIG_UPDATED; + verifier->is_src = dst_host_info->is_src; + pr_warn("CVM is already registered to verifer list, update it\n"); + mutex_unlock(&verifier_list_mutex); + return 0; + } + } + + verifier = kmalloc(sizeof(struct virtcca_mig_verifier), GFP_KERNEL); + if (!verifier) { + pr_err("virtcca_mig_verify_register memory allocation failed!\n"); + mutex_unlock(&verifier_list_mutex); + return -ENOMEM; + } + + strncpy(verifier->name, dst_host_info->name, sizeof(verifier->name) - 1); + verifier->name[sizeof(verifier->name) - 1] = '\0'; + strncpy(verifier->dst_ip, dst_host_info->dst_ip, sizeof(verifier->dst_ip) - 1); + verifier->dst_ip[sizeof(verifier->dst_ip) - 1] = '\0'; + verifier->dst_port = dst_host_info->dst_port; + verifier->is_src = dst_host_info->is_src; + verifier->rd = cvm->rd; + verifier->cvm_vmid = cvm->cvm_vmid; + verifier->status = VIRTCCA_MIG_NEW; + + INIT_LIST_HEAD(&verifier->list); + + list_add_tail(&verifier->list, &virtcca_mig_verifier_list); + mutex_unlock(&verifier_list_mutex); + + return ret; +} + +int virtcca_mig_verify_delete(struct kvm *kvm) +{ + struct virtcca_mig_verifier *verifier, *tmp; + struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; + + mutex_lock(&verifier_list_mutex); + list_for_each_entry_safe(verifier, tmp, &virtcca_mig_verifier_list, list) { + if (verifier->cvm_vmid == cvm->cvm_vmid) { + list_del(&verifier->list); + mutex_unlock(&verifier_list_mutex); + kfree(verifier); + pr_info("Removed CVM ID %d from verifer list\n", cvm->cvm_vmid); + return 0; + } + } + mutex_unlock(&verifier_list_mutex); + pr_warn("VM with ID %d not found in verifer list\n", cvm->cvm_vmid); + return 0; +} + +static int virtcca_mig_notify(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd) +{ + struct virtcca_mig_dst_host_info mig_host_info; + int ret = 0; + + if (copy_from_user(&mig_host_info, (void __user *)cmd->data, sizeof(struct virtcca_mig_dst_host_info))) { + return -EFAULT; + } + + if (virtcca_migcvm_enabled) { + mig_host_info.migcvm_enabled = 1; + if (mig_host_info.is_src) + ret = virtcca_migvm_agent_ratstls(kvm, cmd); + else + ret = virtcca_migvm_agent_ratstls_dst(kvm, cmd); + } else { + mig_host_info.migcvm_enabled = 0; + ret = virtcca_mig_verify_register(kvm, &mig_host_info); + } + + if (ret) { + pr_err("virtcca_mig_notify failed! ret = %d", ret); + return ret; + } + + if (copy_to_user((void __user *)cmd->data, &mig_host_info, sizeof(struct virtcca_mig_dst_host_info))) { + pr_err("copy_to_user failed!"); + return -EFAULT; + } + + return ret; +} + +int virtcca_mig_flat_list_to_agent(void __user *user_data) +{ + struct virtcca_mig_verifier *verifier; + struct virtcca_mig_agent_notify_info *agent_data = NULL; + int notify_count = 0; + int i = 0; + int ret = 0; + + mutex_lock(&verifier_list_mutex); + + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (verifier->status != VIRTCCA_MIG_NOTIFIED && verifier->is_src) + notify_count++; + } + + if (notify_count == 0) { + mutex_unlock(&verifier_list_mutex); + return 0; + } + + notify_count = min(notify_count, CVM_MIG_SYNC_NUM_MAX); + agent_data = kmalloc(sizeof(struct virtcca_mig_agent_notify_info) * notify_count, GFP_KERNEL); + if (!agent_data) { + mutex_unlock(&verifier_list_mutex); + return -ENOMEM; + } + + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (verifier->status != VIRTCCA_MIG_NOTIFIED && verifier->is_src) { + if (i >= notify_count) + break; + + strncpy(agent_data[i].name, verifier->name, sizeof(agent_data[i].name) - 1); + agent_data[i].name[sizeof(agent_data[i].name) - 1] = '\0'; + strncpy(agent_data[i].dst_ip, verifier->dst_ip, sizeof(agent_data[i].dst_ip) - 1); + agent_data[i].dst_ip[sizeof(agent_data[i].dst_ip) - 1] = '\0'; + agent_data[i].rd = verifier->rd; + agent_data[i].dst_port = verifier->dst_port; + agent_data[i].cvm_vmid = verifier->cvm_vmid; + agent_data[i].is_src = verifier->is_src; + + verifier->status = VIRTCCA_MIG_NOTIFIED; + i++; + } + } + mutex_unlock(&verifier_list_mutex); + + if (i > 0) { + if (copy_to_user(user_data, agent_data, sizeof(struct virtcca_mig_agent_notify_info) * i)) { + ret = -EFAULT; + } else { + ret = i; + } + } + + kfree(agent_data); + return ret; +} + +int virtcca_mig_get_notify(struct virtcca_tmi_cmd *cmd) +{ + int count = 0; + count = virtcca_mig_flat_list_to_agent((void __user *)cmd->data); + if (count < 0) { + return count; + } + + cmd->ret_val = count; + return 0; +} + +int virtcca_migvm_mem_checksum_loop(struct virtcca_tmi_cmd *cmd) +{ + unsigned long ret; + struct virtcca_migvm_checksum_info checksuminfo; + + if (copy_from_user(&checksuminfo, (void __user *)cmd->data, sizeof(checksuminfo))) + return -EFAULT; + + ret = tmi_mig_integrity_checksum_loop(checksuminfo.guest_rd, checksuminfo.thread_id); + cmd->ret_val = ret; + + return ret; +} + +int virtcca_get_dstvm_rd(struct virtcca_tmi_cmd *cmd) +{ + struct virtcca_mig_verifier *verifier; + char cvm_name[CVM_NAME_LEN] = {0}; + + if (copy_from_user(&cvm_name, (void __user *)cmd->data, sizeof(cvm_name))) + return -EFAULT; + + mutex_lock(&verifier_list_mutex); + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (!strcmp(verifier->name, cvm_name)) { + cmd->ret_val = verifier->rd; + mutex_unlock(&verifier_list_mutex); + return 0; + } + } + + mutex_unlock(&verifier_list_mutex); + return 0; +} + +static long virtcca_tmi_ioctl_wrapper(struct file *file, unsigned int cmd, unsigned long arg); +static const struct file_operations tmm_tmi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = virtcca_tmi_ioctl_wrapper +}; + +static struct miscdevice ioctl_dev = { + MISC_DYNAMIC_MINOR, + "tmi", + &tmm_tmi_fops, +}; + +#define TMI_MAGIC 'T' +#define VIRTCCA_TMI_IOCTL_ENTER _IOWR(TMI_MAGIC, 0x1, struct virtcca_tmi_cmd) +/* virtcca tmi sub-ioctl() commands. */ +enum virtcca_tmi_cmd_id { + VIRTCCA_TMI_IOCTL_VERSION = 0, + VIRTCCA_TMI_GET_NOTIFY, + VIRTCCA_GET_MIGVM_MEM_CHECKSUM, + VIRTCCA_GET_DSTVM_RD, + + VIRTCCA_TMI_IOCTL_CMD_MAX, +}; + +int virtcca_tmi_ioctl(unsigned long arg) +{ + struct virtcca_tmi_cmd tmi_cmd = {0}; + int ret = 0; + + void __user *argp = (void __user *)arg; + if (copy_from_user(&tmi_cmd, argp, sizeof(struct virtcca_tmi_cmd))) + return -EINVAL; + + if (virtcca_migcvm_enabled && tmi_cmd.id >= VIRTCCA_TMI_GET_NOTIFY && tmi_cmd.id <= VIRTCCA_GET_DSTVM_RD) { + pr_err("migcvm is running, host mig agent is disabled!"); + ret = -EINVAL; + goto out; + } + + switch (tmi_cmd.id) { + case VIRTCCA_TMI_IOCTL_VERSION: + printk("This is a tmi ioctl\n"); + break; + case VIRTCCA_TMI_GET_NOTIFY: + ret = virtcca_mig_get_notify(&tmi_cmd); + break; + case VIRTCCA_GET_MIGVM_MEM_CHECKSUM: + ret = virtcca_migvm_mem_checksum_loop(&tmi_cmd); + break; + case VIRTCCA_GET_DSTVM_RD: + ret = virtcca_get_dstvm_rd(&tmi_cmd); + break; + default: + ret = -EINVAL; + } + +out: + if (copy_to_user(argp, &tmi_cmd, sizeof(struct virtcca_tmi_cmd))) + return -EFAULT; + + return ret; +} + +static long virtcca_tmi_ioctl_wrapper(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + if (!file) { + return -EINVAL; + } + + switch (cmd) { + case VIRTCCA_TMI_IOCTL_ENTER: + ret = virtcca_tmi_ioctl(arg); + break; + default: + pr_err("tmm_tmi: unknown ioctl command (0x%x)!\n", cmd); + return -ENOTTY; + } + + return ret; +} + +static int __init tmm_tmi_init(void) +{ + int ret; + + if (!is_virtcca_cvm_enable()) + return -EIO; + + ret = misc_register(&ioctl_dev); + if (ret) { + pr_err("tmm_tmi: misc device register failed (%d)!\n", ret); + return ret; + } + + return 0; +} + +static void __exit tmm_tmi_exit(void) +{ + misc_deregister(&ioctl_dev); + pr_warn("tmm_tmi: module unloaded.\n"); +} + +module_init(tmm_tmi_init); +module_exit(tmm_tmi_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD."); +MODULE_DESCRIPTION("Interacting with TMM through TMI interface from user space."); + #endif diff --git a/arch/arm64/kvm/virtcca_mig.c b/arch/arm64/kvm/virtcca_mig.c index edbc23ddb1cc..a0a43a064c10 100644 --- a/arch/arm64/kvm/virtcca_mig.c +++ b/arch/arm64/kvm/virtcca_mig.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #define SEC_CRC_PATH "/tmp/sec_memory_check" @@ -1649,8 +1650,8 @@ static int send_and_wait_ack(struct socket *sock, bind_msg_t *req_msg) /* vsock connection*/ /* step 1: send to mig-cvm agent: the migrated rd, the destination platform ip*/ /* step 2: wait for mig-cvm agent's response */ -static int notify_migcvm_agent(uint64_t cid, virtcca_dst_host_info_t *dst_host_info, - uint64_t guest_rd, bool is_src) +static int notify_migcvm_agent(uint64_t cid, struct virtcca_mig_dst_host_info *dst_host_info, + uint64_t guest_rd, bool is_src) { struct socket *sock = NULL; int ret = 0; @@ -1760,7 +1761,7 @@ static int notify_migcvm_agent(uint64_t cid, virtcca_dst_host_info_t *dst_host_i int virtcca_migvm_agent_ratstls_dst(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd) { struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; - struct virtcca_dst_host_info dst_info; + struct virtcca_mig_dst_host_info dst_info; struct arm_smccc_res tmi_ret; int ret = 0; pr_info("virtcca_migvm_agent_ratstls_dst called\n"); @@ -1770,7 +1771,7 @@ int virtcca_migvm_agent_ratstls_dst(struct kvm *kvm, struct kvm_virtcca_mig_cmd } if (copy_from_user(&dst_info, (void __user *)cmd->data, - sizeof(virtcca_dst_host_info_t))) { + sizeof(struct virtcca_mig_dst_host_info))) { return -EFAULT; } @@ -1803,7 +1804,7 @@ int virtcca_migvm_agent_ratstls_dst(struct kvm *kvm, struct kvm_virtcca_mig_cmd int virtcca_migvm_agent_ratstls(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd) { struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; - struct virtcca_dst_host_info dst_info; + struct virtcca_mig_dst_host_info dst_info; struct arm_smccc_res tmi_ret; int ret = 0; pr_info("virtcca_migvm_agent_ratstls called\n"); @@ -1813,7 +1814,7 @@ int virtcca_migvm_agent_ratstls(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd } if (copy_from_user(&dst_info, (void __user *)cmd->data, - sizeof(virtcca_dst_host_info_t))) { + sizeof(struct virtcca_mig_dst_host_info))) { return -EFAULT; } @@ -1941,6 +1942,7 @@ int virtcca_mig_export_abort(struct kvm *kvm) uint64_t granule; uint64_t ret = 0; + virtcca_mig_verify_delete(kvm); ret = tmi_export_abort(cvm->rd); if (ret) { pr_err("%s: err=%llx\n", __func__, ret); diff --git a/arch/arm64/kvm/virtcca_mig.h b/arch/arm64/kvm/virtcca_mig.h index 34c9faec4262..0dd27e023279 100644 --- a/arch/arm64/kvm/virtcca_mig.h +++ b/arch/arm64/kvm/virtcca_mig.h @@ -6,12 +6,6 @@ struct virtcca_bind_info { bool premig_done; }; -typedef struct virtcca_dst_host_info { - char dst_ip[16]; - uint16_t dst_port; - uint8_t version; -} virtcca_dst_host_info_t; - struct virtcca_mig_mbmd_data { /* both kvm and tmm can access */ __u16 size; __u16 mig_version; -- Gitee From cd771a2f182f14fcc64fe906993637eabd8b4885 Mon Sep 17 00:00:00 2001 From: panhengchang Date: Tue, 3 Feb 2026 22:28:12 +0800 Subject: [PATCH 2/2] add host agent transfer key --- arch/arm64/include/asm/kvm_tmi.h | 7 +- arch/arm64/include/asm/kvm_tmm.h | 35 +++- arch/arm64/kvm/tmi.c | 14 ++ arch/arm64/kvm/virtcca_cvm.c | 348 ++++++++++++++++++++++++------- arch/arm64/kvm/virtcca_mig.c | 34 --- arch/arm64/kvm/virtcca_mig.h | 1 - 6 files changed, 319 insertions(+), 120 deletions(-) diff --git a/arch/arm64/include/asm/kvm_tmi.h b/arch/arm64/include/asm/kvm_tmi.h index c09fd62281b3..53a68dc4fef0 100644 --- a/arch/arm64/include/asm/kvm_tmi.h +++ b/arch/arm64/include/asm/kvm_tmi.h @@ -330,7 +330,9 @@ typedef enum tmi_tmm_mig_control_fid_e { TMI_TMM_MIG_IMPORT_COMMIT, TMI_TMM_DUMP_CHECKSUM, TMI_TMM_MIG_EXPORT_ABORT, - TMI_TMM_MIG_EXPORT_PAUSE + TMI_TMM_MIG_EXPORT_PAUSE, + TMI_TMM_MIG_GET_MIG_KEY, + TMI_TMM_MIG_SET_MIG_KEY } tmi_tmm_mig_control_fid_t; typedef enum tmi_tmm_mig_data_fid_e{ @@ -539,6 +541,9 @@ struct arm_smccc_res tmi_export_pause(uint64_t rd); u64 tmi_mig_integrity_checksum_loop(uint64_t rd, uint64_t thread_id); u64 tmi_mig_integrity_checksum_init(unsigned long dst_rd, unsigned long queue_pa); +u64 tmi_mig_get_migration_key(uint64_t rd, uint64_t hsot_mig_agent_attr_pa); +u64 tmi_mig_set_migration_key(uint64_t rd, uint64_t hsot_mig_agent_attr_pa); + /* enable the migcvm ctl */ int kvm_migcvm_ioctl(struct kvm *kvm, unsigned long arg); struct arm_smccc_res tmi_mem_region_protect(u64 rd, u64 start, u64 end); diff --git a/arch/arm64/include/asm/kvm_tmm.h b/arch/arm64/include/asm/kvm_tmm.h index fac3ebabd40a..b6095ed90c15 100644 --- a/arch/arm64/include/asm/kvm_tmm.h +++ b/arch/arm64/include/asm/kvm_tmm.h @@ -55,11 +55,25 @@ struct tmi_cvm_params { struct mig_cvm { /* used by guest cvm */ uint64_t migvm_cid; /* vsock cid of migvm */ - uint8_t version; /* kvm version of migcvm*/ + uint16_t version; /* kvm version of migcvm*/ uint16_t dst_port; /* port of destination cvm */ char dst_ip[CVM_MIG_IP_LEN]; /* ip of destination cvm */ uint8_t is_migcvm; /* indicates whether the device is a migcvm. */ - char reserved[4]; + char reserved; +}; + +#define TMI_MAGIC 'T' +#define VIRTCCA_TMI_IOCTL_ENTER _IOWR(TMI_MAGIC, 0x1, struct virtcca_tmi_cmd) +/* virtcca tmi sub-ioctl() commands. */ +enum virtcca_tmi_cmd_id { + VIRTCCA_TMI_IOCTL_VERSION = 0, + VIRTCCA_TMI_GET_NOTIFY, + VIRTCCA_GET_MIGVM_MEM_CHECKSUM, + VIRTCCA_GET_DSTVM_RD, + VIRTCCA_GET_MIG_KEY, + VIRTCCA_SET_MIG_KEY, + + VIRTCCA_TMI_IOCTL_CMD_MAX, }; struct cvm { @@ -144,6 +158,7 @@ enum virtcca_mig_verifier_status { VIRTCCA_MIG_NEW = 0, VIRTCCA_MIG_UPDATED, VIRTCCA_MIG_NOTIFIED, + VIRTCCA_MIG_KEY_UPDATED, VIRTCCA_MIG_STATUS_MAX, }; @@ -165,7 +180,8 @@ struct virtcca_mig_verifier { uint16_t dst_port; uint16_t cvm_vmid; uint16_t is_src; - uint16_t status; + wait_queue_head_t wait_queue; + atomic_t status; struct list_head list; }; @@ -179,6 +195,19 @@ struct virtcca_mig_dst_host_info { uint8_t version; }; +struct mig_host_key_info { + uint8_t msk[32]; + uint8_t rand_iv[32]; + uint8_t tag[16]; +}; + +/* used for mig agent forwarding data between the secure and non-secure worlds. */ +struct virtcca_mig_host_agent_info { + uint64_t rd; + void *content; + unsigned long size; +}; + struct cvm_ttt_addr { struct list_head list; u64 addr; diff --git a/arch/arm64/kvm/tmi.c b/arch/arm64/kvm/tmi.c index 67413e4d3fef..9641f0e0b5d6 100644 --- a/arch/arm64/kvm/tmi.c +++ b/arch/arm64/kvm/tmi.c @@ -581,4 +581,18 @@ u64 tmi_mig_integrity_checksum_loop(uint64_t rd, uint64_t thread_id) struct arm_smccc_res res; arm_smccc_1_1_smc(TMI_TMM_MIG_ATTESTATION, TMI_TMM_MIG_INTEGRITY_CHECKSUM_LOOP, rd, thread_id, &res); return res.a1; +} + +u64 tmi_mig_get_migration_key(uint64_t rd, uint64_t hsot_mig_agent_attr_p) +{ + struct arm_smccc_res res; + arm_smccc_1_1_smc(TMI_TMM_MIG_CONTROL, TMI_TMM_MIG_GET_MIG_KEY, rd, __pa(hsot_mig_agent_attr_p), &res); + return res.a1; +} + +u64 tmi_mig_set_migration_key(uint64_t rd, uint64_t hsot_mig_agent_attr_p) +{ + struct arm_smccc_res res; + arm_smccc_1_1_smc(TMI_TMM_MIG_CONTROL, TMI_TMM_MIG_SET_MIG_KEY, rd, __pa(hsot_mig_agent_attr_p), &res); + return res.a1; } \ No newline at end of file diff --git a/arch/arm64/kvm/virtcca_cvm.c b/arch/arm64/kvm/virtcca_cvm.c index b73ea61b44dc..6b1bccd5c9f0 100644 --- a/arch/arm64/kvm/virtcca_cvm.c +++ b/arch/arm64/kvm/virtcca_cvm.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,6 +36,7 @@ static int virtcca_migcvm_enabled = 0; #define DTB_MAX_SIZE 0x200000 static int virtcca_mig_notify(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd); +static int virtcca_wait_for_verifier_state(struct kvm *kvm, int expected_state); bool is_virtcca_available(void) { @@ -1075,6 +1078,55 @@ static inline bool is_dtb_info_has_extend_data(u64 dtb_info) return dtb_info & 0x1; } +int virtcca_get_bind_info(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd) +{ + struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; + struct virtcca_bind_info info; + struct arm_smccc_res ret; + + if (copy_from_user(&info, (void __user *)cmd->data, + sizeof(struct virtcca_bind_info))) { + return -EFAULT; + } + + if (cmd->flags || info.version != KVM_CVM_MIGVM_VERSION) + return -EINVAL; + + if (!virtcca_migcvm_enabled) { + ret.a0 = virtcca_wait_for_verifier_state(kvm, VIRTCCA_MIG_KEY_UPDATED); + if (ret.a0) { + info.premig_done = false; + } else { + info.premig_done = true; + } + if (copy_to_user((void __user *)cmd->data, &info, + sizeof(struct virtcca_bind_info))) { + return -EFAULT; + } + + return 0; + } + + ret = tmi_bind_peek(cvm->rd); + if (ret.a1 == TMI_SUCCESS) { + if (ret.a2 == SLOT_IS_READY) { + info.premig_done = true; + } else { + info.premig_done = false; + } + if (copy_to_user((void __user *)cmd->data, &info, + sizeof(struct virtcca_bind_info))) { + return -EFAULT; + } + return ret.a1; + } else { + pr_err("%s: failed, err=%lx\n", __func__, ret.a1); + return -EIO; + } + + return ret.a1; +} + int kvm_migcvm_ioctl(struct kvm *kvm, unsigned long arg) { struct kvm_virtcca_mig_cmd cvm_cmd; @@ -1596,7 +1648,8 @@ int virtcca_cvm_arm_smmu_domain_set_kvm(void *group) } static LIST_HEAD(virtcca_mig_verifier_list); -static DEFINE_MUTEX(verifier_list_mutex); +static DEFINE_RWLOCK(verifier_list_rwlock); +#define VIRTCCA_MIG_STATE_WAIT_TIMEOUT 3000 int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_info *dst_host_info) { @@ -1604,7 +1657,7 @@ int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_inf struct virtcca_mig_verifier *verifier = NULL; int ret = 0; - mutex_lock(&verifier_list_mutex); + write_lock(&verifier_list_rwlock); list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { if (verifier->cvm_vmid == cvm->cvm_vmid) { if (dst_host_info->is_src) { @@ -1613,10 +1666,10 @@ int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_inf verifier->dst_port = dst_host_info->dst_port; } - verifier->status = VIRTCCA_MIG_UPDATED; + atomic_set(&verifier->status, VIRTCCA_MIG_UPDATED); verifier->is_src = dst_host_info->is_src; pr_warn("CVM is already registered to verifer list, update it\n"); - mutex_unlock(&verifier_list_mutex); + write_unlock(&verifier_list_rwlock); return 0; } } @@ -1624,7 +1677,7 @@ int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_inf verifier = kmalloc(sizeof(struct virtcca_mig_verifier), GFP_KERNEL); if (!verifier) { pr_err("virtcca_mig_verify_register memory allocation failed!\n"); - mutex_unlock(&verifier_list_mutex); + write_unlock(&verifier_list_rwlock); return -ENOMEM; } @@ -1636,12 +1689,13 @@ int virtcca_mig_verify_register(struct kvm *kvm, struct virtcca_mig_dst_host_inf verifier->is_src = dst_host_info->is_src; verifier->rd = cvm->rd; verifier->cvm_vmid = cvm->cvm_vmid; - verifier->status = VIRTCCA_MIG_NEW; + init_waitqueue_head(&verifier->wait_queue); + atomic_set(&verifier->status, VIRTCCA_MIG_NEW); INIT_LIST_HEAD(&verifier->list); list_add_tail(&verifier->list, &virtcca_mig_verifier_list); - mutex_unlock(&verifier_list_mutex); + write_unlock(&verifier_list_rwlock); return ret; } @@ -1651,18 +1705,17 @@ int virtcca_mig_verify_delete(struct kvm *kvm) struct virtcca_mig_verifier *verifier, *tmp; struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; - mutex_lock(&verifier_list_mutex); + write_lock(&verifier_list_rwlock); list_for_each_entry_safe(verifier, tmp, &virtcca_mig_verifier_list, list) { if (verifier->cvm_vmid == cvm->cvm_vmid) { list_del(&verifier->list); - mutex_unlock(&verifier_list_mutex); + write_unlock(&verifier_list_rwlock); kfree(verifier); pr_info("Removed CVM ID %d from verifer list\n", cvm->cvm_vmid); return 0; } } - mutex_unlock(&verifier_list_mutex); - pr_warn("VM with ID %d not found in verifer list\n", cvm->cvm_vmid); + write_unlock(&verifier_list_rwlock); return 0; } @@ -1701,61 +1754,58 @@ static int virtcca_mig_notify(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd) int virtcca_mig_flat_list_to_agent(void __user *user_data) { - struct virtcca_mig_verifier *verifier; - struct virtcca_mig_agent_notify_info *agent_data = NULL; - int notify_count = 0; - int i = 0; - int ret = 0; - - mutex_lock(&verifier_list_mutex); - - list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { - if (verifier->status != VIRTCCA_MIG_NOTIFIED && verifier->is_src) - notify_count++; - } - - if (notify_count == 0) { - mutex_unlock(&verifier_list_mutex); - return 0; - } - - notify_count = min(notify_count, CVM_MIG_SYNC_NUM_MAX); - agent_data = kmalloc(sizeof(struct virtcca_mig_agent_notify_info) * notify_count, GFP_KERNEL); - if (!agent_data) { - mutex_unlock(&verifier_list_mutex); - return -ENOMEM; - } - - list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { - if (verifier->status != VIRTCCA_MIG_NOTIFIED && verifier->is_src) { - if (i >= notify_count) - break; - - strncpy(agent_data[i].name, verifier->name, sizeof(agent_data[i].name) - 1); - agent_data[i].name[sizeof(agent_data[i].name) - 1] = '\0'; - strncpy(agent_data[i].dst_ip, verifier->dst_ip, sizeof(agent_data[i].dst_ip) - 1); - agent_data[i].dst_ip[sizeof(agent_data[i].dst_ip) - 1] = '\0'; - agent_data[i].rd = verifier->rd; - agent_data[i].dst_port = verifier->dst_port; - agent_data[i].cvm_vmid = verifier->cvm_vmid; - agent_data[i].is_src = verifier->is_src; - - verifier->status = VIRTCCA_MIG_NOTIFIED; - i++; - } - } - mutex_unlock(&verifier_list_mutex); - - if (i > 0) { - if (copy_to_user(user_data, agent_data, sizeof(struct virtcca_mig_agent_notify_info) * i)) { - ret = -EFAULT; - } else { - ret = i; - } - } - - kfree(agent_data); - return ret; + struct virtcca_mig_verifier *verifier; + struct virtcca_mig_agent_notify_info *agent_data = NULL; + int notify_count = 0; + int i = 0; + int ret = 0; + + read_lock(&verifier_list_rwlock); + + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (atomic_read(&verifier->status) < VIRTCCA_MIG_NOTIFIED && verifier->is_src) + notify_count++; + } + + if (notify_count == 0) { + read_unlock(&verifier_list_rwlock); + return 0; + } + + notify_count = min(notify_count, CVM_MIG_SYNC_NUM_MAX); + agent_data = kmalloc(sizeof(struct virtcca_mig_agent_notify_info) * notify_count, GFP_KERNEL); + if (!agent_data) { + read_unlock(&verifier_list_rwlock); + return -ENOMEM; + } + + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (atomic_read(&verifier->status) < VIRTCCA_MIG_NOTIFIED && verifier->is_src) { + if (i >= notify_count) + break; + strncpy(agent_data[i].name, verifier->name, strlen(verifier->name) + 1); + strncpy(agent_data[i].dst_ip, verifier->dst_ip, strlen(verifier->name) + 1); + agent_data[i].rd = verifier->rd; + agent_data[i].dst_port = verifier->dst_port; + agent_data[i].cvm_vmid = verifier->cvm_vmid; + agent_data[i].is_src = verifier->is_src; + atomic_set(&verifier->status, VIRTCCA_MIG_NOTIFIED); + + i++; + } + } + read_unlock(&verifier_list_rwlock); + + if (i > 0) { + if (copy_to_user(user_data, agent_data, sizeof(struct virtcca_mig_agent_notify_info) * i)) { + ret = -EFAULT; + } else { + ret = i; + } + } + + kfree(agent_data); + return ret; } int virtcca_mig_get_notify(struct virtcca_tmi_cmd *cmd) @@ -1792,19 +1842,161 @@ int virtcca_get_dstvm_rd(struct virtcca_tmi_cmd *cmd) if (copy_from_user(&cvm_name, (void __user *)cmd->data, sizeof(cvm_name))) return -EFAULT; - mutex_lock(&verifier_list_mutex); + read_lock(&verifier_list_rwlock); list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { if (!strcmp(verifier->name, cvm_name)) { cmd->ret_val = verifier->rd; - mutex_unlock(&verifier_list_mutex); + read_unlock(&verifier_list_rwlock); return 0; } } - mutex_unlock(&verifier_list_mutex); + read_unlock(&verifier_list_rwlock); return 0; } +int virtcca_update_verifier_state_by_rd(uint64_t rd, uint16_t verifier_state) +{ + struct virtcca_mig_verifier *verifier; + + read_lock(&verifier_list_rwlock); + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (verifier->rd == rd) { + pr_info("virtcca_update_verifier_state_by_rd: update verifier state to %u\n", verifier_state); + atomic_set(&verifier->status, verifier_state); + read_unlock(&verifier_list_rwlock); + return 0; + } + } + read_unlock(&verifier_list_rwlock); + return -1; +} + +int virtcca_wait_for_verifier_state(struct kvm *kvm, int expected_state) +{ + struct virtcca_mig_verifier *verifier; + unsigned long timeout = msecs_to_jiffies(VIRTCCA_MIG_STATE_WAIT_TIMEOUT); + uint64_t rd = kvm->arch.virtcca_cvm->rd; + + read_lock(&verifier_list_rwlock); + list_for_each_entry(verifier, &virtcca_mig_verifier_list, list) { + if (verifier->rd == rd) { + long time_left = wait_event_timeout(verifier->wait_queue, + atomic_read(&verifier->status) == expected_state, timeout); + read_unlock(&verifier_list_rwlock); + if (time_left < 0) { + pr_err("Timeout waiting for verifier state %d\n", expected_state); + return -ETIMEDOUT; + } + return 0; + } + } + read_unlock(&verifier_list_rwlock); + return -1; +} + +int virtcca_mig_src_get_key(struct virtcca_tmi_cmd *cmd) +{ + unsigned long ret = 0; + struct virtcca_mig_host_agent_info agent_info = {0}; + struct mig_host_key_info *key_info = NULL; + + if (copy_from_user(&agent_info, (void __user *)cmd->data, sizeof(struct virtcca_mig_host_agent_info))) + return -EFAULT; + + if (agent_info.content) { + if (!access_ok(agent_info.content, agent_info.size)) { + pr_err("virtcca_mig_src_get_key: invalid content address\n"); + return -EFAULT; + } + } else { + pr_err("virtcca_mig_src_get_key: invalid content pointer\n"); + return -EFAULT; + } + + if (sizeof(struct mig_host_key_info) != agent_info.size) { + pr_err("virtcca_mig_src_get_key: size mismatch\n"); + return -EINVAL; + } + + key_info = kmalloc(sizeof(struct mig_host_key_info), GFP_KERNEL); + if (!key_info) { + pr_err("virtcca_mig_src_get_key: kmalloc failed\n"); + return -ENOMEM; + } + + ret = tmi_mig_get_migration_key(agent_info.rd, (uint64_t)key_info); + if (ret) { + pr_err("virtcca_mig_src_get_key: tmi_mig_get_migration_key failed\n"); + goto out; + } + cmd->ret_val = ret; + + if (copy_to_user(agent_info.content, key_info, agent_info.size)) { + pr_err("virtcca_mig_src_get_key: copy to user failed\n"); + ret = -EFAULT; + goto out; + } + + virtcca_update_verifier_state_by_rd(agent_info.rd, VIRTCCA_MIG_KEY_UPDATED); + +out: + if (key_info != NULL) + kfree(key_info); + + return ret; +} + +int virtcca_mig_dst_set_key(struct virtcca_tmi_cmd *cmd) +{ + unsigned long ret = 0; + struct virtcca_mig_host_agent_info agent_info = {0}; + struct mig_host_key_info *key_info = NULL; + + if (copy_from_user(&agent_info, (void __user *)cmd->data, sizeof(struct virtcca_mig_host_agent_info))) + return -EFAULT; + + if (agent_info.content) { + if (!access_ok(agent_info.content, agent_info.size)) { + pr_err("virtcca_mig_dst_set_key: invalid content address\n"); + return -EFAULT; + } + } else { + pr_err("virtcca_mig_dst_set_key: invalid content pointer\n"); + return -EFAULT; + } + + if (sizeof(struct mig_host_key_info) != agent_info.size) { + pr_err("virtcca_mig_dst_set_key: size mismatch\n"); + return -EINVAL; + } + + key_info = kmalloc(sizeof(struct mig_host_key_info), GFP_KERNEL); + if (!key_info) { + pr_err("virtcca_mig_dst_set_key: kmalloc failed\n"); + return -ENOMEM; + } + + if (copy_from_user(key_info, (void __user *)agent_info.content, sizeof(struct mig_host_key_info))) { + ret = -EFAULT; + goto out; + } + + ret = tmi_mig_set_migration_key(agent_info.rd, (uint64_t)key_info); + if (ret) { + pr_err("virtcca_mig_dst_set_key: tmi_mig_set_migration_key failed\n"); + ret = -EFAULT; + goto out; + } + + virtcca_update_verifier_state_by_rd(agent_info.rd, VIRTCCA_MIG_KEY_UPDATED); +out: + if (key_info) + kfree(key_info); + + return ret; +} + static long virtcca_tmi_ioctl_wrapper(struct file *file, unsigned int cmd, unsigned long arg); static const struct file_operations tmm_tmi_fops = { .owner = THIS_MODULE, @@ -1817,18 +2009,6 @@ static struct miscdevice ioctl_dev = { &tmm_tmi_fops, }; -#define TMI_MAGIC 'T' -#define VIRTCCA_TMI_IOCTL_ENTER _IOWR(TMI_MAGIC, 0x1, struct virtcca_tmi_cmd) -/* virtcca tmi sub-ioctl() commands. */ -enum virtcca_tmi_cmd_id { - VIRTCCA_TMI_IOCTL_VERSION = 0, - VIRTCCA_TMI_GET_NOTIFY, - VIRTCCA_GET_MIGVM_MEM_CHECKSUM, - VIRTCCA_GET_DSTVM_RD, - - VIRTCCA_TMI_IOCTL_CMD_MAX, -}; - int virtcca_tmi_ioctl(unsigned long arg) { struct virtcca_tmi_cmd tmi_cmd = {0}; @@ -1857,6 +2037,12 @@ int virtcca_tmi_ioctl(unsigned long arg) case VIRTCCA_GET_DSTVM_RD: ret = virtcca_get_dstvm_rd(&tmi_cmd); break; + case VIRTCCA_GET_MIG_KEY: + ret = virtcca_mig_src_get_key(&tmi_cmd); + break; + case VIRTCCA_SET_MIG_KEY: + ret = virtcca_mig_dst_set_key(&tmi_cmd); + break; default: ret = -EINVAL; } diff --git a/arch/arm64/kvm/virtcca_mig.c b/arch/arm64/kvm/virtcca_mig.c index a0a43a064c10..35d542ba711d 100644 --- a/arch/arm64/kvm/virtcca_mig.c +++ b/arch/arm64/kvm/virtcca_mig.c @@ -1849,40 +1849,6 @@ int virtcca_migvm_agent_ratstls(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd return ret; } -int virtcca_get_bind_info(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd) -{ - struct virtcca_cvm *cvm = kvm->arch.virtcca_cvm; - struct virtcca_bind_info info; - struct arm_smccc_res ret; - - if (copy_from_user(&info, (void __user *)cmd->data, - sizeof(struct virtcca_bind_info))) { - return -EFAULT; - } - - if (cmd->flags || info.version != KVM_CVM_MIGVM_VERSION) - return -EINVAL; - - ret = tmi_bind_peek(cvm->rd); - if (ret.a1 == TMI_SUCCESS) { - if (ret.a2 == SLOT_IS_READY) { - info.premig_done = true; - } else { - info.premig_done = false; - } - if (copy_to_user((void __user *)cmd->data, &info, - sizeof(struct virtcca_bind_info))) { - return -EFAULT; - } - return ret.a1; - } else { - pr_err("%s: failed, err=%lx\n", __func__, ret.a1); - return -EIO; - } - - return ret.a1; -} - static struct kvm_device_ops kvm_virtcca_mig_stream_ops = { .name = "kvm-virtcca-mig-stream", .get_attr = virtcca_mig_stream_get_attr, diff --git a/arch/arm64/kvm/virtcca_mig.h b/arch/arm64/kvm/virtcca_mig.h index 0dd27e023279..4bf3ed561737 100644 --- a/arch/arm64/kvm/virtcca_mig.h +++ b/arch/arm64/kvm/virtcca_mig.h @@ -285,7 +285,6 @@ int virtcca_mig_state_create(struct virtcca_cvm *cvm); int virtcca_save_migvm_cid(struct kvm *guest_kvm, struct kvm_virtcca_mig_cmd *cmd); int virtcca_migvm_agent_ratstls(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd); int virtcca_migvm_agent_ratstls_dst(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd); -int virtcca_get_bind_info(struct kvm *kvm, struct kvm_virtcca_mig_cmd *cmd); void virtcca_dump_checksum(struct kvm *kvm); void crc32_init(void); void virtcca_enable_log_dirty(struct kvm *kvm, uint64_t start, uint64_t end); -- Gitee