diff mbox series

[v2] crypto: ccp: Add support for SEV-ES to the PSP driver

Message ID 9530369b1f0be211ae2512a1ab9f54281a4420d9.1587491088.git.thomas.lendacky@amd.com (mailing list archive)
State Accepted
Delegated to: Herbert Xu
Headers show
Series [v2] crypto: ccp: Add support for SEV-ES to the PSP driver | expand

Commit Message

Tom Lendacky April 21, 2020, 5:44 p.m. UTC
To provide support for SEV-ES, the hypervisor must provide an area of
memory to the PSP. Once this Trusted Memory Region (TMR) is provided to
the PSP, the contents of this area of memory are no longer available to
the x86.

Update the PSP driver to allocate a 1MB region for the TMR that is 1MB
aligned and then provide it to the PSP through the SEV INIT command.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>

---

Changes since v1:
- No need to over-allocate the memory area to obtain the required
  alignment when using the page allocator.
---
 drivers/crypto/ccp/sev-dev.c | 43 ++++++++++++++++++++++++++++++++++++
 include/linux/psp-sev.h      |  2 ++
 include/uapi/linux/psp-sev.h |  2 ++
 3 files changed, 47 insertions(+)

Comments

Brijesh Singh April 22, 2020, 3:11 p.m. UTC | #1
On 4/21/20 12:44 PM, Tom Lendacky wrote:
> To provide support for SEV-ES, the hypervisor must provide an area of
> memory to the PSP. Once this Trusted Memory Region (TMR) is provided to
> the PSP, the contents of this area of memory are no longer available to
> the x86.
>
> Update the PSP driver to allocate a 1MB region for the TMR that is 1MB
> aligned and then provide it to the PSP through the SEV INIT command.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
>
> ---


Reviewed-by: Brijesh Singh <brijesh.singh@amd.com>


