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