On 3/6/25 17:10, 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. > > Also ensure that for these SEV ioctls both implicit SNP and SEV INIT is > done followed by both SEV and SNP shutdown as RMP table must be > initialized before calling SEV INIT if SNP host support is enabled. > > 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> Reviewed-by: Tom Lendacky <thomas.lendacky@xxxxxxx> > --- > drivers/crypto/ccp/sev-dev.c | 142 +++++++++++++++++++++++++++++------ > 1 file changed, 119 insertions(+), 23 deletions(-) > > diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c > index ccd7cc4b36d1..5bd3df377370 100644 > --- a/drivers/crypto/ccp/sev-dev.c > +++ b/drivers/crypto/ccp/sev-dev.c > @@ -109,6 +109,8 @@ static void *sev_init_ex_buffer; > */ > static struct sev_data_range_list *snp_range_list; > > +static void __sev_firmware_shutdown(struct sev_device *sev, bool panic); > + > static inline bool sev_version_greater_or_equal(u8 maj, u8 min) > { > struct sev_device *sev = psp_master->sev_data; > @@ -1402,6 +1404,37 @@ static int sev_get_platform_state(int *state, int *error) > return rc; > } > > +static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) > +{ > + struct sev_platform_init_args init_args = {0}; > + int rc; > + > + rc = _sev_platform_init_locked(&init_args); > + if (rc) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + return rc; > + } > + > + *shutdown_required = true; > + > + return 0; > +} > + > +static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) > +{ > + int error, rc; > + > + rc = __sev_snp_init_locked(&error); > + if (rc) { > + argp->error = SEV_RET_INVALID_PLATFORM_STATE; > + return rc; > + } > + > + *shutdown_required = true; > + > + return 0; > +} > + > static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable) > { > int state, rc; > @@ -1454,24 +1487,31 @@ 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; > + bool shutdown_required = false; > int rc; > > if (!writable) > return -EPERM; > > if (sev->state == SEV_STATE_UNINIT) { > - rc = __sev_platform_init_locked(&argp->error); > + rc = sev_move_to_init_state(argp, &shutdown_required); > if (rc) > return rc; > } > > - return __sev_do_cmd_locked(cmd, NULL, &argp->error); > + rc = __sev_do_cmd_locked(cmd, NULL, &argp->error); > + > + if (shutdown_required) > + __sev_firmware_shutdown(sev, false); > + > + 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; > @@ -1503,7 +1543,7 @@ 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); > + ret = sev_move_to_init_state(argp, &shutdown_required); > if (ret) > goto e_free_blob; > } > @@ -1524,6 +1564,9 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) > } > > e_free_blob: > + if (shutdown_required) > + __sev_firmware_shutdown(sev, false); > + > kfree(blob); > return ret; > } > @@ -1743,6 +1786,7 @@ 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; > > @@ -1773,7 +1817,7 @@ 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); > + ret = sev_move_to_init_state(argp, &shutdown_required); > if (ret) > goto e_free_oca; > } > @@ -1781,6 +1825,9 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable) > ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, &data, &argp->error); > > e_free_oca: > + if (shutdown_required) > + __sev_firmware_shutdown(sev, false); > + > kfree(oca_blob); > e_free_pek: > kfree(pek_blob); > @@ -1897,18 +1944,9 @@ 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; > + bool shutdown_required = false; > 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; > - } > - > if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) > return -EFAULT; > > @@ -1948,6 +1986,17 @@ 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) { > + ret = -EPERM; > + goto e_free_cert; > + } > + ret = sev_move_to_init_state(argp, &shutdown_required); > + if (ret) > + goto e_free_cert; > + } > + > ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, &data, &argp->error); > > /* If we query the length, FW responded with expected data. */ > @@ -1974,6 +2023,9 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) > } > > e_free_cert: > + if (shutdown_required) > + __sev_firmware_shutdown(sev, false); > + > kfree(cert_blob); > e_free_pdh: > kfree(pdh_blob); > @@ -1983,12 +2035,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); > @@ -1997,6 +2050,12 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) > > data = page_address(status_page); > > + if (!sev->snp_initialized) { > + ret = snp_move_to_init_state(argp, &shutdown_required); > + if (ret) > + goto cleanup; > + } > + > /* > * Firmware expects status page to be in firmware-owned state, otherwise > * it will report firmware error code INVALID_PAGE_STATE (0x1A). > @@ -2025,6 +2084,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; > } > @@ -2033,21 +2095,33 @@ 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 = snp_move_to_init_state(argp, &shutdown_required); > + if (ret) > + return ret; > + } > > 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) > @@ -2056,17 +2130,29 @@ 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 = snp_move_to_init_state(argp, &shutdown_required); > + if (ret) > + return ret; > + } > + > + 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) > @@ -2085,8 +2171,18 @@ 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 = snp_move_to_init_state(argp, &shutdown_required); > + if (ret) > + goto cleanup; > + } > + > 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;