Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
1
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
724eaba
Documentation
LICENSES
arch
block
certs
crypto
drivers
accessibility
acpi
amba
android
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
agp
hw_random
ipmi
mwave
pcmcia
tpm
eventlog
st33zp24
Kconfig
Makefile
tpm-chip.c
tpm-dev-common.c
tpm-dev.c
tpm-dev.h
tpm-interface.c
tpm-sysfs.c
tpm.h
tpm1-cmd.c
tpm2-cmd.c
tpm2-space.c
tpm_atmel.c
tpm_atmel.h
tpm_crb.c
tpm_ftpm_tee.c
tpm_ftpm_tee.h
tpm_i2c_atmel.c
tpm_i2c_infineon.c
tpm_i2c_nuvoton.c
tpm_ibmvtpm.c
tpm_ibmvtpm.h
tpm_infineon.c
tpm_nsc.c
tpm_ppi.c
tpm_tis.c
tpm_tis_core.c
tpm_tis_core.h
tpm_tis_i2c_cr50.c
tpm_tis_spi.h
tpm_tis_spi_cr50.c
tpm_tis_spi_main.c
tpm_tis_synquacer.c
tpm_vtpm_proxy.c
tpmrm-dev.c
xen-tpmfront.c
xilinx_hwicap
xillybus
Kconfig
Makefile
adi.c
apm-emulation.c
applicom.c
applicom.h
bsr.c
ds1620.c
dsp56k.c
dtlk.c
hangcheck-timer.c
hpet.c
lp.c
mem.c
misc.c
mspec.c
nsc_gpio.c
nvram.c
nwbutton.c
nwbutton.h
nwflash.c
pc8736x_gpio.c
powernv-op-panel.c
ppdev.c
ps3flash.c
random.c
raw.c
scx200_gpio.c
sonypi.c
tb0219.c
tlclk.c
toshiba.c
ttyprintk.c
uv_mmtimer.c
virtio_console.c
clk
clocksource
connector
counter
cpufreq
cpuidle
crypto
dax
dca
devfreq
dio
dma-buf
dma
edac
eisa
extcon
firewire
firmware
fpga
fsi
gnss
gpio
gpu
greybus
hid
hsi
hv
hwmon
hwspinlock
hwtracing
i2c
i3c
ide
idle
iio
infiniband
input
interconnect
iommu
ipack
irqchip
isdn
leds
lightnvm
macintosh
mailbox
mcb
md
media
memory
memstick
message
mfd
misc
mmc
most
mtd
mux
net
nfc
ntb
nubus
nvdimm
nvme
nvmem
of
opp
oprofile
parisc
parport
pci
pcmcia
perf
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
ras
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sfi
sh
siox
slimbus
soc
soundwire
spi
spmi
ssb
staging
target
tc
tee
thermal
thunderbolt
tty
uio
usb
vdpa
vfio
vhost
video
virt
virtio
visorbus
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.clang-format
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
drivers
/
char
/
tpm
/
tpm-dev-common.c
Copy path
Blame
Blame
Latest commit
Sebastian Andrzej Siewior
and
Jarkko Sakkinen
tpm: Remove tpm_dev_wq_lock
Feb 16, 2021
724eaba
·
Feb 16, 2021
History
History
278 lines (237 loc) · 6.67 KB
Breadcrumbs
linux
/
drivers
/
char
/
tpm
/
tpm-dev-common.c
Top
File metadata and controls
Code
Blame
278 lines (237 loc) · 6.67 KB
Raw
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004 IBM Corporation * Authors: * Leendert van Doorn <leendert@watson.ibm.com> * Dave Safford <safford@watson.ibm.com> * Reiner Sailer <sailer@watson.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * * Copyright (C) 2013 Obsidian Research Corp * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> * * Device file system interface to the TPM */ #include <linux/poll.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/workqueue.h> #include "tpm.h" #include "tpm-dev.h" static struct workqueue_struct *tpm_dev_wq; static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space, u8 *buf, size_t bufsiz) { struct tpm_header *header = (void *)buf; ssize_t ret, len; ret = tpm2_prepare_space(chip, space, buf, bufsiz); /* If the command is not implemented by the TPM, synthesize a * response with a TPM2_RC_COMMAND_CODE return for user-space. */ if (ret == -EOPNOTSUPP) { header->length = cpu_to_be32(sizeof(*header)); header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | TSS2_RESMGR_TPM_RC_LAYER); ret = sizeof(*header); } if (ret) goto out_rc; len = tpm_transmit(chip, buf, bufsiz); if (len < 0) ret = len; if (!ret) ret = tpm2_commit_space(chip, space, buf, &len); out_rc: return ret ? ret : len; } static void tpm_dev_async_work(struct work_struct *work) { struct file_priv *priv = container_of(work, struct file_priv, async_work); ssize_t ret; mutex_lock(&priv->buffer_mutex); priv->command_enqueued = false; ret = tpm_try_get_ops(priv->chip); if (ret) { priv->response_length = ret; goto out; } ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); if (ret > 0) { priv->response_length = ret; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); } out: mutex_unlock(&priv->buffer_mutex); wake_up_interruptible(&priv->async_wait); } static void user_reader_timeout(struct timer_list *t) { struct file_priv *priv = from_timer(priv, t, user_read_timer); pr_warn("TPM user space timeout is deprecated (pid=%d)\n", task_tgid_nr(current)); schedule_work(&priv->timeout_work); } static void tpm_timeout_work(struct work_struct *work) { struct file_priv *priv = container_of(work, struct file_priv, timeout_work); mutex_lock(&priv->buffer_mutex); priv->response_read = true; priv->response_length = 0; memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); mutex_unlock(&priv->buffer_mutex); wake_up_interruptible(&priv->async_wait); } void tpm_common_open(struct file *file, struct tpm_chip *chip, struct file_priv *priv, struct tpm_space *space) { priv->chip = chip; priv->space = space; priv->response_read = true; mutex_init(&priv->buffer_mutex); timer_setup(&priv->user_read_timer, user_reader_timeout, 0); INIT_WORK(&priv->timeout_work, tpm_timeout_work); INIT_WORK(&priv->async_work, tpm_dev_async_work); init_waitqueue_head(&priv->async_wait); file->private_data = priv; } ssize_t tpm_common_read(struct file *file, char __user *buf, size_t size, loff_t *off) { struct file_priv *priv = file->private_data; ssize_t ret_size = 0; int rc; mutex_lock(&priv->buffer_mutex); if (priv->response_length) { priv->response_read = true; ret_size = min_t(ssize_t, size, priv->response_length); if (ret_size <= 0) { priv->response_length = 0; goto out; } rc = copy_to_user(buf, priv->data_buffer + *off, ret_size); if (rc) { memset(priv->data_buffer, 0, TPM_BUFSIZE); priv->response_length = 0; ret_size = -EFAULT; } else { memset(priv->data_buffer + *off, 0, ret_size); priv->response_length -= ret_size; *off += ret_size; } } out: if (!priv->response_length) { *off = 0; del_singleshot_timer_sync(&priv->user_read_timer); flush_work(&priv->timeout_work); } mutex_unlock(&priv->buffer_mutex); return ret_size; } ssize_t tpm_common_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { struct file_priv *priv = file->private_data; int ret = 0; if (size > TPM_BUFSIZE) return -E2BIG; mutex_lock(&priv->buffer_mutex); /* Cannot perform a write until the read has cleared either via * tpm_read or a user_read_timer timeout. This also prevents split * buffered writes from blocking here. */ if ((!priv->response_read && priv->response_length) || priv->command_enqueued) { ret = -EBUSY; goto out; } if (copy_from_user(priv->data_buffer, buf, size)) { ret = -EFAULT; goto out; } if (size < 6 || size < be32_to_cpu(*((__be32 *)(priv->data_buffer + 2)))) { ret = -EINVAL; goto out; } priv->response_length = 0; priv->response_read = false; *off = 0; /* * If in nonblocking mode schedule an async job to send * the command return the size. * In case of error the err code will be returned in * the subsequent read call. */ if (file->f_flags & O_NONBLOCK) { priv->command_enqueued = true; queue_work(tpm_dev_wq, &priv->async_work); mutex_unlock(&priv->buffer_mutex); return size; } /* atomic tpm command send and result receive. We only hold the ops * lock during this period so that the tpm can be unregistered even if * the char dev is held open. */ if (tpm_try_get_ops(priv->chip)) { ret = -EPIPE; goto out; } ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); if (ret > 0) { priv->response_length = ret; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); ret = size; } out: mutex_unlock(&priv->buffer_mutex); return ret; } __poll_t tpm_common_poll(struct file *file, poll_table *wait) { struct file_priv *priv = file->private_data; __poll_t mask = 0; poll_wait(file, &priv->async_wait, wait); mutex_lock(&priv->buffer_mutex); /* * The response_length indicates if there is still response * (or part of it) to be consumed. Partial reads decrease it * by the number of bytes read, and write resets it the zero. */ if (priv->response_length) mask = EPOLLIN | EPOLLRDNORM; else mask = EPOLLOUT | EPOLLWRNORM; mutex_unlock(&priv->buffer_mutex); return mask; } /* * Called on file close */ void tpm_common_release(struct file *file, struct file_priv *priv) { flush_work(&priv->async_work); del_singleshot_timer_sync(&priv->user_read_timer); flush_work(&priv->timeout_work); file->private_data = NULL; priv->response_length = 0; } int __init tpm_dev_common_init(void) { tpm_dev_wq = alloc_workqueue("tpm_dev_wq", WQ_MEM_RECLAIM, 0); return !tpm_dev_wq ? -ENOMEM : 0; } void __exit tpm_dev_common_exit(void) { if (tpm_dev_wq) { destroy_workqueue(tpm_dev_wq); tpm_dev_wq = NULL; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
You can’t perform that action at this time.