Commit | Line | Data |
---|---|---|
afdba32e JG |
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 | */ | |
afdba32e JG |
20 | #include <linux/slab.h> |
21 | #include <linux/uaccess.h> | |
22 | #include "tpm.h" | |
23 | ||
e3302e0d JG |
24 | struct 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 | ||
afdba32e JG |
37 | static void user_reader_timeout(unsigned long ptr) |
38 | { | |
e3302e0d | 39 | struct file_priv *priv = (struct file_priv *)ptr; |
afdba32e | 40 | |
e3302e0d | 41 | schedule_work(&priv->work); |
afdba32e JG |
42 | } |
43 | ||
44 | static void timeout_work(struct work_struct *work) | |
45 | { | |
e3302e0d | 46 | struct file_priv *priv = container_of(work, struct file_priv, work); |
afdba32e | 47 | |
e3302e0d JG |
48 | mutex_lock(&priv->buffer_mutex); |
49 | atomic_set(&priv->data_pending, 0); | |
50 | memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); | |
51 | mutex_unlock(&priv->buffer_mutex); | |
afdba32e JG |
52 | } |
53 | ||
54 | static int tpm_open(struct inode *inode, struct file *file) | |
55 | { | |
313d21ee JS |
56 | struct tpm_chip *chip = |
57 | container_of(inode->i_cdev, struct tpm_chip, cdev); | |
e3302e0d | 58 | struct file_priv *priv; |
afdba32e JG |
59 | |
60 | /* It's assured that the chip will be opened just once, | |
61 | * by the check of is_open variable, which is protected | |
62 | * by driver_lock. */ | |
63 | if (test_and_set_bit(0, &chip->is_open)) { | |
8cfffc9d | 64 | dev_dbg(&chip->dev, "Another process owns this TPM\n"); |
afdba32e JG |
65 | return -EBUSY; |
66 | } | |
67 | ||
e3302e0d JG |
68 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
69 | if (priv == NULL) { | |
afdba32e JG |
70 | clear_bit(0, &chip->is_open); |
71 | return -ENOMEM; | |
72 | } | |
73 | ||
e3302e0d JG |
74 | priv->chip = chip; |
75 | atomic_set(&priv->data_pending, 0); | |
76 | mutex_init(&priv->buffer_mutex); | |
77 | setup_timer(&priv->user_read_timer, user_reader_timeout, | |
78 | (unsigned long)priv); | |
79 | INIT_WORK(&priv->work, timeout_work); | |
afdba32e | 80 | |
e3302e0d | 81 | file->private_data = priv; |
afdba32e JG |
82 | return 0; |
83 | } | |
84 | ||
85 | static ssize_t tpm_read(struct file *file, char __user *buf, | |
86 | size_t size, loff_t *off) | |
87 | { | |
e3302e0d | 88 | struct file_priv *priv = file->private_data; |
afdba32e JG |
89 | ssize_t ret_size; |
90 | int rc; | |
91 | ||
e3302e0d JG |
92 | del_singleshot_timer_sync(&priv->user_read_timer); |
93 | flush_work(&priv->work); | |
94 | ret_size = atomic_read(&priv->data_pending); | |
afdba32e JG |
95 | if (ret_size > 0) { /* relay data */ |
96 | ssize_t orig_ret_size = ret_size; | |
97 | if (size < ret_size) | |
98 | ret_size = size; | |
99 | ||
e3302e0d JG |
100 | mutex_lock(&priv->buffer_mutex); |
101 | rc = copy_to_user(buf, priv->data_buffer, ret_size); | |
102 | memset(priv->data_buffer, 0, orig_ret_size); | |
afdba32e JG |
103 | if (rc) |
104 | ret_size = -EFAULT; | |
105 | ||
e3302e0d | 106 | mutex_unlock(&priv->buffer_mutex); |
afdba32e JG |
107 | } |
108 | ||
e3302e0d | 109 | atomic_set(&priv->data_pending, 0); |
afdba32e JG |
110 | |
111 | return ret_size; | |
112 | } | |
113 | ||
114 | static ssize_t tpm_write(struct file *file, const char __user *buf, | |
115 | size_t size, loff_t *off) | |
116 | { | |
e3302e0d | 117 | struct file_priv *priv = file->private_data; |
afdba32e JG |
118 | size_t in_size = size; |
119 | ssize_t out_size; | |
120 | ||
121 | /* cannot perform a write until the read has cleared | |
122 | either via tpm_read or a user_read_timer timeout. | |
123 | This also prevents splitted buffered writes from blocking here. | |
124 | */ | |
e3302e0d | 125 | if (atomic_read(&priv->data_pending) != 0) |
afdba32e JG |
126 | return -EBUSY; |
127 | ||
128 | if (in_size > TPM_BUFSIZE) | |
129 | return -E2BIG; | |
130 | ||
e3302e0d | 131 | mutex_lock(&priv->buffer_mutex); |
afdba32e JG |
132 | |
133 | if (copy_from_user | |
e3302e0d JG |
134 | (priv->data_buffer, (void __user *) buf, in_size)) { |
135 | mutex_unlock(&priv->buffer_mutex); | |
afdba32e JG |
136 | return -EFAULT; |
137 | } | |
138 | ||
139 | /* atomic tpm command send and result receive */ | |
e3302e0d JG |
140 | out_size = tpm_transmit(priv->chip, priv->data_buffer, |
141 | sizeof(priv->data_buffer)); | |
afdba32e | 142 | if (out_size < 0) { |
e3302e0d | 143 | mutex_unlock(&priv->buffer_mutex); |
afdba32e JG |
144 | return out_size; |
145 | } | |
146 | ||
e3302e0d JG |
147 | atomic_set(&priv->data_pending, out_size); |
148 | mutex_unlock(&priv->buffer_mutex); | |
afdba32e JG |
149 | |
150 | /* Set a timeout by which the reader must come claim the result */ | |
e3302e0d | 151 | mod_timer(&priv->user_read_timer, jiffies + (60 * HZ)); |
afdba32e JG |
152 | |
153 | return in_size; | |
154 | } | |
155 | ||
156 | /* | |
157 | * Called on file close | |
158 | */ | |
159 | static int tpm_release(struct inode *inode, struct file *file) | |
160 | { | |
e3302e0d | 161 | struct file_priv *priv = file->private_data; |
afdba32e | 162 | |
e3302e0d JG |
163 | del_singleshot_timer_sync(&priv->user_read_timer); |
164 | flush_work(&priv->work); | |
afdba32e | 165 | file->private_data = NULL; |
e3302e0d JG |
166 | atomic_set(&priv->data_pending, 0); |
167 | clear_bit(0, &priv->chip->is_open); | |
e3302e0d | 168 | kfree(priv); |
afdba32e JG |
169 | return 0; |
170 | } | |
171 | ||
313d21ee | 172 | const struct file_operations tpm_fops = { |
afdba32e JG |
173 | .owner = THIS_MODULE, |
174 | .llseek = no_llseek, | |
175 | .open = tpm_open, | |
176 | .read = tpm_read, | |
177 | .write = tpm_write, | |
178 | .release = tpm_release, | |
179 | }; | |
180 | ||
afdba32e | 181 |