tsm-mr.c 6.9 KB

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