aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2017-01-10 22:08:53 -0500
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2017-04-03 15:46:01 -0400
commitecb38e2f521b01f0fd0b0a3261921b0bcc002dd0 (patch)
treef0d5a01599702f14bcddc5c7a2f78058fffffac2
parent745b361e989af21ad40811c2586b60229f870a68 (diff)
tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
-rw-r--r--drivers/char/tpm/Makefile2
-rw-r--r--drivers/char/tpm/tpm-dev-common.c148
-rw-r--r--drivers/char/tpm/tpm-dev.c143
-rw-r--r--drivers/char/tpm/tpm-dev.h27
4 files changed, 190 insertions, 130 deletions
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 8f07fcfbcdfb..10e5827445fc 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -3,7 +3,7 @@
3# 3#
4obj-$(CONFIG_TCG_TPM) += tpm.o 4obj-$(CONFIG_TCG_TPM) += tpm.o
5tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ 5tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
6 tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o 6 tpm-dev-common.o tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o
7tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o 7tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
8tpm-$(CONFIG_OF) += tpm_of.o 8tpm-$(CONFIG_OF) += tpm_of.o
9obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o 9obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
new file mode 100644
index 000000000000..610638a80383
--- /dev/null
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -0,0 +1,148 @@
1/*
2 * Copyright (C) 2004 IBM Corporation
3 * Authors:
4 * Leendert van Doorn <leendert@watson.ibm.com>
5 * Dave Safford <safford@watson.ibm.com>
6 * Reiner Sailer <sailer@watson.ibm.com>
7 * Kylene Hall <kjhall@us.ibm.com>
8 *
9 * Copyright (C) 2013 Obsidian Research Corp
10 * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
11 *
12 * Device file system interface to the TPM
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation, version 2 of the
17 * License.
18 *
19 */
20#include <linux/slab.h>
21#include <linux/uaccess.h>
22#include "tpm.h"
23#include "tpm-dev.h"
24
25static void user_reader_timeout(unsigned long ptr)
26{
27 struct file_priv *priv = (struct file_priv *)ptr;
28
29 pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
30 task_tgid_nr(current));
31
32 schedule_work(&priv->work);
33}
34
35static void timeout_work(struct work_struct *work)
36{
37 struct file_priv *priv = container_of(work, struct file_priv, work);
38
39 mutex_lock(&priv->buffer_mutex);
40 atomic_set(&priv->data_pending, 0);
41 memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
42 mutex_unlock(&priv->buffer_mutex);
43}
44
45void tpm_common_open(struct file *file, struct tpm_chip *chip,
46 struct file_priv *priv)
47{
48 priv->chip = chip;
49 atomic_set(&priv->data_pending, 0);
50 mutex_init(&priv->buffer_mutex);
51 setup_timer(&priv->user_read_timer, user_reader_timeout,
52 (unsigned long)priv);
53 INIT_WORK(&priv->work, timeout_work);
54
55 file->private_data = priv;
56}
57
58ssize_t tpm_common_read(struct file *file, char __user *buf,
59 size_t size, loff_t *off)
60{
61 struct file_priv *priv = file->private_data;
62 ssize_t ret_size;
63 ssize_t orig_ret_size;
64 int rc;
65
66 del_singleshot_timer_sync(&priv->user_read_timer);
67 flush_work(&priv->work);
68 ret_size = atomic_read(&priv->data_pending);
69 if (ret_size > 0) { /* relay data */
70 orig_ret_size = ret_size;
71 if (size < ret_size)
72 ret_size = size;
73
74 mutex_lock(&priv->buffer_mutex);
75 rc = copy_to_user(buf, priv->data_buffer, ret_size);
76 memset(priv->data_buffer, 0, orig_ret_size);
77 if (rc)
78 ret_size = -EFAULT;
79
80 mutex_unlock(&priv->buffer_mutex);
81 }
82
83 atomic_set(&priv->data_pending, 0);
84
85 return ret_size;
86}
87
88ssize_t tpm_common_write(struct file *file, const char __user *buf,
89 size_t size, loff_t *off, struct tpm_space *space)
90{
91 struct file_priv *priv = file->private_data;
92 size_t in_size = size;
93 ssize_t out_size;
94
95 /* Cannot perform a write until the read has cleared either via
96 * tpm_read or a user_read_timer timeout. This also prevents split
97 * buffered writes from blocking here.
98 */
99 if (atomic_read(&priv->data_pending) != 0)
100 return -EBUSY;
101
102 if (in_size > TPM_BUFSIZE)
103 return -E2BIG;
104
105 mutex_lock(&priv->buffer_mutex);
106
107 if (copy_from_user
108 (priv->data_buffer, (void __user *) buf, in_size)) {
109 mutex_unlock(&priv->buffer_mutex);
110 return -EFAULT;
111 }
112
113 /* atomic tpm command send and result receive. We only hold the ops
114 * lock during this period so that the tpm can be unregistered even if
115 * the char dev is held open.
116 */
117 if (tpm_try_get_ops(priv->chip)) {
118 mutex_unlock(&priv->buffer_mutex);
119 return -EPIPE;
120 }
121 out_size = tpm_transmit(priv->chip, space, priv->data_buffer,
122 sizeof(priv->data_buffer), 0);
123
124 tpm_put_ops(priv->chip);
125 if (out_size < 0) {
126 mutex_unlock(&priv->buffer_mutex);
127 return out_size;
128 }
129
130 atomic_set(&priv->data_pending, out_size);
131 mutex_unlock(&priv->buffer_mutex);
132
133 /* Set a timeout by which the reader must come claim the result */
134 mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
135
136 return in_size;
137}
138
139/*
140 * Called on file close
141 */
142void tpm_common_release(struct file *file, struct file_priv *priv)
143{
144 del_singleshot_timer_sync(&priv->user_read_timer);
145 flush_work(&priv->work);
146 file->private_data = NULL;
147 atomic_set(&priv->data_pending, 0);
148}
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index 414553bc115b..ebd74ab5abef 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -18,48 +18,15 @@
18 * 18 *
19 */ 19 */
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/uaccess.h> 21#include "tpm-dev.h"
22#include "tpm.h"
23
24struct file_priv {
25 struct tpm_chip *chip;
26
27 /* Data passed to and from the tpm via the read/write calls */
28 atomic_t data_pending;
29 struct mutex buffer_mutex;
30
31 struct timer_list user_read_timer; /* user needs to claim result */
32 struct work_struct work;
33
34 u8 data_buffer[TPM_BUFSIZE];
35};
36
37static void user_reader_timeout(unsigned long ptr)
38{
39 struct file_priv *priv = (struct file_priv *)ptr;
40
41 pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
42 task_tgid_nr(current));
43
44 schedule_work(&priv->work);
45}
46
47static void timeout_work(struct work_struct *work)
48{
49 struct file_priv *priv = container_of(work, struct file_priv, work);
50
51 mutex_lock(&priv->buffer_mutex);
52 atomic_set(&priv->data_pending, 0);
53 memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
54 mutex_unlock(&priv->buffer_mutex);
55}
56 22
57static int tpm_open(struct inode *inode, struct file *file) 23static int tpm_open(struct inode *inode, struct file *file)
58{ 24{
59 struct tpm_chip *chip = 25 struct tpm_chip *chip;
60 container_of(inode->i_cdev, struct tpm_chip, cdev);
61 struct file_priv *priv; 26 struct file_priv *priv;
62 27
28 chip = container_of(inode->i_cdev, struct tpm_chip, cdev);
29
63 /* It's assured that the chip will be opened just once, 30 /* It's assured that the chip will be opened just once,
64 * by the check of is_open variable, which is protected 31 * by the check of is_open variable, which is protected
65 * by driver_lock. */ 32 * by driver_lock. */
@@ -69,100 +36,22 @@ static int tpm_open(struct inode *inode, struct file *file)
69 } 36 }
70 37
71 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 38 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
72 if (priv == NULL) { 39 if (priv == NULL)
73 clear_bit(0, &chip->is_open); 40 goto out;
74 return -ENOMEM;
75 }
76 41
77 priv->chip = chip; 42 tpm_common_open(file, chip, priv);
78 atomic_set(&priv->data_pending, 0);
79 mutex_init(&priv->buffer_mutex);
80 setup_timer(&priv->user_read_timer, user_reader_timeout,
81 (unsigned long)priv);
82 INIT_WORK(&priv->work, timeout_work);
83 43
84 file->private_data = priv;
85 return 0; 44 return 0;
86}
87
88static ssize_t tpm_read(struct file *file, char __user *buf,
89 size_t size, loff_t *off)
90{
91 struct file_priv *priv = file->private_data;
92 ssize_t ret_size;
93 int rc;
94 45
95 del_singleshot_timer_sync(&priv->user_read_timer); 46 out:
96 flush_work(&priv->work); 47 clear_bit(0, &chip->is_open);
97 ret_size = atomic_read(&priv->data_pending); 48 return -ENOMEM;
98 if (ret_size > 0) { /* relay data */
99 ssize_t orig_ret_size = ret_size;
100 if (size < ret_size)
101 ret_size = size;
102
103 mutex_lock(&priv->buffer_mutex);
104 rc = copy_to_user(buf, priv->data_buffer, ret_size);
105 memset(priv->data_buffer, 0, orig_ret_size);
106 if (rc)
107 ret_size = -EFAULT;
108
109 mutex_unlock(&priv->buffer_mutex);
110 }
111
112 atomic_set(&priv->data_pending, 0);
113
114 return ret_size;
115} 49}
116 50
117static ssize_t tpm_write(struct file *file, const char __user *buf, 51static ssize_t tpm_write(struct file *file, const char __user *buf,
118 size_t size, loff_t *off) 52 size_t size, loff_t *off)
119{ 53{
120 struct file_priv *priv = file->private_data; 54 return tpm_common_write(file, buf, size, off, NULL);
121 size_t in_size = size;
122 ssize_t out_size;
123
124 /* cannot perform a write until the read has cleared
125 either via tpm_read or a user_read_timer timeout.
126 This also prevents splitted buffered writes from blocking here.
127 */
128 if (atomic_read(&priv->data_pending) != 0)
129 return -EBUSY;
130
131 if (in_size > TPM_BUFSIZE)
132 return -E2BIG;
133
134 mutex_lock(&priv->buffer_mutex);
135
136 if (copy_from_user
137 (priv->data_buffer, (void __user *) buf, in_size)) {
138 mutex_unlock(&priv->buffer_mutex);
139 return -EFAULT;
140 }
141
142 /* atomic tpm command send and result receive. We only hold the ops
143 * lock during this period so that the tpm can be unregistered even if
144 * the char dev is held open.
145 */
146 if (tpm_try_get_ops(priv->chip)) {
147 mutex_unlock(&priv->buffer_mutex);
148 return -EPIPE;
149 }
150 out_size = tpm_transmit(priv->chip, NULL, priv->data_buffer,
151 sizeof(priv->data_buffer), 0);
152
153 tpm_put_ops(priv->chip);
154 if (out_size < 0) {
155 mutex_unlock(&priv->buffer_mutex);
156 return out_size;
157 }
158
159 atomic_set(&priv->data_pending, out_size);
160 mutex_unlock(&priv->buffer_mutex);
161
162 /* Set a timeout by which the reader must come claim the result */
163 mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
164
165 return in_size;
166} 55}
167 56
168/* 57/*
@@ -172,12 +61,10 @@ static int tpm_release(struct inode *inode, struct file *file)
172{ 61{
173 struct file_priv *priv = file->private_data; 62 struct file_priv *priv = file->private_data;
174 63
175 del_singleshot_timer_sync(&priv->user_read_timer); 64 tpm_common_release(file, priv);
176 flush_work(&priv->work);
177 file->private_data = NULL;
178 atomic_set(&priv->data_pending, 0);
179 clear_bit(0, &priv->chip->is_open); 65 clear_bit(0, &priv->chip->is_open);
180 kfree(priv); 66 kfree(priv);
67
181 return 0; 68 return 0;
182} 69}
183 70
@@ -185,9 +72,7 @@ const struct file_operations tpm_fops = {
185 .owner = THIS_MODULE, 72 .owner = THIS_MODULE,
186 .llseek = no_llseek, 73 .llseek = no_llseek,
187 .open = tpm_open, 74 .open = tpm_open,
188 .read = tpm_read, 75 .read = tpm_common_read,
189 .write = tpm_write, 76 .write = tpm_write,
190 .release = tpm_release, 77 .release = tpm_release,
191}; 78};
192
193
diff --git a/drivers/char/tpm/tpm-dev.h b/drivers/char/tpm/tpm-dev.h
new file mode 100644
index 000000000000..ff15cf719bad
--- /dev/null
+++ b/drivers/char/tpm/tpm-dev.h
@@ -0,0 +1,27 @@
1#ifndef _TPM_DEV_H
2#define _TPM_DEV_H
3
4#include "tpm.h"
5
6struct file_priv {
7 struct tpm_chip *chip;
8
9 /* Data passed to and from the tpm via the read/write calls */
10 atomic_t data_pending;
11 struct mutex buffer_mutex;
12
13 struct timer_list user_read_timer; /* user needs to claim result */
14 struct work_struct work;
15
16 u8 data_buffer[TPM_BUFSIZE];
17};
18
19void tpm_common_open(struct file *file, struct tpm_chip *chip,
20 struct file_priv *priv);
21ssize_t tpm_common_read(struct file *file, char __user *buf,
22 size_t size, loff_t *off);
23ssize_t tpm_common_write(struct file *file, const char __user *buf,
24 size_t size, loff_t *off, struct tpm_space *space);
25void tpm_common_release(struct file *file, struct file_priv *priv);
26
27#endif