Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
Loading...
v6.8
 1// SPDX-License-Identifier: GPL-2.0-only
 2/*
 3 * Copyright (C) 2004 IBM Corporation
 4 * Authors:
 5 * Leendert van Doorn <leendert@watson.ibm.com>
 6 * Dave Safford <safford@watson.ibm.com>
 7 * Reiner Sailer <sailer@watson.ibm.com>
 8 * Kylene Hall <kjhall@us.ibm.com>
 9 *
10 * Copyright (C) 2013 Obsidian Research Corp
11 * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
12 *
13 * Device file system interface to the TPM
 
 
 
 
 
 
14 */
 
15#include <linux/slab.h>
16#include "tpm-dev.h"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
18static int tpm_open(struct inode *inode, struct file *file)
19{
20	struct tpm_chip *chip;
 
 
21	struct file_priv *priv;
22
23	chip = container_of(inode->i_cdev, struct tpm_chip, cdev);
24
25	/* It's assured that the chip will be opened just once,
26	 * by the check of is_open variable, which is protected
27	 * by driver_lock. */
28	if (test_and_set_bit(0, &chip->is_open)) {
29		dev_dbg(&chip->dev, "Another process owns this TPM\n");
30		return -EBUSY;
31	}
32
33	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
34	if (priv == NULL)
35		goto out;
 
 
36
37	tpm_common_open(file, chip, priv, NULL);
 
 
 
 
 
38
 
 
39	return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
41 out:
42	clear_bit(0, &chip->is_open);
43	return -ENOMEM;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44}
45
46/*
47 * Called on file close
48 */
49static int tpm_release(struct inode *inode, struct file *file)
50{
51	struct file_priv *priv = file->private_data;
52
53	tpm_common_release(file, priv);
 
 
 
54	clear_bit(0, &priv->chip->is_open);
 
55	kfree(priv);
56
57	return 0;
58}
59
60const struct file_operations tpm_fops = {
61	.owner = THIS_MODULE,
62	.llseek = no_llseek,
63	.open = tpm_open,
64	.read = tpm_common_read,
65	.write = tpm_common_write,
66	.poll = tpm_common_poll,
67	.release = tpm_release,
68};
v3.15
 
  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/miscdevice.h>
 21#include <linux/slab.h>
 22#include <linux/uaccess.h>
 23#include "tpm.h"
 24
 25struct file_priv {
 26	struct tpm_chip *chip;
 27
 28	/* Data passed to and from the tpm via the read/write calls */
 29	atomic_t data_pending;
 30	struct mutex buffer_mutex;
 31
 32	struct timer_list user_read_timer;      /* user needs to claim result */
 33	struct work_struct work;
 34
 35	u8 data_buffer[TPM_BUFSIZE];
 36};
 37
 38static void user_reader_timeout(unsigned long ptr)
 39{
 40	struct file_priv *priv = (struct file_priv *)ptr;
 41
 42	schedule_work(&priv->work);
 43}
 44
 45static void timeout_work(struct work_struct *work)
 46{
 47	struct file_priv *priv = container_of(work, struct file_priv, work);
 48
 49	mutex_lock(&priv->buffer_mutex);
 50	atomic_set(&priv->data_pending, 0);
 51	memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
 52	mutex_unlock(&priv->buffer_mutex);
 53}
 54
 55static int tpm_open(struct inode *inode, struct file *file)
 56{
 57	struct miscdevice *misc = file->private_data;
 58	struct tpm_chip *chip = container_of(misc, struct tpm_chip,
 59					     vendor.miscdev);
 60	struct file_priv *priv;
 61
 
 
 62	/* It's assured that the chip will be opened just once,
 63	 * by the check of is_open variable, which is protected
 64	 * by driver_lock. */
 65	if (test_and_set_bit(0, &chip->is_open)) {
 66		dev_dbg(chip->dev, "Another process owns this TPM\n");
 67		return -EBUSY;
 68	}
 69
 70	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 71	if (priv == NULL) {
 72		clear_bit(0, &chip->is_open);
 73		return -ENOMEM;
 74	}
 75
 76	priv->chip = chip;
 77	atomic_set(&priv->data_pending, 0);
 78	mutex_init(&priv->buffer_mutex);
 79	setup_timer(&priv->user_read_timer, user_reader_timeout,
 80			(unsigned long)priv);
 81	INIT_WORK(&priv->work, timeout_work);
 82
 83	file->private_data = priv;
 84	get_device(chip->dev);
 85	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
 95	del_singleshot_timer_sync(&priv->user_read_timer);
 96	flush_work(&priv->work);
 97	ret_size = atomic_read(&priv->data_pending);
 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}
116
117static ssize_t tpm_write(struct file *file, const char __user *buf,
118			 size_t size, loff_t *off)
119{
120	struct file_priv *priv = file->private_data;
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 */
143	out_size = tpm_transmit(priv->chip, priv->data_buffer,
144				sizeof(priv->data_buffer));
145	if (out_size < 0) {
146		mutex_unlock(&priv->buffer_mutex);
147		return out_size;
148	}
149
150	atomic_set(&priv->data_pending, out_size);
151	mutex_unlock(&priv->buffer_mutex);
152
153	/* Set a timeout by which the reader must come claim the result */
154	mod_timer(&priv->user_read_timer, jiffies + (60 * HZ));
155
156	return in_size;
157}
158
159/*
160 * Called on file close
161 */
162static int tpm_release(struct inode *inode, struct file *file)
163{
164	struct file_priv *priv = file->private_data;
165
166	del_singleshot_timer_sync(&priv->user_read_timer);
167	flush_work(&priv->work);
168	file->private_data = NULL;
169	atomic_set(&priv->data_pending, 0);
170	clear_bit(0, &priv->chip->is_open);
171	put_device(priv->chip->dev);
172	kfree(priv);
 
173	return 0;
174}
175
176static const struct file_operations tpm_fops = {
177	.owner = THIS_MODULE,
178	.llseek = no_llseek,
179	.open = tpm_open,
180	.read = tpm_read,
181	.write = tpm_write,
 
182	.release = tpm_release,
183};
184
185int tpm_dev_add_device(struct tpm_chip *chip)
186{
187	int rc;
188
189	chip->vendor.miscdev.fops = &tpm_fops;
190	if (chip->dev_num == 0)
191		chip->vendor.miscdev.minor = TPM_MINOR;
192	else
193		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
194
195	chip->vendor.miscdev.name = chip->devname;
196	chip->vendor.miscdev.parent = chip->dev;
197
198	rc = misc_register(&chip->vendor.miscdev);
199	if (rc) {
200		chip->vendor.miscdev.name = NULL;
201		dev_err(chip->dev,
202			"unable to misc_register %s, minor %d err=%d\n",
203			chip->vendor.miscdev.name,
204			chip->vendor.miscdev.minor, rc);
205	}
206	return rc;
207}
208
209void tpm_dev_del_device(struct tpm_chip *chip)
210{
211	if (chip->vendor.miscdev.name)
212		misc_deregister(&chip->vendor.miscdev);
213}