Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
afb5abc2 JS |
2 | /* |
3 | * Copyright (C) 2004 IBM Corporation | |
4 | * Copyright (C) 2014 Intel Corporation | |
5 | * | |
6 | * Authors: | |
7 | * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | |
8 | * Leendert van Doorn <leendert@watson.ibm.com> | |
9 | * Dave Safford <safford@watson.ibm.com> | |
10 | * Reiner Sailer <sailer@watson.ibm.com> | |
11 | * Kylene Hall <kjhall@us.ibm.com> | |
12 | * | |
13 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | |
14 | * | |
15 | * TPM chip management routines. | |
afb5abc2 JS |
16 | */ |
17 | ||
18 | #include <linux/poll.h> | |
19 | #include <linux/slab.h> | |
20 | #include <linux/mutex.h> | |
21 | #include <linux/spinlock.h> | |
22 | #include <linux/freezer.h> | |
313d21ee | 23 | #include <linux/major.h> |
fd3ec366 | 24 | #include <linux/tpm_eventlog.h> |
6e592a06 | 25 | #include <linux/hw_random.h> |
afb5abc2 | 26 | #include "tpm.h" |
afb5abc2 | 27 | |
15516788 SB |
28 | DEFINE_IDR(dev_nums_idr); |
29 | static DEFINE_MUTEX(idr_lock); | |
afb5abc2 | 30 | |
d2e8071b IO |
31 | const struct class tpm_class = { |
32 | .name = "tpm", | |
33 | .shutdown_pre = tpm_class_shutdown, | |
34 | }; | |
35 | const struct class tpmrm_class = { | |
ea72883a | 36 | .name = "tpmrm", |
d2e8071b | 37 | }; |
313d21ee JS |
38 | dev_t tpm_devt; |
39 | ||
47a6c28b | 40 | static int tpm_request_locality(struct tpm_chip *chip) |
719b7d81 JS |
41 | { |
42 | int rc; | |
43 | ||
719b7d81 JS |
44 | if (!chip->ops->request_locality) |
45 | return 0; | |
46 | ||
47 | rc = chip->ops->request_locality(chip, 0); | |
48 | if (rc < 0) | |
49 | return rc; | |
50 | ||
51 | chip->locality = rc; | |
52 | return 0; | |
53 | } | |
54 | ||
47a6c28b | 55 | static void tpm_relinquish_locality(struct tpm_chip *chip) |
719b7d81 JS |
56 | { |
57 | int rc; | |
58 | ||
719b7d81 JS |
59 | if (!chip->ops->relinquish_locality) |
60 | return; | |
61 | ||
62 | rc = chip->ops->relinquish_locality(chip, chip->locality); | |
63 | if (rc) | |
64 | dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); | |
65 | ||
66 | chip->locality = -1; | |
67 | } | |
68 | ||
47a6c28b | 69 | static int tpm_cmd_ready(struct tpm_chip *chip) |
719b7d81 | 70 | { |
719b7d81 JS |
71 | if (!chip->ops->cmd_ready) |
72 | return 0; | |
73 | ||
74 | return chip->ops->cmd_ready(chip); | |
75 | } | |
76 | ||
47a6c28b | 77 | static int tpm_go_idle(struct tpm_chip *chip) |
719b7d81 | 78 | { |
719b7d81 JS |
79 | if (!chip->ops->go_idle) |
80 | return 0; | |
81 | ||
82 | return chip->ops->go_idle(chip); | |
83 | } | |
84 | ||
1e5ac630 MB |
85 | static void tpm_clk_enable(struct tpm_chip *chip) |
86 | { | |
87 | if (chip->ops->clk_enable) | |
88 | chip->ops->clk_enable(chip, true); | |
89 | } | |
90 | ||
91 | static void tpm_clk_disable(struct tpm_chip *chip) | |
92 | { | |
93 | if (chip->ops->clk_enable) | |
94 | chip->ops->clk_enable(chip, false); | |
95 | } | |
96 | ||
719b7d81 JS |
97 | /** |
98 | * tpm_chip_start() - power on the TPM | |
99 | * @chip: a TPM chip to use | |
719b7d81 JS |
100 | * |
101 | * Return: | |
102 | * * The response length - OK | |
103 | * * -errno - A system error | |
104 | */ | |
47a6c28b | 105 | int tpm_chip_start(struct tpm_chip *chip) |
719b7d81 JS |
106 | { |
107 | int ret; | |
108 | ||
1e5ac630 | 109 | tpm_clk_enable(chip); |
719b7d81 JS |
110 | |
111 | if (chip->locality == -1) { | |
47a6c28b | 112 | ret = tpm_request_locality(chip); |
719b7d81 | 113 | if (ret) { |
1e5ac630 | 114 | tpm_clk_disable(chip); |
719b7d81 JS |
115 | return ret; |
116 | } | |
117 | } | |
118 | ||
47a6c28b | 119 | ret = tpm_cmd_ready(chip); |
719b7d81 | 120 | if (ret) { |
47a6c28b | 121 | tpm_relinquish_locality(chip); |
1e5ac630 | 122 | tpm_clk_disable(chip); |
719b7d81 JS |
123 | return ret; |
124 | } | |
125 | ||
126 | return 0; | |
127 | } | |
128 | EXPORT_SYMBOL_GPL(tpm_chip_start); | |
129 | ||
130 | /** | |
131 | * tpm_chip_stop() - power off the TPM | |
132 | * @chip: a TPM chip to use | |
719b7d81 JS |
133 | * |
134 | * Return: | |
135 | * * The response length - OK | |
136 | * * -errno - A system error | |
137 | */ | |
47a6c28b | 138 | void tpm_chip_stop(struct tpm_chip *chip) |
719b7d81 | 139 | { |
47a6c28b JS |
140 | tpm_go_idle(chip); |
141 | tpm_relinquish_locality(chip); | |
1e5ac630 | 142 | tpm_clk_disable(chip); |
719b7d81 JS |
143 | } |
144 | EXPORT_SYMBOL_GPL(tpm_chip_stop); | |
145 | ||
4e26195f JG |
146 | /** |
147 | * tpm_try_get_ops() - Get a ref to the tpm_chip | |
148 | * @chip: Chip to ref | |
149 | * | |
150 | * The caller must already have some kind of locking to ensure that chip is | |
151 | * valid. This function will lock the chip so that the ops member can be | |
152 | * accessed safely. The locking prevents tpm_chip_unregister from | |
153 | * completing, so it should not be held for long periods. | |
154 | * | |
155 | * Returns -ERRNO if the chip could not be got. | |
afb5abc2 | 156 | */ |
4e26195f JG |
157 | int tpm_try_get_ops(struct tpm_chip *chip) |
158 | { | |
159 | int rc = -EIO; | |
160 | ||
eb24c978 JB |
161 | if (chip->flags & TPM_CHIP_FLAG_DISABLE) |
162 | return rc; | |
163 | ||
4e26195f JG |
164 | get_device(&chip->dev); |
165 | ||
166 | down_read(&chip->ops_sem); | |
167 | if (!chip->ops) | |
a3fbfae8 | 168 | goto out_ops; |
4e26195f | 169 | |
2f257402 | 170 | mutex_lock(&chip->tpm_mutex); |
47a6c28b | 171 | rc = tpm_chip_start(chip); |
a3fbfae8 JS |
172 | if (rc) |
173 | goto out_lock; | |
174 | ||
4e26195f JG |
175 | return 0; |
176 | out_lock: | |
a3fbfae8 JS |
177 | mutex_unlock(&chip->tpm_mutex); |
178 | out_ops: | |
4e26195f JG |
179 | up_read(&chip->ops_sem); |
180 | put_device(&chip->dev); | |
181 | return rc; | |
182 | } | |
183 | EXPORT_SYMBOL_GPL(tpm_try_get_ops); | |
184 | ||
185 | /** | |
186 | * tpm_put_ops() - Release a ref to the tpm_chip | |
187 | * @chip: Chip to put | |
188 | * | |
189 | * This is the opposite pair to tpm_try_get_ops(). After this returns chip may | |
190 | * be kfree'd. | |
191 | */ | |
192 | void tpm_put_ops(struct tpm_chip *chip) | |
193 | { | |
47a6c28b | 194 | tpm_chip_stop(chip); |
2f257402 | 195 | mutex_unlock(&chip->tpm_mutex); |
4e26195f JG |
196 | up_read(&chip->ops_sem); |
197 | put_device(&chip->dev); | |
198 | } | |
199 | EXPORT_SYMBOL_GPL(tpm_put_ops); | |
200 | ||
aaae8153 SB |
201 | /** |
202 | * tpm_default_chip() - find a TPM chip and get a reference to it | |
203 | */ | |
204 | struct tpm_chip *tpm_default_chip(void) | |
205 | { | |
206 | struct tpm_chip *chip, *res = NULL; | |
207 | int chip_num = 0; | |
208 | int chip_prev; | |
209 | ||
210 | mutex_lock(&idr_lock); | |
211 | ||
212 | do { | |
213 | chip_prev = chip_num; | |
214 | chip = idr_get_next(&dev_nums_idr, &chip_num); | |
215 | if (chip) { | |
216 | get_device(&chip->dev); | |
217 | res = chip; | |
218 | break; | |
219 | } | |
220 | } while (chip_prev != chip_num); | |
221 | ||
222 | mutex_unlock(&idr_lock); | |
223 | ||
224 | return res; | |
225 | } | |
226 | EXPORT_SYMBOL_GPL(tpm_default_chip); | |
227 | ||
4e26195f | 228 | /** |
fc1d52b7 | 229 | * tpm_find_get_ops() - find and reserve a TPM chip |
aad887f6 | 230 | * @chip: a &struct tpm_chip instance, %NULL for the default chip |
4e26195f | 231 | * |
aad887f6 | 232 | * Finds a TPM chip and reserves its class device and operations. The chip must |
fc1d52b7 SB |
233 | * be released with tpm_put_ops() after use. |
234 | * This function is for internal use only. It supports existing TPM callers | |
235 | * by accepting NULL, but those callers should be converted to pass in a chip | |
236 | * directly. | |
aad887f6 JS |
237 | * |
238 | * Return: | |
239 | * A reserved &struct tpm_chip instance. | |
240 | * %NULL if a chip is not found. | |
241 | * %NULL if the chip is not available. | |
37f4915f | 242 | */ |
fc1d52b7 | 243 | struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) |
afb5abc2 | 244 | { |
eccc9bb8 | 245 | int rc; |
15516788 | 246 | |
eccc9bb8 | 247 | if (chip) { |
aad887f6 | 248 | if (!tpm_try_get_ops(chip)) |
eccc9bb8 SB |
249 | return chip; |
250 | return NULL; | |
15516788 | 251 | } |
afb5abc2 | 252 | |
eccc9bb8 SB |
253 | chip = tpm_default_chip(); |
254 | if (!chip) | |
255 | return NULL; | |
256 | rc = tpm_try_get_ops(chip); | |
257 | /* release additional reference we got from tpm_default_chip() */ | |
258 | put_device(&chip->dev); | |
259 | if (rc) | |
260 | return NULL; | |
261 | return chip; | |
afb5abc2 JS |
262 | } |
263 | ||
264 | /** | |
313d21ee JS |
265 | * tpm_dev_release() - free chip memory and the device number |
266 | * @dev: the character device for the TPM chip | |
afb5abc2 | 267 | * |
313d21ee | 268 | * This is used as the release function for the character device. |
afb5abc2 | 269 | */ |
313d21ee | 270 | static void tpm_dev_release(struct device *dev) |
afb5abc2 | 271 | { |
313d21ee | 272 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); |
afb5abc2 | 273 | |
15516788 SB |
274 | mutex_lock(&idr_lock); |
275 | idr_remove(&dev_nums_idr, chip->dev_num); | |
276 | mutex_unlock(&idr_lock); | |
277 | ||
745b361e | 278 | kfree(chip->work_space.context_buf); |
4d57856a | 279 | kfree(chip->work_space.session_buf); |
bcfff838 | 280 | kfree(chip->allocated_banks); |
699e3efd JB |
281 | #ifdef CONFIG_TCG_TPM2_HMAC |
282 | kfree(chip->auth); | |
283 | #endif | |
afb5abc2 JS |
284 | kfree(chip); |
285 | } | |
286 | ||
d1bd4a79 JZ |
287 | /** |
288 | * tpm_class_shutdown() - prepare the TPM device for loss of power. | |
289 | * @dev: device to which the chip is associated. | |
290 | * | |
291 | * Issues a TPM2_Shutdown command prior to loss of power, as required by the | |
28eba2fd | 292 | * TPM 2.0 spec. Then, calls bus- and device- specific shutdown code. |
d1bd4a79 | 293 | * |
28eba2fd | 294 | * Return: always 0 (i.e. success) |
d1bd4a79 | 295 | */ |
a010eb88 | 296 | int tpm_class_shutdown(struct device *dev) |
d1bd4a79 JZ |
297 | { |
298 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); | |
299 | ||
db4d8cb9 | 300 | down_write(&chip->ops_sem); |
d1bd4a79 | 301 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
47a6c28b | 302 | if (!tpm_chip_start(chip)) { |
a3fbfae8 | 303 | tpm2_shutdown(chip, TPM2_SU_CLEAR); |
47a6c28b | 304 | tpm_chip_stop(chip); |
a3fbfae8 | 305 | } |
d1bd4a79 | 306 | } |
db4d8cb9 VS |
307 | chip->ops = NULL; |
308 | up_write(&chip->ops_sem); | |
7521621e | 309 | |
d1bd4a79 JZ |
310 | return 0; |
311 | } | |
312 | ||
afb5abc2 | 313 | /** |
3897cd9c JG |
314 | * tpm_chip_alloc() - allocate a new struct tpm_chip instance |
315 | * @pdev: device to which the chip is associated | |
316 | * At this point pdev mst be initialized, but does not have to | |
317 | * be registered | |
afb5abc2 JS |
318 | * @ops: struct tpm_class_ops instance |
319 | * | |
320 | * Allocates a new struct tpm_chip instance and assigns a free | |
3897cd9c | 321 | * device number for it. Must be paired with put_device(&chip->dev). |
afb5abc2 | 322 | */ |
2998b02b | 323 | struct tpm_chip *tpm_chip_alloc(struct device *pdev, |
3897cd9c | 324 | const struct tpm_class_ops *ops) |
afb5abc2 JS |
325 | { |
326 | struct tpm_chip *chip; | |
4f3b193d | 327 | int rc; |
afb5abc2 JS |
328 | |
329 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
330 | if (chip == NULL) | |
331 | return ERR_PTR(-ENOMEM); | |
332 | ||
333 | mutex_init(&chip->tpm_mutex); | |
4e26195f | 334 | init_rwsem(&chip->ops_sem); |
afb5abc2 JS |
335 | |
336 | chip->ops = ops; | |
337 | ||
15516788 SB |
338 | mutex_lock(&idr_lock); |
339 | rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL); | |
340 | mutex_unlock(&idr_lock); | |
341 | if (rc < 0) { | |
2998b02b | 342 | dev_err(pdev, "No available tpm device numbers\n"); |
afb5abc2 | 343 | kfree(chip); |
15516788 | 344 | return ERR_PTR(rc); |
afb5abc2 | 345 | } |
15516788 | 346 | chip->dev_num = rc; |
afb5abc2 | 347 | |
3635e2ec | 348 | device_initialize(&chip->dev); |
afb5abc2 | 349 | |
d2e8071b | 350 | chip->dev.class = &tpm_class; |
313d21ee | 351 | chip->dev.release = tpm_dev_release; |
2998b02b | 352 | chip->dev.parent = pdev; |
9b774d5c | 353 | chip->dev.groups = chip->groups; |
313d21ee JS |
354 | |
355 | if (chip->dev_num == 0) | |
356 | chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); | |
357 | else | |
358 | chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); | |
359 | ||
3635e2ec JG |
360 | rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num); |
361 | if (rc) | |
362 | goto out; | |
313d21ee | 363 | |
2998b02b | 364 | if (!pdev) |
2f9f5377 SB |
365 | chip->flags |= TPM_CHIP_FLAG_VIRTUAL; |
366 | ||
313d21ee | 367 | cdev_init(&chip->cdev, &tpm_fops); |
2072df40 | 368 | chip->cdev.owner = THIS_MODULE; |
313d21ee | 369 | |
6c4e79d9 JS |
370 | rc = tpm2_init_space(&chip->work_space, TPM2_SPACE_BUFFER_SIZE); |
371 | if (rc) { | |
4d57856a JB |
372 | rc = -ENOMEM; |
373 | goto out; | |
374 | } | |
745b361e | 375 | |
877c57d0 | 376 | chip->locality = -1; |
3897cd9c JG |
377 | return chip; |
378 | ||
379 | out: | |
380 | put_device(&chip->dev); | |
381 | return ERR_PTR(rc); | |
382 | } | |
383 | EXPORT_SYMBOL_GPL(tpm_chip_alloc); | |
384 | ||
e10de46b AB |
385 | static void tpm_put_device(void *dev) |
386 | { | |
387 | put_device(dev); | |
388 | } | |
389 | ||
3897cd9c JG |
390 | /** |
391 | * tpmm_chip_alloc() - allocate a new struct tpm_chip instance | |
392 | * @pdev: parent device to which the chip is associated | |
393 | * @ops: struct tpm_class_ops instance | |
394 | * | |
395 | * Same as tpm_chip_alloc except devm is used to do the put_device | |
396 | */ | |
397 | struct tpm_chip *tpmm_chip_alloc(struct device *pdev, | |
398 | const struct tpm_class_ops *ops) | |
399 | { | |
400 | struct tpm_chip *chip; | |
401 | int rc; | |
402 | ||
403 | chip = tpm_chip_alloc(pdev, ops); | |
404 | if (IS_ERR(chip)) | |
405 | return chip; | |
406 | ||
2b88cd96 | 407 | rc = devm_add_action_or_reset(pdev, |
e10de46b | 408 | tpm_put_device, |
2b88cd96 SM |
409 | &chip->dev); |
410 | if (rc) | |
4f3b193d | 411 | return ERR_PTR(rc); |
8e0ee3c9 | 412 | |
3897cd9c | 413 | dev_set_drvdata(pdev, chip); |
3635e2ec | 414 | |
3897cd9c | 415 | return chip; |
afb5abc2 JS |
416 | } |
417 | EXPORT_SYMBOL_GPL(tpmm_chip_alloc); | |
418 | ||
72c91ce8 | 419 | static int tpm_add_char_device(struct tpm_chip *chip) |
313d21ee JS |
420 | { |
421 | int rc; | |
422 | ||
8dbbf582 | 423 | rc = cdev_device_add(&chip->cdev, &chip->dev); |
313d21ee JS |
424 | if (rc) { |
425 | dev_err(&chip->dev, | |
8dbbf582 | 426 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", |
3635e2ec | 427 | dev_name(&chip->dev), MAJOR(chip->dev.devt), |
313d21ee | 428 | MINOR(chip->dev.devt), rc); |
313d21ee JS |
429 | return rc; |
430 | } | |
431 | ||
0aa69878 | 432 | if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) { |
7e0438f8 LS |
433 | rc = tpm_devs_add(chip); |
434 | if (rc) | |
435 | goto err_del_cdev; | |
fdc915f7 JB |
436 | } |
437 | ||
15516788 SB |
438 | /* Make the chip available. */ |
439 | mutex_lock(&idr_lock); | |
440 | idr_replace(&dev_nums_idr, chip, chip->dev_num); | |
441 | mutex_unlock(&idr_lock); | |
442 | ||
7e0438f8 LS |
443 | return 0; |
444 | ||
445 | err_del_cdev: | |
446 | cdev_device_del(&chip->cdev, &chip->dev); | |
313d21ee JS |
447 | return rc; |
448 | } | |
449 | ||
72c91ce8 | 450 | static void tpm_del_char_device(struct tpm_chip *chip) |
313d21ee | 451 | { |
8dbbf582 | 452 | cdev_device_del(&chip->cdev, &chip->dev); |
15516788 SB |
453 | |
454 | /* Make the chip unavailable. */ | |
455 | mutex_lock(&idr_lock); | |
456 | idr_replace(&dev_nums_idr, NULL, chip->dev_num); | |
457 | mutex_unlock(&idr_lock); | |
4e26195f JG |
458 | |
459 | /* Make the driver uncallable. */ | |
460 | down_write(&chip->ops_sem); | |
eabad7ba LS |
461 | |
462 | /* | |
463 | * Check if chip->ops is still valid: In case that the controller | |
464 | * drivers shutdown handler unregisters the controller in its | |
465 | * shutdown handler we are called twice and chip->ops to NULL. | |
466 | */ | |
467 | if (chip->ops) { | |
468 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { | |
469 | if (!tpm_chip_start(chip)) { | |
470 | tpm2_shutdown(chip, TPM2_SU_CLEAR); | |
471 | tpm_chip_stop(chip); | |
472 | } | |
a3fbfae8 | 473 | } |
eabad7ba | 474 | chip->ops = NULL; |
a3fbfae8 | 475 | } |
4e26195f | 476 | up_write(&chip->ops_sem); |
313d21ee JS |
477 | } |
478 | ||
062807f2 JG |
479 | static void tpm_del_legacy_sysfs(struct tpm_chip *chip) |
480 | { | |
481 | struct attribute **i; | |
482 | ||
0aa69878 | 483 | if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) || |
484 | tpm_is_firmware_upgrade(chip)) | |
062807f2 | 485 | return; |
34d47b63 | 486 | |
062807f2 JG |
487 | sysfs_remove_link(&chip->dev.parent->kobj, "ppi"); |
488 | ||
489 | for (i = chip->groups[0]->attrs; *i != NULL; ++i) | |
490 | sysfs_remove_link(&chip->dev.parent->kobj, (*i)->name); | |
34d47b63 JS |
491 | } |
492 | ||
062807f2 JG |
493 | /* For compatibility with legacy sysfs paths we provide symlinks from the |
494 | * parent dev directory to selected names within the tpm chip directory. Old | |
495 | * kernel versions created these files directly under the parent. | |
496 | */ | |
497 | static int tpm_add_legacy_sysfs(struct tpm_chip *chip) | |
498 | { | |
499 | struct attribute **i; | |
500 | int rc; | |
501 | ||
0aa69878 | 502 | if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) || |
503 | tpm_is_firmware_upgrade(chip)) | |
062807f2 JG |
504 | return 0; |
505 | ||
70fbdfef LT |
506 | rc = compat_only_sysfs_link_entry_to_kobj( |
507 | &chip->dev.parent->kobj, &chip->dev.kobj, "ppi", NULL); | |
062807f2 JG |
508 | if (rc && rc != -ENOENT) |
509 | return rc; | |
510 | ||
511 | /* All the names from tpm-sysfs */ | |
512 | for (i = chip->groups[0]->attrs; *i != NULL; ++i) { | |
70fbdfef LT |
513 | rc = compat_only_sysfs_link_entry_to_kobj( |
514 | &chip->dev.parent->kobj, &chip->dev.kobj, (*i)->name, NULL); | |
062807f2 JG |
515 | if (rc) { |
516 | tpm_del_legacy_sysfs(chip); | |
517 | return rc; | |
518 | } | |
519 | } | |
520 | ||
521 | return 0; | |
522 | } | |
6e592a06 JG |
523 | |
524 | static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) | |
525 | { | |
526 | struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); | |
527 | ||
99d46450 JS |
528 | /* Give back zero bytes, as TPM chip has not yet fully resumed: */ |
529 | if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) | |
530 | return 0; | |
531 | ||
6e592a06 JG |
532 | return tpm_get_random(chip, data, max); |
533 | } | |
534 | ||
cacc6e22 ML |
535 | static bool tpm_is_hwrng_enabled(struct tpm_chip *chip) |
536 | { | |
537 | if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) | |
538 | return false; | |
539 | if (tpm_is_firmware_upgrade(chip)) | |
540 | return false; | |
541 | if (chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED) | |
542 | return false; | |
543 | return true; | |
544 | } | |
545 | ||
6e592a06 JG |
546 | static int tpm_add_hwrng(struct tpm_chip *chip) |
547 | { | |
cacc6e22 | 548 | if (!tpm_is_hwrng_enabled(chip)) |
6e592a06 JG |
549 | return 0; |
550 | ||
551 | snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), | |
552 | "tpm-rng-%d", chip->dev_num); | |
553 | chip->hwrng.name = chip->hwrng_name; | |
554 | chip->hwrng.read = tpm_hwrng_read; | |
555 | return hwrng_register(&chip->hwrng); | |
556 | } | |
557 | ||
fa4f99c0 NJ |
558 | static int tpm_get_pcr_allocation(struct tpm_chip *chip) |
559 | { | |
560 | int rc; | |
561 | ||
0aa69878 | 562 | if (tpm_is_firmware_upgrade(chip)) |
563 | return 0; | |
564 | ||
fa4f99c0 NJ |
565 | rc = (chip->flags & TPM_CHIP_FLAG_TPM2) ? |
566 | tpm2_get_pcr_allocation(chip) : | |
567 | tpm1_get_pcr_allocation(chip); | |
568 | ||
569 | if (rc > 0) | |
570 | return -ENODEV; | |
571 | ||
572 | return rc; | |
573 | } | |
574 | ||
548eb516 | 575 | /* |
0c8862de | 576 | * tpm_chip_bootstrap() - Boostrap TPM chip after power on |
548eb516 | 577 | * @chip: TPM chip to use. |
0c8862de JS |
578 | * |
579 | * Initialize TPM chip after power on. This a one-shot function: subsequent | |
580 | * calls will have no effect. | |
548eb516 | 581 | */ |
0c8862de | 582 | int tpm_chip_bootstrap(struct tpm_chip *chip) |
548eb516 LS |
583 | { |
584 | int rc; | |
585 | ||
0c8862de JS |
586 | if (chip->flags & TPM_CHIP_FLAG_BOOTSTRAPPED) |
587 | return 0; | |
588 | ||
548eb516 LS |
589 | rc = tpm_chip_start(chip); |
590 | if (rc) | |
591 | return rc; | |
592 | ||
593 | rc = tpm_auto_startup(chip); | |
594 | if (rc) | |
595 | goto stop; | |
596 | ||
597 | rc = tpm_get_pcr_allocation(chip); | |
598 | stop: | |
599 | tpm_chip_stop(chip); | |
600 | ||
0c8862de JS |
601 | /* |
602 | * Unconditionally set, as driver initialization should cease, when the | |
603 | * boostrapping process fails. | |
604 | */ | |
605 | chip->flags |= TPM_CHIP_FLAG_BOOTSTRAPPED; | |
606 | ||
548eb516 LS |
607 | return rc; |
608 | } | |
0c8862de | 609 | EXPORT_SYMBOL_GPL(tpm_chip_bootstrap); |
548eb516 | 610 | |
afb5abc2 | 611 | /* |
313d21ee | 612 | * tpm_chip_register() - create a character device for the TPM chip |
afb5abc2 JS |
613 | * @chip: TPM chip to use. |
614 | * | |
d972b052 JS |
615 | * Creates a character device for the TPM chip and adds sysfs attributes for |
616 | * the device. As the last step this function adds the chip to the list of TPM | |
617 | * chips available for in-kernel use. | |
afb5abc2 | 618 | * |
d972b052 JS |
619 | * This function should be only called after the chip initialization is |
620 | * complete. | |
afb5abc2 JS |
621 | */ |
622 | int tpm_chip_register(struct tpm_chip *chip) | |
623 | { | |
624 | int rc; | |
625 | ||
0c8862de JS |
626 | rc = tpm_chip_bootstrap(chip); |
627 | if (rc) | |
628 | return rc; | |
629 | ||
7518a21a JS |
630 | tpm_sysfs_add_device(chip); |
631 | ||
805fa88e | 632 | tpm_bios_log_setup(chip); |
afb5abc2 | 633 | |
9b774d5c JS |
634 | tpm_add_ppi(chip); |
635 | ||
6e592a06 JG |
636 | rc = tpm_add_hwrng(chip); |
637 | if (rc) | |
638 | goto out_ppi; | |
639 | ||
72c91ce8 | 640 | rc = tpm_add_char_device(chip); |
6e592a06 JG |
641 | if (rc) |
642 | goto out_hwrng; | |
d972b052 | 643 | |
062807f2 JG |
644 | rc = tpm_add_legacy_sysfs(chip); |
645 | if (rc) { | |
646 | tpm_chip_unregister(chip); | |
647 | return rc; | |
d56e4f75 JS |
648 | } |
649 | ||
afb5abc2 | 650 | return 0; |
6e592a06 JG |
651 | |
652 | out_hwrng: | |
cacc6e22 | 653 | if (tpm_is_hwrng_enabled(chip)) |
6e592a06 JG |
654 | hwrng_unregister(&chip->hwrng); |
655 | out_ppi: | |
656 | tpm_bios_log_teardown(chip); | |
657 | ||
658 | return rc; | |
afb5abc2 JS |
659 | } |
660 | EXPORT_SYMBOL_GPL(tpm_chip_register); | |
661 | ||
662 | /* | |
663 | * tpm_chip_unregister() - release the TPM driver | |
664 | * @chip: TPM chip to use. | |
665 | * | |
666 | * Takes the chip first away from the list of available TPM chips and then | |
667 | * cleans up all the resources reserved by tpm_chip_register(). | |
668 | * | |
4e26195f JG |
669 | * Once this function returns the driver call backs in 'op's will not be |
670 | * running and will no longer start. | |
671 | * | |
afb5abc2 JS |
672 | * NOTE: This function should be only called before deinitializing chip |
673 | * resources. | |
674 | */ | |
675 | void tpm_chip_unregister(struct tpm_chip *chip) | |
676 | { | |
062807f2 | 677 | tpm_del_legacy_sysfs(chip); |
cacc6e22 | 678 | if (tpm_is_hwrng_enabled(chip)) |
6e592a06 | 679 | hwrng_unregister(&chip->hwrng); |
7518a21a | 680 | tpm_bios_log_teardown(chip); |
0aa69878 | 681 | if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) |
7e0438f8 | 682 | tpm_devs_remove(chip); |
72c91ce8 | 683 | tpm_del_char_device(chip); |
afb5abc2 JS |
684 | } |
685 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); |