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.
+ */
+ 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
/**
--
2.34.1
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 >>>> >>>> /**
© 2016 - 2024 Red Hat, Inc.