File Index
Files and directories
Sign in
FILE

tsm-mr.c

File preview with syntax highlighting.

linux-6.19.14/drivers/virt/coco/guest/tsm-mr.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */
  3
  4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  5
  6#include <linux/module.h>
  7#include <linux/slab.h>
  8#include <linux/sysfs.h>
  9
 10#define CREATE_TRACE_POINTS
 11#include <trace/events/tsm_mr.h>
 12
 13/*
 14 * struct tm_context - contains everything necessary to implement sysfs
 15 * attributes for MRs.
 16 * @rwsem: protects the MR cache from concurrent access.
 17 * @agrp: contains all MR attributes created by tsm_mr_create_attribute_group().
 18 * @tm: input to tsm_mr_create_attribute_group() containing MR definitions/ops.
 19 * @in_sync: %true if MR cache is up-to-date.
 20 * @mrs: array of &struct bin_attribute, one for each MR.
 21 *
 22 * This internal structure contains everything needed to implement
 23 * tm_digest_read() and tm_digest_write().
 24 *
 25 * Given tm->refresh() is potentially expensive, tm_digest_read() caches MR
 26 * values and calls tm->refresh() only when necessary. Only live MRs (i.e., with
 27 * %TSM_MR_F_LIVE set) can trigger tm->refresh(), while others are assumed to
 28 * retain their values from the last tm->write(). @in_sync tracks if there have
 29 * been tm->write() calls since the last tm->refresh(). That is, tm->refresh()
 30 * will be called only when a live MR is being read and the cache is stale
 31 * (@in_sync is %false).
 32 *
 33 * tm_digest_write() sets @in_sync to %false and calls tm->write(), whose
 34 * semantics is arch and MR specific. Most (if not all) writable MRs support the
 35 * extension semantics (i.e., tm->write() extends the input buffer into the MR).
 36 */
 37struct tm_context {
 38	struct rw_semaphore rwsem;
 39	struct attribute_group agrp;
 40	const struct tsm_measurements *tm;
 41	bool in_sync;
 42	struct bin_attribute mrs[];
 43};
 44
 45static ssize_t tm_digest_read(struct file *filp, struct kobject *kobj,
 46			      const struct bin_attribute *attr, char *buffer,
 47			      loff_t off, size_t count)
 48{
 49	struct tm_context *ctx;
 50	const struct tsm_measurement_register *mr;
 51	int rc;
 52
 53	ctx = attr->private;
 54	rc = down_read_interruptible(&ctx->rwsem);
 55	if (rc)
 56		return rc;
 57
 58	mr = &ctx->tm->mrs[attr - ctx->mrs];
 59
 60	/*
 61	 * @ctx->in_sync indicates if the MR cache is stale. It is a global
 62	 * instead of a per-MR flag for simplicity, as most (if not all) archs
 63	 * allow reading all MRs in oneshot.
 64	 *
 65	 * ctx->refresh() is necessary only for LIVE MRs, while others retain
 66	 * their values from their respective last ctx->write().
 67	 */
 68	if ((mr->mr_flags & TSM_MR_F_LIVE) && !ctx->in_sync) {
 69		up_read(&ctx->rwsem);
 70
 71		rc = down_write_killable(&ctx->rwsem);
 72		if (rc)
 73			return rc;
 74
 75		if (!ctx->in_sync) {
 76			rc = ctx->tm->refresh(ctx->tm);
 77			ctx->in_sync = !rc;
 78			trace_tsm_mr_refresh(mr, rc);
 79		}
 80
 81		downgrade_write(&ctx->rwsem);
 82	}
 83
 84	memcpy(buffer, mr->mr_value + off, count);
 85	trace_tsm_mr_read(mr);
 86
 87	up_read(&ctx->rwsem);
 88	return rc ?: count;
 89}
 90
 91static ssize_t tm_digest_write(struct file *filp, struct kobject *kobj,
 92			       const struct bin_attribute *attr, char *buffer,
 93			       loff_t off, size_t count)
 94{
 95	struct tm_context *ctx;
 96	const struct tsm_measurement_register *mr;
 97	ssize_t rc;
 98
 99	/* partial writes are not supported */
100	if (off != 0 || count != attr->size)
101		return -EINVAL;
102
103	ctx = attr->private;
104	mr = &ctx->tm->mrs[attr - ctx->mrs];
105
106	rc = down_write_killable(&ctx->rwsem);
107	if (rc)
108		return rc;
109
110	rc = ctx->tm->write(ctx->tm, mr, buffer);
111
112	/* mark MR cache stale */
113	if (!rc) {
114		ctx->in_sync = false;
115		trace_tsm_mr_write(mr, buffer);
116	}
117
118	up_write(&ctx->rwsem);
119	return rc ?: count;
120}
121
122/**
123 * tsm_mr_create_attribute_group() - creates an attribute group for measurement
124 * registers (MRs)
125 * @tm: pointer to &struct tsm_measurements containing the MR definitions.
126 *
127 * This function creates attributes corresponding to the MR definitions
128 * provided by @tm->mrs.
129 *
130 * The created attributes will reference @tm and its members. The caller must
131 * not free @tm until after tsm_mr_free_attribute_group() is called.
132 *
133 * Context: Process context. May sleep due to memory allocation.
134 *
135 * Return:
136 * * On success, the pointer to a an attribute group is returned; otherwise
137 * * %-EINVAL - Invalid MR definitions.
138 * * %-ENOMEM - Out of memory.
139 */
140const struct attribute_group *
141tsm_mr_create_attribute_group(const struct tsm_measurements *tm)
142{
143	size_t nlen;
144
145	if (!tm || !tm->mrs)
146		return ERR_PTR(-EINVAL);
147
148	/* aggregated length of all MR names */
149	nlen = 0;
150	for (size_t i = 0; i < tm->nr_mrs; ++i) {
151		if ((tm->mrs[i].mr_flags & TSM_MR_F_LIVE) && !tm->refresh)
152			return ERR_PTR(-EINVAL);
153
154		if ((tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) && !tm->write)
155			return ERR_PTR(-EINVAL);
156
157		if (!tm->mrs[i].mr_name)
158			return ERR_PTR(-EINVAL);
159
160		if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH)
161			continue;
162
163		if (tm->mrs[i].mr_hash >= HASH_ALGO__LAST)
164			return ERR_PTR(-EINVAL);
165
166		/* MR sysfs attribute names have the form of MRNAME:HASH */
167		nlen += strlen(tm->mrs[i].mr_name) + 1 +
168			strlen(hash_algo_name[tm->mrs[i].mr_hash]) + 1;
169	}
170
171	/*
172	 * @attrs and the MR name strings are combined into a single allocation
173	 * so that we don't have to free MR names one-by-one in
174	 * tsm_mr_free_attribute_group()
175	 */
176	const struct bin_attribute **attrs __free(kfree) =
177		kzalloc(sizeof(*attrs) * (tm->nr_mrs + 1) + nlen, GFP_KERNEL);
178	struct tm_context *ctx __free(kfree) =
179		kzalloc(struct_size(ctx, mrs, tm->nr_mrs), GFP_KERNEL);
180	char *name, *end;
181
182	if (!ctx || !attrs)
183		return ERR_PTR(-ENOMEM);
184
185	/* @attrs is followed immediately by MR name strings */
186	name = (char *)&attrs[tm->nr_mrs + 1];
187	end = name + nlen;
188
189	for (size_t i = 0; i < tm->nr_mrs; ++i) {
190		struct bin_attribute *bap = &ctx->mrs[i];
191
192		sysfs_bin_attr_init(bap);
193
194		if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH)
195			bap->attr.name = tm->mrs[i].mr_name;
196		else if (name < end) {
197			bap->attr.name = name;
198			name += snprintf(name, end - name, "%s:%s",
199					 tm->mrs[i].mr_name,
200					 hash_algo_name[tm->mrs[i].mr_hash]);
201			++name;
202		} else
203			return ERR_PTR(-EINVAL);
204
205		/* check for duplicated MR definitions */
206		for (size_t j = 0; j < i; ++j)
207			if (!strcmp(bap->attr.name, attrs[j]->attr.name))
208				return ERR_PTR(-EINVAL);
209
210		if (tm->mrs[i].mr_flags & TSM_MR_F_READABLE) {
211			bap->attr.mode |= 0444;
212			bap->read = tm_digest_read;
213		}
214
215		if (tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) {
216			bap->attr.mode |= 0200;
217			bap->write = tm_digest_write;
218		}
219
220		bap->size = tm->mrs[i].mr_size;
221		bap->private = ctx;
222
223		attrs[i] = bap;
224	}
225
226	if (name != end)
227		return ERR_PTR(-EINVAL);
228
229	init_rwsem(&ctx->rwsem);
230	ctx->agrp.name = "measurements";
231	ctx->agrp.bin_attrs = no_free_ptr(attrs);
232	ctx->tm = tm;
233	return &no_free_ptr(ctx)->agrp;
234}
235EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group);
236
237/**
238 * tsm_mr_free_attribute_group() - frees the attribute group returned by
239 * tsm_mr_create_attribute_group()
240 * @attr_grp: attribute group returned by tsm_mr_create_attribute_group()
241 *
242 * Context: Process context.
243 */
244void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp)
245{
246	if (!IS_ERR_OR_NULL(attr_grp)) {
247		kfree(attr_grp->bin_attrs);
248		kfree(container_of(attr_grp, struct tm_context, agrp));
249	}
250}
251EXPORT_SYMBOL_GPL(tsm_mr_free_attribute_group);
~/ Read-only file preview.