> Changes since v1:
> - No need to over-allocate the memory area to obtain the required
>   alignment when using the page allocator.
> ---
>  drivers/crypto/ccp/sev-dev.c | 43 ++++++++++++++++++++++++++++++++++++
>  include/linux/psp-sev.h      |  2 ++
>  include/uapi/linux/psp-sev.h |  2 ++
>  3 files changed, 47 insertions(+)
>
> diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
> index 896f190b9a50..439cd737076e 100644
> --- a/drivers/crypto/ccp/sev-dev.c
> +++ b/drivers/crypto/ccp/sev-dev.c
> @@ -20,6 +20,7 @@
>  #include <linux/hw_random.h>
>  #include <linux/ccp.h>
>  #include <linux/firmware.h>
> +#include <linux/gfp.h>
>  
>  #include <asm/smp.h>
>  
> @@ -44,6 +45,14 @@ MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during
>  static bool psp_dead;
>  static int psp_timeout;
>  
> +/* Trusted Memory Region (TMR):
> + *   The TMR is a 1MB area that must be 1MB aligned.  Use the page allocator
> + *   to allocate the memory, which will return aligned memory for the specified
> + *   allocation order.
> + */
> +#define SEV_ES_TMR_SIZE		(1024 * 1024)
> +static void *sev_es_tmr;
> +
>  static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
>  {
>  	struct sev_device *sev = psp_master->sev_data;
> @@ -214,6 +223,20 @@ static int __sev_platform_init_locked(int *error)
>  	if (sev->state == SEV_STATE_INIT)
>  		return 0;
>  
> +	if (sev_es_tmr) {
> +		u64 tmr_pa;
> +
> +		/*
> +		 * Do not include the encryption mask on the physical
> +		 * address of the TMR (firmware should clear it anyway).
> +		 */
> +		tmr_pa = __pa(sev_es_tmr);
> +
> +		sev->init_cmd_buf.flags |= SEV_INIT_FLAGS_SEV_ES;
> +		sev->init_cmd_buf.tmr_address = tmr_pa;
> +		sev->init_cmd_buf.tmr_len = SEV_ES_TMR_SIZE;
> +	}
> +
>  	rc = __sev_do_cmd_locked(SEV_CMD_INIT, &sev->init_cmd_buf, error);
>  	if (rc)
>  		return rc;
> @@ -1012,6 +1035,7 @@ EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
>  void sev_pci_init(void)
>  {
>  	struct sev_device *sev = psp_master->sev_data;
> +	struct page *tmr_page;
>  	int error, rc;
>  
>  	if (!sev)
> @@ -1041,6 +1065,16 @@ void sev_pci_init(void)
>  	    sev_update_firmware(sev->dev) == 0)
>  		sev_get_api_version();
>  
> +	/* Obtain the TMR memory area for SEV-ES use */
> +	tmr_page = alloc_pages(GFP_KERNEL, get_order(SEV_ES_TMR_SIZE));
> +	if (tmr_page) {
> +		sev_es_tmr = page_address(tmr_page);
> +	} else {
> +		sev_es_tmr = NULL;
> +		dev_warn(sev->dev,
> +			 "SEV: TMR allocation failed, SEV-ES support unavailable\n");
> +	}
> +
>  	/* Initialize the platform */
>  	rc = sev_platform_init(&error);
>  	if (rc && (error == SEV_RET_SECURE_DATA_INVALID)) {
> @@ -1075,4 +1109,13 @@ void sev_pci_exit(void)
>  		return;
>  
>  	sev_platform_shutdown(NULL);
> +
> +	if (sev_es_tmr) {
> +		/* The TMR area was encrypted, flush it from the cache */
> +		wbinvd_on_all_cpus();
> +
> +		free_pages((unsigned long)sev_es_tmr,
> +			   get_order(SEV_ES_TMR_SIZE));
> +		sev_es_tmr = NULL;
> +	}
>  }
> diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h
> index 5167bf2bfc75..7fbc8679145c 100644
> --- a/include/linux/psp-sev.h
> +++ b/include/linux/psp-sev.h
> @@ -100,6 +100,8 @@ struct sev_data_init {
>  	u32 tmr_len;			/* In */
>  } __packed;
>  
> +#define SEV_INIT_FLAGS_SEV_ES	0x01
> +
>  /**
>   * struct sev_data_pek_csr - PEK_CSR command parameters
>   *
> diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h
> index 0549a5c622bf..91b4c63d5cbf 100644
> --- a/include/uapi/linux/psp-sev.h
> +++ b/include/uapi/linux/psp-sev.h
> @@ -83,6 +83,8 @@ struct sev_user_data_status {
>  	__u32 guest_count;			/* Out */
>  } __packed;
>  
> +#define SEV_STATUS_FLAGS_CONFIG_ES	0x0100
> +
>  /**
>   * struct sev_user_data_pek_csr - PEK_CSR command parameters
>   *
Joerg Roedel April 29, 2020, 11:23 a.m. UTC | #2
On Tue, Apr 21, 2020 at 12:44:49PM -0500, Tom Lendacky wrote:
> To provide support for SEV-ES, the hypervisor must provide an area of
> memory to the PSP. Once this Trusted Memory Region (TMR) is provided to
> the PSP, the contents of this area of memory are no longer available to
> the x86.
> 
> Update the PSP driver to allocate a 1MB region for the TMR that is 1MB
> aligned and then provide it to the PSP through the SEV INIT command.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> 
> ---
> 
> Changes since v1:
> - No need to over-allocate the memory area to obtain the required
>   alignment when using the page allocator.

Reviewed-by: Joerg Roedel <jroedel@suse.de>
Herbert Xu April 30, 2020, 5:29 a.m. UTC | #3
On Tue, Apr 21, 2020 at 12:44:49PM -0500, Tom Lendacky wrote:
> To provide support for SEV-ES, the hypervisor must provide an area of
> memory to the PSP. Once this Trusted Memory Region (TMR) is provided to
> the PSP, the contents of this area of memory are no longer available to
> the x86.
> 
> Update the PSP driver to allocate a 1MB region for the TMR that is 1MB
> aligned and then provide it to the PSP through the SEV INIT command.
> 
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
> 
> ---
> 
> Changes since v1:
> - No need to over-allocate the memory area to obtain the required
>   alignment when using the page allocator.
> ---
>  drivers/crypto/ccp/sev-dev.c | 43 ++++++++++++++++++++++++++++++++++++
>  include/linux/psp-sev.h      |  2 ++
>  include/uapi/linux/psp-sev.h |  2 ++
>  3 files changed, 47 insertions(+)

Patch applied.  Thanks.
diff mbox series

Patch

diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 896f190b9a50..439cd737076e 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -20,6 +20,7 @@ 
 #include <linux/hw_random.h>
 #include <linux/ccp.h>
 #include <linux/firmware.h>
+#include <linux/gfp.h>
 
 #include <asm/smp.h>
 
@@ -44,6 +45,14 @@  MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during
 static bool psp_dead;
 static int psp_timeout;
 
+/* Trusted Memory Region (TMR):
+ *   The TMR is a 1MB area that must be 1MB aligned.  Use the page allocator
+ *   to allocate the memory, which will return aligned memory for the specified
+ *   allocation order.
+ */
+#define SEV_ES_TMR_SIZE		(1024 * 1024)
+static void *sev_es_tmr;
+
 static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
 {
 	struct sev_device *sev = psp_master->sev_data;
@@ -214,6 +223,20 @@  static int __sev_platform_init_locked(int *error)
 	if (sev->state == SEV_STATE_INIT)
 		return 0;
 
+	if (sev_es_tmr) {
+		u64 tmr_pa;
+
+		/*
+		 * Do not include the encryption mask on the physical
+		 * address of the TMR (firmware should clear it anyway).
+		 */
+		tmr_pa = __pa(sev_es_tmr);
+
+		sev->init_cmd_buf.flags |= SEV_INIT_FLAGS_SEV_ES;
+		sev->init_cmd_buf.tmr_address = tmr_pa;
+		sev->init_cmd_buf.tmr_len = SEV_ES_TMR_SIZE;
+	}
+
 	rc = __sev_do_cmd_locked(SEV_CMD_INIT, &sev->init_cmd_buf, error);
 	if (rc)
 		return rc;
@@ -1012,6 +1035,7 @@  EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
 void sev_pci_init(void)
 {
 	struct sev_device *sev = psp_master->sev_data;
+	struct page *tmr_page;
 	int error, rc;
 
 	if (!sev)
@@ -1041,6 +1065,16 @@  void sev_pci_init(void)
 	    sev_update_firmware(sev->dev) == 0)
 		sev_get_api_version();
 
+	/* Obtain the TMR memory area for SEV-ES use */
+	tmr_page = alloc_pages(GFP_KERNEL, get_order(SEV_ES_TMR_SIZE));
+	if (tmr_page) {
+		sev_es_tmr = page_address(tmr_page);
+	} else {
+		sev_es_tmr = NULL;
+		dev_warn(sev->dev,
+			 "SEV: TMR allocation failed, SEV-ES support unavailable\n");
+	}
+
 	/* Initialize the platform */
 	rc = sev_platform_init(&error);
 	if (rc && (error == SEV_RET_SECURE_DATA_INVALID)) {
@@ -1075,4 +1109,13 @@  void sev_pci_exit(void)
 		return;
 
 	sev_platform_shutdown(NULL);
+
+	if (sev_es_tmr) {
+		/* The TMR area was encrypted, flush it from the cache */
+		wbinvd_on_all_cpus();
+
+		free_pages((unsigned long)sev_es_tmr,
+			   get_order(SEV_ES_TMR_SIZE));
+		sev_es_tmr = NULL;
+	}
 }
diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h
index 5167bf2bfc75..7fbc8679145c 100644
--- a/include/linux/psp-sev.h
+++ b/include/linux/psp-sev.h
@@ -100,6 +100,8 @@  struct sev_data_init {
 	u32 tmr_len;			/* In */
 } __packed;
 
+#define SEV_INIT_FLAGS_SEV_ES	0x01
+
 /**
  * struct sev_data_pek_csr - PEK_CSR command parameters
  *
diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h
index 0549a5c622bf..91b4c63d5cbf 100644
--- a/include/uapi/linux/psp-sev.h
+++ b/include/uapi/linux/psp-sev.h
@@ -83,6 +83,8 @@  struct sev_user_data_status {
 	__u32 guest_count;			/* Out */
 } __packed;
 
+#define SEV_STATUS_FLAGS_CONFIG_ES	0x0100
+
 /**
  * struct sev_user_data_pek_csr - PEK_CSR command parameters
  *