1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* |
3 | * Cryptographic scatter and gather helpers. |
4 | * |
5 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> |
6 | * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com> |
7 | * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com> |
8 | * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> |
9 | */ |
10 | |
11 | #ifndef _CRYPTO_SCATTERWALK_H |
12 | #define _CRYPTO_SCATTERWALK_H |
13 | |
14 | #include <crypto/algapi.h> |
15 | |
16 | #include <linux/highmem.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/scatterlist.h> |
19 | |
20 | static inline void scatterwalk_crypto_chain(struct scatterlist *head, |
21 | struct scatterlist *sg, int num) |
22 | { |
23 | if (sg) |
24 | sg_chain(prv: head, prv_nents: num, sgl: sg); |
25 | else |
26 | sg_mark_end(sg: head); |
27 | } |
28 | |
29 | static inline unsigned int scatterwalk_pagelen(struct scatter_walk *walk) |
30 | { |
31 | unsigned int len = walk->sg->offset + walk->sg->length - walk->offset; |
32 | unsigned int len_this_page = offset_in_page(~walk->offset) + 1; |
33 | return len_this_page > len ? len : len_this_page; |
34 | } |
35 | |
36 | static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk, |
37 | unsigned int nbytes) |
38 | { |
39 | unsigned int len_this_page = scatterwalk_pagelen(walk); |
40 | return nbytes > len_this_page ? len_this_page : nbytes; |
41 | } |
42 | |
43 | static inline void scatterwalk_advance(struct scatter_walk *walk, |
44 | unsigned int nbytes) |
45 | { |
46 | walk->offset += nbytes; |
47 | } |
48 | |
49 | static inline struct page *scatterwalk_page(struct scatter_walk *walk) |
50 | { |
51 | return sg_page(sg: walk->sg) + (walk->offset >> PAGE_SHIFT); |
52 | } |
53 | |
54 | static inline void scatterwalk_unmap(void *vaddr) |
55 | { |
56 | kunmap_local(vaddr); |
57 | } |
58 | |
59 | static inline void scatterwalk_start(struct scatter_walk *walk, |
60 | struct scatterlist *sg) |
61 | { |
62 | walk->sg = sg; |
63 | walk->offset = sg->offset; |
64 | } |
65 | |
66 | static inline void *scatterwalk_map(struct scatter_walk *walk) |
67 | { |
68 | return kmap_local_page(page: scatterwalk_page(walk)) + |
69 | offset_in_page(walk->offset); |
70 | } |
71 | |
72 | static inline void scatterwalk_pagedone(struct scatter_walk *walk, int out, |
73 | unsigned int more) |
74 | { |
75 | if (out) { |
76 | struct page *page; |
77 | |
78 | page = sg_page(sg: walk->sg) + ((walk->offset - 1) >> PAGE_SHIFT); |
79 | flush_dcache_page(page); |
80 | } |
81 | |
82 | if (more && walk->offset >= walk->sg->offset + walk->sg->length) |
83 | scatterwalk_start(walk, sg: sg_next(walk->sg)); |
84 | } |
85 | |
86 | static inline void scatterwalk_done(struct scatter_walk *walk, int out, |
87 | int more) |
88 | { |
89 | if (!more || walk->offset >= walk->sg->offset + walk->sg->length || |
90 | !(walk->offset & (PAGE_SIZE - 1))) |
91 | scatterwalk_pagedone(walk, out, more); |
92 | } |
93 | |
94 | void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, |
95 | size_t nbytes, int out); |
96 | |
97 | void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, |
98 | unsigned int start, unsigned int nbytes, int out); |
99 | |
100 | struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], |
101 | struct scatterlist *src, |
102 | unsigned int len); |
103 | |
104 | #endif /* _CRYPTO_SCATTERWALK_H */ |
105 | |