scatterwalk.c (2065B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Cryptographic API. 4 * 5 * Cipher operations. 6 * 7 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 8 * 2002 Adam J. Richter <adam@yggdrasil.com> 9 * 2004 Jean-Luc Cooke <jlcooke@certainkey.com> 10 */ 11 12#include <crypto/scatterwalk.h> 13#include <linux/kernel.h> 14#include <linux/mm.h> 15#include <linux/module.h> 16#include <linux/scatterlist.h> 17 18static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) 19{ 20 void *src = out ? buf : sgdata; 21 void *dst = out ? sgdata : buf; 22 23 memcpy(dst, src, nbytes); 24} 25 26void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, 27 size_t nbytes, int out) 28{ 29 for (;;) { 30 unsigned int len_this_page = scatterwalk_pagelen(walk); 31 u8 *vaddr; 32 33 if (len_this_page > nbytes) 34 len_this_page = nbytes; 35 36 if (out != 2) { 37 vaddr = scatterwalk_map(walk); 38 memcpy_dir(buf, vaddr, len_this_page, out); 39 scatterwalk_unmap(vaddr); 40 } 41 42 scatterwalk_advance(walk, len_this_page); 43 44 if (nbytes == len_this_page) 45 break; 46 47 buf += len_this_page; 48 nbytes -= len_this_page; 49 50 scatterwalk_pagedone(walk, out & 1, 1); 51 } 52} 53EXPORT_SYMBOL_GPL(scatterwalk_copychunks); 54 55void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, 56 unsigned int start, unsigned int nbytes, int out) 57{ 58 struct scatter_walk walk; 59 struct scatterlist tmp[2]; 60 61 if (!nbytes) 62 return; 63 64 sg = scatterwalk_ffwd(tmp, sg, start); 65 66 scatterwalk_start(&walk, sg); 67 scatterwalk_copychunks(buf, &walk, nbytes, out); 68 scatterwalk_done(&walk, out, 0); 69} 70EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); 71 72struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], 73 struct scatterlist *src, 74 unsigned int len) 75{ 76 for (;;) { 77 if (!len) 78 return src; 79 80 if (src->length > len) 81 break; 82 83 len -= src->length; 84 src = sg_next(src); 85 } 86 87 sg_init_table(dst, 2); 88 sg_set_page(dst, sg_page(src), src->length - len, src->offset + len); 89 scatterwalk_crypto_chain(dst, sg_next(src), 2); 90 91 return dst; 92} 93EXPORT_SYMBOL_GPL(scatterwalk_ffwd);