From nobody Sun Feb 8 08:48:49 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) (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 E41A9258CF5 for ; Mon, 7 Apr 2025 18:59:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.8 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052390; cv=none; b=BzUQfwunLiddD6G9tQqGoadYhZnP6vNNK3gmkSgvWHe8VzaLls22AxZMB+Vi+aJ6jXK8HBcLVCQp5iozErAs4lr5qO5KIxg+KxY99KPflykIJeFbC/zmQisPIs28y+tfBrceCZwV8x9DJJA3f3F+e6/tOMhbgPNJGVNayZqgIRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052390; c=relaxed/simple; bh=6sGPyKTSJ79R5hErVeZrKboBKA18jxG4yTOJpTR4cUA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QzaW/E7hMn7CjmzYF8R5YTPjo25Ocw4xjrJ40a6MfYCMrL+341RbPs7luETMIBSsAjELDLlF8k5nVX7uy7XSRHigF0XnzjeRF6thReFRbMScfWrjnhiicNLl5tMs6Jz3e9Y1skArKScdm15xKXWfW0r/TXDohwQFEjxMZBoAke8= 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=BjTS9apl; arc=none smtp.client-ip=192.198.163.8 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="BjTS9apl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744052388; x=1775588388; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=6sGPyKTSJ79R5hErVeZrKboBKA18jxG4yTOJpTR4cUA=; b=BjTS9aplEf1lqx85Nsp53BSNa04hAEeiEcogATIjZdm0AsElbelCqUmv AdLSUI1DaPNySHYmStGRAHWuq0mm6XKan1Up1aEpB7igdhSMYY9CI+Bys bsxKDZFYdyjjRgJ15CPg0lGrR3eemWSkSmyozSWKsxPQR08Ggj1QJGOf5 eS3Fe12Q+7ZF0w9d29lSUtaGtrD14dqvgZbnX58Z8ahyOLzILYRNw3GFZ 31hetAs0cXGCNAArAdg8r69f9WDRX1nQ231DkU3HycTYnmJS61QHQ9C5I YGAHPMHRLj0lQTEZz1AtK8vFOvmYppy2yNlkCQa4yDp0J3fenOXPS7icQ w==; X-CSE-ConnectionGUID: R0up1s9IRiGzz0RtzCQfuw== X-CSE-MsgGUID: DPF327VNQUq/5SFnTZBQjQ== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="62999688" X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="62999688" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:47 -0700 X-CSE-ConnectionGUID: hoT2Ae1cS32UkxGAj8t1lQ== X-CSE-MsgGUID: iBZvu7RYTEiEpetUWK+n/A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="128899309" Received: from trung68x-mobl.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.115.210]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:46 -0700 From: Cedric Xing Date: Mon, 07 Apr 2025 13:59:28 -0500 Subject: [PATCH v3 1/5] tsm-mr: Add TVM Measurement Register support 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: <20250407-tdx-rtmr-v3-1-54f17bc65228@intel.com> References: <20250407-tdx-rtmr-v3-0-54f17bc65228@intel.com> In-Reply-To: <20250407-tdx-rtmr-v3-0-54f17bc65228@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, Dionna Amalie Glaze , Guorui Yu , James Bottomley , Dan Middleton , Mikko Ylinen , Sathyanarayanan Kuppuswamy X-Mailer: b4 0.13.0 Introduce new TSM Measurement helper library (tsm-mr) for TVM guest drivers to expose MRs (Measurement Registers) as sysfs attributes, with Crypto Agility support. Add the following new APIs (see include/linux/tsm-mr.h for details): - tsm_mr_create_attribute_group(): Take on input a `struct tsm_measurements` instance, which includes one `struct tsm_measurement_register` per MR with properties like `TSM_MR_F_READABLE` and `TSM_MR_F_WRITABLE`, to determine the supported operations and create the sysfs attributes accordingly. On success, return a `struct attribute_group` instance that will typically be included by the guest driver into `miscdevice.groups` before calling misc_register(). - tsm_mr_free_attribute_group(): Free the memory allocated to the attrubute group returned by tsm_mr_create_attribute_group(). tsm_mr_create_attribute_group() creates one attribute for each MR, with names following this pattern: MRNAME[:HASH] - MRNAME - Placeholder for the MR name, as specified by `tsm_measurement_register.mr_name`. - :HASH - Optional suffix indicating the hash algorithm associated with this MR, as specified by `tsm_measurement_register.mr_hash`. Support Crypto Agility by allowing multiple definitions of the same MR (i.e., with the same `mr_name`) with distinct HASH algorithms. NOTE: Crypto Agility, introduced in TPM 2.0, allows new hash algorithms to be introduced without breaking compatibility with applications using older algorithms. CC architectures may face the same challenge in the future, needing new hashes for security while retaining compatibility with older hashes, hence the need for Crypto Agility. Signed-off-by: Cedric Xing --- MAINTAINERS | 4 +- drivers/virt/coco/Kconfig | 5 ++ drivers/virt/coco/Makefile | 1 + drivers/virt/coco/tsm-mr.c | 209 +++++++++++++++++++++++++++++++++++++++++= ++++ include/linux/tsm-mr.h | 93 ++++++++++++++++++++ 5 files changed, 310 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..df3aada3ada6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24558,8 +24558,8 @@ M: Dan Williams L: linux-coco@lists.linux.dev S: Maintained F: Documentation/ABI/testing/configfs-tsm -F: drivers/virt/coco/tsm.c -F: include/linux/tsm.h +F: drivers/virt/coco/tsm*.c +F: include/linux/tsm*.h =20 TRUSTED SERVICES TEE DRIVER M: Balint Dobszay diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig index ff869d883d95..737106d5dcbc 100644 --- a/drivers/virt/coco/Kconfig +++ b/drivers/virt/coco/Kconfig @@ -7,6 +7,11 @@ config TSM_REPORTS select CONFIGFS_FS tristate =20 +config TSM_MEASUREMENTS + select CRYPTO_HASH_INFO + select CRYPTO + bool + source "drivers/virt/coco/efi_secret/Kconfig" =20 source "drivers/virt/coco/pkvm-guest/Kconfig" diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile index c3d07cfc087e..eb6ec5c1d2e1 100644 --- a/drivers/virt/coco/Makefile +++ b/drivers/virt/coco/Makefile @@ -3,6 +3,7 @@ # Confidential computing related collateral # obj-$(CONFIG_TSM_REPORTS) +=3D tsm.o +obj-$(CONFIG_TSM_MEASUREMENTS) +=3D tsm-mr.o obj-$(CONFIG_EFI_SECRET) +=3D efi_secret/ obj-$(CONFIG_ARM_PKVM_GUEST) +=3D pkvm-guest/ obj-$(CONFIG_SEV_GUEST) +=3D sev-guest/ diff --git a/drivers/virt/coco/tsm-mr.c b/drivers/virt/coco/tsm-mr.c new file mode 100644 index 000000000000..695ac28530e3 --- /dev/null +++ b/drivers/virt/coco/tsm-mr.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +struct tm_context { + struct rw_semaphore rwsem; + struct attribute_group agrp; + const struct tsm_measurements *tm; + bool in_sync; + struct bin_attribute mrs[]; +}; + +static ssize_t tm_digest_read(struct file *filp, struct kobject *kobj, + const struct bin_attribute *attr, char *buffer, + loff_t off, size_t count) +{ + struct tm_context *ctx; + const struct tsm_measurement_register *mr; + int rc; + + ctx =3D attr->private; + rc =3D down_read_interruptible(&ctx->rwsem); + if (rc) + return rc; + + /* + * @ctx->in_sync indicates if any MRs have been written since the last + * ctx->refresh() call. When @ctx->in_sync is false, ctx->refresh() is + * necessary to sync the cached values of all live MRs (i.e., with + * %TSM_MR_F_LIVE set) with the underlying hardware. + */ + mr =3D &ctx->tm->mrs[attr - ctx->mrs]; + if ((mr->mr_flags & TSM_MR_F_LIVE) && !ctx->in_sync) { + up_read(&ctx->rwsem); + + rc =3D down_write_killable(&ctx->rwsem); + if (rc) + return rc; + + if (!ctx->in_sync) { + rc =3D ctx->tm->refresh(ctx->tm, mr); + ctx->in_sync =3D !rc; + } + + downgrade_write(&ctx->rwsem); + } + + memcpy(buffer, mr->mr_value + off, count); + + up_read(&ctx->rwsem); + return rc ?: count; +} + +static ssize_t tm_digest_write(struct file *filp, struct kobject *kobj, + const struct bin_attribute *attr, char *buffer, + loff_t off, size_t count) +{ + struct tm_context *ctx; + const struct tsm_measurement_register *mr; + ssize_t rc; + + /* partial writes are not supported */ + if (off !=3D 0 || count !=3D attr->size) + return -EINVAL; + + ctx =3D attr->private; + mr =3D &ctx->tm->mrs[attr - ctx->mrs]; + + rc =3D down_write_killable(&ctx->rwsem); + if (rc) + return rc; + + rc =3D ctx->tm->write(ctx->tm, mr, buffer); + + /* reset @ctx->in_sync to refresh LIVE MRs on next read */ + if (!rc) + ctx->in_sync =3D false; + + up_write(&ctx->rwsem); + return rc ?: count; +} + +/** + * tsm_mr_create_attribute_group() - creates an attribute group for measur= ement + * registers + * @tm: pointer to &struct tsm_measurements containing the MR definitions. + * + * This function creates attributes corresponding to the MR definitions + * provided by @tm->mrs. + * + * The created attributes will reference @tm and its members. The caller m= ust + * not free @tm until after tsm_mr_free_attribute_group() is called. + * + * Context: Process context. May sleep due to memory allocation. + * + * Return: + * * On success, the pointer to a an attribute group is returned; otherwise + * * %-EINVAL - Invalid MR definitions. + * * %-ENOMEM - Out of memory. + */ +const struct attribute_group *__must_check +tsm_mr_create_attribute_group(const struct tsm_measurements *tm) +{ + if (!tm->mrs) + return ERR_PTR(-EINVAL); + + /* aggregated length of all MR names */ + size_t nlen =3D 0; + + for (size_t i =3D 0; i < tm->nr_mrs; ++i) { + if ((tm->mrs[i].mr_flags & TSM_MR_F_LIVE) && !tm->refresh) + return ERR_PTR(-EINVAL); + + if ((tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) && !tm->write) + return ERR_PTR(-EINVAL); + + if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH) + continue; + + if (WARN_ON(tm->mrs[i].mr_hash >=3D HASH_ALGO__LAST)) + return ERR_PTR(-EINVAL); + + /* MR sysfs attribute names have the form of MRNAME:HASH */ + nlen +=3D strlen(tm->mrs[i].mr_name) + 1 + + strlen(hash_algo_name[tm->mrs[i].mr_hash]) + 1; + } + + /* + * @bas and the MR name strings are combined into a single allocation + * so that we don't have to free MR names one-by-one in + * tsm_mr_free_attribute_group() + */ + struct bin_attribute **bas __free(kfree) =3D + kzalloc(sizeof(*bas) * (tm->nr_mrs + 1) + nlen, GFP_KERNEL); + struct tm_context *ctx __free(kfree) =3D + kzalloc(struct_size(ctx, mrs, tm->nr_mrs), GFP_KERNEL); + char *name, *end; + + if (!ctx || !bas) + return ERR_PTR(-ENOMEM); + + /* @bas is followed immediately by MR name strings */ + name =3D (char *)&bas[tm->nr_mrs + 1]; + end =3D name + nlen; + + for (size_t i =3D 0; i < tm->nr_mrs; ++i) { + bas[i] =3D &ctx->mrs[i]; + sysfs_bin_attr_init(bas[i]); + + if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH) + bas[i]->attr.name =3D tm->mrs[i].mr_name; + else if (name < end) { + bas[i]->attr.name =3D name; + name +=3D snprintf(name, end - name, "%s:%s", + tm->mrs[i].mr_name, + hash_algo_name[tm->mrs[i].mr_hash]); + ++name; + } else + return ERR_PTR(-EINVAL); + + /* check for duplicated MR definitions */ + for (size_t j =3D 0; j < i; ++j) + if (!strcmp(bas[i]->attr.name, bas[j]->attr.name)) + return ERR_PTR(-EINVAL); + + if (tm->mrs[i].mr_flags & TSM_MR_F_READABLE) { + bas[i]->attr.mode |=3D 0444; + bas[i]->read_new =3D tm_digest_read; + } + + if (tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) { + bas[i]->attr.mode |=3D 0220; + bas[i]->write_new =3D tm_digest_write; + } + + bas[i]->size =3D tm->mrs[i].mr_size; + bas[i]->private =3D ctx; + } + + if (name !=3D end) + return ERR_PTR(-EINVAL); + + init_rwsem(&ctx->rwsem); + ctx->agrp.name =3D tm->name; + ctx->agrp.bin_attrs =3D no_free_ptr(bas); + ctx->tm =3D tm; + return &no_free_ptr(ctx)->agrp; +} +EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group); + +/** + * tsm_mr_free_attribute_group() - frees the attribute group returned by + * tsm_mr_create_attribute_group() + * @attr_grp: attribute group returned by tsm_mr_create_attribute_group() + * + * Context: Process context. + */ +void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp) +{ + kfree(attr_grp->bin_attrs); + kfree(container_of(attr_grp, struct tm_context, agrp)); +} +EXPORT_SYMBOL_GPL(tsm_mr_free_attribute_group); diff --git a/include/linux/tsm-mr.h b/include/linux/tsm-mr.h new file mode 100644 index 000000000000..94a14d48a012 --- /dev/null +++ b/include/linux/tsm-mr.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __TSM_MR_H +#define __TSM_MR_H + +#include + +/** + * struct tsm_measurement_register - describes an architectural measurement + * register (MR) + * @mr_name: name of the MR + * @mr_value: buffer containing the current value of the MR + * @mr_size: size of the MR - typically the digest size of @mr_hash + * @mr_flags: bitwise OR of one or more flags, detailed below + * @mr_hash: optional hash identifier defined in include/uapi/linux/hash_i= nfo.h. + * + * A CC guest driver encloses an array of this structure in struct + * tsm_measurements to detail the measurement facility supported by the + * underlying CC hardware. + * + * @mr_name and @mr_value must stay valid until this structure is no longe= r in + * use. + * + * @mr_flags is the bitwise-OR of zero or more of the flags below. + * + * * %TSM_MR_F_READABLE - the sysfs attribute corresponding to this MR is = readable. + * * %TSM_MR_F_WRITABLE - the sysfs attribute corresponding to this MR is = writable. + * * %TSM_MR_F_LIVE - this MR's value may differ from the last value writt= en, so + * must be read back from the underlying CC hardware/firmware. + * * %TSM_MR_F_RTMR - bitwise-OR of %TSM_MR_F_LIVE and %TSM_MR_F_WRITABLE. + * * %TSM_MR_F_NOHASH - this MR does NOT have an associated hash algorithm. + * @mr_hash will be ignored when this flag is set. + */ +struct tsm_measurement_register { + const char *mr_name; + void *mr_value; + u32 mr_size; + u32 mr_flags; + enum hash_algo mr_hash; +}; + +#define TSM_MR_F_NOHASH 1 +#define TSM_MR_F_WRITABLE 2 +#define TSM_MR_F_READABLE 4 +#define TSM_MR_F_LIVE 8 +#define TSM_MR_F_RTMR (TSM_MR_F_LIVE | TSM_MR_F_WRITABLE) + +#define TSM_MR_(mr, hash) \ + .mr_name =3D #mr, .mr_size =3D hash##_DIGEST_SIZE, \ + .mr_hash =3D HASH_ALGO_##hash, .mr_flags =3D TSM_MR_F_READABLE + +/** + * struct tsm_measurements - Defines the CC-specific measurement facility = and + * methods for updating measurement registers (MRs). + * @name: Optional parent directory name. + * @mrs: Array of MR definitions. + * @nr_mrs: Number of elements in @mrs. + * @refresh: Callback function to load/sync all MRs from TVM hardware/firm= ware + * into the kernel cache. + * @write: Callback function to write to the MR specified by the parameter= @mr. + * + * @refresh takes two parameters: + * + * * @tm - points back to this structure. + * * @mr - points to the MR (an element of @mrs) being read (hence trigger= ed + * this callback). + * + * Note that @refresh is invoked only when an MR with %TSM_MR_F_LIVE set is + * being read and the cache is stale. However, @refresh must reload not on= ly + * the MR being read (@mr) but also all MRs with %TSM_MR_F_LIVE set. + * + * @write takes an additional parameter besides @tm and @mr: + * + * * @data - contains the bytes to write and whose size is @mr->mr_size. + * + * Both @refresh and @write should return 0 on success and an appropriate = error + * code on failure. + */ +struct tsm_measurements { + const char *name; + const struct tsm_measurement_register *mrs __counted_by(nr_mrs); + size_t nr_mrs; + int (*refresh)(const struct tsm_measurements *tm, + const struct tsm_measurement_register *mr); + int (*write)(const struct tsm_measurements *tm, + const struct tsm_measurement_register *mr, const u8 *data); +}; + +const struct attribute_group *__must_check +tsm_mr_create_attribute_group(const struct tsm_measurements *tm); +void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp); + +#endif --=20 2.43.0 From nobody Sun Feb 8 08:48:49 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) (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 DAC58258CFD for ; Mon, 7 Apr 2025 18:59:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.8 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052391; cv=none; b=tov04Lvsf/GJKhA4QUENYTF5UWsL9Fa2Dk1SIVEXCEDt9s6Jg0aNnZX1gndtZgsx1uzn4pd3eq8Q11SvemWCsWOKrdqd5lBVKY3ni6idPTeiuLI1BM5YaPSatJAGg1HNcDdmQyK9dYXX9MXOZaT55J19YjxM3o1haS3gOEP6/3I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052391; c=relaxed/simple; bh=hwKilEFU79JSH0RVcTi/ki+5CJkLBJ5KTFhAHd71Ago=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rOwyxfet7ljV7VtVgRkLBoZLYlDhDjwV93QGtRVJa/mQzRRlbK8iBry8/qUbWGdwlf3fVrV09DnrJfHrawtyWQ8zsz+W4fowCEzunZpx5lIJCd61Uz2kOHD7iKITgL9F5zqEocJvx9c0GRHp8SrP0+EztgznuDSzLQVKnQZ/Mpg= 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=gik4D3ty; arc=none smtp.client-ip=192.198.163.8 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="gik4D3ty" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744052389; x=1775588389; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=hwKilEFU79JSH0RVcTi/ki+5CJkLBJ5KTFhAHd71Ago=; b=gik4D3tyV2JDy5OHsNESNWfRtJG29sRF0kC7Qr5KMKsFUhiDeFfzGfmj cPbke9Ytpj4+si/nf8BcP1/yquk1vo25l8Mlhp2eHHvUP86sEn0q2rJiJ MdNEH9qgFBpkgMq48JSnn06wdYkPoP6Gq3ZcVzitsSrR6nkv5xX4caq0X R5tBgDDNy/mQVNc270xGFEddjleD2FHyTpunA5oEnJ/1tsVq8F5v0/sLa M4kHpbUUK8vWYJFROI31AMVEk527g9fAIjV7ukiaehk73D1YaFNPChkG+ L85W7T+/AvFbGGNFHP9J91RQkKJfjs40k2V6TeXY/h03Ig9W4r0VZrLV8 A==; X-CSE-ConnectionGUID: I5og9zr9TQOwAbnL6L+cFw== X-CSE-MsgGUID: XBFQEDyGSUywd5ZM1I19nw== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="62999700" X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="62999700" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:49 -0700 X-CSE-ConnectionGUID: 7DaiEWpmRVKKpiZNvDIxHg== X-CSE-MsgGUID: 0P+ZyW1gTOCUYiHLF89uOQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="128899316" Received: from trung68x-mobl.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.115.210]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:47 -0700 From: Cedric Xing Date: Mon, 07 Apr 2025 13:59:29 -0500 Subject: [PATCH v3 2/5] tsm-mr: Add tsm-mr sample code 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: <20250407-tdx-rtmr-v3-2-54f17bc65228@intel.com> References: <20250407-tdx-rtmr-v3-0-54f17bc65228@intel.com> In-Reply-To: <20250407-tdx-rtmr-v3-0-54f17bc65228@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, Dionna Amalie Glaze , Guorui Yu , James Bottomley , Dan Middleton , Mikko Ylinen , Sathyanarayanan Kuppuswamy X-Mailer: b4 0.13.0 This sample kernel module demonstrates how to make MRs accessible to user mode through the tsm-mr library. Once loaded, this module registers a `miscdevice` that host a set of emulated measurement registers as shown in the directory tree below. /sys/class/misc/tsm_mr_sample =E2=94=94=E2=94=80=E2=94=80 emulated_mr =E2=94=9C=E2=94=80=E2=94=80 config_mr =E2=94=9C=E2=94=80=E2=94=80 report_digest:sha512 =E2=94=9C=E2=94=80=E2=94=80 rtmr0:sha256 =E2=94=9C=E2=94=80=E2=94=80 rtmr1:sha384 =E2=94=9C=E2=94=80=E2=94=80 rtmr_crypto_agile:sha256 =E2=94=9C=E2=94=80=E2=94=80 rtmr_crypto_agile:sha384 =E2=94=94=E2=94=80=E2=94=80 static_mr:sha384 Among the MRs in this example: - `config_mr` demonstrates a hashless MR, like MRCONFIGID in Intel TDX or HOSTDATA in AMD SEV. - `static_mr` demonstrates a static MR. The suffix `:sha384` indicates its value is a sha384 digest. - `rtmr0` is an RTMR with `TSM_MR_F_WRITABLE` **cleared**, preventing direct extensions; as a result, the attribute `rtmr0:sha256` is read-only. - `rtmr1` is an RTMR with `TSM_MR_F_WRITABLE` **set**, permitting direct extensions; thus, the attribute `rtmr1:sha384` is writable. - `rtmr_crypto_agile` demonstrates a "single" MR that supports multiple hash algorithms. Each supported algorithm has a corresponding digest, usually referred to as a "bank" in TCG terminology. In this specific sample, the 2 banks are aliased to `rtmr0` and `rtmr1`, respectively. - `report_digest` contains the digest of the internal report structure living in this sample module's memory. It is to demonstrate the use of the `TSM_MR_F_LIVE` flag. Its value changes each time an RTMR is extended. Signed-off-by: Cedric Xing --- MAINTAINERS | 1 + samples/Kconfig | 10 +++ samples/Makefile | 1 + samples/tsm-mr/Makefile | 2 + samples/tsm-mr/tsm_mr_sample.c | 138 +++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 152 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index df3aada3ada6..b210ac3389a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24560,6 +24560,7 @@ S: Maintained F: Documentation/ABI/testing/configfs-tsm F: drivers/virt/coco/tsm*.c F: include/linux/tsm*.h +F: samples/tsm/* =20 TRUSTED SERVICES TEE DRIVER M: Balint Dobszay diff --git a/samples/Kconfig b/samples/Kconfig index 09011be2391a..828bc4bebde8 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -184,6 +184,16 @@ config SAMPLE_TIMER bool "Timer sample" depends on CC_CAN_LINK && HEADERS_INSTALL =20 +config SAMPLE_TSM_MR + tristate "TSM measurement sample" + select TSM_MEASUREMENTS + help + Build a sample module that emulates MRs (Measurement Registers) and + exposes them to user mode applications through the TSM sysfs + interface (/sys/class/misc/tsm_mr_sample/emulated_mr/). + + The module name will be tsm-mr-sample when built as a module. + config SAMPLE_UHID bool "UHID sample" depends on CC_CAN_LINK && HEADERS_INSTALL diff --git a/samples/Makefile b/samples/Makefile index bf6e6fca5410..c95bac31851c 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_SAMPLES_RUST) +=3D rust/ obj-$(CONFIG_SAMPLE_DAMON_WSSE) +=3D damon/ obj-$(CONFIG_SAMPLE_DAMON_PRCL) +=3D damon/ obj-$(CONFIG_SAMPLE_HUNG_TASK) +=3D hung_task/ +obj-$(CONFIG_SAMPLE_TSM_MR) +=3D tsm-mr/ diff --git a/samples/tsm-mr/Makefile b/samples/tsm-mr/Makefile new file mode 100644 index 000000000000..587c3947b3a7 --- /dev/null +++ b/samples/tsm-mr/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_SAMPLE_TSM_MR) +=3D tsm_mr_sample.o diff --git a/samples/tsm-mr/tsm_mr_sample.c b/samples/tsm-mr/tsm_mr_sample.c new file mode 100644 index 000000000000..163f0f56e165 --- /dev/null +++ b/samples/tsm-mr/tsm_mr_sample.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +#define DEBUG +#define pr_fmt(x) KBUILD_MODNAME ": " x + +#include +#include +#include +#include + +struct { + u8 static_mr[SHA384_DIGEST_SIZE]; + u8 config_mr[SHA512_DIGEST_SIZE]; + u8 rtmr0[SHA256_DIGEST_SIZE]; + u8 rtmr1[SHA384_DIGEST_SIZE]; + u8 report_digest[SHA512_DIGEST_SIZE]; +} sample_report =3D { + .static_mr =3D "static_mr", + .config_mr =3D "config_mr", + .rtmr0 =3D "rtmr0", + .rtmr1 =3D "rtmr1", +}; + +static int sample_report_refresh(const struct tsm_measurements *tm, + const struct tsm_measurement_register *mr) +{ + struct crypto_shash *tfm; + int rc; + + pr_debug("%s(%s) is called\n", __func__, mr ? mr->mr_name : ""); + + tfm =3D crypto_alloc_shash(hash_algo_name[HASH_ALGO_SHA512], 0, 0); + if (IS_ERR(tfm)) { + pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + + rc =3D crypto_shash_tfm_digest(tfm, (u8 *)&sample_report, + offsetof(typeof(sample_report), + report_digest), + sample_report.report_digest); + crypto_free_shash(tfm); + if (rc) + pr_err("crypto_shash_tfm_digest failed: %d\n", rc); + return rc; +} + +static int sample_report_extend_mr(const struct tsm_measurements *tm, + const struct tsm_measurement_register *mr, + const u8 *data) +{ + SHASH_DESC_ON_STACK(desc, 0); + int rc; + + pr_debug("%s(%s) is called\n", __func__, mr->mr_name); + + desc->tfm =3D crypto_alloc_shash(hash_algo_name[mr->mr_hash], 0, 0); + if (IS_ERR(desc->tfm)) { + pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(desc->tfm)); + return PTR_ERR(desc->tfm); + } + + rc =3D crypto_shash_init(desc); + if (!rc) + rc =3D crypto_shash_update(desc, mr->mr_value, mr->mr_size); + if (!rc) + rc =3D crypto_shash_finup(desc, data, mr->mr_size, mr->mr_value); + crypto_free_shash(desc->tfm); + if (rc) + pr_err("SHA calculation failed: %d\n", rc); + return rc; +} + +#define MR_(mr, hash) .mr_value =3D &sample_report.mr, TSM_MR_(mr, hash) +static const struct tsm_measurement_register emulated_mrs[] =3D { + /* static MR, read-only */ + { MR_(static_mr, SHA384) }, + /* config MR, read-only */ + { MR_(config_mr, SHA512) | TSM_MR_F_NOHASH }, + /* RTMR, direct extension prohibited */ + { MR_(rtmr0, SHA256) | TSM_MR_F_LIVE }, + /* RTMR, direct extension allowed */ + { MR_(rtmr1, SHA384) | TSM_MR_F_RTMR }, + /* RTMR, crypto agile, alaised to rtmr0 and rtmr1, respectively */ + { .mr_value =3D &sample_report.rtmr0, + TSM_MR_(rtmr_crypto_agile, SHA256) | TSM_MR_F_RTMR }, + { .mr_value =3D &sample_report.rtmr1, + TSM_MR_(rtmr_crypto_agile, SHA384) | TSM_MR_F_RTMR }, + /* sha512 digest of the whole structure */ + { MR_(report_digest, SHA512) | TSM_MR_F_LIVE }, +}; +#undef MR_ + +static struct tsm_measurements emulated_mr =3D { + .name =3D "emulated_mr", + .mrs =3D emulated_mrs, + .nr_mrs =3D ARRAY_SIZE(emulated_mrs), + .refresh =3D sample_report_refresh, + .write =3D sample_report_extend_mr, +}; + +static const struct attribute_group *sample_groups[] =3D { + NULL, + NULL, +}; + +static struct miscdevice sample_misc_dev =3D { + .name =3D KBUILD_MODNAME, + .minor =3D MISC_DYNAMIC_MINOR, + .groups =3D sample_groups, +}; + +static int __init tsm_mr_sample_init(void) +{ + int rc; + + sample_groups[0] =3D tsm_mr_create_attribute_group(&emulated_mr); + if (IS_ERR(sample_groups[0])) + return PTR_ERR(sample_groups[0]); + + rc =3D misc_register(&sample_misc_dev); + if (rc) + tsm_mr_free_attribute_group(sample_groups[0]); + return rc; +} + +static void __exit tsm_mr_sample_exit(void) +{ + misc_deregister(&sample_misc_dev); + tsm_mr_free_attribute_group(sample_groups[0]); +} + +module_init(tsm_mr_sample_init); +module_exit(tsm_mr_sample_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Sample module using tsm-mr to expose emulated MRs"); --=20 2.43.0 From nobody Sun Feb 8 08:48:49 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) (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 394BC259C83 for ; Mon, 7 Apr 2025 18:59:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.8 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052392; cv=none; b=DW0e54NrAwSj/u3KTKjPEzG8shas+ZdqwnNm9G02bG55rjm+ecn63i0kTjbcyaVgehbqz9VhhJ5xSDFu/e4BZK5HT/ceM1g0axdmepiH2kM6pdewVs3Vb5Uuh9fEnT4CZOOW/oeo5zGjZH+FisiQNb8+b+QgxruLeWzvMc+2rjU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052392; c=relaxed/simple; bh=9Y5DnEYEwH1nz6mcqdGkg38W01G5BExqAvl0dZDCh/M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OgtPFOWFnzbp+TWTXlqnh6KVxAgPMClJO17mtEJHTlEZDD/PY+MoWMeYKQMBGKGKN2fqkHY0qYeSRk5ZhspCFAgfgyc8EDMbaWOR+vhVBxYtJpxQwBuf0jWQkcZhVc22Z2BLPabvcsoow4i3FyZtU1AI9knQ/R1sF65+pmRG4bk= 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=Nyponodm; arc=none smtp.client-ip=192.198.163.8 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="Nyponodm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744052390; x=1775588390; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=9Y5DnEYEwH1nz6mcqdGkg38W01G5BExqAvl0dZDCh/M=; b=NyponodmZZu3zyar/wd4JgOy5U3Bx8k8CXJlIPIafIyWavQjNbk9PNNC S9SfyNcCyveLN4dlU92gvPN2zlJFmYD0Gks11qp+r0xxC7r20MdrWDJcz naaysNm/ep2ADy4QjJ3rRQWJg1ZqPof78Y+RjbAGfVOJOTPXM9arv6GKi HbTq44wxtrb1Piongtk9RPxWODkFNDuvCl8K8VdpQTAGMgatczFOc4Ock jBlW3kC07p7e58gf3IjIZvD776gw9G/OnT3vtofcSnuYY/m/YkJPzmnxq MQGqnt+WRv8WzJBGxVcTbx0Jmv/o/byNU4r/ECZ1j5s7Mq5jELs78hTq7 A==; X-CSE-ConnectionGUID: hSu5+blkTHaBa11J75I/9A== X-CSE-MsgGUID: puGvmEJiT2iYfKhs9/pWbA== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="62999710" X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="62999710" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:50 -0700 X-CSE-ConnectionGUID: fRoB4Om7SACkBB/cGEpqkg== X-CSE-MsgGUID: vfmKSEoJR0+S3bunBCiJ0w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="128899320" Received: from trung68x-mobl.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.115.210]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:48 -0700 From: Cedric Xing Date: Mon, 07 Apr 2025 13:59:30 -0500 Subject: [PATCH v3 3/5] x86/tdx: Add tdx_mcall_extend_rtmr() 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: <20250407-tdx-rtmr-v3-3-54f17bc65228@intel.com> References: <20250407-tdx-rtmr-v3-0-54f17bc65228@intel.com> In-Reply-To: <20250407-tdx-rtmr-v3-0-54f17bc65228@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, Dionna Amalie Glaze , Guorui Yu , James Bottomley , Dan Middleton , Mikko Ylinen , Sathyanarayanan Kuppuswamy X-Mailer: b4 0.13.0 The TDX guest exposes one MRTD (Build-time Measurement Register) and four RTMR (Run-time Measurement Register) registers to record the build and boot measurements of a virtual machine (VM). These registers are similar to PCR (Platform Configuration Register) registers in the TPM (Trusted Platform Module) space. This measurement data is used to implement security features like attestation and trusted boot. To facilitate updating the RTMR registers, the TDX module provides support for the `TDG.MR.RTMR.EXTEND` TDCALL which can be used to securely extend the RTMR registers. Add helper function to update RTMR registers. It will be used by the TDX guest driver in enabling RTMR extension support. Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Cedric Xing Reviewed-by: Dan Williams --- arch/x86/coco/tdx/tdx.c | 36 ++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/shared/tdx.h | 1 + arch/x86/include/asm/tdx.h | 2 ++ 3 files changed, 39 insertions(+) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index edab6d6049be..b042ca74bcd3 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -36,6 +36,7 @@ /* TDX Module call error codes */ #define TDCALL_RETURN_CODE(a) ((a) >> 32) #define TDCALL_INVALID_OPERAND 0xc0000100 +#define TDCALL_OPERAND_BUSY 0x80000200 =20 #define TDREPORT_SUBTYPE_0 0 =20 @@ -136,6 +137,41 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport) } EXPORT_SYMBOL_GPL(tdx_mcall_get_report0); =20 +/** + * tdx_mcall_extend_rtmr() - Wrapper to extend RTMR registers using + * TDG.MR.RTMR.EXTEND TDCALL. + * @index: Index of RTMR register to be extended. + * @data: Address of the input buffer with RTMR register extend data. + * + * Refer to section titled "TDG.MR.RTMR.EXTEND leaf" in the TDX Module + * v1.0 specification for more information on TDG.MR.RTMR.EXTEND TDCALL. + * It is used in the TDX guest driver module to allow user extend the + * RTMR registers (index > 1). + * + * Return 0 on success, -EINVAL for invalid operands, -EBUSY for busy + * operation or -EIO on other TDCALL failures. + */ +int tdx_mcall_extend_rtmr(u8 index, u8 *data) +{ + struct tdx_module_args args =3D { + .rcx =3D virt_to_phys(data), + .rdx =3D index, + }; + u64 ret; + + ret =3D __tdcall(TDG_MR_RTMR_EXTEND, &args); + if (ret) { + if (TDCALL_RETURN_CODE(ret) =3D=3D TDCALL_INVALID_OPERAND) + return -EINVAL; + if (TDCALL_RETURN_CODE(ret) =3D=3D TDCALL_OPERAND_BUSY) + return -EBUSY; + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(tdx_mcall_extend_rtmr); + /** * tdx_hcall_get_quote() - Wrapper to request TD Quote using GetQuote * hypercall. diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/share= d/tdx.h index a28ff6b14145..738f583f65cb 100644 --- a/arch/x86/include/asm/shared/tdx.h +++ b/arch/x86/include/asm/shared/tdx.h @@ -13,6 +13,7 @@ /* TDX module Call Leaf IDs */ #define TDG_VP_VMCALL 0 #define TDG_VP_INFO 1 +#define TDG_MR_RTMR_EXTEND 2 #define TDG_VP_VEINFO_GET 3 #define TDG_MR_REPORT 4 #define TDG_MEM_PAGE_ACCEPT 6 diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 4a1922ec80cf..12d17f3ca301 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -64,6 +64,8 @@ bool tdx_early_handle_ve(struct pt_regs *regs); =20 int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport); =20 +int tdx_mcall_extend_rtmr(u8 index, u8 *data); + u64 tdx_hcall_get_quote(u8 *buf, size_t size); =20 void __init tdx_dump_attributes(u64 td_attr); --=20 2.43.0 From nobody Sun Feb 8 08:48:49 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) (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 8BBBD259C9A for ; Mon, 7 Apr 2025 18:59:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.8 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052394; cv=none; b=R/+Z/RyO9n6eCoSFo4bKihmzBm+n5B6V1/wqhjH7bNkwPfVtIaubMuY4e2r0Zjga88lU2P4C60TFJk2heog0uHLi/Q9rkbykGldE/cZlpdnBg4GObEdps7cwDkOo/Aip8ddlH20oqxqifSMdZNc+rOhs4udYav9zjxfvpJQKWJk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052394; c=relaxed/simple; bh=ZECpWZmFTOCCjMu8O11c5UTIMsPsE5gaR3qSnn5+IkY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=B3gZICB2tvkD9Snt8gqNQftcLde80Dph7BbsBKxbdICxsDu89bivL+dJ3IrvUeYX79uxugenBK5yItBfpqska3tOLdxyYpAGmX8S83Di8qLfhaMHA5V6vLytR0haiZw9DteojOPW80+jbaloHeHYz2BVrmd/vdv5A09PPHkX9Wg= 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=nAsaW2ne; arc=none smtp.client-ip=192.198.163.8 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="nAsaW2ne" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744052392; x=1775588392; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=ZECpWZmFTOCCjMu8O11c5UTIMsPsE5gaR3qSnn5+IkY=; b=nAsaW2neIunEoIBupM3w0SMjvJU6/SUiExihxWCJrB3LW2bn/LFcS7c8 nmNMSe2s+Hwou4+KS2sKWIB4bmX3bC9/TVra86tnxnBr3r6NUMvEapC5H qOnMiVfFagp7H580us9E1KXv13ADh8HTMkCOg+04ywkk1GjDw59Lhq8tm 2x4ZmICcvaHLV25xmVBen6kL/GLrf2CWRv0ZYfPEs9rkxVkcU8EnPUh5w xdggD47Sp136O1LAt0rG7wZJVozqNNFYEa6vlThsxrFdkg0EJ6xYGuPK/ UdE/xD9z0c1fXgHeNxhHWVOZLeJEtRPL5cwWI2fJkicdS0EWsvkloz4tl g==; X-CSE-ConnectionGUID: e4WJKU7ySf+UsmIdsmpDYQ== X-CSE-MsgGUID: AOyTGjiIQEy+e7FxZOOiJg== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="62999721" X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="62999721" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:51 -0700 X-CSE-ConnectionGUID: R3VwNTcXSdqBHI0wWVzOwA== X-CSE-MsgGUID: NfViTsiUTyGU8C4XtJIUzA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="128899328" Received: from trung68x-mobl.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.115.210]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:50 -0700 From: Cedric Xing Date: Mon, 07 Apr 2025 13:59:31 -0500 Subject: [PATCH v3 4/5] x86/tdx: tdx_mcall_get_report0: Return -EBUSY on TDCALL_OPERAND_BUSY error 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: <20250407-tdx-rtmr-v3-4-54f17bc65228@intel.com> References: <20250407-tdx-rtmr-v3-0-54f17bc65228@intel.com> In-Reply-To: <20250407-tdx-rtmr-v3-0-54f17bc65228@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, Dionna Amalie Glaze , Guorui Yu , James Bottomley , Dan Middleton , Mikko Ylinen , Sathyanarayanan Kuppuswamy X-Mailer: b4 0.13.0 Return `-EBUSY` from tdx_mcall_get_report0() when `TDG.MR.REPORT` returns `TDCALL_OPERAND_BUSY`. This enables the caller to retry obtaining a TDREPORT later if another VCPU is extending an RTMR concurrently. Signed-off-by: Cedric Xing --- arch/x86/coco/tdx/tdx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index b042ca74bcd3..c94e0061fe53 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -114,8 +114,8 @@ static inline u64 tdg_vm_wr(u64 field, u64 value, u64 m= ask) * v1.0 specification for more information on TDG.MR.REPORT TDCALL. * It is used in the TDX guest driver module to get the TDREPORT0. * - * Return 0 on success, -EINVAL for invalid operands, or -EIO on - * other TDCALL failures. + * Return 0 on success, -EINVAL for invalid operands, -EBUSY for busy + * operation or -EIO on other TDCALL failures. */ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport) { @@ -130,6 +130,8 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport) if (ret) { if (TDCALL_RETURN_CODE(ret) =3D=3D TDCALL_INVALID_OPERAND) return -EINVAL; + else if (TDCALL_RETURN_CODE(ret) =3D=3D TDCALL_OPERAND_BUSY) + return -EBUSY; return -EIO; } =20 --=20 2.43.0 From nobody Sun Feb 8 08:48:49 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) (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 DC168259CBA for ; Mon, 7 Apr 2025 18:59:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.8 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052395; cv=none; b=kSuuzG1Nv0fQJWMCJPKTvW0uu5/YJu503TrOIfbqN8kOPrg8BmpvUxsgCeBxwZFAp40X15XqesLPvoJHVLM6dg5Eb2z84ALq32QloQCAPp+uCIqNa7WKb6LM237Hbjo2BobgeUs2EodIPFOUXQVc6NzRGmfi/zTMbDoQmsUX+yQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744052395; c=relaxed/simple; bh=NE0tNXAYqSzmOnnFtNjH0NP/9T7ARhN+xOJeISYddgU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=U+QQ9LQsPNEpbuMpLF9ILb37Kw8m6+3i0q4blX91ZdBX5JYmqwQsM4eIXAJooW1HkocK2xj+EkWkaKk2r5o55ThaZxJ8uUyynFIp+fCkm4RYczT+yJEkF0r0iImbQ4mTBGTsUNx2afdhDrcMeC6miITuFdnpcQUkGttrXI/oJlI= 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=R6HzREuw; arc=none smtp.client-ip=192.198.163.8 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="R6HzREuw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744052393; x=1775588393; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=NE0tNXAYqSzmOnnFtNjH0NP/9T7ARhN+xOJeISYddgU=; b=R6HzREuw94nIJcUJPH3aqKSbL77Pf+9tQUVaVyMLQm4K66Fon3pm3lWP yeQUn5XmwiV3xEJbRt/ngnay6kXOrbrV+kJ/r14cS8aIv4bOOebigCqwU +T/N/IjYVXIxd+Bv3LZP60EbbwWXVb5lFbTw7RaGPUjmkH6UswEn7KNjl 0bIhygZanpKih/3j7pYCkd9oNcgLvOdfRzcQ0lkKMVgEixusPB4ZB136d zal7DWD9ghJYv5sqxXvw3sRxvtVOAMACRGMYTzJeSk47trZ3kqS4tdPeW VJ1btWIjQSU7G3ahmovh+fdesZtNbsBAaJn8ADY5DGBm/a5P+SYborMpN g==; X-CSE-ConnectionGUID: MAsMEvkrScKchaIEuG8sGA== X-CSE-MsgGUID: Va622hemSHe9A1IRc+HSwg== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="62999733" X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="62999733" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:53 -0700 X-CSE-ConnectionGUID: ZQSxcxGASXm6/aF+qPn8zQ== X-CSE-MsgGUID: QjJ+RrzaQDyzmzBmTiyvrQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,194,1739865600"; d="scan'208";a="128899334" Received: from trung68x-mobl.amr.corp.intel.com (HELO bxing-mobl1.clients.intel.com) ([10.246.115.210]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Apr 2025 11:59:51 -0700 From: Cedric Xing Date: Mon, 07 Apr 2025 13:59:32 -0500 Subject: [PATCH v3 5/5] virt: tdx-guest: Expose TDX MRs as sysfs attributes 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: <20250407-tdx-rtmr-v3-5-54f17bc65228@intel.com> References: <20250407-tdx-rtmr-v3-0-54f17bc65228@intel.com> In-Reply-To: <20250407-tdx-rtmr-v3-0-54f17bc65228@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, Dionna Amalie Glaze , Guorui Yu , James Bottomley , Dan Middleton , Mikko Ylinen , Sathyanarayanan Kuppuswamy X-Mailer: b4 0.13.0 Expose the most commonly used TDX MRs (Measurement Registers) as sysfs attributes. Use the ioctl() interface of /dev/tdx_guest to request a full TDREPORT for access to other TD measurements. Directory structure of TDX MRs inside a TDVM is as follows: /sys/class/misc/tdx_guest =E2=94=94=E2=94=80=E2=94=80 mr =E2=94=9C=E2=94=80=E2=94=80 mrconfigid =E2=94=9C=E2=94=80=E2=94=80 mrowner =E2=94=9C=E2=94=80=E2=94=80 mrownerconfig =E2=94=9C=E2=94=80=E2=94=80 mrtd:sha384 =E2=94=9C=E2=94=80=E2=94=80 rtmr0:sha384 =E2=94=9C=E2=94=80=E2=94=80 rtmr1:sha384 =E2=94=9C=E2=94=80=E2=94=80 rtmr2:sha384 =E2=94=94=E2=94=80=E2=94=80 rtmr3:sha384 Read the file/attribute to retrieve the current value of an MR. Write to the file/attribute (if writable) to extend the corresponding RTMR. Refer to Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr for more information. Signed-off-by: Cedric Xing --- .../sysfs-devices-virtual-misc-tdx_guest-mr | 48 ++++++ MAINTAINERS | 1 + drivers/virt/coco/tdx-guest/Kconfig | 1 + drivers/virt/coco/tdx-guest/tdx-guest.c | 169 +++++++++++++++++= +++- 4 files changed, 217 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest= -mr b/Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr new file mode 100644 index 000000000000..682b2973737a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr @@ -0,0 +1,48 @@ +What: /sys/devices/virtual/misc/tdx_guest/mr/MRNAME[:HASH] +Date: April, 2025 +KernelVersion: v6.16 +Contact: linux-coco@lists.linux.dev +Description: + Value of a TDX measurement register (MR). MRNAME and HASH above + are placeholders. The optional suffix :HASH is used for MRs + that have associated hash algorithms. See below for a complete + list of TDX MRs exposed via sysfs. Comprehensive information is + available at https://intel.com/tdx + +What: /sys/devices/virtual/misc/tdx_guest/mr/mrconfigid +Date: April, 2025 +KernelVersion: v6.16 +Contact: cedric.xing@intel.com +Description: + (RO) Value of MRCONFIGID - immutable storage for SW use. + +What: /sys/devices/virtual/misc/tdx_guest/mr/mrowner +Date: April, 2025 +KernelVersion: v6.16 +Contact: cedric.xing@intel.com +Description: + (RO) Value of MROWNER - immutable storage for SW use. + +What: /sys/devices/virtual/misc/tdx_guest/mr/mrownerconfig +Date: April, 2025 +KernelVersion: v6.16 +Contact: cedric.xing@intel.com +Description: + (RO) Value of MROWNERCONFIG - immutable storage for SW use. + +What: /sys/devices/virtual/misc/tdx_guest/mr/mrtd:sha384 +Date: April, 2025 +KernelVersion: v6.16 +Contact: cedric.xing@intel.com +Description: + (RO) Value of MRTD - the measurement of the initial memory + image of the current TD. + +What: /sys/devices/virtual/misc/tdx_guest/mr/rtmr[0123]:sha384 +Date: April, 2025 +KernelVersion: v6.16 +Contact: cedric.xing@intel.com +Description: + (RW) Read returns the current value of the RTMR. Write extends + the written buffer to the RTMR. All writes must start at offset + 0 and be 48 bytes in size. Partial writes are not supported. diff --git a/MAINTAINERS b/MAINTAINERS index b210ac3389a7..c702f456643a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26226,6 +26226,7 @@ L: x86@kernel.org L: linux-coco@lists.linux.dev S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/tdx +F: Documentation/ABI/testing/sysfs-devices-virtual-misc-tdx_guest-mr F: arch/x86/boot/compressed/tdx* F: arch/x86/coco/tdx/ F: arch/x86/include/asm/shared/tdx.h diff --git a/drivers/virt/coco/tdx-guest/Kconfig b/drivers/virt/coco/tdx-gu= est/Kconfig index 22dd59e19431..dbbdc14383b1 100644 --- a/drivers/virt/coco/tdx-guest/Kconfig +++ b/drivers/virt/coco/tdx-guest/Kconfig @@ -2,6 +2,7 @@ config TDX_GUEST_DRIVER tristate "TDX Guest driver" depends on INTEL_TDX_GUEST select TSM_REPORTS + select TSM_MEASUREMENTS help The driver provides userspace interface to communicate with the TDX module to request the TDX guest details like attestation diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/td= x-guest/tdx-guest.c index 224e7dde9cde..1160f861c027 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 @@ -16,7 +18,7 @@ #include #include #include -#include +#include =20 #include =20 @@ -86,8 +88,14 @@ static long tdx_get_report0(struct tdx_report_req __user= *req) goto out; } =20 + if (mutex_lock_interruptible("e_lock)) { + ret =3D -EINTR; + goto out; + } + /* Generate TDREPORT0 using "TDG.MR.REPORT" TDCALL */ ret =3D tdx_mcall_get_report0(reportdata, tdreport); + mutex_unlock("e_lock); if (ret) goto out; =20 @@ -285,10 +293,16 @@ static const struct file_operations tdx_guest_fops = =3D { .unlocked_ioctl =3D tdx_guest_ioctl, }; =20 +static const struct attribute_group *tdx_attr_groups[] =3D { + NULL, + NULL, +}; + static struct miscdevice tdx_misc_dev =3D { .name =3D KBUILD_MODNAME, .minor =3D MISC_DYNAMIC_MINOR, .fops =3D &tdx_guest_fops, + .groups =3D tdx_attr_groups, }; =20 static const struct x86_cpu_id tdx_guest_ids[] =3D { @@ -304,6 +318,144 @@ 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_tee_tcb_info =3D 256, + TDREPORT_tdinfo =3D TDREPORT_tee_tcb_info + 256, + TDREPORT_attributes =3D TDREPORT_tdinfo, + TDREPORT_xfam =3D TDREPORT_attributes + sizeof(u64), + TDREPORT_mrtd =3D TDREPORT_xfam + sizeof(u64), + TDREPORT_mrconfigid =3D TDREPORT_mrtd + SHA384_DIGEST_SIZE, + TDREPORT_mrowner =3D TDREPORT_mrconfigid + SHA384_DIGEST_SIZE, + TDREPORT_mrownerconfig =3D TDREPORT_mrowner + SHA384_DIGEST_SIZE, + TDREPORT_rtmr0 =3D TDREPORT_mrownerconfig + SHA384_DIGEST_SIZE, + TDREPORT_rtmr1 =3D TDREPORT_rtmr0 + SHA384_DIGEST_SIZE, + TDREPORT_rtmr2 =3D TDREPORT_rtmr1 + SHA384_DIGEST_SIZE, + TDREPORT_rtmr3 =3D TDREPORT_rtmr2 + SHA384_DIGEST_SIZE, + TDREPORT_servtd_hash =3D TDREPORT_rtmr3 + SHA384_DIGEST_SIZE, +}; + +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 }, + { TDX_MR_(rtmr1) | TSM_MR_F_RTMR }, + { TDX_MR_(rtmr2) | TSM_MR_F_RTMR }, + { TDX_MR_(rtmr3) | TSM_MR_F_RTMR }, + { TDX_MR_(mrtd) }, + { TDX_MR_(mrconfigid) | TSM_MR_F_NOHASH }, + { TDX_MR_(mrowner) | TSM_MR_F_NOHASH }, + { TDX_MR_(mrownerconfig) | TSM_MR_F_NOHASH }, +}; +#undef TDX_MR_ + +static int tdx_mr_try_refresh(void) +{ + 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 (IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER)) + tdreport =3D tdx_mr_report; + else { + /* TDREPORT buffer must be naturally aligned */ + tdreport =3D kmalloc(__alignof(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 (!IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER)) { + if (!ret) + memcpy(tdx_mr_report, tdreport, sizeof(tdx_mr_report)); + kfree(tdreport); + } + + return ret; +} + +static int tdx_mr_refresh(const struct tsm_measurements *tm, + const struct tsm_measurement_register *mr) +{ + int ret =3D -EINTR; + + if (!mutex_lock_interruptible("e_lock)) { + ret =3D tdx_mr_try_refresh(); + mutex_unlock("e_lock); + + WARN_ON(ret); + } + return ret; +} + +static int tdx_mr_try_extend(ptrdiff_t mr_ind, const u8 *data) +{ +#if IS_BUILTIN(CONFIG_TDX_GUEST_DRIVER) + /* + * TDG.MR.RTMR.EXTEND takes the GPA of a 64-byte aligned buffer on + * input. virt_to_phys() works on static buffers only if the current + * module is built-in. + */ + static u8 buf[SHA384_DIGEST_SIZE] __aligned(64); +#else + /* + * Otherwise, kmalloc() must be used to allocate the 64-byte aligned + * input buffer. + */ + u8 *buf __free(kfree) =3D kmalloc(64, GFP_KERNEL); + if (!buf) + return -ENOMEM; +#endif + + int ret; + + memcpy(buf, data, SHA384_DIGEST_SIZE); + + ret =3D tdx_mcall_extend_rtmr((u8)mr_ind, buf); + if (ret) + pr_err("Extending RTMR%ld failed\n", mr_ind); + + return ret; +} + +static int tdx_mr_extend(const struct tsm_measurements *tm, + const struct tsm_measurement_register *mr, + const u8 *data) +{ + int ret =3D -EINTR; + + if (!mutex_lock_interruptible("e_lock)) { + ret =3D tdx_mr_try_extend(mr - tm->mrs, data); + mutex_unlock("e_lock); + + WARN_ON(ret); + } + return ret; +} + +static struct tsm_measurements tdx_measurements =3D { + .name =3D "mr", + .mrs =3D tdx_mrs, + .nr_mrs =3D ARRAY_SIZE(tdx_mrs), + .refresh =3D tdx_mr_refresh, + .write =3D tdx_mr_extend, +}; + static int __init tdx_guest_init(void) { int ret; @@ -311,9 +463,19 @@ static int __init tdx_guest_init(void) if (!x86_match_cpu(tdx_guest_ids)) return -ENODEV; =20 + ret =3D tdx_mr_try_refresh(); + if (ret) { + pr_err("Failed to read MRs: %d\n", ret); + return ret; + } + + tdx_attr_groups[0] =3D tsm_mr_create_attribute_group(&tdx_measurements); + if (IS_ERR(tdx_attr_groups[0])) + return PTR_ERR(tdx_attr_groups[0]); + ret =3D misc_register(&tdx_misc_dev); if (ret) - return ret; + goto free_tsm_mr; =20 quote_data =3D alloc_quote_buf(); if (!quote_data) { @@ -332,6 +494,8 @@ static int __init tdx_guest_init(void) free_quote_buf(quote_data); free_misc: misc_deregister(&tdx_misc_dev); +free_tsm_mr: + tsm_mr_free_attribute_group(tdx_attr_groups[0]); =20 return ret; } @@ -342,6 +506,7 @@ static void __exit tdx_guest_exit(void) tsm_unregister(&tdx_tsm_ops); free_quote_buf(quote_data); misc_deregister(&tdx_misc_dev); + tsm_mr_free_attribute_group(tdx_attr_groups[0]); } module_exit(tdx_guest_exit); =20 --=20 2.43.0