diff mbox series

[v2,1/6] x86/tdx: Add TDREPORT TDX Module call support

Message ID 20210707204249.3046665-2-sathyanarayanan.kuppuswamy@linux.intel.com
State New
Headers show
Series [v2,1/6] x86/tdx: Add TDREPORT TDX Module call support | expand

Commit Message

Kuppuswamy Sathyanarayanan July 7, 2021, 8:42 p.m. UTC
The TDX Guest-Host Communication Interface (GHCI) includes a module
call (TDREPORT TDCALL) that a guest can make to acquire a copy of the
attestation data that it needs to verify its trustworthiness.

Add a wrapper function tdx_mcall_tdreport() that makes the module
call to get this data.

See GHCI section 2.4.5 "TDCALL [TDG.MR.REPORT] leaf" for additional
details.

[Xiaoyao: Proposed error code fix]
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 arch/x86/include/asm/tdx.h |  2 ++
 arch/x86/kernel/tdx.c      | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

Comments

Xiaoyao Li July 8, 2021, 8:16 a.m. UTC | #1
On 7/8/2021 4:42 AM, Kuppuswamy Sathyanarayanan wrote:
> The TDX Guest-Host Communication Interface (GHCI) includes a module

> call (TDREPORT TDCALL) that a guest can make to acquire a copy of the

> attestation data that it needs to verify its trustworthiness.

> 

> Add a wrapper function tdx_mcall_tdreport() that makes the module

> call to get this data.

> 

> See GHCI section 2.4.5 "TDCALL [TDG.MR.REPORT] leaf" for additional

> details.

> 

> [Xiaoyao: Proposed error code fix]

> Reviewed-by: Tony Luck <tony.luck@intel.com>

> Reviewed-by: Andi Kleen <ak@linux.intel.com>

> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

> ---

>   arch/x86/include/asm/tdx.h |  2 ++

>   arch/x86/kernel/tdx.c      | 33 +++++++++++++++++++++++++++++++++

>   2 files changed, 35 insertions(+)

> 

> diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h

> index 48927fac9e12..4f1b5c14a09b 100644

> --- a/arch/x86/include/asm/tdx.h

> +++ b/arch/x86/include/asm/tdx.h

> @@ -96,6 +96,8 @@ extern int tdx_hcall_gpa_intent(phys_addr_t gpa, int numpages,

>   

>   bool tdg_filter_enabled(void);

>   

> +int tdx_mcall_tdreport(u64 data, u64 reportdata);

> +

>   /*

>    * To support I/O port access in decompressor or early kernel init

>    * code, since #VE exception handler cannot be used, use paravirt

> diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c

> index f76af7661046..0f797803f4c8 100644

> --- a/arch/x86/kernel/tdx.c

> +++ b/arch/x86/kernel/tdx.c

> @@ -23,6 +23,7 @@

>   /* TDX Module call Leaf IDs */

>   #define TDINFO				1

>   #define TDGETVEINFO			3

> +#define TDREPORT			4

>   #define TDACCEPTPAGE			6

>   

>   /* TDX hypercall Leaf IDs */

> @@ -30,6 +31,11 @@

>   

>   /* TDX Module call error codes */

>   #define TDX_PAGE_ALREADY_ACCEPTED       0x8000000000000001

> +#define TDCALL_RETURN_CODE_MASK		0xFFFFFFFF00000000

> +#define TDCALL_OPERAND_BUSY		0x8000020000000000

> +#define TDCALL_INVALID_OPERAND		0x8000000000000000

> +#define TDCALL_RETURN_CODE(a)		((a) & TDCALL_RETURN_CODE_MASK)

> +

>   

>   #define VE_IS_IO_OUT(exit_qual)		(((exit_qual) & 8) ? 0 : 1)

>   #define VE_GET_IO_SIZE(exit_qual)	(((exit_qual) & 7) + 1)

> @@ -139,6 +145,33 @@ static bool tdg_perfmon_enabled(void)

>   	return td_info.attributes & BIT(63);

>   }

>   

> +/*

> + * tdx_mcall_tdreport() - Generate TDREPORT_STRUCT using TDCALL.

> + *

> + * @data        : Physical address of 1024B aligned data to store

> + *                TDREPORT_STRUCT.

> + * @reportdata  : Physical address of 64B aligned report data

> + *

> + * return 0 on success or failure error number.

> + */

> +int tdx_mcall_tdreport(u64 data, u64 reportdata)

> +{

> +	u64 ret;

> +

> +	if (!data || !reportdata || !prot_guest_has(PR_GUEST_TDX))

> +		return -EINVAL;

> +

> +	ret = __trace_tdx_module_call(TDREPORT, data, reportdata, 0, 0, NULL);

> +

> +	if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)

> +		return -EINVAL;

> +	else if (TDCALL_RETURN_CODE(ret) == TDCALL_OPERAND_BUSY)

> +		return -EBUSY;


Sorry I guess I didn't state it clearly during internal review.

I suggest something like this

if (ret != TDCALL_SUCCESS) {
	if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)
		return -EINVAL;
	else if (TDCALL_RETURN_CODE(ret) == TDCALL_OPERAND_BUSY)
		return -EBUSY;
	else
		return -EFAULT; //I'm not sure if -EFAULT is proper.
}

> +	return 0;

> +}

> +EXPORT_SYMBOL_GPL(tdx_mcall_tdreport);

> +

>   static void tdg_get_info(void)

