From nobody Sun Feb 8 07:49:20 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0201820010B for ; Thu, 13 Feb 2025 02:23:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739413407; cv=none; b=bENtzWwYx0m51QxoAP0zBecfyS5ksbL/k6+awcKQYcQyQq6kNzecdtoI6r6dJ0xXUcerVa9x6fzcCZq3y57LGz0sOjxj8EaDQJutQVgQGo+GcDcTTEVuvGt9hANNvKaxONohOwUJIg/IuX09zYKzEqKp5fRDzsSuWe8Kq/3A4/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739413407; c=relaxed/simple; bh=KyIi0V4Mp6gPo+F4KA4qOFqrz0MVhzqomVxCnu29utQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JsnIZX/ziVTpy7D1gmF2AZri8UbuQLRpuF825Wfz9e+IOAZ2sW+OZO7du73pn1ooMKNZ57bePqlP49TCQAu6DIKz5taFbzYcFnqLHmXKfHAaQbLRxHnxipwYKR0FE8oIqVmscPIoNPjLljkhTYTIRsdnXWHzHF847GOM4ViffgY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=mLduJNIU; arc=none smtp.client-ip=198.175.65.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="mLduJNIU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1739413407; x=1770949407; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=KyIi0V4Mp6gPo+F4KA4qOFqrz0MVhzqomVxCnu29utQ=; b=mLduJNIULksOSB9eejBp3rpCV9dLydy8YbPdRwX+9rleISEAD1+imQSl mUjD+CLO59D2uClXQEgYCsL63JnnxgxhwyxBICHcdNZFVjoZdeUSWqM4m vBZeSTeZjGoayE/w8iFdUa5ySpB48EuUNAlj9trXXjuWgD6hxaWWsVSjz hmsKz2EaF4DNmKRKbmI0xHnVNMeTglJyku8b5T4zWLGHOVU9h3+LCVe+O t3rQxP0pmZ7ErtiipRpNAeexiZstul4VdOcMGqkvG3SI4i+/30IhvRRjF 6LyF6HNC6u5/+uj8xQhzd8ce1T4s03ZRN3i5ZmDieuFn0SYASHM3r0//r w==; X-CSE-ConnectionGUID: VYQ5zIQYR5i2IDaF3FrKrA== X-CSE-MsgGUID: e3Yyt3raR4KE6PmDsfy2VA== X-IronPort-AV: E=McAfee;i="6700,10204,11343"; a="62566646" X-IronPort-AV: E=Sophos;i="6.13,281,1732608000"; d="scan'208";a="62566646" Received: from orviesa008.jf.intel.com ([10.64.159.148]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Feb 2025 18:23:26 -0800 X-CSE-ConnectionGUID: hYXVCTrfT0eCv6yYg+g/TQ== X-CSE-MsgGUID: WDHwzdiOS9W3/MyhQCSt9w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="113905850" Received: from rtice-desk1.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.116.160]) by orviesa008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Feb 2025 18:23:24 -0800 From: Cedric Xing Date: Wed, 12 Feb 2025 20:23:07 -0600 Subject: [PATCH 4/4] x86/tdx: Expose TDX MRs through TSM sysfs interface Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250212-tdx-rtmr-v1-4-9795dc49e132@intel.com> References: <20250212-tdx-rtmr-v1-0-9795dc49e132@intel.com> In-Reply-To: <20250212-tdx-rtmr-v1-0-9795dc49e132@intel.com> To: Dan Williams , "Kirill A. Shutemov" , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , x86@kernel.org, "H. Peter Anvin" Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, Cedric Xing X-Mailer: b4 0.13.0 TDX MRs are made accessible to user mode as files (attributes) in sysfs. Below shows the directory structure of TDX MRs inside a TDVM. /sys/kernel/tsm =E2=94=94=E2=94=80=E2=94=80 tdx =E2=94=9C=E2=94=80=E2=94=80 mrconfigid =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 mrowner =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 mrownerconfig =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 mrtd =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 report0 =E2=94=9C=E2=94=80=E2=94=80 reportdata =E2=94=9C=E2=94=80=E2=94=80 rtmr0 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 rtmr1 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 rtmr2 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=9C=E2=94=80=E2=94=80 rtmr3 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 digest =E2=94=94=E2=94=80=E2=94=80 servtd_hash =E2=94=94=E2=94=80=E2=94=80 sha384 =E2=94=94=E2=94=80=E2=94=80 digest The digest attribute/file of each MR contains the MR's current value. Writing to the digest attribute/file of an RTMR extends the written value to that RTMR. The report0 and reportdata attributes offer a simple interface for user mode applications to request TDREPORTs. These 2 attributes can be enabled/disabled by setting CONFIG_TDX_GUEST_DRIVER_TSM_REPORT to Y/n. Signed-off-by: Cedric Xing --- drivers/virt/coco/tdx-guest/Kconfig | 15 ++++ drivers/virt/coco/tdx-guest/tdx-guest.c | 119 ++++++++++++++++++++++++++++= ++++ 2 files changed, 134 insertions(+) diff --git a/drivers/virt/coco/tdx-guest/Kconfig b/drivers/virt/coco/tdx-gu= est/Kconfig index 22dd59e19431..effadcfd9918 100644 --- a/drivers/virt/coco/tdx-guest/Kconfig +++ b/drivers/virt/coco/tdx-guest/Kconfig @@ -9,3 +9,18 @@ config TDX_GUEST_DRIVER =20 To compile this driver as module, choose M here. The module will be called tdx-guest. + +if TDX_GUEST_DRIVER + +config TDX_GUEST_DRIVER_TSM_REPORT + bool "tdx-guest: Enable TSM raw TDREPORT interface" + default y + help + This option adds 2 files, namely report0 and reportdata, to the TSM + sysfs directory tree (/sys/kernel/tsm/tdx/). + + To request a TDREPORT, set REPORTDATA by writing to + /sys/kernel/tsm/tdx/reportdata, then read + /sys/kernel/tsm/tdx/report0. + +endif diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/td= x-guest/tdx-guest.c index 224e7dde9cde..c95aa17e728c 100644 --- a/drivers/virt/coco/tdx-guest/tdx-guest.c +++ b/drivers/virt/coco/tdx-guest/tdx-guest.c @@ -5,6 +5,8 @@ * Copyright (C) 2022 Intel Corporation */ =20 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -18,6 +20,8 @@ #include #include =20 +#include + #include =20 #include @@ -304,6 +308,114 @@ static const struct tsm_ops tdx_tsm_ops =3D { .report_bin_attr_visible =3D tdx_report_bin_attr_visible, }; =20 +enum { + TDREPORT_reportdata =3D 128, + TDREPORT_tdinfo =3D 512, + TDREPORT_mrtd =3D TDREPORT_tdinfo + 16, + TDREPORT_mrconfigid =3D TDREPORT_mrtd + 48, + TDREPORT_mrowner =3D TDREPORT_mrconfigid + 48, + TDREPORT_mrownerconfig =3D TDREPORT_mrowner + 48, + TDREPORT_rtmr0 =3D TDREPORT_mrownerconfig + 48, + TDREPORT_rtmr1 =3D TDREPORT_rtmr0 + 48, + TDREPORT_rtmr2 =3D TDREPORT_rtmr1 + 48, + TDREPORT_rtmr3 =3D TDREPORT_rtmr2 + 48, + TDREPORT_servtd_hash =3D TDREPORT_rtmr3 + 48, +}; + +static u8 tdx_mr_report[TDX_REPORT_LEN] __aligned(TDX_REPORT_LEN); + +#define TDX_MR_(r) .mr_value =3D tdx_mr_report + TDREPORT_##r, TSM_MR_(r, = SHA384) +static const struct tsm_measurement_register tdx_mrs[] =3D { + { TDX_MR_(rtmr0) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(rtmr1) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(rtmr2) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(rtmr3) | TSM_MR_F_RTMR | TSM_MR_F_W }, + { TDX_MR_(mrtd) }, + { TDX_MR_(mrconfigid) }, + { TDX_MR_(mrowner) }, + { TDX_MR_(mrownerconfig) }, + { TDX_MR_(servtd_hash) }, +#ifdef CONFIG_TDX_GUEST_DRIVER_TSM_REPORT + { .mr_value =3D tdx_mr_report, .mr_size =3D sizeof(tdx_mr_report), + .mr_name =3D "report0", .mr_flags =3D TSM_MR_F_LIVE | TSM_MR_F_F }, + { .mr_value =3D tdx_mr_report + TDREPORT_reportdata, + TSM_MR_(reportdata, SHA512) | TSM_MR_F_W | TSM_MR_F_F }, +#endif + {} +}; +#undef TDX_MR_ + +static int tdx_mr_refresh(struct tsm_measurement *tmr, + const struct tsm_measurement_register *mr) +{ + u8 *reportdata, *tdreport; + int ret; + + reportdata =3D tdx_mr_report + TDREPORT_reportdata; + + /* + * TDCALL requires a GPA as input. Depending on whether this module is + * built as a built-in (Y) or a module (M), tdx_mr_report may or may + * not be converted to a GPA using virt_to_phys. If not, a directly + * mapped buffer must be allocated using kmalloc and used as an + * intermediary. + */ + if (virt_addr_valid(tdx_mr_report)) + tdreport =3D tdx_mr_report; + else { + tdreport =3D kmalloc(sizeof(tdx_mr_report), GFP_KERNEL); + if (!tdreport) + return -ENOMEM; + + reportdata =3D memcpy(tdreport + TDREPORT_reportdata, reportdata, + TDX_REPORTDATA_LEN); + } + + ret =3D tdx_mcall_get_report0(reportdata, tdreport); + if (ret) + pr_err("GetReport call failed\n"); + + if (tdreport !=3D tdx_mr_report) { + memcpy(tdx_mr_report, tdreport, sizeof(tdx_mr_report)); + kfree(tdreport); + } + + return ret; +} + +static int tdx_mr_extend(struct tsm_measurement *tmr, + const struct tsm_measurement_register *mr, const u8 *data) +{ + u8 *buf; + int ret; + + if (virt_addr_valid(data)) + buf =3D (u8 *)data; + else { + buf =3D kmalloc(64, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, data, mr->mr_size); + } + + ret =3D tdx_mcall_rtmr_extend((u8)(mr - tmr->mrs), buf); + if (ret) + pr_err("Extending RTMR%ld failed\n", mr - tmr->mrs); + + if (buf !=3D data) + kfree(buf); + + return ret; +} + +static struct tsm_measurement tdx_measurement =3D { + .name =3D "tdx", + .mrs =3D tdx_mrs, + .refresh =3D tdx_mr_refresh, + .extend =3D tdx_mr_extend, +}; + static int __init tdx_guest_init(void) { int ret; @@ -326,8 +438,14 @@ static int __init tdx_guest_init(void) if (ret) goto free_quote; =20 + ret =3D tsm_register_measurement(&tdx_measurement); + if (ret) + goto unregister_tsm; + return 0; =20 +unregister_tsm: + tsm_unregister(&tdx_tsm_ops); free_quote: free_quote_buf(quote_data); free_misc: @@ -339,6 +457,7 @@ module_init(tdx_guest_init); =20 static void __exit tdx_guest_exit(void) { + tsm_unregister_measurement(&tdx_measurement); tsm_unregister(&tdx_tsm_ops); free_quote_buf(quote_data); misc_deregister(&tdx_misc_dev); --=20 2.43.0