On 2/25/25 15:00, Ashish Kalra wrote: > From: Ashish Kalra <ashish.kalra@xxxxxxx> > > Modify the behavior of implicit SEV initialization in some of the > SEV ioctls to do both SEV initialization and shutdown and add > implicit SNP initialization and shutdown to some of the SNP ioctls > so that the change of SEV/SNP platform initialization not being > done during PSP driver probe time does not break userspace tools > such as sevtool, etc. > > Prior to this patch, SEV has always been initialized before these > ioctls as SEV initialization is done as part of PSP module probe, > but now with SEV initialization being moved to KVM module load instead > of PSP driver probe, the implied SEV INIT actually makes sense and gets > used and additionally to maintain SEV platform state consistency > before and after the ioctl SEV shutdown needs to be done after the > firmware call. > > It is important to do SEV Shutdown here with the SEV/SNP initialization > moving to KVM, an implicit SEV INIT here as part of the SEV ioctls not > followed with SEV Shutdown will cause SEV to remain in INIT state and > then a future SNP INIT in KVM module load will fail. > > Similarly, prior to this patch, SNP has always been initialized before > these ioctls as SNP initialization is done as part of PSP module probe, > therefore, to keep a consistent behavior, SNP init needs to be done > here implicitly as part of these ioctls followed with SNP shutdown > before returning from the ioctl to maintain the consistent platform > state before and after the ioctl. > > Suggested-by: Tom Lendacky <thomas.lendacky@xxxxxxx> > Signed-off-by: Ashish Kalra <ashish.kalra@xxxxxxx> > --- > drivers/crypto/ccp/sev-dev.c | 145 +++++++++++++++++++++++++++-------- > 1 file changed, 115 insertions(+), 30 deletions(-) > > diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c > index 8962a0dbc66f..14847f1c05fc 100644 > --- a/drivers/crypto/ccp/sev-dev.c > +++ b/drivers/crypto/ccp/sev-dev.c > @@ -1459,28 +1459,38 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) > static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp, bool writable) > { > struct sev_device *sev = psp_master->sev_data; > - int rc; > + bool shutdown_required = false; > + int rc, error; > > if (!writable) > return -EPERM; > > if (sev->state == SEV_STATE_UNINIT) { > - rc = __sev_platform_init_locked(&argp->error); > - if (rc) > + rc = __sev_platform_init_locked(&error); > + if (rc) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > return rc; > + } > + shutdown_required = true; > } I see this block of code multiple times throughout this patch, both for SEV and SNP. Can this be consolidated into one or two functions that get called? Maybe something like: rc = sev_move_to_cmd_state(argp, &shutdown_required); Thanks, Tom > > - return __sev_do_cmd_locked(cmd, NULL, &argp->error); > + rc = __sev_do_cmd_locked(cmd, NULL, &argp->error); > + > + if (shutdown_required) > + __sev_platform_shutdown_locked(&error); > + > + return rc; > } > > static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) > { > struct sev_device *sev = psp_master->sev_data; > struct sev_user_data_pek_csr input; > + bool shutdown_required = false; > struct sev_data_pek_csr data; > void __user *input_address; > void *blob = NULL; > - int ret; > + int ret, error; > > if (!writable) > return -EPERM; > @@ -1508,9 +1518,12 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) > > cmd: > if (sev->state == SEV_STATE_UNINIT) { > - ret = __sev_platform_init_locked(&argp->error); > - if (ret) > + ret = __sev_platform_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > goto e_free_blob; > + } > + shutdown_required = true; > } > > ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, &data, &argp->error); > @@ -1529,6 +1542,9 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) > } > > e_free_blob: > + if (shutdown_required) > + __sev_platform_shutdown_locked(&error); > + > kfree(blob); > return ret; > } > @@ -1746,8 +1762,9 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) > struct sev_device *sev = psp_master->sev_data; > struct sev_user_data_pek_cert_import input; > struct sev_data_pek_cert_import data; > + bool shutdown_required = false; > void *pek_blob, *oca_blob; > - int ret; > + int ret, error; > > if (!writable) > return -EPERM; > @@ -1776,14 +1793,20 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) > > /* If platform is not in INIT state then transition it to INIT */ > if (sev->state != SEV_STATE_INIT) { > - ret = __sev_platform_init_locked(&argp->error); > - if (ret) > + ret = __sev_platform_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > goto e_free_oca; > + } > + shutdown_required = true; > } > > ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, &data, &argp->error); > > e_free_oca: > + if (shutdown_required) > + __sev_platform_shutdown_locked(&error); > + > kfree(oca_blob); > e_free_pek: > kfree(pek_blob); > @@ -1900,17 +1923,8 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) > struct sev_data_pdh_cert_export data; > void __user *input_cert_chain_address; > void __user *input_pdh_cert_address; > - int ret; > - > - /* If platform is not in INIT state then transition it to INIT. */ > - if (sev->state != SEV_STATE_INIT) { > - if (!writable) > - return -EPERM; > - > - ret = __sev_platform_init_locked(&argp->error); > - if (ret) > - return ret; > - } > + bool shutdown_required = false; > + int ret, error; > > if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) > return -EFAULT; > @@ -1951,6 +1965,18 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) > data.cert_chain_len = input.cert_chain_len; > > cmd: > + /* If platform is not in INIT state then transition it to INIT. */ > + if (sev->state != SEV_STATE_INIT) { > + if (!writable) > + goto e_free_cert; > + ret = __sev_platform_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + goto e_free_cert; > + } > + shutdown_required = true; > + } > + > ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, &data, &argp->error); > > /* If we query the length, FW responded with expected data. */ > @@ -1977,6 +2003,9 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) > } > > e_free_cert: > + if (shutdown_required) > + __sev_platform_shutdown_locked(&error); > + > kfree(cert_blob); > e_free_pdh: > kfree(pdh_blob); > @@ -1986,12 +2015,13 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) > static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) > { > struct sev_device *sev = psp_master->sev_data; > + bool shutdown_required = false; > struct sev_data_snp_addr buf; > struct page *status_page; > + int ret, error; > void *data; > - int ret; > > - if (!sev->snp_initialized || !argp->data) > + if (!argp->data) > return -EINVAL; > > status_page = alloc_page(GFP_KERNEL_ACCOUNT); > @@ -2000,6 +2030,15 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) > > data = page_address(status_page); > > + if (!sev->snp_initialized) { > + ret = __sev_snp_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + goto cleanup; > + } > + shutdown_required = true; > + } > + > /* > * Firmware expects status page to be in firmware-owned state, otherwise > * it will report firmware error code INVALID_PAGE_STATE (0x1A). > @@ -2028,6 +2067,9 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) > ret = -EFAULT; > > cleanup: > + if (shutdown_required) > + __sev_snp_shutdown_locked(&error, false); > + > __free_pages(status_page, 0); > return ret; > } > @@ -2036,21 +2078,36 @@ static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp) > { > struct sev_device *sev = psp_master->sev_data; > struct sev_data_snp_commit buf; > + bool shutdown_required = false; > + int ret, error; > > - if (!sev->snp_initialized) > - return -EINVAL; > + if (!sev->snp_initialized) { > + ret = __sev_snp_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + return ret; > + } > + shutdown_required = true; > + } > > buf.len = sizeof(buf); > > - return __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); > + ret = __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); > + > + if (shutdown_required) > + __sev_snp_shutdown_locked(&error, false); > + > + return ret; > } > > static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable) > { > struct sev_device *sev = psp_master->sev_data; > struct sev_user_data_snp_config config; > + bool shutdown_required = false; > + int ret, error; > > - if (!sev->snp_initialized || !argp->data) > + if (!argp->data) > return -EINVAL; > > if (!writable) > @@ -2059,17 +2116,32 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable > if (copy_from_user(&config, (void __user *)argp->data, sizeof(config))) > return -EFAULT; > > - return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); > + if (!sev->snp_initialized) { > + ret = __sev_snp_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + return ret; > + } > + shutdown_required = true; > + } > + > + ret = __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); > + > + if (shutdown_required) > + __sev_snp_shutdown_locked(&error, false); > + > + return ret; > } > > static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) > { > struct sev_device *sev = psp_master->sev_data; > struct sev_user_data_snp_vlek_load input; > + bool shutdown_required = false; > + int ret, error; > void *blob; > - int ret; > > - if (!sev->snp_initialized || !argp->data) > + if (!argp->data) > return -EINVAL; > > if (!writable) > @@ -2088,8 +2160,21 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) > > input.vlek_wrapped_address = __psp_pa(blob); > > + if (!sev->snp_initialized) { > + ret = __sev_snp_init_locked(&error); > + if (ret) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + goto cleanup; > + } > + shutdown_required = true; > + } > + > ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error); > > + if (shutdown_required) > + __sev_snp_shutdown_locked(&error, false); > + > +cleanup: > kfree(blob); > > return ret;