-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathcaam_keyblob.c
724 lines (625 loc) · 21.4 KB
/
caam_keyblob.c
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
/*
* Key blob driver based on CAAM hardware
*
* Copyright (C) 2015 Freescale Semiconductor, Inc.
*/
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/miscdevice.h>
#include "compat.h"
#include "regs.h"
#include "jr.h"
#include "desc.h"
#include "intern.h"
#include "sm.h"
#include "caam_keyblob.h"
#define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */
#define MAX_KEYBLOB_LEN 65535
#define MAX_RAWKEY_LEN (MAX_KEYBLOB_LEN - BLOB_OVERHEAD)
#define SNVS_HPSR_REG 0x020cc014
#define SNVS_HPSR_SSM_STATE_MASK 0xf00
#define SNVS_HPSR_SSM_STATE_TRUSTED 0xd00
#define SNVS_HPSR_SSM_STATE_SECURE 0xf00
/**
* struct kb_device - the metadata of the caam key blob device node
* @dev: the actual misc device
*/
struct kb_device {
struct miscdevice misc_dev;
struct device *jr_dev;
};
/*
* Pseudo-synchronous ring access functions for carrying out key
* encapsulation and decapsulation
*/
struct sm_key_job_result {
int error;
struct completion completion;
};
static struct kb_device *kb_dev;
static struct kb_device *kb_device_create(void);
static int kb_device_destroy(struct kb_device *kb_dev);
static int kb_open(struct inode *inode, struct file *file);
static int kb_release(struct inode *inode, struct file *file);
static void sm_key_job_done(struct device *dev, u32 *desc,
u32 err, void *context);
static int gen_mem_encap(struct device *jr_dev, void __user *secretbuf,
size_t keylen, void __user *kmodbuf, void __user *outbuf);
static int gen_mem_decap(struct device *jr_dev, void __user *keyblobbuf,
size_t bloblen, void __user *kmodbuf, void __user *outbuf);
static long kb_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int caam_keyblob_probe(struct platform_device *pdev);
static int caam_keyblob_remove(struct platform_device *pdev);
static int kb_open(struct inode *inode, struct file *file)
{
struct miscdevice *miscdev = file->private_data;
struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev);
struct device *jr_dev;
if (!dev->jr_dev) {
jr_dev = caam_jr_alloc();
if (IS_ERR(jr_dev)) {
pr_err("caam_keyblob: job ring device allocation for transform failed\n");
return -ENOMEM;
}
dev->jr_dev = jr_dev;
}
else {
pr_err("caam_keyblob: job ring device already created");
return -EPERM;
}
return 0;
}
static int kb_release(struct inode *inode, struct file *file)
{
struct miscdevice *miscdev = file->private_data;
struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev);
if (dev && dev->jr_dev) {
caam_jr_free(dev->jr_dev);
dev->jr_dev = NULL;
}
return 0;
}
static void sm_key_job_done(struct device *dev, u32 *desc,
u32 err, void *context)
{
struct sm_key_job_result *res = context;
res->error = err; /* save off the error for postprocessing */
complete(&res->completion); /* mark us complete */
}
/*
* Construct a blob encapsulation job descriptor
*
* This function dynamically constructs a blob encapsulation job descriptor
* from the following arguments:
*
* - desc pointer to a pointer to the descriptor generated by this
* function. Caller will be responsible to kfree() this
* descriptor after execution.
* - keymod Physical pointer to a key modifier, which must reside in a
* contiguous piece of memory. Modifier will be assumed to be
* 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
* for a blob of type SM_GENMEM (see blobtype argument).
* - secretbuf Physical pointer to a secret, normally a black or red key,
* possibly residing within an accessible secure memory page,
* of the secret to be encapsulated to an output blob.
* - outbuf Physical pointer to the destination buffer to receive the
* encapsulated output. This buffer will need to be 48 bytes
* larger than the input because of the added encapsulation data.
* The generated descriptor will account for the increase in size,
* but the caller must also account for this increase in the
* buffer allocator.
* - secretsz Size of input secret, in bytes. This is limited to 65536
* less the size of blob overhead, since the length embeds into
* DECO pointer in/out instructions.
* - keycolor Determines if the source data is covered (black key) or
* plaintext (red key). RED_KEY or BLACK_KEY are defined in
* for this purpose.
* - blobtype Determine if encapsulated blob should be a secure memory
* blob (SM_SECMEM), with partition data embedded with key
* material, or a general memory blob (SM_GENMEM).
* - auth If BLACK_KEY source is covered via AES-CCM, specify
* KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
*
* Upon completion, desc points to a buffer containing a CAAM job
* descriptor which encapsulates data into an externally-storable blob
* suitable for use across power cycles.
*
* This is an example of a black key encapsulation job into a general memory
* blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
* the output 48 bytes longer than the input:
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400010 ld: ccb2-key len=16 offs=0
* [02] 08144891 ptr->@0x08144891
* [03] F800003A seqoutptr: len=58
* [04] 01000000 out_ptr->@0x01000000
* [05] F000000A seqinptr: len=10
* [06] 09745090 in_ptr->@0x09745090
* [07] 870D0004 operation: encap blob reg=memory, black, format=normal
*
* This is an example of a red key encapsulation job for storing a red key
* into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
* in the LOAD instruction; this accounts for blob permission storage:
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400C08 ld: ccb2-key len=8 offs=12
* [02] 087D0784 ptr->@0x087d0784
* [03] F8000050 seqoutptr: len=80
* [04] 09251BB2 out_ptr->@0x09251bb2
* [05] F0000020 seqinptr: len=32
* [06] 40000F31 in_ptr->@0x40000f31
* [07] 870D0008 operation: encap blob reg=memory, red, sec_mem,
* format=normal
*
* Note: this function only generates 32-bit pointers at present, and should
* be refactored using a scheme that allows both 32 and 64 bit addressing
*/
static int blob_encap_jobdesc(u32 **desc, dma_addr_t keymod,
void *secretbuf, dma_addr_t outbuf,
u16 secretsz, u8 keycolor, u8 blobtype, u8 auth)
{
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
u16 dsize, idx;
memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
idx = 1;
/*
* Key modifier works differently for secure/general memory blobs
* This accounts for the permission/protection data encapsulated
* within the blob if a secure memory blob is requested
*/
if (blobtype == SM_SECMEM)
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_KEY |
((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
| (8 & LDST_LEN_MASK);
else /* is general memory blob */
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
tmpdesc[idx++] = (u32)keymod;
/*
* Encapsulation output must include space for blob key encryption
* key and MAC tag
*/
tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + BLOB_OVERHEAD);
tmpdesc[idx++] = (u32)outbuf;
/* Input data, should be somewhere in secure memory */
tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz;
tmpdesc[idx++] = (u32)secretbuf;
/* Set blob encap, then color */
tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
if (blobtype == SM_SECMEM)
tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
if (auth == KEY_COVER_CCM)
tmpdesc[idx] |= OP_PCL_BLOB_EKT;
if (keycolor == BLACK_KEY)
tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
idx++;
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
dsize = idx * sizeof(u32);
tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
if (tdesc == NULL)
return 0;
memcpy(tdesc, tmpdesc, dsize);
*desc = tdesc;
return dsize;
}
/*
* Construct a blob decapsulation job descriptor
*
* This function dynamically constructs a blob decapsulation job descriptor
* from the following arguments:
*
* - desc pointer to a pointer to the descriptor generated by this
* function. Caller will be responsible to kfree() this
* descriptor after execution.
* - keymod Physical pointer to a key modifier, which must reside in a
* contiguous piece of memory. Modifier will be assumed to be
* 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
* for a blob of type SM_GENMEM (see blobtype argument).
* - blobbuf Physical pointer (into external memory) of the blob to
* be decapsulated. Blob must reside in a contiguous memory
* segment.
* - outbuf Physical pointer of the decapsulated output, possibly into
* a location within a secure memory page. Must be contiguous.
* - secretsz Size of encapsulated secret in bytes (not the size of the
* input blob).
* - keycolor Determines if decapsulated content is encrypted (BLACK_KEY)
* or left as plaintext (RED_KEY).
* - blobtype Determine if encapsulated blob should be a secure memory
* blob (SM_SECMEM), with partition data embedded with key
* material, or a general memory blob (SM_GENMEM).
* - auth If decapsulation path is specified by BLACK_KEY, then if
* AES-CCM is requested for key covering use KEY_COVER_CCM, else
* use AES-ECB (KEY_COVER_ECB).
*
* Upon completion, desc points to a buffer containing a CAAM job descriptor
* that decapsulates a key blob from external memory into a black (encrypted)
* key or red (plaintext) content.
*
* This is an example of a black key decapsulation job from a general memory
* blob. Notice the 16-byte key modifier in the LOAD instruction.
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400010 ld: ccb2-key len=16 offs=0
* [02] 08A63B7F ptr->@0x08a63b7f
* [03] F8000010 seqoutptr: len=16
* [04] 01000000 out_ptr->@0x01000000
* [05] F000003A seqinptr: len=58
* [06] 01000010 in_ptr->@0x01000010
* [07] 860D0004 operation: decap blob reg=memory, black, format=normal
*
* This is an example of a red key decapsulation job for restoring a red key
* from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
* in the LOAD instruction:
*
* [00] B0800008 jobhdr: stidx=0 len=8
* [01] 14400C08 ld: ccb2-key len=8 offs=12
* [02] 01000000 ptr->@0x01000000
* [03] F8000020 seqoutptr: len=32
* [04] 400000E6 out_ptr->@0x400000e6
* [05] F0000050 seqinptr: len=80
* [06] 08F0C0EA in_ptr->@0x08f0c0ea
* [07] 860D0008 operation: decap blob reg=memory, red, sec_mem,
* format=normal
*
* Note: this function only generates 32-bit pointers at present, and should
* be refactored using a scheme that allows both 32 and 64 bit addressing
*/
static int blob_decap_jobdesc(u32 **desc, dma_addr_t keymod, dma_addr_t blobbuf,
u8 *outbuf, u16 secretsz, u8 keycolor,
u8 blobtype, u8 auth)
{
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
u16 dsize, idx;
memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
idx = 1;
/* Load key modifier */
if (blobtype == SM_SECMEM)
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_KEY |
((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
| (8 & LDST_LEN_MASK);
else /* is general memory blob */
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
tmpdesc[idx++] = (u32)keymod;
/* Compensate BKEK + MAC tag over size of encapsulated secret */
tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + BLOB_OVERHEAD);
tmpdesc[idx++] = (u32)blobbuf;
tmpdesc[idx++] = CMD_SEQ_OUT_PTR | secretsz;
tmpdesc[idx++] = (u32)outbuf;
/* Decapsulate from secure memory partition to black blob */
tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB;
if (blobtype == SM_SECMEM)
tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
if (auth == KEY_COVER_CCM)
tmpdesc[idx] |= OP_PCL_BLOB_EKT;
if (keycolor == BLACK_KEY)
tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
idx++;
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
dsize = idx * sizeof(u32);
tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
if (tdesc == NULL)
return 0;
memcpy(tdesc, tmpdesc, dsize);
*desc = tdesc;
return dsize;
}
static int gen_mem_encap(struct device *jr_dev, void __user *secretbuf,
size_t keylen, void __user *kmodbuf, void __user *outbuf)
{
int retval = 0;
u32 dsize;
u32 __iomem *encapdesc = NULL;
dma_addr_t secret_dma = 0, keymod_dma = 0, outbuf_dma = 0;
u8 __iomem *lsecret = NULL, *lkeymod = NULL, *loutbuf = NULL;
struct sm_key_job_result testres;
/* Build/map/flush the scret */
lsecret = kmalloc(keylen, GFP_KERNEL | GFP_DMA);
if (!lsecret) {
dev_err(jr_dev, "caam_keyblob: %s can't alloc for key\n", __func__);
retval = -ENOMEM;
goto out;
}
if (copy_from_user(lsecret, secretbuf, keylen)) {
dev_err(jr_dev, "caam_keyblob: %s can't copy for key\n", __func__);
retval = -EFAULT;
goto out;
}
secret_dma = dma_map_single(jr_dev, lsecret, keylen,
DMA_TO_DEVICE);
/* Build/map/flush the key modifier */
lkeymod = kmalloc(GENMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
if (!lkeymod) {
dev_err(jr_dev, "caam_keyblob: %s can't alloc for keymod\n", __func__);
retval = -ENOMEM;
goto out;
}
if (copy_from_user(lkeymod, kmodbuf, GENMEM_KEYMOD_LEN)) {
dev_err(jr_dev, "caam_keyblob: %s can't Copy for keymod\n", __func__);
retval = -EFAULT;
goto out;
}
keymod_dma = dma_map_single(jr_dev, lkeymod, GENMEM_KEYMOD_LEN,
DMA_TO_DEVICE);
loutbuf = kmalloc(keylen + BLOB_OVERHEAD, GFP_KERNEL | GFP_DMA);
if (!lkeymod) {
dev_err(jr_dev, "caam_keyblob: %s can't alloc for output\n", __func__);
retval = -ENOMEM;
goto out;
}
outbuf_dma = dma_map_single(jr_dev, loutbuf, keylen + BLOB_OVERHEAD,
DMA_FROM_DEVICE);
dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, (void *)secret_dma, outbuf_dma,
keylen, RED_KEY, SM_GENMEM, KEY_COVER_ECB);
if (!dsize) {
dev_err(jr_dev, "caam_keyblob: can't alloc an encapsulation descriptor\n");
retval = -ENOMEM;
goto out;
}
init_completion(&testres.completion);
retval = caam_jr_enqueue(jr_dev, encapdesc, sm_key_job_done,
&testres);
if (retval == 0 || retval == -EINPROGRESS) {
retval = 0;
wait_for_completion_interruptible(&testres.completion);
if (testres.error) {
retval = -EFAULT;
dev_err(jr_dev, "caam_keyblob: job ring error\n");
goto out;
}
dma_sync_single_for_cpu(jr_dev, outbuf_dma, keylen + BLOB_OVERHEAD,
DMA_FROM_DEVICE);
if (copy_to_user(outbuf, loutbuf, keylen + BLOB_OVERHEAD)) {
retval = -EFAULT;
dev_err(jr_dev, "caam_keyblob: can't copy for output\n");
goto out;
}
}
out:
if (outbuf_dma)
dma_unmap_single(jr_dev, outbuf_dma, keylen + BLOB_OVERHEAD,
DMA_FROM_DEVICE);
if (keymod_dma)
dma_unmap_single(jr_dev, keymod_dma, GENMEM_KEYMOD_LEN, DMA_TO_DEVICE);
if (secret_dma)
dma_unmap_single(jr_dev, secret_dma, keylen, DMA_TO_DEVICE);
kfree(encapdesc);
kfree(lkeymod);
kfree(lsecret);
kfree(loutbuf);
return retval;
}
static int gen_mem_decap(struct device *jr_dev, void __user *keyblobbuf,
size_t bloblen, void __user *kmodbuf, void __user *outbuf)
{
int retval = 0;
size_t keylen = bloblen - BLOB_OVERHEAD;
u32 dsize;
dma_addr_t keyblob_dma = 0, keymod_dma = 0, outbuf_dma = 0;
u8 __iomem *lkeyblob = NULL, *lkeymod = NULL, *loutbuf = NULL;
struct sm_key_job_result testres;
u32 __iomem *decapdesc = NULL;
/* Build/map/flush the scret */
lkeyblob = kmalloc(bloblen, GFP_KERNEL | GFP_DMA);
if (!lkeyblob) {
dev_err(jr_dev, "caam_keyblob: %s can't alloc for keylob\n", __func__);
retval = -ENOMEM;
goto out;
}
if (copy_from_user(lkeyblob, keyblobbuf, bloblen)) {
dev_err(jr_dev, "caam_keyblob: %s can't copy for keyblob\n", __func__);
retval = -EFAULT;
goto out;
}
keyblob_dma = dma_map_single(jr_dev, lkeyblob, bloblen,
DMA_TO_DEVICE);
/* Build/map/flush the key modifier */
lkeymod = kmalloc(GENMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
if (!lkeymod) {
dev_err(jr_dev, "caam_keyblob: %s can't alloc for keymod\n", __func__);
retval = -ENOMEM;
goto out;
}
if (copy_from_user(lkeymod, kmodbuf, GENMEM_KEYMOD_LEN)) {
dev_err(jr_dev, "caam_keyblob: %s can't copy for keymod\n", __func__);
retval = -EFAULT;
goto out;
}
keymod_dma = dma_map_single(jr_dev, lkeymod, GENMEM_KEYMOD_LEN,
DMA_TO_DEVICE);
loutbuf = kmalloc(keylen, GFP_KERNEL | GFP_DMA);
if (!loutbuf) {
dev_err(jr_dev, "caam_keyblob: %s can't alloc for outbuf\n", __func__);
retval = -ENOMEM;
goto out;
}
outbuf_dma = dma_map_single(jr_dev, loutbuf, keylen,
DMA_FROM_DEVICE);
/* Build the encapsulation job descriptor */
dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, keyblob_dma, (u8 *)outbuf_dma,
keylen, RED_KEY, SM_GENMEM, KEY_COVER_ECB);
if (!dsize) {
dev_err(jr_dev, "caam_keyblob: can't alloc a decapsulation descriptor\n");
retval = -ENOMEM;
goto out;
}
init_completion(&testres.completion);
retval = caam_jr_enqueue(jr_dev, decapdesc, sm_key_job_done,
&testres);
if (retval == 0 || retval == -EINPROGRESS) {
retval = 0;
wait_for_completion_interruptible(&testres.completion);
if (testres.error) {
retval = -EFAULT;
dev_err(jr_dev, "caam_keyblob: job ring error\n");
goto out;
}
dma_sync_single_for_cpu(jr_dev, outbuf_dma, keylen,
DMA_FROM_DEVICE);
if (copy_to_user(outbuf, loutbuf, keylen)) {
retval = -EFAULT;
dev_err(jr_dev, "caam_keyblob: can't copy for output\n");
goto out;
}
}
out:
if (outbuf_dma)
dma_unmap_single(jr_dev, outbuf_dma, keylen,
DMA_FROM_DEVICE);
if (keymod_dma)
dma_unmap_single(jr_dev, keymod_dma, GENMEM_KEYMOD_LEN,
DMA_TO_DEVICE);
if (keyblob_dma)
dma_unmap_single(jr_dev, keyblob_dma, bloblen,
DMA_TO_DEVICE);
kfree(decapdesc);
kfree(lkeymod);
kfree(lkeyblob);
kfree(loutbuf);
return retval;
}
static long kb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
struct caam_kb_data kb_data;
struct miscdevice *miscdev = file->private_data;
struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev);
if (copy_from_user(&kb_data, (void *)arg, sizeof(kb_data))) {
retval = -EFAULT;
goto err;
}
if (!kb_data.rawkey || !kb_data.keyblob ||
(kb_data.rawkey_len + BLOB_OVERHEAD != kb_data.keyblob_len) ||
(kb_data.rawkey_len > MAX_RAWKEY_LEN) ||
(kb_data.keyblob_len > MAX_KEYBLOB_LEN) ||
(kb_data.keyblob_len <= BLOB_OVERHEAD) ||
(kb_data.keymod_len != GENMEM_KEYMOD_LEN)) {
retval = -EINVAL;
goto err;
}
printk(KERN_INFO "caam_keyblob: %s rawkey_len:%d keyblob_len:%d\n",
__func__, kb_data.rawkey_len, kb_data.keyblob_len);
switch (cmd) {
case CAAM_KB_ENCRYPT:
{
retval = gen_mem_encap(dev->jr_dev, kb_data.rawkey, kb_data.rawkey_len,
kb_data.keymod, kb_data.keyblob);
break;
}
case CAAM_KB_DECRYPT:
{
retval = gen_mem_decap(dev->jr_dev, kb_data.keyblob, kb_data.keyblob_len,
kb_data.keymod, kb_data.rawkey);
break;
}
default:
return -ENOTTY;
}
err:
return retval;
}
static const struct file_operations kb_fops = {
.owner = THIS_MODULE,
.open = kb_open,
.release = kb_release,
.unlocked_ioctl = kb_ioctl,
};
static struct kb_device *kb_device_create(void)
{
struct kb_device *idev;
int ret;
idev = kzalloc(sizeof(struct kb_device), GFP_KERNEL);
if (!idev)
return ERR_PTR(-ENOMEM);
idev->misc_dev.minor = MISC_DYNAMIC_MINOR;
idev->misc_dev.name = "caam_kb";
idev->misc_dev.fops = &kb_fops;
idev->misc_dev.parent = NULL;
ret = misc_register(&idev->misc_dev);
if (ret) {
pr_err("caam_keyblob: caam_kb, failed to register misc device.\n");
return ERR_PTR(ret);
}
return idev;
}
static int kb_device_destroy(struct kb_device *kb_dev)
{
if ((kb_dev) && (kb_dev->jr_dev)) {
caam_jr_free(kb_dev->jr_dev);
kb_dev->jr_dev = NULL;
}
if (kb_dev)
misc_deregister(&kb_dev->misc_dev);
return 0;
}
/*
* Probe key blob device
*/
static int caam_keyblob_probe(struct platform_device *pdev)
{
int err;
void __iomem *page;
u32 ssm_state, offset;
dev_dbg(&pdev->dev, "caam_keylob: %s enter\n", __func__);
kb_dev = kb_device_create();
if (IS_ERR_OR_NULL(kb_dev)) {
err = PTR_ERR(kb_dev);
goto err;
}
dev_info(&pdev->dev, "caam_keyblob: initialized\n");
page = ioremap(SNVS_HPSR_REG & ~(SZ_4K - 1), SZ_4K);
offset = SNVS_HPSR_REG & (SZ_4K - 1);
ssm_state = (__raw_readl(page + offset) & SNVS_HPSR_SSM_STATE_MASK);
if (ssm_state == SNVS_HPSR_SSM_STATE_TRUSTED) {
printk(KERN_INFO "caam_keyblob: Trusted State detected\n");
} else if (ssm_state == SNVS_HPSR_SSM_STATE_SECURE) {
printk(KERN_INFO "caam_keyblob: Secure State detected\n");
} else {
printk(KERN_NOTICE "caam_keyblob: WARNING - not in Trusted or Secure State, Non-volatile Test Key in effect\n");
}
return 0;
err:
return err;
}
/*
* Remove key blob device
*/
static int caam_keyblob_remove(struct platform_device *pdev)
{
kb_device_destroy(kb_dev);
return 0;
}
static struct of_device_id caam_keyblob_match[] = {
{
.compatible = "fsl,sec-v4.0-keyblob",
},
{
.compatible = "fsl,sec4.0-keyblob",
},
{},
};
MODULE_DEVICE_TABLE(of, caam_keyblob_match);
static struct platform_driver caam_keyblob_driver = {
.driver = {
.name = "caam_keyblob",
.owner = THIS_MODULE,
.of_match_table = caam_keyblob_match,
},
.probe = caam_keyblob_probe,
.remove = caam_keyblob_remove,
};
static int __init keyblob_driver_init(void)
{
return platform_driver_register(&caam_keyblob_driver);
}
static void __exit keyblob_driver_exit(void)
{
platform_driver_unregister(&caam_keyblob_driver);
}
module_init(keyblob_driver_init);
module_exit(keyblob_driver_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore");
MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");