diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index a0b73e6ed747..b57ecb4d1087 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -2470,16 +2470,34 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct sn vc_ghcb_invalidate(ghcb); - if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { + switch (exit_code) { + case SVM_VMGEXIT_EXT_GUEST_REQUEST: ghcb_set_rax(ghcb, input->data_gpa); ghcb_set_rbx(ghcb, input->data_npages); + break; + case SVM_VMGEXIT_TIO_GUEST_REQUEST: + ghcb_set_rax(ghcb, input->data_gpa); + ghcb_set_rbx(ghcb, input->data_npages); + ghcb_set_rcx(ghcb, rio->pci_id); + ghcb_set_rdx(ghcb, rio->mmio_range); + ghcb_set_sw_exit_info_1(ghcb, rio->exitinfo1); + ghcb_set_sw_exit_info_2(ghcb, rio->exitinfo2); + break; + default: + break; } ret = sev_es_ghcb_hv_call(ghcb, &ctxt, exit_code, input->req_gpa, input->resp_gpa); if (ret) goto e_put; + rio->exitinfo1 = ghcb->save.sw_exit_info_1; rio->exitinfo2 = ghcb->save.sw_exit_info_2; + + /* TODO: Only defined for the TIO_MSG_TDI_INFO_RSP */ + if (exit_code == SVM_VMGEXIT_TIO_GUEST_REQUEST) + rio->tdisp_state = ghcb_get_rdx(ghcb); + switch (rio->exitinfo2) { case 0: break; diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 1814b413fd57..da7b576e1f05 100644 --- a/arch/x86/include/uapi/asm/svm.h +++ b/arch/x86/include/uapi/asm/svm.h @@ -116,6 +116,7 @@ #define SVM_VMGEXIT_AP_CREATE 1 #define SVM_VMGEXIT_AP_DESTROY 2 #define SVM_VMGEXIT_SNP_RUN_VMPL 0x80000018 +#define SVM_VMGEXIT_TIO_GUEST_REQUEST 0x80000019 #define SVM_VMGEXIT_HV_FEATURES 0x8000fffd #define SVM_VMGEXIT_TERM_REQUEST 0x8000fffe #define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code) \ diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c index 89754b019be2..bb96e279fc86 100644 --- a/drivers/virt/coco/sev-guest/sev-guest.c +++ b/drivers/virt/coco/sev-guest/sev-guest.c @@ -656,6 +656,44 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques return ret; } +static int handle_tio_request(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg) +{ + void *req = NULL, *resp = NULL; + int rc = 0; + + lockdep_assert_held(&snp_cmd_mutex); + + req = kmalloc(arg->req_size, GFP_KERNEL); + if (!req) { + rc = -ENOMEM; + goto exit; + } + resp = kmalloc(arg->resp_size, GFP_KERNEL); + if (!resp) { + rc = -ENOMEM; + goto exit; + } + + if (copy_from_user(req, (void __user *)arg->req_data, arg->req_size)) + rc = -EFAULT; + + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_TIO_GUEST_REQUEST, arg, arg->tio_msg, + req, arg->req_size, resp, arg->resp_size); + if (rc) + goto exit; + + if (copy_to_user((void __user *)arg->resp_data, resp, arg->resp_size)) + rc = -EFAULT; + +exit: + if (req) + kfree(req); + if (resp) + kfree(resp); + + return rc; +} + static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) { struct snp_guest_dev *snp_dev = to_snp_dev(file); @@ -699,6 +737,9 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long io.resp_data = USER_SOCKPTR((void __user *)input.resp_data); ret = get_ext_report(snp_dev, &input, &io); break; + case SNP_TIO_GUEST_REQUEST: + ret = handle_tio_request(snp_dev, &input); + break; default: break; } diff --git a/include/uapi/linux/sev-guest.h b/include/uapi/linux/sev-guest.h index fcdfea767fca..0effcaed9813 100644 --- a/include/uapi/linux/sev-guest.h +++ b/include/uapi/linux/sev-guest.h @@ -62,6 +62,28 @@ struct snp_guest_request_ioctl { __u32 vmm_error; }; }; + + /* For the TIO requests; MESSY, just to unblock */ + __u64 exitinfo1; + + /* 19 - TIO_MSG_TDI_INFO_REQ */ + /* 20 - TIO_MSG_TDI_INFO_RSP */ + /* 21 - TIO_MSG_MMIO_VALIDATE_REQ */ + /* 22 - TIO_MSG_MMIO_VALIDATE_RSP */ + /* 23 - TIO_MSG_MMIO_CONFIG_REQ */ + /* 24 - TIO_MSG_MMIO_CONFIG_RSP */ + /* 25 - TIO_MSG_SDTE_WRITE_REQ */ + /* 26 - TIO_MSG_SDTE_WRITE_RSP */ + __u64 tio_msg; + + __u64 req_size; + __u64 resp_size; + + __u64 pci_id; + union { + __u64 mmio_range; + __u64 tdisp_state; + }; }; struct snp_ext_report_req { @@ -85,6 +107,9 @@ struct snp_ext_report_req { /* Get SNP extended report as defined in the GHCB specification version 2. */ #define SNP_GET_EXT_REPORT _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x2, struct snp_guest_request_ioctl) +/* Get SNP extended report as defined in the GHCB specification version 2. */ +#define SNP_TIO_GUEST_REQUEST _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x3, struct snp_guest_request_ioctl) + /* Guest message request EXIT_INFO_2 constants */ #define SNP_GUEST_FW_ERR_MASK GENMASK_ULL(31, 0) #define SNP_GUEST_VMM_ERR_SHIFT 32