>   {

>   	u64 ret;

>
Kuppuswamy Sathyanarayanan July 8, 2021, 2:07 p.m. UTC | #2
On 7/8/21 1:16 AM, Xiaoyao Li wrote:
> 

> Sorry I guess I didn't state it clearly during internal review.

> 

> I suggest something like this

> 

> if (ret != TDCALL_SUCCESS) {

>      if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)

>          return -EINVAL;

>      else if (TDCALL_RETURN_CODE(ret) == TDCALL_OPERAND_BUSY)

>          return -EBUSY;

>      else

>          return -EFAULT; //I'm not sure if -EFAULT is proper.

> }


As per current spec, TDCALL_INVALID_OPERAND, TDCALL_OPERAND_BUSY and
0 are the only possible return values. So I have checked for failure case
in if condition and returned success by default. Any reason for specifically
checking for success code ?

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer
Hans de Goede July 8, 2021, 2:20 p.m. UTC | #3
Hi,

On 7/8/21 4:07 PM, Kuppuswamy, Sathyanarayanan wrote:
> 

> 

> On 7/8/21 1:16 AM, Xiaoyao Li wrote:

>>

>> Sorry I guess I didn't state it clearly during internal review.

>>

>> I suggest something like this

>>

>> if (ret != TDCALL_SUCCESS) {

>>      if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)

>>          return -EINVAL;

>>      else if (TDCALL_RETURN_CODE(ret) == TDCALL_OPERAND_BUSY)

>>          return -EBUSY;

>>      else

>>          return -EFAULT; //I'm not sure if -EFAULT is proper.

>> }

> 

> As per current spec, TDCALL_INVALID_OPERAND, TDCALL_OPERAND_BUSY and

> 0 are the only possible return values. So I have checked for failure case

> in if condition and returned success by default. Any reason for specifically

> checking for success code ?


Yes, new error codes might be introduced and you might forget to
update this (or other) checks.

Checking for errors really MUST always be done by checking for
ret != success (typically ret != 0 or ret < 0).

Only checking for known error codes means that if somehow an
unknown error code gets thrown this gets treated as success,
which is not acceptable behavior.

Regards,

Hans
Kuppuswamy Sathyanarayanan July 8, 2021, 5:06 p.m. UTC | #4
On 7/8/21 7:20 AM, Hans de Goede wrote:
> Yes, new error codes might be introduced and you might forget to

> update this (or other) checks.

> 

> Checking for errors really MUST always be done by checking for

> ret != success (typically ret != 0 or ret < 0).

> 

> Only checking for known error codes means that if somehow an

> unknown error code gets thrown this gets treated as success,

> which is not acceptable behavior.


Got it. I will include this change in next version.

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer
diff mbox series

Patch

diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 48927fac9e12..4f1b5c14a09b 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -96,6 +96,8 @@  extern int tdx_hcall_gpa_intent(phys_addr_t gpa, int numpages,
 
 bool tdg_filter_enabled(void);
 
+int tdx_mcall_tdreport(u64 data, u64 reportdata);
+
 /*
  * To support I/O port access in decompressor or early kernel init
  * code, since #VE exception handler cannot be used, use paravirt
diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c
index f76af7661046..0f797803f4c8 100644
--- a/arch/x86/kernel/tdx.c
+++ b/arch/x86/kernel/tdx.c
@@ -23,6 +23,7 @@ 
 /* TDX Module call Leaf IDs */
 #define TDINFO				1
 #define TDGETVEINFO			3
+#define TDREPORT			4
 #define TDACCEPTPAGE			6
 
 /* TDX hypercall Leaf IDs */
@@ -30,6 +31,11 @@ 
 
 /* TDX Module call error codes */
 #define TDX_PAGE_ALREADY_ACCEPTED       0x8000000000000001
+#define TDCALL_RETURN_CODE_MASK		0xFFFFFFFF00000000
+#define TDCALL_OPERAND_BUSY		0x8000020000000000
+#define TDCALL_INVALID_OPERAND		0x8000000000000000
+#define TDCALL_RETURN_CODE(a)		((a) & TDCALL_RETURN_CODE_MASK)
+
 
 #define VE_IS_IO_OUT(exit_qual)		(((exit_qual) & 8) ? 0 : 1)
 #define VE_GET_IO_SIZE(exit_qual)	(((exit_qual) & 7) + 1)
@@ -139,6 +145,33 @@  static bool tdg_perfmon_enabled(void)
 	return td_info.attributes & BIT(63);
 }
 
+/*
+ * tdx_mcall_tdreport() - Generate TDREPORT_STRUCT using TDCALL.
+ *
+ * @data        : Physical address of 1024B aligned data to store
+ *                TDREPORT_STRUCT.
+ * @reportdata  : Physical address of 64B aligned report data
+ *
+ * return 0 on success or failure error number.
+ */
+int tdx_mcall_tdreport(u64 data, u64 reportdata)
+{
+	u64 ret;
+
+	if (!data || !reportdata || !prot_guest_has(PR_GUEST_TDX))
+		return -EINVAL;
+
+	ret = __trace_tdx_module_call(TDREPORT, data, reportdata, 0, 0, NULL);
+
+	if (TDCALL_RETURN_CODE(ret) == TDCALL_INVALID_OPERAND)
+		return -EINVAL;
+	else if (TDCALL_RETURN_CODE(ret) == TDCALL_OPERAND_BUSY)
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tdx_mcall_tdreport);
+
 static void tdg_get_info(void)
 {
 	u64 ret;