Skip to content

Commit 9488585

Browse files
tstrukJarkko Sakkinen
authored andcommitted
tpm: add support for partial reads
Currently to read a response from the TPM device an application needs provide big enough buffer for the whole response and read it in one go. The application doesn't know how big the response it beforehand so it always needs to maintain a 4K buffer and read the max (4K). In case if the user of the TSS library doesn't provide big enough buffer the TCTI spec says that the library should set the required size and return TSS2_TCTI_RC_INSUFFICIENT_BUFFER error code so that the application could allocate a bigger buffer and call receive again. To make it possible in the TSS library, this requires being able to do partial reads from the driver. The library would read the 10 bytes header first to get the actual size of the response from the header, and then read the rest of the response. This patch adds support for partial reads, i.e. the user can read the response in one or multiple reads, until the whole response is consumed. The user can also read only part of the response and ignore the rest by issuing a new write to send a new command. Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
1 parent 09c573a commit 9488585

File tree

2 files changed

+38
-19
lines changed

2 files changed

+38
-19
lines changed

drivers/char/tpm/tpm-dev-common.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static void tpm_async_work(struct work_struct *work)
4040

4141
tpm_put_ops(priv->chip);
4242
if (ret > 0) {
43-
priv->data_pending = ret;
43+
priv->response_length = ret;
4444
mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
4545
}
4646
mutex_unlock(&priv->buffer_mutex);
@@ -63,7 +63,8 @@ static void tpm_timeout_work(struct work_struct *work)
6363
timeout_work);
6464

6565
mutex_lock(&priv->buffer_mutex);
66-
priv->data_pending = 0;
66+
priv->response_read = true;
67+
priv->response_length = 0;
6768
memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
6869
mutex_unlock(&priv->buffer_mutex);
6970
wake_up_interruptible(&priv->async_wait);
@@ -74,6 +75,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
7475
{
7576
priv->chip = chip;
7677
priv->space = space;
78+
priv->response_read = true;
7779

7880
mutex_init(&priv->buffer_mutex);
7981
timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
@@ -90,22 +92,35 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
9092
ssize_t ret_size = 0;
9193
int rc;
9294

93-
del_singleshot_timer_sync(&priv->user_read_timer);
94-
flush_work(&priv->timeout_work);
9595
mutex_lock(&priv->buffer_mutex);
9696

97-
if (priv->data_pending) {
98-
ret_size = min_t(ssize_t, size, priv->data_pending);
99-
if (ret_size > 0) {
100-
rc = copy_to_user(buf, priv->data_buffer, ret_size);
101-
memset(priv->data_buffer, 0, priv->data_pending);
102-
if (rc)
103-
ret_size = -EFAULT;
97+
if (priv->response_length) {
98+
priv->response_read = true;
99+
100+
ret_size = min_t(ssize_t, size, priv->response_length);
101+
if (!ret_size) {
102+
priv->response_length = 0;
103+
goto out;
104104
}
105105

106-
priv->data_pending = 0;
106+
rc = copy_to_user(buf, priv->data_buffer + *off, ret_size);
107+
if (rc) {
108+
memset(priv->data_buffer, 0, TPM_BUFSIZE);
109+
priv->response_length = 0;
110+
ret_size = -EFAULT;
111+
} else {
112+
memset(priv->data_buffer + *off, 0, ret_size);
113+
priv->response_length -= ret_size;
114+
*off += ret_size;
115+
}
107116
}
108117

118+
out:
119+
if (!priv->response_length) {
120+
*off = 0;
121+
del_singleshot_timer_sync(&priv->user_read_timer);
122+
flush_work(&priv->timeout_work);
123+
}
109124
mutex_unlock(&priv->buffer_mutex);
110125
return ret_size;
111126
}
@@ -125,7 +140,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
125140
* tpm_read or a user_read_timer timeout. This also prevents split
126141
* buffered writes from blocking here.
127142
*/
128-
if (priv->data_pending != 0 || priv->command_enqueued) {
143+
if ((!priv->response_read && priv->response_length) ||
144+
priv->command_enqueued) {
129145
ret = -EBUSY;
130146
goto out;
131147
}
@@ -150,6 +166,10 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
150166
goto out;
151167
}
152168

169+
priv->response_length = 0;
170+
priv->response_read = false;
171+
*off = 0;
172+
153173
/*
154174
* If in nonblocking mode schedule an async job to send
155175
* the command return the size.
@@ -168,7 +188,7 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
168188
tpm_put_ops(priv->chip);
169189

170190
if (ret > 0) {
171-
priv->data_pending = ret;
191+
priv->response_length = ret;
172192
mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
173193
ret = size;
174194
}
@@ -184,7 +204,7 @@ __poll_t tpm_common_poll(struct file *file, poll_table *wait)
184204

185205
poll_wait(file, &priv->async_wait, wait);
186206

187-
if (priv->data_pending)
207+
if (!priv->response_read || priv->response_length)
188208
mask = EPOLLIN | EPOLLRDNORM;
189209
else
190210
mask = EPOLLOUT | EPOLLWRNORM;
@@ -201,7 +221,7 @@ void tpm_common_release(struct file *file, struct file_priv *priv)
201221
del_singleshot_timer_sync(&priv->user_read_timer);
202222
flush_work(&priv->timeout_work);
203223
file->private_data = NULL;
204-
priv->data_pending = 0;
224+
priv->response_length = 0;
205225
}
206226

207227
int __init tpm_dev_common_init(void)

drivers/char/tpm/tpm-dev.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ struct file_priv {
99
struct tpm_chip *chip;
1010
struct tpm_space *space;
1111

12-
/* Holds the amount of data passed or an error code from async op */
13-
ssize_t data_pending;
1412
struct mutex buffer_mutex;
15-
1613
struct timer_list user_read_timer; /* user needs to claim result */
1714
struct work_struct timeout_work;
1815
struct work_struct async_work;
1916
wait_queue_head_t async_wait;
17+
size_t response_length;
18+
bool response_read;
2019
bool command_enqueued;
2120

2221
u8 data_buffer[TPM_BUFSIZE];

0 commit comments

Comments
 (0)