Different RSI calls that require device communication result in a REC exit, which is handled by the device communication exit handler. Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@xxxxxxxxxx> --- arch/arm64/include/asm/rmi_smc.h | 6 ++ drivers/virt/coco/arm-cca-host/arm-cca.c | 1 + drivers/virt/coco/arm-cca-host/rmm-da.c | 75 ++++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmm-da.h | 4 ++ 4 files changed, 86 insertions(+) diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h index 6b23afa070d1..7073eccaec5f 100644 --- a/arch/arm64/include/asm/rmi_smc.h +++ b/arch/arm64/include/asm/rmi_smc.h @@ -457,4 +457,10 @@ struct rmi_vdev_params { }; }; +#define RMI_VDEV_ACTION_GET_INTERFACE_REPORT 0x0 +#define RMI_VDEV_ACTION_GET_MEASUREMENTS 0x1 +#define RMI_VDEV_ACTION_LOCK 0x2 +#define RMI_VDEV_ACTION_START 0x3 +#define RMI_VDEV_ACTION_STOP 0x4 + #endif /* __ASM_RMI_SMC_H */ diff --git a/drivers/virt/coco/arm-cca-host/arm-cca.c b/drivers/virt/coco/arm-cca-host/arm-cca.c index 837bd10ccd47..be1296fb1bf2 100644 --- a/drivers/virt/coco/arm-cca-host/arm-cca.c +++ b/drivers/virt/coco/arm-cca-host/arm-cca.c @@ -243,6 +243,7 @@ static struct pci_tdi *cca_tsm_bind(struct pci_dev *pdev, struct pci_dev *pf0_de rmm_vdev = rme_create_vdev(realm, pdev, pf0_dev, tdi_id); if (!IS_ERR_OR_NULL(rmm_vdev)) { host_tdi->rmm_vdev = rmm_vdev; + host_tdi->vdev_id = tdi_id; return &no_free_ptr(host_tdi)->tdi; } diff --git a/drivers/virt/coco/arm-cca-host/rmm-da.c b/drivers/virt/coco/arm-cca-host/rmm-da.c index d4f1da590b90..bef33e618fd3 100644 --- a/drivers/virt/coco/arm-cca-host/rmm-da.c +++ b/drivers/virt/coco/arm-cca-host/rmm-da.c @@ -233,6 +233,16 @@ static int __do_dev_communicate(int type, struct pci_tsm *tsm) cache_offset = &dsc_pf0->cert_chain.cache.size; cache_remaining = sizeof(dsc_pf0->cert_chain.cache.buf) - *cache_offset; break; + case RMI_DEV_INTERFACE_REPORT: + cache_buf = dsc_pf0->interface_report.buf; + cache_offset = &dsc_pf0->interface_report.size; + cache_remaining = sizeof(dsc_pf0->interface_report.buf) - *cache_offset; + break; + case RMI_DEV_MEASUREMENTS: + cache_buf = dsc_pf0->measurements.buf; + cache_offset = &dsc_pf0->measurements.size; + cache_remaining = sizeof(dsc_pf0->measurements.buf) - *cache_offset; + break; default: /* FIXME!! depending on the DevComms status, * it might require to ABORT the communcation. @@ -661,6 +671,21 @@ void rme_unbind_vdev(struct realm *realm, struct pci_dev *pdev, struct pci_dev * } } +static struct pci_tsm *find_pci_tsm_from_vdev(phys_addr_t vdev_phys) +{ + struct pci_dev *pdev = NULL; + struct cca_host_tdi *host_tdi; + + for_each_pci_dev(pdev) { + host_tdi = to_cca_host_tdi(pdev); + if (!host_tdi) + continue; + if (virt_to_phys(host_tdi->rmm_vdev) == vdev_phys) + return pdev->tsm; + } + return NULL; +} + static struct pci_tsm *find_pci_tsm_from_vdev_id(unsigned long vdev_id) { struct pci_dev *pdev = NULL; @@ -676,6 +701,55 @@ static struct pci_tsm *find_pci_tsm_from_vdev_id(unsigned long vdev_id) return NULL; } +static int rme_exit_vdev_comm_handler(struct realm_rec *rec) +{ + int ret; + unsigned long state; + struct cca_host_tdi *host_tdi; + struct cca_host_comm_data *comm_data; + phys_addr_t vdev_phys = rec->run->exit.vdev; + struct pci_tsm *tsm = find_pci_tsm_from_vdev(vdev_phys); + + if (!tsm) + goto err_out; + + host_tdi = to_cca_host_tdi(tsm->pdev); + if (!host_tdi) + goto err_out; + + comm_data = to_cca_comm_data(tsm->pdev); + if (!comm_data->vdev_comm_active) { + struct rmi_dev_comm_enter *io_enter; + + io_enter = &comm_data->io_params->enter; + io_enter->resp_len = 0; + io_enter->status = RMI_DEV_COMM_NONE; + comm_data->vdev_comm_active = true; + } + + /* FIXME!! Should this be a work? */ + ret = __do_dev_communicate(VDEV_COMMUNICATE, tsm); + if (ret) + goto err_out; + + ret = rmi_vdev_get_state(virt_to_phys(host_tdi->rmm_vdev), &state); + if (ret) + goto err_out; + /* + * If vdev is done communicating, the next update should + * reinitialize the cache + */ + if (state != RMI_VDEV_COMMUNICATING) + comm_data->vdev_comm_active = false; + +err_out: + /* + * Return back to the guest without calling DEV communicate. + * The Realm will treat that as an error. + */ + return 1; +} + static int rme_exit_vdev_req_handler(struct realm_rec *rec) { struct cca_host_tdi *host_tdi = NULL; @@ -697,5 +771,6 @@ static int rme_exit_vdev_req_handler(struct realm_rec *rec) void rme_register_exit_handlers(void) { + realm_exit_vdev_comm_handler = rme_exit_vdev_comm_handler; realm_exit_vdev_req_handler = rme_exit_vdev_req_handler; } diff --git a/drivers/virt/coco/arm-cca-host/rmm-da.h b/drivers/virt/coco/arm-cca-host/rmm-da.h index 7f51b611467b..cebddab8464d 100644 --- a/drivers/virt/coco/arm-cca-host/rmm-da.h +++ b/drivers/virt/coco/arm-cca-host/rmm-da.h @@ -22,6 +22,8 @@ struct cca_host_comm_data { void *resp_buff; void *req_buff; struct rmi_dev_comm_data *io_params; + + bool vdev_comm_active; }; struct cca_host_dsc_pf0 { @@ -43,6 +45,8 @@ struct cca_host_dsc_pf0 { bool valid; } cert_chain; struct cache_object vca; + struct cache_object interface_report; + struct cache_object measurements; }; struct cca_host_tdi { -- 2.43.0