2 * Driver for /dev/crypto device (aka CryptoDev)
4 * Copyright (c) 2009-2011 Nikos Mavrogiannopoulos <nmav@gnutls.org>
5 * Copyright (c) 2010 Phil Sutter
6 * Copyright (c) 2011, 2012 OpenSSL Software Foundation, Inc.
8 * This file is part of linux cryptodev.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include <crypto/hash.h>
27 #include <linux/crypto.h>
29 #include <linux/highmem.h>
30 #include <linux/ioctl.h>
31 #include <linux/random.h>
32 #include <linux/syscalls.h>
33 #include <linux/pagemap.h>
34 #include <linux/uaccess.h>
35 #include <crypto/scatterwalk.h>
36 #include <linux/scatterlist.h>
37 #include "cryptodev_int.h"
41 /* Helper functions to assist zero copy.
42 * This needs to be redesigned and moved out of the session. --nmav
45 /* offset of buf in it's first page */
46 #define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK)
48 /* fetch the pages addr resides in into pg and initialise sg with them */
49 int __get_userbuf(uint8_t __user
*addr
, uint32_t len
, int write
,
50 unsigned int pgcount
, struct page
**pg
, struct scatterlist
*sg
,
51 struct task_struct
*task
, struct mm_struct
*mm
)
53 int ret
, pglen
, i
= 0;
54 struct scatterlist
*sgp
;
56 if (unlikely(!pgcount
|| !len
|| !addr
)) {
61 down_read(&mm
->mmap_sem
);
62 ret
= get_user_pages(task
, mm
,
63 (unsigned long)addr
, pgcount
, write
, 0, pg
, NULL
);
64 up_read(&mm
->mmap_sem
);
68 sg_init_table(sg
, pgcount
);
70 pglen
= min((ptrdiff_t)(PAGE_SIZE
- PAGEOFFSET(addr
)), (ptrdiff_t)len
);
71 sg_set_page(sg
, pg
[i
++], pglen
, PAGEOFFSET(addr
));
74 for (sgp
= sg_next(sg
); len
; sgp
= sg_next(sgp
)) {
75 pglen
= min((uint32_t)PAGE_SIZE
, len
);
76 sg_set_page(sgp
, pg
[i
++], pglen
, 0);
79 sg_mark_end(sg_last(sg
, pgcount
));
83 int adjust_sg_array(struct csession
* ses
, int pagecount
)
85 struct scatterlist
*sg
;
89 for (array_size
= ses
->array_size
; array_size
< pagecount
;
92 dprintk(0, KERN_DEBUG
, "reallocating from %d to %d pages\n",
93 ses
->array_size
, array_size
);
94 pages
= krealloc(ses
->pages
, array_size
* sizeof(struct page
*),
99 sg
= krealloc(ses
->sg
, array_size
* sizeof(struct scatterlist
),
104 ses
->array_size
= array_size
;
109 void release_user_pages(struct csession
*ses
)
113 for (i
=0;i
<ses
->used_pages
;i
++) {
114 if (!PageReserved(ses
->pages
[i
]))
115 SetPageDirty(ses
->pages
[i
]);
117 if (ses
->readonly_pages
== 0)
118 flush_dcache_page(ses
->pages
[i
]);
120 ses
->readonly_pages
--;
122 page_cache_release(ses
->pages
[i
]);
127 /* make src and dst available in scatterlists.
128 * dst might be the same as src.
130 int get_userbuf(struct csession
*ses
,
131 void* __user src
, unsigned int src_len
,
132 void* __user dst
, unsigned int dst_len
,
133 struct task_struct
*task
, struct mm_struct
*mm
,
134 struct scatterlist
**src_sg
,
135 struct scatterlist
**dst_sg
)
137 int src_pagecount
, dst_pagecount
;
140 /* Empty input is a valid option to many algorithms & is tested by NIST/FIPS */
141 /* Make sure NULL input has 0 length */
145 /* I don't know that null output is ever useful, but we can handle it gracefully */
146 /* Make sure NULL output has 0 length */
150 if (ses
->alignmask
&& !IS_ALIGNED((unsigned long)src
, ses
->alignmask
)) {
151 dprintk(2, KERN_WARNING
, "careful - source address %lx is not %d byte aligned\n",
152 (unsigned long)src
, ses
->alignmask
+ 1);
155 if (ses
->alignmask
&& !IS_ALIGNED((unsigned long)dst
, ses
->alignmask
)) {
156 dprintk(2, KERN_WARNING
, "careful - destination address %lx is not %d byte aligned\n",
157 (unsigned long)dst
, ses
->alignmask
+ 1);
160 src_pagecount
= PAGECOUNT(src
, src_len
);
161 dst_pagecount
= PAGECOUNT(dst
, dst_len
);
163 ses
->used_pages
= (src
== dst
) ? max(src_pagecount
, dst_pagecount
)
164 : src_pagecount
+ dst_pagecount
;
166 ses
->readonly_pages
= (src
== dst
) ? 0 : src_pagecount
;
168 if (ses
->used_pages
> ses
->array_size
) {
169 rc
= adjust_sg_array(ses
, ses
->used_pages
);
174 if (src
== dst
) { /* inplace operation */
175 rc
= __get_userbuf(src
, src_len
, 1, ses
->used_pages
,
176 ses
->pages
, ses
->sg
, task
, mm
);
179 "failed to get user pages for data IO\n");
182 (*src_sg
) = (*dst_sg
) = ses
->sg
;
186 *src_sg
= NULL
; // default to no input
187 *dst_sg
= NULL
; // default to ignore output
190 rc
= __get_userbuf(src
, src_len
, 0, ses
->readonly_pages
,
191 ses
->pages
, ses
->sg
, task
, mm
);
194 "failed to get user pages for data input\n");
201 const unsigned int writable_pages
=
202 ses
->used_pages
- ses
->readonly_pages
;
203 struct page
**dst_pages
= ses
->pages
+ ses
->readonly_pages
;
204 *dst_sg
= ses
->sg
+ ses
->readonly_pages
;
206 rc
= __get_userbuf(dst
, dst_len
, 1, writable_pages
,
207 dst_pages
, *dst_sg
, task
, mm
);
210 "failed to get user pages for data output\n");
211 release_user_pages(ses
); /* FIXME: use __release_userbuf(src, ...) */