This repository has been archived by the owner on Jul 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
0030-rpmb-VRPMB-FE-create-virtio-rpmb-frontend-driver.patch
375 lines (369 loc) · 9.47 KB
/
0030-rpmb-VRPMB-FE-create-virtio-rpmb-frontend-driver.patch
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tomas Winkler <[email protected]>
Date: Thu, 24 May 2018 14:57:02 +0300
Subject: [PATCH] rpmb: VRPMB-FE create virtio rpmb frontend driver
This patch implements virtio rpmb frontend driver.
The driver will work with RPMB VBS-U together to
provide one communication channel between UOS and SOS.
V2: 1. Change license to dual BSD/GPL
2. Fix coding style.
3. Use pr_fmt macro instead of ERR, DBG, ...
V3: 1. Replace - with _ in file name.
2. Plug to rpmb framework instead of using own misc device
3. Use arrays of scatter lists instead of linearizing the data.
V4: 1. Allocate memory for control structures, it's not possible to DMA
from the stack.
V5: 1. Add mutex and use wait queue instead of completion.
2. WIP code for getting capabilities
V6: 1. Fix calculation of the allocation size for seq cmd
2. WIP code for getting capabilities
3. Drop unused constant RPMB_MAX_FRAMES
Change-Id: I88a42f2e8f2ea1573aad9b5cafeae812c669a73e
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/char/rpmb/Kconfig | 10 ++
drivers/char/rpmb/Makefile | 1 +
drivers/char/rpmb/virtio_rpmb.c | 305 ++++++++++++++++++++++++++++++++
3 files changed, 316 insertions(+)
create mode 100644 drivers/char/rpmb/virtio_rpmb.c
diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
index c069664eec92..48f11c19bbda 100644
--- a/drivers/char/rpmb/Kconfig
+++ b/drivers/char/rpmb/Kconfig
@@ -30,3 +30,13 @@ config RPMB_SIM
suitable only for testing of the RPMB subsystem or RPMB applications
prior to RPMB key provisioning.
Most people should say N here.
+
+config VIRTIO_RPMB
+ tristate "Virtio RPMB character device interface /dev/vrpmb"
+ default n
+ depends on VIRTIO
+ select RPMB
+ help
+ Say yes here if you want to access virtio RPMB from user space
+ via character device interface /dev/vrpmb.
+ This device interface is only for guest/frontend virtio driver.
diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile
index 8bd1186948b0..281c012712ca 100644
--- a/drivers/char/rpmb/Makefile
+++ b/drivers/char/rpmb/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_RPMB) += rpmb.o
rpmb-objs += core.o
rpmb-$(CONFIG_RPMB_INTF_DEV) += cdev.o
obj-$(CONFIG_RPMB_SIM) += rpmb_sim.o
+obj-$(CONFIG_VIRTIO_RPMB) += virtio_rpmb.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/char/rpmb/virtio_rpmb.c b/drivers/char/rpmb/virtio_rpmb.c
new file mode 100644
index 000000000000..ef3487c98805
--- /dev/null
+++ b/drivers/char/rpmb/virtio_rpmb.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/*
+ * Virtio RPMB Front End Driver
+ *
+ * Copyright (c) 2018 Intel Corporation. All rights reserved.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <linux/module.h>
+#include <linux/virtio_ids.h>
+#include <linux/fs.h>
+#include <linux/virtio_config.h>
+#include <linux/uaccess.h>
+#include <linux/rpmb.h>
+
+static const char id[] = "RPMB:VIRTIO";
+#ifndef VIRTIO_ID_RPMB
+#define VIRTIO_ID_RPMB 0xFFFF
+#endif
+
+#define RPMB_SEQ_CMD_MAX 3 /* support up to 3 cmds */
+
+struct virtio_rpmb_info {
+ struct virtqueue *vq;
+ struct mutex lock; /* info lock */
+ wait_queue_head_t have_data;
+ struct rpmb_dev *rdev;
+};
+
+struct virtio_rpmb_ioc {
+ unsigned int ioc_cmd;
+ int result;
+ u8 target;
+ u8 reserved[3];
+};
+
+static void virtio_rpmb_recv_done(struct virtqueue *vq)
+{
+ struct virtio_rpmb_info *vi;
+ struct virtio_device *vdev = vq->vdev;
+
+ vi = vq->vdev->priv;
+ if (!vi) {
+ dev_err(&vdev->dev, "Error: no found vi data.\n");
+ return;
+ }
+
+ wake_up(&vi->have_data);
+}
+
+static int rpmb_virtio_cmd_seq(struct device *dev, u8 target,
+ struct rpmb_cmd *cmds, u32 ncmds)
+{
+ struct virtio_device *vdev = dev_to_virtio(dev);
+ struct virtio_rpmb_info *vi = vdev->priv;
+ unsigned int i;
+ struct virtio_rpmb_ioc *vio_cmd;
+ struct rpmb_ioc_seq_cmd *seq_cmd;
+ size_t seq_cmd_sz;
+ struct scatterlist vio_ioc, vio_seq, frame[3];
+ struct scatterlist *sgs[5];
+ unsigned int num_out = 0, num_in = 0;
+ size_t sz;
+ int ret;
+ unsigned int len;
+
+ if (ncmds > RPMB_SEQ_CMD_MAX)
+ return -EINVAL;
+
+ mutex_lock(&vi->lock);
+
+ vio_cmd = kzalloc(sizeof(*vio_cmd), GFP_KERNEL);
+ seq_cmd_sz = sizeof(*seq_cmd) + sizeof(struct rpmb_ioc_cmd) * ncmds;
+ seq_cmd = kzalloc(seq_cmd_sz, GFP_KERNEL);
+ if (!vio_cmd || !seq_cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ vio_cmd->ioc_cmd = RPMB_IOC_SEQ_CMD;
+ vio_cmd->result = 0;
+ vio_cmd->target = target;
+ sg_init_one(&vio_ioc, vio_cmd, sizeof(*vio_cmd));
+ sgs[num_out + num_in++] = &vio_ioc;
+
+ seq_cmd->num_of_cmds = ncmds;
+ for (i = 0; i < ncmds; i++) {
+ seq_cmd->cmds[i].flags = cmds[i].flags;
+ seq_cmd->cmds[i].nframes = cmds[i].nframes;
+ seq_cmd->cmds[i].frames_ptr = i;
+ }
+ sg_init_one(&vio_seq, seq_cmd, seq_cmd_sz);
+ sgs[num_out + num_in++] = &vio_seq;
+
+ for (i = 0; i < ncmds; i++) {
+ sz = sizeof(struct rpmb_frame_jdec) * (cmds[i].nframes ?: 1);
+ sg_init_one(&frame[i], cmds[i].frames, sz);
+ sgs[num_out + num_in++] = &frame[i];
+ }
+
+ virtqueue_add_sgs(vi->vq, sgs, num_out, num_in, vi, GFP_KERNEL);
+ virtqueue_kick(vi->vq);
+
+ wait_event(vi->have_data, virtqueue_get_buf(vi->vq, &len));
+
+ ret = 0;
+
+ if (vio_cmd->result != 0) {
+ dev_err(dev, "Error: command error = %d.\n", vio_cmd->result);
+ ret = -EIO;
+ }
+
+out:
+ kfree(vio_cmd);
+ kfree(seq_cmd);
+ mutex_unlock(&vi->lock);
+ return ret;
+}
+
+static int rpmb_virtio_cmd_cap(struct device *dev, u8 target)
+{
+ struct virtio_device *vdev = dev_to_virtio(dev);
+ struct virtio_rpmb_info *vi = vdev->priv;
+ struct virtio_rpmb_ioc *vio_cmd;
+ struct rpmb_ioc_cap_cmd *cap_cmd;
+ struct scatterlist vio_ioc, cap_ioc;
+ struct scatterlist *sgs[2];
+ unsigned int num_out = 0, num_in = 0;
+ unsigned int len;
+ int ret;
+
+ mutex_lock(&vi->lock);
+
+ vio_cmd = kzalloc(sizeof(*vio_cmd), GFP_KERNEL);
+ cap_cmd = kzalloc(sizeof(*cap_cmd), GFP_KERNEL);
+ if (!vio_cmd || !cap_cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ vio_cmd->ioc_cmd = RPMB_IOC_CAP_CMD;
+ vio_cmd->result = 0;
+ vio_cmd->target = target;
+ sg_init_one(&vio_ioc, vio_cmd, sizeof(*vio_cmd));
+ sgs[num_out + num_in++] = &vio_ioc;
+
+ sg_init_one(&cap_ioc, cap_cmd, sizeof(*cap_cmd));
+ sgs[num_out + num_in++] = &cap_ioc;
+
+ virtqueue_add_sgs(vi->vq, sgs, num_out, num_in, vi, GFP_KERNEL);
+ virtqueue_kick(vi->vq);
+
+ wait_event(vi->have_data, virtqueue_get_buf(vi->vq, &len));
+
+ ret = 0;
+
+ if (vio_cmd->result != 0) {
+ dev_err(dev, "Error: command error = %d.\n", vio_cmd->result);
+ ret = -EIO;
+ }
+
+out:
+ kfree(vio_cmd);
+ kfree(cap_cmd);
+
+ mutex_unlock(&vi->lock);
+ return ret;
+}
+
+static int rpmb_virtio_get_capacity(struct device *dev, u8 target)
+{
+ return 0;
+}
+
+static struct rpmb_ops rpmb_virtio_ops = {
+ .cmd_seq = rpmb_virtio_cmd_seq,
+ .get_capacity = rpmb_virtio_get_capacity,
+ .type = RPMB_TYPE_EMMC,
+};
+
+static int rpmb_virtio_dev_init(struct virtio_rpmb_info *vi)
+{
+ int ret = 0;
+ struct device *dev = &vi->vq->vdev->dev;
+
+ rpmb_virtio_ops.dev_id_len = strlen(id);
+ rpmb_virtio_ops.dev_id = id;
+ rpmb_virtio_ops.wr_cnt_max = 1;
+ rpmb_virtio_ops.rd_cnt_max = 1;
+ rpmb_virtio_ops.block_size = 1;
+
+ vi->rdev = rpmb_dev_register(dev, 0, &rpmb_virtio_ops);
+ if (IS_ERR(vi->rdev)) {
+ ret = PTR_ERR(vi->rdev);
+ goto err;
+ }
+
+ dev_set_drvdata(dev, vi);
+err:
+ return ret;
+}
+
+static int virtio_rpmb_init(struct virtio_device *vdev)
+{
+ int ret;
+ struct virtio_rpmb_info *vi;
+
+ vi = kzalloc(sizeof(*vi), GFP_KERNEL);
+ if (!vi)
+ return -ENOMEM;
+
+ init_waitqueue_head(&vi->have_data);
+ mutex_init(&vi->lock);
+ vdev->priv = vi;
+
+ /* We expect a single virtqueue. */
+ vi->vq = virtio_find_single_vq(vdev, virtio_rpmb_recv_done, "request");
+ if (IS_ERR(vi->vq)) {
+ dev_err(&vdev->dev, "get single vq failed!\n");
+ ret = PTR_ERR(vi->vq);
+ goto err;
+ }
+
+ /* create vrpmb device. */
+ ret = rpmb_virtio_dev_init(vi);
+ if (ret) {
+ dev_err(&vdev->dev, "create vrpmb device failed.\n");
+ goto err;
+ }
+
+ dev_info(&vdev->dev, "init done!\n");
+
+ return 0;
+
+err:
+ kfree(vi);
+ return ret;
+}
+
+static void virtio_rpmb_remove(struct virtio_device *vdev)
+{
+ struct virtio_rpmb_info *vi;
+
+ vi = vdev->priv;
+ if (!vi)
+ return;
+
+ if (wq_has_sleeper(&vi->have_data))
+ wake_up(&vi->have_data);
+
+ rpmb_dev_unregister(vi->rdev);
+
+ if (vdev->config->reset)
+ vdev->config->reset(vdev);
+
+ if (vdev->config->del_vqs)
+ vdev->config->del_vqs(vdev);
+
+ kfree(vi);
+}
+
+static int virtio_rpmb_probe(struct virtio_device *vdev)
+{
+ return virtio_rpmb_init(vdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int virtio_rpmb_freeze(struct virtio_device *vdev)
+{
+ virtio_rpmb_remove(vdev);
+ return 0;
+}
+
+static int virtio_rpmb_restore(struct virtio_device *vdev)
+{
+ return virtio_rpmb_init(vdev);
+}
+#endif
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_RPMB, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_rpmb_driver = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtio_rpmb_probe,
+ .remove = virtio_rpmb_remove,
+#ifdef CONFIG_PM_SLEEP
+ .freeze = virtio_rpmb_freeze,
+ .restore = virtio_rpmb_restore,
+#endif
+};
+
+module_virtio_driver(virtio_rpmb_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+MODULE_DESCRIPTION("Virtio rpmb frontend driver");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
--
https://clearlinux.org