From nobody Sun May 10 15:02:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B8B92C433EF for ; Sun, 1 May 2022 18:35:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356643AbiEASjR (ORCPT ); Sun, 1 May 2022 14:39:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55458 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356324AbiEASi4 (ORCPT ); Sun, 1 May 2022 14:38:56 -0400 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 768381B789 for ; Sun, 1 May 2022 11:35:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1651430129; x=1682966129; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BP222DMTAYsPb0C55wfaMsufpYq0EZdPnY9TcKsxMHM=; b=ShC3SswV9LyLBeyWVRknHDMq0hR7jpsBbin+yZTPFq7PULIJI2ZHaDUH nwKczekB/nTlkdQ93LMlqRNtrMOr9zEuNFC5SpsQzl+oKouehwzqodGrI IIkSaQw7uXrh7tu+6dyndiCQXrG48Cx1LTbIVeDlf7ckMcRZrScRo4ep8 aTQVK85Hd3p17aKJWVIBrv45qQEWVgWiO9GzCpYpvO18LfrefLHkuJr0L JMHcWTdaFTJ3bkvM6Ay/61IEYNX3PQJQ+vbrQh89CfjHa/JYJPnzcEi38 9KlJuONC0mSy6uqt6t38cOc9WFk1VCxLhrmlvuitMqdgWCEdAKheiYieX w==; X-IronPort-AV: E=McAfee;i="6400,9594,10334"; a="247598668" X-IronPort-AV: E=Sophos;i="5.91,190,1647327600"; d="scan'208";a="247598668" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 May 2022 11:35:28 -0700 X-IronPort-AV: E=Sophos;i="5.91,190,1647327600"; d="scan'208";a="515731264" Received: from pghaisax-mobl1.amr.corp.intel.com (HELO skuppusw-desk1.home) ([10.209.85.28]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 May 2022 11:35:27 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org Cc: "H . Peter Anvin" , Kuppuswamy Sathyanarayanan , "Kirill A . Shutemov" , Tony Luck , Andi Kleen , Kai Huang , Wander Lairson Costa , Isaku Yamahata , marcelo.cerri@canonical.com, tim.gardner@canonical.com, khalid.elmously@canonical.com, philip.cox@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v5 1/3] x86/tdx: Add TDX Guest attestation interface driver Date: Sun, 1 May 2022 11:34:58 -0700 Message-Id: <20220501183500.2242828-2-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220501183500.2242828-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20220501183500.2242828-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In TDX guest, attestation is used to verify the trustworthiness of a TD to other entities before provisioning secrets to the TD. =C2=A0 =C2=A0 One usage example is, when a TD guest uses encrypted drive and if the decryption keys required to access the drive are stored in a secure 3rd party keyserver, the key server can use attestation to verify TD's trustworthiness and release the decryption keys to the TD. The attestation process consists of two steps: TDREPORT generation and Quote generation. TDREPORT (TDREPORT_STRUCT) is a fixed-size data structure generated by the TDX module which contains TD-specific information (such as TD measurements), platform security version, and the MAC to protect the integrity of the TDREPORT. The TD kernel uses TDCALL[TDG.MR.REPORT] to get the TDREPORT from the TDX module. A user-provided 64-Byte REPORTDATA is used as input and included in the TDREPORT. Typically it can be some nonce provided by attestation service so the TDREPORT can be verified uniquely. More details about TDREPORT can be found in Intel TDX Module specification, section titled "TDG.MR.REPORT Leaf". After getting the TDREPORT, the second step of the attestation process is to send the TDREPORT to Quoting Enclave (QE) or Quote Generation Service (QGS) to generate the Quote. However the method of sending the TDREPORT to QE/QGS, communication channel used and data format used is specific to the implementation of QE/QGS. A typical implementation is, TD userspace attestation software gets the TDREPORT from TD kernel, sends it to QE/QGS, and QE/QGS returns the Quote. TD attestation software can use any available communication channel to talk to QE/QGS, such as using vsock and tcp/ip. To support the case that those communication channels are not directly available to the TD, TDX also defines TDVMCALLs to allow TD to ask VMM to help with sending the TDREPORT and receiving the Quote. This support is documented in the GHCI spec section titled "5.4 TD attestation". Implement a basic attestation driver to allow TD userspace to get the TDREPORT, which is sent to QE by the attestation software to generate a Quote for remote verification. Also note that explicit access permissions are not enforced in this driver because the quote and measurements are not a secret. However the access permissions of the device node can be used to set any desired access policy. The udev default is usually root access only. Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Acked-by: Kirill A. Shutemov Signed-off-by: Kuppuswamy Sathyanarayanan --- arch/x86/coco/tdx/Makefile | 2 +- arch/x86/coco/tdx/attest.c | 138 ++++++++++++++++++++++++++++++++ arch/x86/include/uapi/asm/tdx.h | 36 +++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 arch/x86/coco/tdx/attest.c create mode 100644 arch/x86/include/uapi/asm/tdx.h diff --git a/arch/x86/coco/tdx/Makefile b/arch/x86/coco/tdx/Makefile index 46c55998557d..d2db3e6770e5 100644 --- a/arch/x86/coco/tdx/Makefile +++ b/arch/x86/coco/tdx/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 =20 -obj-y +=3D tdx.o tdcall.o +obj-y +=3D tdx.o tdcall.o attest.o diff --git a/arch/x86/coco/tdx/attest.c b/arch/x86/coco/tdx/attest.c new file mode 100644 index 000000000000..4543a0264ce7 --- /dev/null +++ b/arch/x86/coco/tdx/attest.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * attest.c - TDX guest attestation interface driver. + * + * Implements user interface to trigger attestation process. + * + * Copyright (C) 2022 Intel Corporation + * + */ + +#define pr_fmt(fmt) "x86/tdx: attest: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "tdx-attest" + +/* TDREPORT module call leaf ID */ +#define TDX_GET_REPORT 4 + +/* Upper 32 bits has the status code, so mask it */ +#define TDCALL_STATUS_CODE_MASK 0xffffffff00000000 +#define TDCALL_STATUS_CODE(a) ((a) & TDCALL_STATUS_CODE_MASK) + +static struct miscdevice miscdev; + +static long tdx_get_report(void __user *argp) +{ + void *reportdata =3D NULL, *tdreport =3D NULL; + long ret =3D 0; + + /* Allocate buffer space for REPORTDATA */ + reportdata =3D kmalloc(TDX_REPORTDATA_LEN, GFP_KERNEL); + if (!reportdata) + return -ENOMEM; + + /* Allocate buffer space for TDREPORT */ + tdreport =3D kmalloc(TDX_REPORT_LEN, GFP_KERNEL); + if (!tdreport) { + ret =3D -ENOMEM; + goto failed; + } + + /* Copy REPORTDATA from the user buffer */ + if (copy_from_user(reportdata, argp, TDX_REPORTDATA_LEN)) { + ret =3D -EFAULT; + goto failed; + } + + /* + * Generate TDREPORT using "TDG.MR.REPORT" TDCALL. + * + * Pass the physical address of user generated REPORTDATA + * and the physical address of the output buffer to the TDX + * module to generate the TDREPORT. Generated data contains + * measurements/configuration data of the TD guest. More info + * about ABI can be found in TDX 1.0 Module specification, sec + * titled "TDG.MR.REPORT". + */ + ret =3D __tdx_module_call(TDX_GET_REPORT, virt_to_phys(tdreport), + virt_to_phys(reportdata), 0, 0, NULL); + if (ret) { + pr_debug("TDREPORT TDCALL failed, status:%lx\n", + TDCALL_STATUS_CODE(ret)); + ret =3D -EIO; + goto failed; + } + + /* Copy TDREPORT back to the user buffer */ + if (copy_to_user(argp, tdreport, TDX_REPORT_LEN)) + ret =3D -EFAULT; + +failed: + kfree(reportdata); + kfree(tdreport); + return ret; +} + +static long tdx_attest_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp =3D (void __user *)arg; + long ret =3D 0; + + switch (cmd) { + case TDX_CMD_GET_REPORT: + ret =3D tdx_get_report(argp); + break; + default: + pr_debug("cmd %d not supported\n", cmd); + ret =3D -EINVAL; + break; + } + + return ret; +} + +static const struct file_operations tdx_attest_fops =3D { + .owner =3D THIS_MODULE, + .unlocked_ioctl =3D tdx_attest_ioctl, + .llseek =3D no_llseek, +}; + +static int __init tdx_attestation_init(void) +{ + long ret; + + /* Make sure we are in a valid TDX platform */ + if (!cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) + return -EIO; + + miscdev.name =3D DRIVER_NAME; + miscdev.minor =3D MISC_DYNAMIC_MINOR; + miscdev.fops =3D &tdx_attest_fops; + + ret =3D misc_register(&miscdev); + if (ret) { + pr_err("misc device registration failed\n"); + return ret; + } + + pr_debug("module initialization success\n"); + + return 0; +} +device_initcall(tdx_attestation_init) diff --git a/arch/x86/include/uapi/asm/tdx.h b/arch/x86/include/uapi/asm/td= x.h new file mode 100644 index 000000000000..9a7377723667 --- /dev/null +++ b/arch/x86/include/uapi/asm/tdx.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_ASM_X86_TDX_H +#define _UAPI_ASM_X86_TDX_H + +#include +#include + +/* Length of the REPORTDATA used in TDG.MR.REPORT TDCALL */ +#define TDX_REPORTDATA_LEN 64 + +/* Length of TDREPORT used in TDG.MR.REPORT TDCALL */ +#define TDX_REPORT_LEN 1024 + +/** + * struct tdx_report_req: Get TDREPORT from the TDX module. + * + * @reportdata : User-defined 64-Byte REPORTDATA to be included into + * TDREPORT. Typically it can be some nonce provided by + * attestation software so the generated TDREPORT can be + * uniquely verified. + * @tdreport : TDREPORT output from TDCALL[TDG.MR.REPORT] of size + * TDX_REPORT_LEN. + * + * Used in TDX_CMD_GET_REPORT IOCTL request. + */ +struct tdx_report_req { + union { + __u8 reportdata[TDX_REPORTDATA_LEN]; + __u8 tdreport[TDX_REPORT_LEN]; + }; +}; + +/* Get TDREPORT from the TDX module using TDCALL[TDG.MR.REPORT) */ +#define TDX_CMD_GET_REPORT _IOWR('T', 0x01, struct tdx_report_req) + +#endif /* _UAPI_ASM_X86_TDX_H */ --=20 2.25.1 From nobody Sun May 10 15:02:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1CC78C433EF for ; Sun, 1 May 2022 18:35:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355049AbiEASjH (ORCPT ); Sun, 1 May 2022 14:39:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356393AbiEASi4 (ORCPT ); Sun, 1 May 2022 14:38:56 -0400 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 674CE1C100 for ; Sun, 1 May 2022 11:35:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1651430130; x=1682966130; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eZOuqvJAJAatwWXkjiLrzrD9uxIGDis5Q5fH8KPhoSA=; b=DUxAINnlg+EOC9THw0w+dTE9EqSG5GXrF9CEHevemcnRyn1UVaXJKWe/ xOq3eBIwDFUzcjJr8YnOdU9gUz6fpHv++HA3wrMLLSwPkYn/UXN2wmzSI w44mNcNCF9/xiDRTCV8Uv+JRMJ4CvKlfuajLF081BkXgU/rKATmjUL45t dpHU87vRO2U1qBQiF23/jVSRGCxnVmufZ/4bkI0uTIy1yVIKlJfbLJmdl IysuLmWfInH+JNkdlN7amwcWEiqpkZnS3jTYw7WfU8makX6jWh7TrOEKS bgOzrt/+HAE/+CQc+I3C7RHW1pBH6bwp/33OCm0s/nJFtQvoxqouwEwzX g==; X-IronPort-AV: E=McAfee;i="6400,9594,10334"; a="247598671" X-IronPort-AV: E=Sophos;i="5.91,190,1647327600"; d="scan'208";a="247598671" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 May 2022 11:35:29 -0700 X-IronPort-AV: E=Sophos;i="5.91,190,1647327600"; d="scan'208";a="515731275" Received: from pghaisax-mobl1.amr.corp.intel.com (HELO skuppusw-desk1.home) ([10.209.85.28]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 May 2022 11:35:28 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org Cc: "H . Peter Anvin" , Kuppuswamy Sathyanarayanan , "Kirill A . Shutemov" , Tony Luck , Andi Kleen , Kai Huang , Wander Lairson Costa , Isaku Yamahata , marcelo.cerri@canonical.com, tim.gardner@canonical.com, khalid.elmously@canonical.com, philip.cox@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v5 2/3] x86/tdx: Add TDX Guest event notify interrupt support Date: Sun, 1 May 2022 11:34:59 -0700 Message-Id: <20220501183500.2242828-3-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220501183500.2242828-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20220501183500.2242828-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Host-guest event notification via configured interrupt vector is useful in cases where a guest makes an asynchronous request and needs a callback from the host to indicate the completion or to let the host notify the guest about events like device removal. One usage example is, callback requirement of GetQuote asynchronous hypercall. In TDX guest, SetupEventNotifyInterrupt hypercall can be used by the guest to specify which interrupt vector to use as an event-notify vector to the VMM. Details about the SetupEventNotifyInterrupt hypercall can be found in TDX Guest-Host Communication Interface (GHCI) Specification, sec 3.5 "VP.VMCALL". Add a tdx_hcall_set_notify_intr() helper function to implement the SetupEventNotifyInterrupt hypercall. Reserve 0xec IRQ vector address for TDX guest to receive the event completion notification from VMM. Also add related IDT handler to process the notification event. Add support to track the notification event status via /proc/interrupts. Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Acked-by: Kirill A. Shutemov Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Wander Lairson Costa --- arch/x86/coco/tdx/tdx.c | 73 ++++++++++++++++++++++++++++++ arch/x86/include/asm/hardirq.h | 3 ++ arch/x86/include/asm/idtentry.h | 4 ++ arch/x86/include/asm/irq_vectors.h | 7 ++- arch/x86/include/asm/tdx.h | 4 ++ arch/x86/kernel/irq.c | 7 +++ 6 files changed, 97 insertions(+), 1 deletion(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 03deb4d6920d..b49211994864 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -11,6 +11,10 @@ #include #include #include +#include +#include +#include +#include =20 /* TDX module Call Leaf IDs */ #define TDX_GET_INFO 1 @@ -19,6 +23,7 @@ =20 /* TDX hypercall Leaf IDs */ #define TDVMCALL_MAP_GPA 0x10001 +#define TDVMCALL_SETUP_NOTIFY_INTR 0x10004 =20 /* MMIO direction */ #define EPT_READ 0 @@ -34,6 +39,28 @@ #define VE_GET_PORT_NUM(e) ((e) >> 16) #define VE_IS_IO_STRING(e) ((e) & BIT(4)) =20 +/* + * Handler used to report notifications about + * TDX_GUEST_EVENT_NOTIFY_VECTOR IRQ. Currently it will be + * used only by the attestation driver. So, race condition + * with read/write operation is not considered. + */ +static void (*tdx_event_notify_handler)(void); + +/* Helper function to register tdx_event_notify_handler */ +void tdx_setup_ev_notify_handler(void (*handler)(void)) +{ + tdx_event_notify_handler =3D handler; +} +EXPORT_SYMBOL_GPL(tdx_setup_ev_notify_handler); + +/* Helper function to unregister tdx_event_notify_handler */ +void tdx_remove_ev_notify_handler(void) +{ + tdx_event_notify_handler =3D NULL; +} +EXPORT_SYMBOL_GPL(tdx_remove_ev_notify_handler); + /* * Wrapper for standard use of __tdx_hypercall with no output aside from * return code. @@ -98,6 +125,46 @@ static inline void tdx_module_call(u64 fn, u64 rcx, u64= rdx, u64 r8, u64 r9, panic("TDCALL %lld failed (Buggy TDX module!)\n", fn); } =20 +/* TDX guest event notification handler */ +DEFINE_IDTENTRY_SYSVEC(sysvec_tdx_event_notify) +{ + struct pt_regs *old_regs =3D set_irq_regs(regs); + + inc_irq_stat(irq_tdx_event_notify_count); + + if (tdx_event_notify_handler) + tdx_event_notify_handler(); + + ack_APIC_irq(); + + set_irq_regs(old_regs); +} + +/* + * tdx_hcall_set_notify_intr() - Setup Event Notify Interrupt Vector. + * + * @vector: Vector address to be used for notification. + * + * return 0 on success or failure error number. + */ +static long tdx_hcall_set_notify_intr(u8 vector) +{ + /* Minimum vector value allowed is 32 */ + if (vector < 32) + return -EINVAL; + + /* + * Register callback vector address with VMM. More details + * about the ABI can be found in TDX Guest-Host-Communication + * Interface (GHCI), sec titled + * "TDG.VP.VMCALL". + */ + if (_tdx_hypercall(TDVMCALL_SETUP_NOTIFY_INTR, vector, 0, 0, 0)) + return -EIO; + + return 0; +} + static u64 get_cc_mask(void) { struct tdx_module_output out; @@ -688,5 +755,11 @@ void __init tdx_early_init(void) x86_platform.guest.enc_tlb_flush_required =3D tdx_tlb_flush_required; x86_platform.guest.enc_status_change_finish =3D tdx_enc_status_changed; =20 + alloc_intr_gate(TDX_GUEST_EVENT_NOTIFY_VECTOR, + asm_sysvec_tdx_event_notify); + + if (tdx_hcall_set_notify_intr(TDX_GUEST_EVENT_NOTIFY_VECTOR)) + pr_warn("Setting event notification interrupt failed\n"); + pr_info("Guest detected\n"); } diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 275e7fd20310..582deff56210 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -44,6 +44,9 @@ typedef struct { unsigned int irq_hv_reenlightenment_count; unsigned int hyperv_stimer0_count; #endif +#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) + unsigned int irq_tdx_event_notify_count; +#endif } ____cacheline_aligned irq_cpustat_t; =20 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentr= y.h index 72184b0b2219..655086dd940e 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -700,6 +700,10 @@ DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sy= svec_xen_hvm_callback); DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_kvm_asyncpf_int= errupt); #endif =20 +#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) +DECLARE_IDTENTRY_SYSVEC(TDX_GUEST_EVENT_NOTIFY_VECTOR, sysvec_tdx_event_no= tify); +#endif + #undef X86_TRAP_OTHER =20 #endif diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_= vectors.h index 43dcb9284208..82ac0c0a34b1 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -104,7 +104,12 @@ #define HYPERV_STIMER0_VECTOR 0xed #endif =20 -#define LOCAL_TIMER_VECTOR 0xec +#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) +/* Vector on which TDX Guest event notification is delivered */ +#define TDX_GUEST_EVENT_NOTIFY_VECTOR 0xec +#endif + +#define LOCAL_TIMER_VECTOR 0xeb =20 #define NR_VECTORS 256 =20 diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 020c81a7c729..eb4db837cc44 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -67,6 +67,10 @@ void tdx_safe_halt(void); =20 bool tdx_early_handle_ve(struct pt_regs *regs); =20 +void tdx_setup_ev_notify_handler(void (*handler)(void)); + +void tdx_remove_ev_notify_handler(void); + #else =20 static inline void tdx_early_init(void) { }; diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 766ffe3ba313..a96ecd866723 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -181,6 +181,13 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_wakeup_ipis); seq_puts(p, " Posted-interrupt wakeup event\n"); +#endif +#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST) + seq_printf(p, "%*s: ", prec, "TGN"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", + irq_stats(j)->irq_tdx_event_notify_count); + seq_puts(p, " TDX Guest event notification\n"); #endif return 0; } --=20 2.25.1 From nobody Sun May 10 15:02:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20117C433EF for ; Sun, 1 May 2022 18:35:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1351695AbiEASjU (ORCPT ); Sun, 1 May 2022 14:39:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1356447AbiEASi6 (ORCPT ); Sun, 1 May 2022 14:38:58 -0400 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B592515A12 for ; Sun, 1 May 2022 11:35:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1651430131; x=1682966131; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=J7MITVQDoFRMxYxGn9fxqS8JfrjoBTz62kPmO3NoxjA=; b=F1JKUkPAVWRXFeggwqbv5ex87MFsu6lQkgGQYGnlGIVDM/NZqf6+DR0g 46kFEJiKW9H2uZtS6jDQ07is4y64yOkln5eDrtYwluUtUFDCyA75+54N1 8zJFk9/LdcCFntR/pl1xOlLsfpTcE5fY8WYaPgi5BqfI5UcBz7Gc69rK6 S0aqHywujgk1t1dU/rri1vWZwxQRx4/bLN3uX6W3zuoj0MX0+oGCiAl23 SxYTtbK/qzzYIzM3fGZTZJE16b1QMWiqXuH6gWW22d6JF//tILB4FL63s GgnLMWq44zn/jh/3x1uu9eLUtYoJJfPWZDrA2+mFsJ1wyXibjN0x1hBKI w==; X-IronPort-AV: E=McAfee;i="6400,9594,10334"; a="247598673" X-IronPort-AV: E=Sophos;i="5.91,190,1647327600"; d="scan'208";a="247598673" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 May 2022 11:35:30 -0700 X-IronPort-AV: E=Sophos;i="5.91,190,1647327600"; d="scan'208";a="515731282" Received: from pghaisax-mobl1.amr.corp.intel.com (HELO skuppusw-desk1.home) ([10.209.85.28]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 May 2022 11:35:29 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org Cc: "H . Peter Anvin" , Kuppuswamy Sathyanarayanan , "Kirill A . Shutemov" , Tony Luck , Andi Kleen , Kai Huang , Wander Lairson Costa , Isaku Yamahata , marcelo.cerri@canonical.com, tim.gardner@canonical.com, khalid.elmously@canonical.com, philip.cox@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v5 3/3] x86/tdx: Add Quote generation support Date: Sun, 1 May 2022 11:35:00 -0700 Message-Id: <20220501183500.2242828-4-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220501183500.2242828-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20220501183500.2242828-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In TDX guest, the second stage in attestation process is to send the TDREPORT to QE/QGS to generate the TD Quote. For platforms that does not support communication channels like vsock or TCP/IP, implement support to get TD Quote using TDVMCALL. GetQuote hypercall can be used by the TD guest to request VMM facilitate the Quote generation via QE/QGS. More details about GetQuote hypercall can be found in TDX Guest-Host Communication Interface (GHCI) for Intel TDX 1.0, section titled "TDG.VP.VMCALL. Since GetQuote is an asynchronous request hypercall, it will not block till the TD Quote is generated. So VMM uses callback interrupt vector configured by SetupEventNotifyInterrupt hypercall to notify the guest about Quote generation completion or failure. Upon receiving the completion notification, status can be found in the TD Quote request header. Although GHCI specification does not restrict parallel GetQuote requests, since Quote generation is not in performance critical path and the frequency of attestation requests are expected to be low, only support serialized quote generation requests. Parallel quote request support can be added once demand arises. Currently the buffer required to get the TD Quote data and its shared mapping conversion (using set_memory_decrypted()) is handled within the IOCTL handler. Although it will increase the TDX_CMD_GET_QUOTE IOCTL response time, it is negligible compared to the time required for the quote generation completion. So IOCTL performance optimization is not considered at this time. Reviewed-by: Tony Luck Reviewed-by: Andi Kleen Acked-by: Kirill A. Shutemov Signed-off-by: Kuppuswamy Sathyanarayanan --- arch/x86/coco/tdx/attest.c | 135 ++++++++++++++++++++++++++++++++ arch/x86/include/uapi/asm/tdx.h | 40 ++++++++++ 2 files changed, 175 insertions(+) diff --git a/arch/x86/coco/tdx/attest.c b/arch/x86/coco/tdx/attest.c index 4543a0264ce7..6aba85297708 100644 --- a/arch/x86/coco/tdx/attest.c +++ b/arch/x86/coco/tdx/attest.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include =20 @@ -29,12 +30,20 @@ =20 /* TDREPORT module call leaf ID */ #define TDX_GET_REPORT 4 +/* GetQuote hypercall leaf ID */ +#define TDVMCALL_GET_QUOTE 0x10002 =20 /* Upper 32 bits has the status code, so mask it */ #define TDCALL_STATUS_CODE_MASK 0xffffffff00000000 #define TDCALL_STATUS_CODE(a) ((a) & TDCALL_STATUS_CODE_MASK) =20 static struct miscdevice miscdev; +/* Completion object to track GetQuote completion status */ +static DECLARE_COMPLETION(req_compl); +/* Mutex to serialize GetQuote requests */ +static DEFINE_MUTEX(quote_lock); +/* Pointer to track current quote request */ +static void *tdquote; =20 static long tdx_get_report(void __user *argp) { @@ -88,6 +97,126 @@ static long tdx_get_report(void __user *argp) return ret; } =20 +/* tdx_get_quote_hypercall() - Request to get TD Quote using TDREPORT. + * + * @quote_buf : Address of 4KB aligned GPA memory which contains + * TDREPORT. It is also used as output buffer to copy + * the GetQuote output upon successful execution. + * @quote_len : Length of the GPA in bytes. + * + * Return hypercall status code. + */ +static long tdx_get_quote_hypercall(void *quote_buf, u64 quote_len) +{ + struct tdx_hypercall_args args =3D {0}; + + args.r10 =3D TDX_HYPERCALL_STANDARD; + args.r11 =3D TDVMCALL_GET_QUOTE; + args.r12 =3D cc_mkdec(virt_to_phys(quote_buf)); + args.r13 =3D quote_len; + + /* + * Pass the physical address of TDREPORT to the VMM and + * trigger the Quote generation. It is not a blocking + * call, hence completion of this request will be notified to + * the TD guest via a callback interrupt. More info about ABI + * can be found in TDX Guest-Host-Communication Interface + * (GHCI), sec titled "TDG.VP.VMCALL". + */ + return __tdx_hypercall(&args, 0); +} + +static long tdx_get_quote(void __user *argp) +{ + struct tdx_quote_req quote_req; + long ret =3D 0; + int order; + + /* Hold lock to serialize GetQuote requests */ + mutex_lock("e_lock); + + reinit_completion(&req_compl); + + /* Copy GetQuote request struct from user buffer */ + if (copy_from_user("e_req, argp, sizeof(struct tdx_quote_req))) { + ret =3D -EFAULT; + goto quote_failed; + } + + /* Make sure the length & timeout is valid */ + if (!quote_req.len || !quote_req.timeout) { + ret =3D -EINVAL; + goto quote_failed; + } + + /* Get order for Quote buffer page allocation */ + order =3D get_order(quote_req.len); + + /* + * Allocate buffer to get TD Quote from the VMM. + * Size needs to be 4KB aligned (which is already + * met in page allocation). + */ + tdquote =3D (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); + if (!tdquote) { + ret =3D -ENOMEM; + goto quote_failed; + } + + /* + * Since this buffer will be shared with the VMM via GetQuote + * hypercall, decrypt it. + */ + ret =3D set_memory_decrypted((unsigned long)tdquote, 1UL << order); + if (ret) + goto quote_failed; + + /* Copy TDREPORT from user buffer to kernel Quote buffer */ + if (copy_from_user(tdquote, (void __user *)quote_req.buf, quote_req.len))= { + ret =3D -EFAULT; + goto quote_failed; + } + + /* Submit GetQuote Request */ + ret =3D tdx_get_quote_hypercall(tdquote, (1ULL << order) * PAGE_SIZE); + if (ret) { + pr_err("GetQuote hypercall failed, status:%lx\n", ret); + ret =3D -EIO; + goto quote_failed; + } + + /* Wait for attestation completion */ + ret =3D wait_for_completion_interruptible(&req_compl); + if (ret <=3D 0) { + ret =3D -EIO; + goto quote_failed; + } + + /* Copy output data back to user buffer */ + if (copy_to_user((void __user *)quote_req.buf, tdquote, quote_req.len)) + ret =3D -EFAULT; + +quote_failed: + if (tdquote) + free_pages((unsigned long)tdquote, order); + tdquote =3D NULL; + mutex_unlock("e_lock); + return ret; +} + +static void attestation_callback_handler(void) +{ + struct tdx_quote_hdr *quote_hdr; + + quote_hdr =3D (struct tdx_quote_hdr *) tdquote; + + /* Check for spurious callback IRQ case */ + if (!tdquote || quote_hdr->status =3D=3D GET_QUOTE_IN_FLIGHT) + return; + + complete(&req_compl); +} + static long tdx_attest_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -98,6 +227,9 @@ static long tdx_attest_ioctl(struct file *file, unsigned= int cmd, case TDX_CMD_GET_REPORT: ret =3D tdx_get_report(argp); break; + case TDX_CMD_GET_QUOTE: + ret =3D tdx_get_quote(argp); + break; default: pr_debug("cmd %d not supported\n", cmd); ret =3D -EINVAL; @@ -121,6 +253,9 @@ static int __init tdx_attestation_init(void) if (!cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) return -EIO; =20 + /* Register attestation event notify handler */ + tdx_setup_ev_notify_handler(attestation_callback_handler); + miscdev.name =3D DRIVER_NAME; miscdev.minor =3D MISC_DYNAMIC_MINOR; miscdev.fops =3D &tdx_attest_fops; diff --git a/arch/x86/include/uapi/asm/tdx.h b/arch/x86/include/uapi/asm/td= x.h index 9a7377723667..3eb60253432c 100644 --- a/arch/x86/include/uapi/asm/tdx.h +++ b/arch/x86/include/uapi/asm/tdx.h @@ -33,4 +33,44 @@ struct tdx_report_req { /* Get TDREPORT from the TDX module using TDCALL[TDG.MR.REPORT) */ #define TDX_CMD_GET_REPORT _IOWR('T', 0x01, struct tdx_report_req) =20 +/* struct tdx_quote_req: Request to generate TD Quote using TDREPORT + * + * @buf : Pass user data that includes TDREPORT as input. Upon + * successful completion of IOCTL, output is copied + * back to the same buffer. + * @len : Length of the buffer. + */ +struct tdx_quote_req { + __u64 buf; + __u64 len; + __u32 timeout; +}; + +/* Get TD Quote from QE/QGS using TDREPORT passed by the user */ +#define TDX_CMD_GET_QUOTE _IOR('T', 0x02, struct tdx_quote_req) + +/* TD Quote status codes */ +#define GET_QUOTE_SUCCESS 0 +#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff +#define GET_QUOTE_ERROR 0x8000000000000000 +#define GET_QUOTE_SERVICE_UNAVAILABLE 0x8000000000000001 + +/* + * Format of Quote data header. More details can be found in TDX + * Guest-Host Communication Interface (GHCI) for Intel TDX 1.0, + * section titled "TDG.VP.VMCALL" + */ +struct tdx_quote_hdr { + /* Quote version, filled by TD */ + __u64 version; + /* Status code of Quote request, filled by VMM */ + __u64 status; + /* Length of TDREPORT, filled by TD */ + __u32 in_len; + /* Length of Quote, filled by VMM */ + __u32 out_len; + /* Actual Quote data */ + __u64 data[0]; +}; + #endif /* _UAPI_ASM_X86_TDX_H */ --=20 2.25.1