Message ID | 0f225b9d547694cc473ec14d90d1a821845534c3.1726602374.git.ashish.kalra@amd.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Herbert Xu |
Headers | show |
Series | Add SEV-SNP CipherTextHiding feature support | expand |
On 9/17/24 15:16, Ashish Kalra wrote: > From: Ashish Kalra <ashish.kalra@amd.com> > > The FEATURE_INFO command provides host and guests a programmatic means > to learn about the supported features of the currently loaded firmware. > FEATURE_INFO command leverages the same mechanism as the CPUID instruction. > Instead of using the CPUID instruction to retrieve Fn8000_0024, > software can use FEATURE_INFO. > > Host/Hypervisor would use the FEATURE_INFO command, while guests would > actually issue the CPUID instruction. > > The hypervisor can provide Fn8000_0024 values to the guest via the CPUID > page in SNP_LAUNCH_UPDATE. As with all CPUID output recorded in that page, > the hypervisor can filter Fn8000_0024. The firmware will examine > Fn8000_0024 and apply its CPUID policy. > > During CCP module initialization, after firmware update, the SNP > platform status and feature information from CPUID 0x8000_0024, > sub-function 0, are cached in the sev_device structure. > > Signed-off-by: Ashish Kalra <ashish.kalra@amd.com> > --- > drivers/crypto/ccp/sev-dev.c | 47 ++++++++++++++++++++++++++++++++++++ > drivers/crypto/ccp/sev-dev.h | 3 +++ > include/linux/psp-sev.h | 29 ++++++++++++++++++++++ > 3 files changed, 79 insertions(+) > > diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c > index af018afd9cd7..564daf748293 100644 > --- a/drivers/crypto/ccp/sev-dev.c > +++ b/drivers/crypto/ccp/sev-dev.c > @@ -223,6 +223,7 @@ static int sev_cmd_buffer_len(int cmd) > case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request); > case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); > case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); > + case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct snp_feature_info); > default: return 0; > } > > @@ -1063,6 +1064,50 @@ static void snp_set_hsave_pa(void *arg) > wrmsrl(MSR_VM_HSAVE_PA, 0); > } > > +static void snp_get_platform_data(void) > +{ > + struct sev_device *sev = psp_master->sev_data; > + struct sev_data_snp_feature_info snp_feat_info; > + struct snp_feature_info *feat_info; > + struct sev_data_snp_addr buf; > + int error = 0, rc; > + > + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) > + return; > + > + /* > + * The output buffer must be firmware page if SEV-SNP is > + * initialized. This comment is a little confusing relative to the "if" check that is performed. Add some more detail about what this check is for. But... would this ever need to be called after SNP_INIT? Would we want to call this again after, say, a DOWNLOAD_FIRMWARE command? Thanks, Tom > + */ > + if (sev->snp_initialized) > + return; > + > + buf.address = __psp_pa(&sev->snp_plat_status); > + rc = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &error); > + > + /* > + * Do feature discovery of the currently loaded firmware, > + * and cache feature information from CPUID 0x8000_0024, > + * sub-function 0. > + */ > + if (!rc && sev->snp_plat_status.feature_info) { > + /* > + * Use dynamically allocated structure for the SNP_FEATURE_INFO > + * command to handle any alignment and page boundary check > + * requirements. > + */ > + feat_info = kzalloc(sizeof(*feat_info), GFP_KERNEL); > + snp_feat_info.length = sizeof(snp_feat_info); > + snp_feat_info.ecx_in = 0; > + snp_feat_info.feature_info_paddr = __psp_pa(feat_info); > + > + rc = __sev_do_cmd_locked(SEV_CMD_SNP_FEATURE_INFO, &snp_feat_info, &error); > + if (!rc) > + sev->feat_info = *feat_info; > + kfree(feat_info); > + } > +} > + > static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) > { > struct sev_data_range_list *range_list = arg; > @@ -2415,6 +2460,8 @@ void sev_pci_init(void) > api_major, api_minor, build, > sev->api_major, sev->api_minor, sev->build); > > + snp_get_platform_data(); > + > /* Initialize the platform */ > args.probe = true; > rc = sev_platform_init(&args); > diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h > index 3e4e5574e88a..1c1a51e52d2b 100644 > --- a/drivers/crypto/ccp/sev-dev.h > +++ b/drivers/crypto/ccp/sev-dev.h > @@ -57,6 +57,9 @@ struct sev_device { > bool cmd_buf_backup_active; > > bool snp_initialized; > + > + struct sev_user_data_snp_status snp_plat_status; > + struct snp_feature_info feat_info; > }; > > int sev_dev_init(struct psp_device *psp); > diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h > index 903ddfea8585..6068a89839e1 100644 > --- a/include/linux/psp-sev.h > +++ b/include/linux/psp-sev.h > @@ -107,6 +107,7 @@ enum sev_cmd { > SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA, > SEV_CMD_SNP_COMMIT = 0x0CB, > SEV_CMD_SNP_VLEK_LOAD = 0x0CD, > + SEV_CMD_SNP_FEATURE_INFO = 0x0CE, > > SEV_CMD_MAX, > }; > @@ -812,6 +813,34 @@ struct sev_data_snp_commit { > u32 len; > } __packed; > > +/** > + * struct sev_data_snp_feature_info - SEV_SNP_FEATURE_INFO structure > + * > + * @length: len of the command buffer read by the PSP > + * @ecx_in: subfunction index > + * @feature_info_paddr : SPA of the FEATURE_INFO structure > + */ > +struct sev_data_snp_feature_info { > + u32 length; > + u32 ecx_in; > + u64 feature_info_paddr; > +} __packed; > + > +/** > + * struct feature_info - FEATURE_INFO structure > + * > + * @eax: output of SNP_FEATURE_INFO command > + * @ebx: output of SNP_FEATURE_INFO command > + * @ecx: output of SNP_FEATURE_INFO command > + * #edx: output of SNP_FEATURE_INFO command > + */ > +struct snp_feature_info { > + u32 eax; > + u32 ebx; > + u32 ecx; > + u32 edx; > +} __packed; > + > #ifdef CONFIG_CRYPTO_DEV_SP_PSP > > /**
On 10/2/24 16:18, Tom Lendacky wrote: > On 9/17/24 15:16, Ashish Kalra wrote: >> From: Ashish Kalra <ashish.kalra@amd.com> >> >> The FEATURE_INFO command provides host and guests a programmatic means >> to learn about the supported features of the currently loaded firmware. >> FEATURE_INFO command leverages the same mechanism as the CPUID instruction. >> Instead of using the CPUID instruction to retrieve Fn8000_0024, >> software can use FEATURE_INFO. >> >> Host/Hypervisor would use the FEATURE_INFO command, while guests would >> actually issue the CPUID instruction. >> >> The hypervisor can provide Fn8000_0024 values to the guest via the CPUID >> page in SNP_LAUNCH_UPDATE. As with all CPUID output recorded in that page, >> the hypervisor can filter Fn8000_0024. The firmware will examine >> Fn8000_0024 and apply its CPUID policy. >> >> During CCP module initialization, after firmware update, the SNP >> platform status and feature information from CPUID 0x8000_0024, >> sub-function 0, are cached in the sev_device structure. >> >> Signed-off-by: Ashish Kalra <ashish.kalra@amd.com> >> --- >> drivers/crypto/ccp/sev-dev.c | 47 ++++++++++++++++++++++++++++++++++++ >> drivers/crypto/ccp/sev-dev.h | 3 +++ >> include/linux/psp-sev.h | 29 ++++++++++++++++++++++ >> 3 files changed, 79 insertions(+) >> >> diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c >> index af018afd9cd7..564daf748293 100644 >> --- a/drivers/crypto/ccp/sev-dev.c >> +++ b/drivers/crypto/ccp/sev-dev.c >> @@ -223,6 +223,7 @@ static int sev_cmd_buffer_len(int cmd) >> case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request); >> case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); >> case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); >> + case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct snp_feature_info); >> default: return 0; >> } >> >> @@ -1063,6 +1064,50 @@ static void snp_set_hsave_pa(void *arg) >> wrmsrl(MSR_VM_HSAVE_PA, 0); >> } >> >> +static void snp_get_platform_data(void) >> +{ >> + struct sev_device *sev = psp_master->sev_data; >> + struct sev_data_snp_feature_info snp_feat_info; >> + struct snp_feature_info *feat_info; >> + struct sev_data_snp_addr buf; >> + int error = 0, rc; >> + >> + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) >> + return; >> + >> + /* >> + * The output buffer must be firmware page if SEV-SNP is >> + * initialized. > > This comment is a little confusing relative to the "if" check that is > performed. Add some more detail about what this check is for. > > But... would this ever need to be called after SNP_INIT? Would we want > to call this again after, say, a DOWNLOAD_FIRMWARE command? Although, as I hit send I realized that we only do DOWNLOAD_FIRMWARE before SNP is initialized (currently). Thanks, Tom > > Thanks, > Tom > >> + */ >> + if (sev->snp_initialized) >> + return; >> + >> + buf.address = __psp_pa(&sev->snp_plat_status); >> + rc = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &error); >> + >> + /* >> + * Do feature discovery of the currently loaded firmware, >> + * and cache feature information from CPUID 0x8000_0024, >> + * sub-function 0. >> + */ >> + if (!rc && sev->snp_plat_status.feature_info) { >> + /* >> + * Use dynamically allocated structure for the SNP_FEATURE_INFO >> + * command to handle any alignment and page boundary check >> + * requirements. >> + */ >> + feat_info = kzalloc(sizeof(*feat_info), GFP_KERNEL); >> + snp_feat_info.length = sizeof(snp_feat_info); >> + snp_feat_info.ecx_in = 0; >> + snp_feat_info.feature_info_paddr = __psp_pa(feat_info); >> + >> + rc = __sev_do_cmd_locked(SEV_CMD_SNP_FEATURE_INFO, &snp_feat_info, &error); >> + if (!rc) >> + sev->feat_info = *feat_info; >> + kfree(feat_info); >> + } >> +} >> + >> static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) >> { >> struct sev_data_range_list *range_list = arg; >> @@ -2415,6 +2460,8 @@ void sev_pci_init(void) >> api_major, api_minor, build, >> sev->api_major, sev->api_minor, sev->build); >> >> + snp_get_platform_data(); >> + >> /* Initialize the platform */ >> args.probe = true; >> rc = sev_platform_init(&args); >> diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h >> index 3e4e5574e88a..1c1a51e52d2b 100644 >> --- a/drivers/crypto/ccp/sev-dev.h >> +++ b/drivers/crypto/ccp/sev-dev.h >> @@ -57,6 +57,9 @@ struct sev_device { >> bool cmd_buf_backup_active; >> >> bool snp_initialized; >> + >> + struct sev_user_data_snp_status snp_plat_status; >> + struct snp_feature_info feat_info; >> }; >> >> int sev_dev_init(struct psp_device *psp); >> diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h >> index 903ddfea8585..6068a89839e1 100644 >> --- a/include/linux/psp-sev.h >> +++ b/include/linux/psp-sev.h >> @@ -107,6 +107,7 @@ enum sev_cmd { >> SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA, >> SEV_CMD_SNP_COMMIT = 0x0CB, >> SEV_CMD_SNP_VLEK_LOAD = 0x0CD, >> + SEV_CMD_SNP_FEATURE_INFO = 0x0CE, >> >> SEV_CMD_MAX, >> }; >> @@ -812,6 +813,34 @@ struct sev_data_snp_commit { >> u32 len; >> } __packed; >> >> +/** >> + * struct sev_data_snp_feature_info - SEV_SNP_FEATURE_INFO structure >> + * >> + * @length: len of the command buffer read by the PSP >> + * @ecx_in: subfunction index >> + * @feature_info_paddr : SPA of the FEATURE_INFO structure >> + */ >> +struct sev_data_snp_feature_info { >> + u32 length; >> + u32 ecx_in; >> + u64 feature_info_paddr; >> +} __packed; >> + >> +/** >> + * struct feature_info - FEATURE_INFO structure >> + * >> + * @eax: output of SNP_FEATURE_INFO command >> + * @ebx: output of SNP_FEATURE_INFO command >> + * @ecx: output of SNP_FEATURE_INFO command >> + * #edx: output of SNP_FEATURE_INFO command >> + */ >> +struct snp_feature_info { >> + u32 eax; >> + u32 ebx; >> + u32 ecx; >> + u32 edx; >> +} __packed; >> + >> #ifdef CONFIG_CRYPTO_DEV_SP_PSP >> >> /**
Hello Tom, On 10/2/2024 4:19 PM, Tom Lendacky wrote: > On 10/2/24 16:18, Tom Lendacky wrote: >> On 9/17/24 15:16, Ashish Kalra wrote: >>> From: Ashish Kalra <ashish.kalra@amd.com> >>> >>> The FEATURE_INFO command provides host and guests a programmatic means >>> to learn about the supported features of the currently loaded firmware. >>> FEATURE_INFO command leverages the same mechanism as the CPUID instruction. >>> Instead of using the CPUID instruction to retrieve Fn8000_0024, >>> software can use FEATURE_INFO. >>> >>> Host/Hypervisor would use the FEATURE_INFO command, while guests would >>> actually issue the CPUID instruction. >>> >>> The hypervisor can provide Fn8000_0024 values to the guest via the CPUID >>> page in SNP_LAUNCH_UPDATE. As with all CPUID output recorded in that page, >>> the hypervisor can filter Fn8000_0024. The firmware will examine >>> Fn8000_0024 and apply its CPUID policy. >>> >>> During CCP module initialization, after firmware update, the SNP >>> platform status and feature information from CPUID 0x8000_0024, >>> sub-function 0, are cached in the sev_device structure. >>> >>> Signed-off-by: Ashish Kalra <ashish.kalra@amd.com> >>> --- >>> drivers/crypto/ccp/sev-dev.c | 47 ++++++++++++++++++++++++++++++++++++ >>> drivers/crypto/ccp/sev-dev.h | 3 +++ >>> include/linux/psp-sev.h | 29 ++++++++++++++++++++++ >>> 3 files changed, 79 insertions(+) >>> >>> diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c >>> index af018afd9cd7..564daf748293 100644 >>> --- a/drivers/crypto/ccp/sev-dev.c >>> +++ b/drivers/crypto/ccp/sev-dev.c >>> @@ -223,6 +223,7 @@ static int sev_cmd_buffer_len(int cmd) >>> case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request); >>> case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); >>> case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); >>> + case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct snp_feature_info); >>> default: return 0; >>> } >>> >>> @@ -1063,6 +1064,50 @@ static void snp_set_hsave_pa(void *arg) >>> wrmsrl(MSR_VM_HSAVE_PA, 0); >>> } >>> >>> +static void snp_get_platform_data(void) >>> +{ >>> + struct sev_device *sev = psp_master->sev_data; >>> + struct sev_data_snp_feature_info snp_feat_info; >>> + struct snp_feature_info *feat_info; >>> + struct sev_data_snp_addr buf; >>> + int error = 0, rc; >>> + >>> + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) >>> + return; >>> + >>> + /* >>> + * The output buffer must be firmware page if SEV-SNP is >>> + * initialized. >> This comment is a little confusing relative to the "if" check that is >> performed. Add some more detail about what this check is for. >> >> But... would this ever need to be called after SNP_INIT? Would we want >> to call this again after, say, a DOWNLOAD_FIRMWARE command? > Although, as I hit send I realized that we only do DOWNLOAD_FIRMWARE > before SNP is initialized (currently). We do have DOWNLOAD_FIRMWARE_EX support coming up which can/will happen after SNP_INIT, but there we can still use SEV's PLATFORM_DATA command to get (updated) SEV/SNP firmware version. Thanks, Ashish > > Thanks, > Tom > >> Thanks, >> Tom >> >>> + */ >>> + if (sev->snp_initialized) >>> + return; >>> + >>> + buf.address = __psp_pa(&sev->snp_plat_status); >>> + rc = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &error); >>> + >>> + /* >>> + * Do feature discovery of the currently loaded firmware, >>> + * and cache feature information from CPUID 0x8000_0024, >>> + * sub-function 0. >>> + */ >>> + if (!rc && sev->snp_plat_status.feature_info) { >>> + /* >>> + * Use dynamically allocated structure for the SNP_FEATURE_INFO >>> + * command to handle any alignment and page boundary check >>> + * requirements. >>> + */ >>> + feat_info = kzalloc(sizeof(*feat_info), GFP_KERNEL); >>> + snp_feat_info.length = sizeof(snp_feat_info); >>> + snp_feat_info.ecx_in = 0; >>> + snp_feat_info.feature_info_paddr = __psp_pa(feat_info); >>> + >>> + rc = __sev_do_cmd_locked(SEV_CMD_SNP_FEATURE_INFO, &snp_feat_info, &error); >>> + if (!rc) >>> + sev->feat_info = *feat_info; >>> + kfree(feat_info); >>> + } >>> +} >>> + >>> static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) >>> { >>> struct sev_data_range_list *range_list = arg; >>> @@ -2415,6 +2460,8 @@ void sev_pci_init(void) >>> api_major, api_minor, build, >>> sev->api_major, sev->api_minor, sev->build); >>> >>> + snp_get_platform_data(); >>> + >>> /* Initialize the platform */ >>> args.probe = true; >>> rc = sev_platform_init(&args); >>> diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h >>> index 3e4e5574e88a..1c1a51e52d2b 100644 >>> --- a/drivers/crypto/ccp/sev-dev.h >>> +++ b/drivers/crypto/ccp/sev-dev.h >>> @@ -57,6 +57,9 @@ struct sev_device { >>> bool cmd_buf_backup_active; >>> >>> bool snp_initialized; >>> + >>> + struct sev_user_data_snp_status snp_plat_status; >>> + struct snp_feature_info feat_info; >>> }; >>> >>> int sev_dev_init(struct psp_device *psp); >>> diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h >>> index 903ddfea8585..6068a89839e1 100644 >>> --- a/include/linux/psp-sev.h >>> +++ b/include/linux/psp-sev.h >>> @@ -107,6 +107,7 @@ enum sev_cmd { >>> SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA, >>> SEV_CMD_SNP_COMMIT = 0x0CB, >>> SEV_CMD_SNP_VLEK_LOAD = 0x0CD, >>> + SEV_CMD_SNP_FEATURE_INFO = 0x0CE, >>> >>> SEV_CMD_MAX, >>> }; >>> @@ -812,6 +813,34 @@ struct sev_data_snp_commit { >>> u32 len; >>> } __packed; >>> >>> +/** >>> + * struct sev_data_snp_feature_info - SEV_SNP_FEATURE_INFO structure >>> + * >>> + * @length: len of the command buffer read by the PSP >>> + * @ecx_in: subfunction index >>> + * @feature_info_paddr : SPA of the FEATURE_INFO structure >>> + */ >>> +struct sev_data_snp_feature_info { >>> + u32 length; >>> + u32 ecx_in; >>> + u64 feature_info_paddr; >>> +} __packed; >>> + >>> +/** >>> + * struct feature_info - FEATURE_INFO structure >>> + * >>> + * @eax: output of SNP_FEATURE_INFO command >>> + * @ebx: output of SNP_FEATURE_INFO command >>> + * @ecx: output of SNP_FEATURE_INFO command >>> + * #edx: output of SNP_FEATURE_INFO command >>> + */ >>> +struct snp_feature_info { >>> + u32 eax; >>> + u32 ebx; >>> + u32 ecx; >>> + u32 edx; >>> +} __packed; >>> + >>> #ifdef CONFIG_CRYPTO_DEV_SP_PSP >>> >>> /**
On 10/2/24 16:40, Kalra, Ashish wrote: > Hello Tom, > > On 10/2/2024 4:19 PM, Tom Lendacky wrote: >> On 10/2/24 16:18, Tom Lendacky wrote: >>> On 9/17/24 15:16, Ashish Kalra wrote: >>>> From: Ashish Kalra <ashish.kalra@amd.com> >>>> >>>> The FEATURE_INFO command provides host and guests a programmatic means >>>> to learn about the supported features of the currently loaded firmware. >>>> FEATURE_INFO command leverages the same mechanism as the CPUID instruction. >>>> Instead of using the CPUID instruction to retrieve Fn8000_0024, >>>> software can use FEATURE_INFO. >>>> >>>> Host/Hypervisor would use the FEATURE_INFO command, while guests would >>>> actually issue the CPUID instruction. >>>> >>>> The hypervisor can provide Fn8000_0024 values to the guest via the CPUID >>>> page in SNP_LAUNCH_UPDATE. As with all CPUID output recorded in that page, >>>> the hypervisor can filter Fn8000_0024. The firmware will examine >>>> Fn8000_0024 and apply its CPUID policy. >>>> >>>> During CCP module initialization, after firmware update, the SNP >>>> platform status and feature information from CPUID 0x8000_0024, >>>> sub-function 0, are cached in the sev_device structure. >>>> >>>> Signed-off-by: Ashish Kalra <ashish.kalra@amd.com> >>>> --- >>>> drivers/crypto/ccp/sev-dev.c | 47 ++++++++++++++++++++++++++++++++++++ >>>> drivers/crypto/ccp/sev-dev.h | 3 +++ >>>> include/linux/psp-sev.h | 29 ++++++++++++++++++++++ >>>> 3 files changed, 79 insertions(+) >>>> >>>> diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c >>>> index af018afd9cd7..564daf748293 100644 >>>> --- a/drivers/crypto/ccp/sev-dev.c >>>> +++ b/drivers/crypto/ccp/sev-dev.c >>>> @@ -223,6 +223,7 @@ static int sev_cmd_buffer_len(int cmd) >>>> case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request); >>>> case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); >>>> case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); >>>> + case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct snp_feature_info); >>>> default: return 0; >>>> } >>>> >>>> @@ -1063,6 +1064,50 @@ static void snp_set_hsave_pa(void *arg) >>>> wrmsrl(MSR_VM_HSAVE_PA, 0); >>>> } >>>> >>>> +static void snp_get_platform_data(void) >>>> +{ >>>> + struct sev_device *sev = psp_master->sev_data; >>>> + struct sev_data_snp_feature_info snp_feat_info; >>>> + struct snp_feature_info *feat_info; >>>> + struct sev_data_snp_addr buf; >>>> + int error = 0, rc; >>>> + >>>> + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) >>>> + return; >>>> + >>>> + /* >>>> + * The output buffer must be firmware page if SEV-SNP is >>>> + * initialized. >>> This comment is a little confusing relative to the "if" check that is >>> performed. Add some more detail about what this check is for. >>> >>> But... would this ever need to be called after SNP_INIT? Would we want >>> to call this again after, say, a DOWNLOAD_FIRMWARE command? >> Although, as I hit send I realized that we only do DOWNLOAD_FIRMWARE >> before SNP is initialized (currently). > > We do have DOWNLOAD_FIRMWARE_EX support coming up which can/will happen after SNP_INIT, but there we can still use SEV's PLATFORM_DATA command to get (updated) SEV/SNP firmware version. But you probably also want to get updated platform data, too. So I would think you would want to be able to call this routine again, post SNP_INIT. Thanks, Tom > > Thanks, Ashish > >> >> Thanks, >> Tom >> >>> Thanks, >>> Tom >>> >>>> + */ >>>> + if (sev->snp_initialized) >>>> + return; >>>> + >>>> + buf.address = __psp_pa(&sev->snp_plat_status); >>>> + rc = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &error); >>>> + >>>> + /* >>>> + * Do feature discovery of the currently loaded firmware, >>>> + * and cache feature information from CPUID 0x8000_0024, >>>> + * sub-function 0. >>>> + */ >>>> + if (!rc && sev->snp_plat_status.feature_info) { >>>> + /* >>>> + * Use dynamically allocated structure for the SNP_FEATURE_INFO >>>> + * command to handle any alignment and page boundary check >>>> + * requirements. >>>> + */ >>>> + feat_info = kzalloc(sizeof(*feat_info), GFP_KERNEL); >>>> + snp_feat_info.length = sizeof(snp_feat_info); >>>> + snp_feat_info.ecx_in = 0; >>>> + snp_feat_info.feature_info_paddr = __psp_pa(feat_info); >>>> + >>>> + rc = __sev_do_cmd_locked(SEV_CMD_SNP_FEATURE_INFO, &snp_feat_info, &error); >>>> + if (!rc) >>>> + sev->feat_info = *feat_info; >>>> + kfree(feat_info); >>>> + } >>>> +} >>>> + >>>> static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) >>>> { >>>> struct sev_data_range_list *range_list = arg; >>>> @@ -2415,6 +2460,8 @@ void sev_pci_init(void) >>>> api_major, api_minor, build, >>>> sev->api_major, sev->api_minor, sev->build); >>>> >>>> + snp_get_platform_data(); >>>> + >>>> /* Initialize the platform */ >>>> args.probe = true; >>>> rc = sev_platform_init(&args); >>>> diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h >>>> index 3e4e5574e88a..1c1a51e52d2b 100644 >>>> --- a/drivers/crypto/ccp/sev-dev.h >>>> +++ b/drivers/crypto/ccp/sev-dev.h >>>> @@ -57,6 +57,9 @@ struct sev_device { >>>> bool cmd_buf_backup_active; >>>> >>>> bool snp_initialized; >>>> + >>>> + struct sev_user_data_snp_status snp_plat_status; >>>> + struct snp_feature_info feat_info; >>>> }; >>>> >>>> int sev_dev_init(struct psp_device *psp); >>>> diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h >>>> index 903ddfea8585..6068a89839e1 100644 >>>> --- a/include/linux/psp-sev.h >>>> +++ b/include/linux/psp-sev.h >>>> @@ -107,6 +107,7 @@ enum sev_cmd { >>>> SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA, >>>> SEV_CMD_SNP_COMMIT = 0x0CB, >>>> SEV_CMD_SNP_VLEK_LOAD = 0x0CD, >>>> + SEV_CMD_SNP_FEATURE_INFO = 0x0CE, >>>> >>>> SEV_CMD_MAX, >>>> }; >>>> @@ -812,6 +813,34 @@ struct sev_data_snp_commit { >>>> u32 len; >>>> } __packed; >>>> >>>> +/** >>>> + * struct sev_data_snp_feature_info - SEV_SNP_FEATURE_INFO structure >>>> + * >>>> + * @length: len of the command buffer read by the PSP >>>> + * @ecx_in: subfunction index >>>> + * @feature_info_paddr : SPA of the FEATURE_INFO structure >>>> + */ >>>> +struct sev_data_snp_feature_info { >>>> + u32 length; >>>> + u32 ecx_in; >>>> + u64 feature_info_paddr; >>>> +} __packed; >>>> + >>>> +/** >>>> + * struct feature_info - FEATURE_INFO structure >>>> + * >>>> + * @eax: output of SNP_FEATURE_INFO command >>>> + * @ebx: output of SNP_FEATURE_INFO command >>>> + * @ecx: output of SNP_FEATURE_INFO command >>>> + * #edx: output of SNP_FEATURE_INFO command >>>> + */ >>>> +struct snp_feature_info { >>>> + u32 eax; >>>> + u32 ebx; >>>> + u32 ecx; >>>> + u32 edx; >>>> +} __packed; >>>> + >>>> #ifdef CONFIG_CRYPTO_DEV_SP_PSP >>>> >>>> /**
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index af018afd9cd7..564daf748293 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -223,6 +223,7 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request); case SEV_CMD_SNP_CONFIG: return sizeof(struct sev_user_data_snp_config); case SEV_CMD_SNP_COMMIT: return sizeof(struct sev_data_snp_commit); + case SEV_CMD_SNP_FEATURE_INFO: return sizeof(struct snp_feature_info); default: return 0; } @@ -1063,6 +1064,50 @@ static void snp_set_hsave_pa(void *arg) wrmsrl(MSR_VM_HSAVE_PA, 0); } +static void snp_get_platform_data(void) +{ + struct sev_device *sev = psp_master->sev_data; + struct sev_data_snp_feature_info snp_feat_info; + struct snp_feature_info *feat_info; + struct sev_data_snp_addr buf; + int error = 0, rc; + + if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP)) + return; + + /* + * The output buffer must be firmware page if SEV-SNP is + * initialized. + */ + if (sev->snp_initialized) + return; + + buf.address = __psp_pa(&sev->snp_plat_status); + rc = __sev_do_cmd_locked(SEV_CMD_SNP_PLATFORM_STATUS, &buf, &error); + + /* + * Do feature discovery of the currently loaded firmware, + * and cache feature information from CPUID 0x8000_0024, + * sub-function 0. + */ + if (!rc && sev->snp_plat_status.feature_info) { + /* + * Use dynamically allocated structure for the SNP_FEATURE_INFO + * command to handle any alignment and page boundary check + * requirements. + */ + feat_info = kzalloc(sizeof(*feat_info), GFP_KERNEL); + snp_feat_info.length = sizeof(snp_feat_info); + snp_feat_info.ecx_in = 0; + snp_feat_info.feature_info_paddr = __psp_pa(feat_info); + + rc = __sev_do_cmd_locked(SEV_CMD_SNP_FEATURE_INFO, &snp_feat_info, &error); + if (!rc) + sev->feat_info = *feat_info; + kfree(feat_info); + } +} + static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg) { struct sev_data_range_list *range_list = arg; @@ -2415,6 +2460,8 @@ void sev_pci_init(void) api_major, api_minor, build, sev->api_major, sev->api_minor, sev->build); + snp_get_platform_data(); + /* Initialize the platform */ args.probe = true; rc = sev_platform_init(&args); diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h index 3e4e5574e88a..1c1a51e52d2b 100644 --- a/drivers/crypto/ccp/sev-dev.h +++ b/drivers/crypto/ccp/sev-dev.h @@ -57,6 +57,9 @@ struct sev_device { bool cmd_buf_backup_active; bool snp_initialized; + + struct sev_user_data_snp_status snp_plat_status; + struct snp_feature_info feat_info; }; int sev_dev_init(struct psp_device *psp); diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 903ddfea8585..6068a89839e1 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -107,6 +107,7 @@ enum sev_cmd { SEV_CMD_SNP_DOWNLOAD_FIRMWARE_EX = 0x0CA, SEV_CMD_SNP_COMMIT = 0x0CB, SEV_CMD_SNP_VLEK_LOAD = 0x0CD, + SEV_CMD_SNP_FEATURE_INFO = 0x0CE, SEV_CMD_MAX, }; @@ -812,6 +813,34 @@ struct sev_data_snp_commit { u32 len; } __packed; +/** + * struct sev_data_snp_feature_info - SEV_SNP_FEATURE_INFO structure + * + * @length: len of the command buffer read by the PSP + * @ecx_in: subfunction index + * @feature_info_paddr : SPA of the FEATURE_INFO structure + */ +struct sev_data_snp_feature_info { + u32 length; + u32 ecx_in; + u64 feature_info_paddr; +} __packed; + +/** + * struct feature_info - FEATURE_INFO structure + * + * @eax: output of SNP_FEATURE_INFO command + * @ebx: output of SNP_FEATURE_INFO command + * @ecx: output of SNP_FEATURE_INFO command + * #edx: output of SNP_FEATURE_INFO command + */ +struct snp_feature_info { + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; +} __packed; + #ifdef CONFIG_CRYPTO_DEV_SP_PSP /**