forked from clearlinux-pkgs/linux-iot-lts2018
-
Notifications
You must be signed in to change notification settings - Fork 0
/
0020-char-rpmb-provide-a-user-space-interface.patch
821 lines (798 loc) · 23.7 KB
/
0020-char-rpmb-provide-a-user-space-interface.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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
From 8ebe341725016b753b1c2f8bdf355267ceb0feec Mon Sep 17 00:00:00 2001
From: Tomas Winkler <[email protected]>
Date: Thu, 16 Jul 2015 12:29:50 +0300
Subject: [PATCH 05/22] char: rpmb: provide a user space interface
The user space API is achieved via two synchronous IOCTLs.
Simplified one, RPMB_IOC_REQ_CMD, were read result cycles is performed
by the framework on behalf the user and second, RPMB_IOC_SEQ_CMD where
the whole RPMB sequence including RESULT_READ is supplied by the caller.
The latter is intended for easier adjusting of the applications that
use MMC_IOC_MULTI_CMD ioctl.
V2: use memdup_user
V3: commit message fix
V4: resend
V5: 1. Add RPMB_IOC_SEQ_CMD API.
2. Export uapi rpmb.h header
V6: 1. Remove #include <linux/module.h>.
2. Add ioctl documentation.
V7: 1. copy_from_user the value of the frame pointer.
2. Fix possible macro side-effect due to macro argument reuse.
V8: 1. Fix kdoc errors
2. Move IOCTL to a different range due to conflict
3. Change license to dual BSD/GPL
V9: 1. Add version and capability ioctls and drop the request ioctl
2. Use zero based frame count: 0 means only meted are in a frame.
2. Add SPDX identifiers.
3. Fix comment typo in uapi/linux/rpmb.h
V10:
1. Rebase on 4.18
V11:
1. Rebase on 4.19
Change-Id: I00f2b5d5c92982fa2a3814a8bc56a3fecd19456f
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Alexander Usyskin <[email protected]>
Tested-by: Avri Altman <[email protected]>
---
Documentation/ioctl/ioctl-number.txt | 1 +
MAINTAINERS | 1 +
drivers/char/rpmb/Kconfig | 7 +
drivers/char/rpmb/Makefile | 1 +
drivers/char/rpmb/cdev.c | 296 +++++++++++++++++++++++++++
drivers/char/rpmb/core.c | 9 +-
drivers/char/rpmb/rpmb-cdev.h | 17 ++
include/linux/rpmb.h | 107 +---------
include/uapi/linux/rpmb.h | 192 +++++++++++++++++
9 files changed, 532 insertions(+), 99 deletions(-)
create mode 100644 drivers/char/rpmb/cdev.c
create mode 100644 drivers/char/rpmb/rpmb-cdev.h
create mode 100644 include/uapi/linux/rpmb.h
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 13a7c999c04a..ae2f081324f4 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -324,6 +324,7 @@ Code Seq#(hex) Include File Comments
0xB3 00 linux/mmc/ioctl.h
0xB4 00-0F linux/gpio.h <mailto:[email protected]>
0xB5 00-0F uapi/linux/rpmsg.h <mailto:[email protected]>
+0xB5 80-8F linux/uapi/linux/rpmb.h <mailto:[email protected]>
0xB6 all linux/fpga-dfl.h
0xC0 00-0F linux/usb/iowarrior.h
0xCA 00-0F uapi/misc/cxl.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 070cb20bcf78..1868f61fffc1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12532,6 +12532,7 @@ M: Tomas Winkler <[email protected]>
S: Supported
F: drivers/char/rpmb/*
+F: include/uapi/linux/rpmb.h
F: include/linux/rpmb.h
F: Documentation/ABI/testing/sysfs-class-rpmb
diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
index b5cd02de91bb..cfecb1fccfc0 100644
--- a/drivers/char/rpmb/Kconfig
+++ b/drivers/char/rpmb/Kconfig
@@ -7,3 +7,10 @@ config RPMB
access RPMB partition.
If unsure, select N.
+
+config RPMB_INTF_DEV
+ bool "RPMB character device interface /dev/rpmbN"
+ depends on RPMB
+ help
+ Say yes here if you want to access RPMB from user space
+ via character device interface /dev/rpmb%d
diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile
index badc1cd9428b..c171a5cfaed3 100644
--- a/drivers/char/rpmb/Makefile
+++ b/drivers/char/rpmb/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_RPMB) += rpmb.o
rpmb-objs += core.o
+rpmb-$(CONFIG_RPMB_INTF_DEV) += cdev.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/char/rpmb/cdev.c b/drivers/char/rpmb/cdev.c
new file mode 100644
index 000000000000..bdac3894b111
--- /dev/null
+++ b/drivers/char/rpmb/cdev.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/*
+ * Copyright(c) 2015 - 2018 Intel Corporation. All rights reserved.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <linux/slab.h>
+#include <linux/capability.h>
+
+#include <linux/rpmb.h>
+
+#include "rpmb-cdev.h"
+
+static dev_t rpmb_devt;
+#define RPMB_MAX_DEVS MINORMASK
+
+#define RPMB_DEV_OPEN 0 /** single open bit (position) */
+/* from MMC_IOC_MAX_CMDS */
+#define RPMB_MAX_FRAMES 255
+
+/**
+ * rpmb_open - the open function
+ *
+ * @inode: pointer to inode structure
+ * @fp: pointer to file structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_open(struct inode *inode, struct file *fp)
+{
+ struct rpmb_dev *rdev;
+
+ rdev = container_of(inode->i_cdev, struct rpmb_dev, cdev);
+ if (!rdev)
+ return -ENODEV;
+
+ /* the rpmb is single open! */
+ if (test_and_set_bit(RPMB_DEV_OPEN, &rdev->status))
+ return -EBUSY;
+
+ mutex_lock(&rdev->lock);
+
+ fp->private_data = rdev;
+
+ mutex_unlock(&rdev->lock);
+
+ return nonseekable_open(inode, fp);
+}
+
+/**
+ * rpmb_release - the cdev release function
+ *
+ * @inode: pointer to inode structure
+ * @fp: pointer to file structure
+ *
+ * Return: 0 always.
+ */
+static int rpmb_release(struct inode *inode, struct file *fp)
+{
+ struct rpmb_dev *rdev = fp->private_data;
+
+ clear_bit(RPMB_DEV_OPEN, &rdev->status);
+
+ return 0;
+}
+
+/**
+ * rpmb_cmd_copy_from_user - copy rpmb command from the user space
+ *
+ * @cmd: internal cmd structure
+ * @ucmd: user space cmd structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_cmd_copy_from_user(struct rpmb_cmd *cmd,
+ struct rpmb_ioc_cmd __user *ucmd)
+{
+ struct rpmb_frame *frames;
+ u64 frames_ptr;
+
+ if (get_user(cmd->flags, &ucmd->flags))
+ return -EFAULT;
+
+ if (get_user(cmd->nframes, &ucmd->nframes))
+ return -EFAULT;
+
+ if (cmd->nframes > RPMB_MAX_FRAMES)
+ return -EOVERFLOW;
+
+ /* some archs have issues with 64bit get_user */
+ if (copy_from_user(&frames_ptr, &ucmd->frames_ptr, sizeof(frames_ptr)))
+ return -EFAULT;
+
+ frames = memdup_user(u64_to_user_ptr(frames_ptr),
+ rpmb_ioc_frames_len_jdec(cmd->nframes));
+ if (IS_ERR(frames))
+ return PTR_ERR(frames);
+
+ cmd->frames = frames;
+ return 0;
+}
+
+/**
+ * rpmb_cmd_copy_to_user - copy rpmb command to the user space
+ *
+ * @ucmd: user space cmd structure
+ * @cmd: internal cmd structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_cmd_copy_to_user(struct rpmb_ioc_cmd __user *ucmd,
+ struct rpmb_cmd *cmd)
+{
+ u64 frames_ptr;
+
+ if (copy_from_user(&frames_ptr, &ucmd->frames_ptr, sizeof(frames_ptr)))
+ return -EFAULT;
+
+ /* some archs have issues with 64bit get_user */
+ if (copy_to_user(u64_to_user_ptr(frames_ptr), cmd->frames,
+ rpmb_ioc_frames_len_jdec(cmd->nframes)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
+ * rpmb_ioctl_seq_cmd - issue an rpmb command sequence
+ *
+ * @rdev: rpmb device
+ * @ptr: rpmb cmd sequence
+ *
+ * RPMB_IOC_SEQ_CMD handler
+ *
+ * Return: 0 on success, <0 on error
+ */
+static long rpmb_ioctl_seq_cmd(struct rpmb_dev *rdev,
+ struct rpmb_ioc_seq_cmd __user *ptr)
+{
+ __u64 ncmds;
+ struct rpmb_cmd *cmds;
+ struct rpmb_ioc_cmd __user *ucmds;
+
+ int i;
+ int ret;
+
+ /* The caller must have CAP_SYS_RAWIO, like mmc ioctl */
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* some archs have issues with 64bit get_user */
+ if (copy_from_user(&ncmds, &ptr->num_of_cmds, sizeof(ncmds)))
+ return -EFAULT;
+
+ if (ncmds > 3) {
+ dev_err(&rdev->dev, "supporting up to 3 packets (%llu)\n",
+ ncmds);
+ return -EINVAL;
+ }
+
+ cmds = kcalloc(ncmds, sizeof(*cmds), GFP_KERNEL);
+ if (!cmds)
+ return -ENOMEM;
+
+ ucmds = (struct rpmb_ioc_cmd __user *)ptr->cmds;
+ for (i = 0; i < ncmds; i++) {
+ ret = rpmb_cmd_copy_from_user(&cmds[i], &ucmds[i]);
+ if (ret)
+ goto out;
+ }
+
+ ret = rpmb_cmd_seq(rdev, cmds, ncmds);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < ncmds; i++) {
+ ret = rpmb_cmd_copy_to_user(&ucmds[i], &cmds[i]);
+ if (ret)
+ goto out;
+ }
+out:
+ for (i = 0; i < ncmds; i++)
+ kfree(cmds[i].frames);
+ kfree(cmds);
+ return ret;
+}
+
+static long rpmb_ioctl_ver_cmd(struct rpmb_dev *rdev,
+ struct rpmb_ioc_ver_cmd __user *ptr)
+{
+ struct rpmb_ioc_ver_cmd ver = {
+ .api_version = RPMB_API_VERSION,
+ };
+
+ return copy_to_user(ptr, &ver, sizeof(ver)) ? -EFAULT : 0;
+}
+
+static long rpmb_ioctl_cap_cmd(struct rpmb_dev *rdev,
+ struct rpmb_ioc_cap_cmd __user *ptr)
+{
+ struct rpmb_ioc_cap_cmd cap;
+
+ cap.device_type = rdev->ops->type;
+ cap.target = rdev->target;
+ cap.block_size = rdev->ops->block_size;
+ cap.wr_cnt_max = rdev->ops->wr_cnt_max;
+ cap.rd_cnt_max = rdev->ops->rd_cnt_max;
+ cap.auth_method = rdev->ops->auth_method;
+ cap.capacity = rpmb_get_capacity(rdev);
+ cap.reserved = 0;
+
+ return copy_to_user(ptr, &cap, sizeof(cap)) ? -EFAULT : 0;
+}
+
+/**
+ * rpmb_ioctl - rpmb ioctl dispatcher
+ *
+ * @fp: a file pointer
+ * @cmd: ioctl command RPMB_IOC_SEQ_CMD RPMB_IOC_VER_CMD RPMB_IOC_CAP_CMD
+ * @arg: ioctl data: rpmb_ioc_ver_cmd rpmb_ioc_cap_cmd pmb_ioc_seq_cmd
+ *
+ * Return: 0 on success; < 0 on error
+ */
+static long rpmb_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ struct rpmb_dev *rdev = fp->private_data;
+ void __user *ptr = (void __user *)arg;
+
+ switch (cmd) {
+ case RPMB_IOC_VER_CMD:
+ return rpmb_ioctl_ver_cmd(rdev, ptr);
+ case RPMB_IOC_CAP_CMD:
+ return rpmb_ioctl_cap_cmd(rdev, ptr);
+ case RPMB_IOC_SEQ_CMD:
+ return rpmb_ioctl_seq_cmd(rdev, ptr);
+ default:
+ dev_err(&rdev->dev, "unsupported ioctl 0x%x.\n", cmd);
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long rpmb_compat_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ return rpmb_ioctl(fp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif /* CONFIG_COMPAT */
+
+static const struct file_operations rpmb_fops = {
+ .open = rpmb_open,
+ .release = rpmb_release,
+ .unlocked_ioctl = rpmb_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = rpmb_compat_ioctl,
+#endif
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+};
+
+void rpmb_cdev_prepare(struct rpmb_dev *rdev)
+{
+ rdev->dev.devt = MKDEV(MAJOR(rpmb_devt), rdev->id);
+ rdev->cdev.owner = THIS_MODULE;
+ cdev_init(&rdev->cdev, &rpmb_fops);
+}
+
+void rpmb_cdev_add(struct rpmb_dev *rdev)
+{
+ cdev_add(&rdev->cdev, rdev->dev.devt, 1);
+}
+
+void rpmb_cdev_del(struct rpmb_dev *rdev)
+{
+ if (rdev->dev.devt)
+ cdev_del(&rdev->cdev);
+}
+
+int __init rpmb_cdev_init(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&rpmb_devt, 0, RPMB_MAX_DEVS, "rpmb");
+ if (ret < 0)
+ pr_err("unable to allocate char dev region\n");
+
+ return ret;
+}
+
+void __exit rpmb_cdev_exit(void)
+{
+ unregister_chrdev_region(rpmb_devt, RPMB_MAX_DEVS);
+}
diff --git a/drivers/char/rpmb/core.c b/drivers/char/rpmb/core.c
index 41a249c0c58f..e02c12b8046c 100644
--- a/drivers/char/rpmb/core.c
+++ b/drivers/char/rpmb/core.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/rpmb.h>
+#include "rpmb-cdev.h"
static DEFINE_IDA(rpmb_ida);
@@ -307,6 +308,7 @@ int rpmb_dev_unregister(struct rpmb_dev *rdev)
return -EINVAL;
mutex_lock(&rdev->lock);
+ rpmb_cdev_del(rdev);
device_del(&rdev->dev);
mutex_unlock(&rdev->lock);
@@ -413,10 +415,14 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev, u8 target,
rdev->dev.parent = dev;
rdev->dev.groups = rpmb_attr_groups;
+ rpmb_cdev_prepare(rdev);
+
ret = device_register(&rdev->dev);
if (ret)
goto exit;
+ rpmb_cdev_add(rdev);
+
dev_dbg(&rdev->dev, "registered device\n");
return rdev;
@@ -433,11 +439,12 @@ static int __init rpmb_init(void)
{
ida_init(&rpmb_ida);
class_register(&rpmb_class);
- return 0;
+ return rpmb_cdev_init();
}
static void __exit rpmb_exit(void)
{
+ rpmb_cdev_exit();
class_unregister(&rpmb_class);
ida_destroy(&rpmb_ida);
}
diff --git a/drivers/char/rpmb/rpmb-cdev.h b/drivers/char/rpmb/rpmb-cdev.h
new file mode 100644
index 000000000000..e59ff0c05e9d
--- /dev/null
+++ b/drivers/char/rpmb/rpmb-cdev.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/*
+ * Copyright (C) 2015-2018 Intel Corp. All rights reserved
+ */
+#ifdef CONFIG_RPMB_INTF_DEV
+int __init rpmb_cdev_init(void);
+void __exit rpmb_cdev_exit(void);
+void rpmb_cdev_prepare(struct rpmb_dev *rdev);
+void rpmb_cdev_add(struct rpmb_dev *rdev);
+void rpmb_cdev_del(struct rpmb_dev *rdev);
+#else
+static inline int __init rpmb_cdev_init(void) { return 0; }
+static inline void __exit rpmb_cdev_exit(void) {}
+static inline void rpmb_cdev_prepare(struct rpmb_dev *rdev) {}
+static inline void rpmb_cdev_add(struct rpmb_dev *rdev) {}
+static inline void rpmb_cdev_del(struct rpmb_dev *rdev) {}
+#endif /* CONFIG_RPMB_INTF_DEV */
diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h
index 6acd9b1e70f6..fb535336d50f 100644
--- a/include/linux/rpmb.h
+++ b/include/linux/rpmb.h
@@ -7,105 +7,14 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/cdev.h>
+#include <uapi/linux/rpmb.h>
#include <linux/kref.h>
-/**
- * struct rpmb_frame_jdec - rpmb frame as defined by JDEC specs
- *
- * @stuff : stuff bytes
- * @key_mac : The authentication key or the message authentication
- * code (MAC) depending on the request/response type.
- * The MAC will be delivered in the last (or the only)
- * block of data.
- * @data : Data to be written or read by signed access.
- * @nonce : Random number generated by the host for the requests
- * and copied to the response by the RPMB engine.
- * @write_counter: Counter value for the total amount of the successful
- * authenticated data write requests made by the host.
- * @addr : Address of the data to be programmed to or read
- * from the RPMB. Address is the serial number of
- * the accessed block (half sector 256B).
- * @block_count : Number of blocks (half sectors, 256B) requested to be
- * read/programmed.
- * @result : Includes information about the status of the write counter
- * (valid, expired) and result of the access made to the RPMB.
- * @req_resp : Defines the type of request and response to/from the memory.
- */
-struct rpmb_frame_jdec {
- u8 stuff[196];
- u8 key_mac[32];
- u8 data[256];
- u8 nonce[16];
- __be32 write_counter;
- __be16 addr;
- __be16 block_count;
- __be16 result;
- __be16 req_resp;
-} __packed;
-
-#define RPMB_PROGRAM_KEY 0x0001 /* Program RPMB Authentication Key */
-#define RPMB_GET_WRITE_COUNTER 0x0002 /* Read RPMB write counter */
-#define RPMB_WRITE_DATA 0x0003 /* Write data to RPMB partition */
-#define RPMB_READ_DATA 0x0004 /* Read data from RPMB partition */
-#define RPMB_RESULT_READ 0x0005 /* Read result request (Internal) */
-
-#define RPMB_REQ2RESP(_OP) ((_OP) << 8)
-#define RPMB_RESP2REQ(_OP) ((_OP) >> 8)
-
-/**
- * enum rpmb_op_result - rpmb operation results
- *
- * @RPMB_ERR_OK : operation successful
- * @RPMB_ERR_GENERAL : general failure
- * @RPMB_ERR_AUTH : mac doesn't match or ac calculation failure
- * @RPMB_ERR_COUNTER : counter doesn't match or counter increment failure
- * @RPMB_ERR_ADDRESS : address out of range or wrong address alignment
- * @RPMB_ERR_WRITE : data, counter, or result write failure
- * @RPMB_ERR_READ : data, counter, or result read failure
- * @RPMB_ERR_NO_KEY : authentication key not yet programmed
- *
- * @RPMB_ERR_COUNTER_EXPIRED: counter expired
- */
-enum rpmb_op_result {
- RPMB_ERR_OK = 0x0000,
- RPMB_ERR_GENERAL = 0x0001,
- RPMB_ERR_AUTH = 0x0002,
- RPMB_ERR_COUNTER = 0x0003,
- RPMB_ERR_ADDRESS = 0x0004,
- RPMB_ERR_WRITE = 0x0005,
- RPMB_ERR_READ = 0x0006,
- RPMB_ERR_NO_KEY = 0x0007,
-
- RPMB_ERR_COUNTER_EXPIRED = 0x0080
-};
-
-/**
- * enum rpmb_type - type of underlying storage technology
- *
- * @RPMB_TYPE_ANY : any type used for search only
- * @RPMB_TYPE_EMMC : eMMC (JESD84-B50.1)
- * @RPMB_TYPE_UFS : UFS (JESD220)
- * @RPMB_TYPE_NVME : NVM Express Revision 1.3a
- * @RPMB_TYPE_SIM : Simulation device.
- * @RPMB_TYPE_MAX : upper sentinel
- */
-enum rpmb_type {
- RPMB_TYPE_ANY = 0,
- RPMB_TYPE_EMMC,
- RPMB_TYPE_UFS,
- RPMB_TYPE_NVME,
-
- RPMB_TYPE_SIM = 0x0100,
- RPMB_TYPE_MAX = RPMB_TYPE_SIM | RPMB_TYPE_NVME,
-};
-
-#define RPMB_TYPE_HW(_type) ((_type) & 0xFF)
+#define RPMB_API_VERSION 0x80000001
extern struct class rpmb_class;
-#define RPMB_F_WRITE BIT(0)
-#define RPMB_F_REL_WRITE BIT(1)
-
/**
* struct rpmb_cmd: rpmb access command
*
@@ -122,10 +31,6 @@ struct rpmb_cmd {
void *frames;
};
-enum rpmb_auth_method {
- RPMB_HMAC_ALGO_SHA_256 = 0,
-};
-
/**
* struct rpmb_ops - RPMB ops to be implemented by underlying block device
*
@@ -163,6 +68,8 @@ struct rpmb_ops {
* @dev : device
* @id : device id
* @target : RPMB target/region within the physical device
+ * @cdev : character dev
+ * @status : device status
* @ops : operation exported by block layer
*/
struct rpmb_dev {
@@ -170,6 +77,10 @@ struct rpmb_dev {
struct device dev;
int id;
u8 target;
+#ifdef CONFIG_RPMB_INTF_DEV
+ struct cdev cdev;
+ unsigned long status;
+#endif /* CONFIG_RPMB_INTF_DEV */
const struct rpmb_ops *ops;
};
diff --git a/include/uapi/linux/rpmb.h b/include/uapi/linux/rpmb.h
new file mode 100644
index 000000000000..d304701cd258
--- /dev/null
+++ b/include/uapi/linux/rpmb.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * Copyright (C) 2015-2018 Intel Corp. All rights reserved
+ */
+#ifndef _UAPI_LINUX_RPMB_H_
+#define _UAPI_LINUX_RPMB_H_
+
+#include <linux/types.h>
+
+/**
+ * enum rpmb_type - type of underlying storage technology
+ *
+ * @RPMB_TYPE_ANY : any type used for search only
+ * @RPMB_TYPE_EMMC : eMMC (JESD84-B50.1)
+ * @RPMB_TYPE_UFS : UFS (JESD220)
+ * @RPMB_TYPE_NVME : NVM Express Revision 1.3a
+ * @RPMB_TYPE_SIM : Simulation device.
+ * @RPMB_TYPE_MAX : upper sentinel
+ */
+enum rpmb_type {
+ RPMB_TYPE_ANY = 0,
+ RPMB_TYPE_EMMC,
+ RPMB_TYPE_UFS,
+ RPMB_TYPE_NVME,
+
+ RPMB_TYPE_SIM = 0x0100,
+ RPMB_TYPE_MAX = RPMB_TYPE_SIM | RPMB_TYPE_NVME,
+};
+
+#define RPMB_TYPE_HW(_type) ((_type) & 0xFF)
+
+/**
+ * struct rpmb_frame_jdec - rpmb frame as defined by JDEC specs
+ *
+ * @stuff : stuff bytes
+ * @key_mac : The authentication key or the message authentication
+ * code (MAC) depending on the request/response type.
+ * The MAC will be delivered in the last (or the only)
+ * block of data.
+ * @data : Data to be written or read by signed access.
+ * @nonce : Random number generated by the host for the requests
+ * and copied to the response by the RPMB engine.
+ * @write_counter: Counter value for the total amount of the successful
+ * authenticated data write requests made by the host.
+ * @addr : Address of the data to be programmed to or read
+ * from the RPMB. Address is the serial number of
+ * the accessed block (half sector 256B).
+ * @block_count : Number of blocks (half sectors, 256B) requested to be
+ * read/programmed.
+ * @result : Includes information about the status of the write counter
+ * (valid, expired) and result of the access made to the RPMB.
+ * @req_resp : Defines the type of request and response to/from the memory.
+ */
+struct rpmb_frame_jdec {
+ __u8 stuff[196];
+ __u8 key_mac[32];
+ __u8 data[256];
+ __u8 nonce[16];
+ __be32 write_counter;
+ __be16 addr;
+ __be16 block_count;
+ __be16 result;
+ __be16 req_resp;
+} __attribute__((packed));
+
+/* length of the part of the frame used for HMAC computation */
+#define rpmb_jdec_hmac_data_len \
+ (sizeof(struct rpmb_frame_jdec) - \
+ offsetof(struct rpmb_frame_jdec, data))
+
+#define RPMB_PROGRAM_KEY 0x0001 /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 0x0002 /* Read RPMB write counter */
+#define RPMB_WRITE_DATA 0x0003 /* Write data to RPMB partition */
+#define RPMB_READ_DATA 0x0004 /* Read data from RPMB partition */
+#define RPMB_RESULT_READ 0x0005 /* Read result request (Internal) */
+
+#define RPMB_REQ2RESP(_OP) ((_OP) << 8)
+#define RPMB_RESP2REQ(_OP) ((_OP) >> 8)
+
+/**
+ * enum rpmb_op_result - rpmb operation results
+ *
+ * @RPMB_ERR_OK: operation successful
+ * @RPMB_ERR_GENERAL: general failure
+ * @RPMB_ERR_AUTH: mac doesn't match or ac calculation failure
+ * @RPMB_ERR_COUNTER: counter doesn't match or counter increment failure
+ * @RPMB_ERR_ADDRESS: address out of range or wrong address alignment
+ * @RPMB_ERR_WRITE: data, counter, or result write failure
+ * @RPMB_ERR_READ: data, counter, or result read failure
+ * @RPMB_ERR_NO_KEY: authentication key not yet programmed
+ *
+ * @RPMB_ERR_COUNTER_EXPIRED: counter expired
+ */
+enum rpmb_op_result {
+ RPMB_ERR_OK = 0x0000,
+ RPMB_ERR_GENERAL = 0x0001,
+ RPMB_ERR_AUTH = 0x0002,
+ RPMB_ERR_COUNTER = 0x0003,
+ RPMB_ERR_ADDRESS = 0x0004,
+ RPMB_ERR_WRITE = 0x0005,
+ RPMB_ERR_READ = 0x0006,
+ RPMB_ERR_NO_KEY = 0x0007,
+
+ RPMB_ERR_COUNTER_EXPIRED = 0x0080
+};
+
+#define RPMB_F_READ 0UL
+#define RPMB_F_WRITE (1UL << 0)
+#define RPMB_F_REL_WRITE (1UL << 1)
+
+enum rpmb_auth_method {
+ RPMB_HMAC_ALGO_SHA_256 = 0,
+};
+
+/**
+ * struct rpmb_cmd - rpmb access command
+ *
+ * @flags: command flags
+ * 0 - read command
+ * 1 - write command RPMB_F_WRITE
+ * 2 - reliable write RPMB_F_REL_WRITE
+ * @nframes: number of rpmb data frames in the command.
+ * 0 means 1 frame with meta data only.
+ * @frames_ptr: a pointer to the list of rpmb frames
+ */
+struct rpmb_ioc_cmd {
+ __u32 flags;
+ __u32 nframes;
+ __aligned_u64 frames_ptr;
+};
+
+#define rpmb_ioc_cmd_set_frames(_cmd, _ptr) \
+ (_cmd).frames_ptr = (__aligned_u64)(intptr_t)(_ptr)
+
+#define rpmb_ioc_cmd_set(_cmd, _flags, _ptr, _n) do { \
+ struct rpmb_ioc_cmd *icmd = &(_cmd); \
+ icmd->flags = (_flags); \
+ icmd->nframes = (_n); \
+ icmd->frames_ptr = (__aligned_u64)(intptr_t)(_ptr); \
+} while (0)
+
+#define rpmb_ioc_frames_len_jdec(_n) \
+ (((_n) ?: 1) * sizeof(struct rpmb_frame_jdec))
+
+/**
+ * struct rpmb_ioc_seq_cmd - rpmb command sequence
+ *
+ * @num_of_cmds: number of commands
+ * @cmds: list of rpmb commands
+ */
+struct rpmb_ioc_seq_cmd {
+ __u64 num_of_cmds;
+ struct rpmb_ioc_cmd cmds[0];
+} __attribute__((packed));
+
+/**
+ * struct rpmb_ioc_ver_cmd - rpmb api version
+ *
+ * @api_version: rpmb API version.
+ */
+struct rpmb_ioc_ver_cmd {
+ __u32 api_version;
+} __attribute__((packed));
+
+/**
+ * struct rpmb_ioc_ver_cmd - rpmb api version
+ *
+ * @device_type: underlying storage device type
+ * @target: rpmb target/region within RPMB partition.
+ * @capacity: storage capacity
+ * @block_size: storage data block size
+ * @wr_cnt_max: maximal number of block that can be written in a single request.
+ * @rd_cnt_max: maximal number of block that can be read in a single request.
+ * @auth_method: authentication method: currently always HMAC_SHA_256
+ * @reserved: reserved to align to 4 bytes.
+ */
+struct rpmb_ioc_cap_cmd {
+ __u16 device_type;
+ __u16 target;
+ __u16 capacity;
+ __u16 block_size;
+ __u16 wr_cnt_max;
+ __u16 rd_cnt_max;
+ __u16 auth_method;
+ __u16 reserved;
+} __attribute__((packed));
+
+#define RPMB_IOC_VER_CMD _IOR(0xB5, 80, struct rpmb_ioc_ver_cmd)
+#define RPMB_IOC_CAP_CMD _IOR(0xB5, 81, struct rpmb_ioc_cap_cmd)
+#define RPMB_IOC_SEQ_CMD _IOWR(0xB5, 82, struct rpmb_ioc_seq_cmd)
+
+#endif /* _UAPI_LINUX_RPMB_H_ */
--
2.19.1