mirror of
https://github.com/torvalds/linux.git
synced 2025-04-09 14:45:27 +00:00

Add memcpy_sglist which copies one SG list to another. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
138 lines
3.1 KiB
C
138 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Cryptographic API.
|
|
*
|
|
* Cipher operations.
|
|
*
|
|
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
|
|
* 2002 Adam J. Richter <adam@yggdrasil.com>
|
|
* 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
|
|
*/
|
|
|
|
#include <crypto/scatterwalk.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/module.h>
|
|
#include <linux/scatterlist.h>
|
|
|
|
void scatterwalk_skip(struct scatter_walk *walk, unsigned int nbytes)
|
|
{
|
|
struct scatterlist *sg = walk->sg;
|
|
|
|
nbytes += walk->offset - sg->offset;
|
|
|
|
while (nbytes > sg->length) {
|
|
nbytes -= sg->length;
|
|
sg = sg_next(sg);
|
|
}
|
|
walk->sg = sg;
|
|
walk->offset = sg->offset + nbytes;
|
|
}
|
|
EXPORT_SYMBOL_GPL(scatterwalk_skip);
|
|
|
|
inline void memcpy_from_scatterwalk(void *buf, struct scatter_walk *walk,
|
|
unsigned int nbytes)
|
|
{
|
|
do {
|
|
unsigned int to_copy;
|
|
|
|
to_copy = scatterwalk_next(walk, nbytes);
|
|
memcpy(buf, walk->addr, to_copy);
|
|
scatterwalk_done_src(walk, to_copy);
|
|
buf += to_copy;
|
|
nbytes -= to_copy;
|
|
} while (nbytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(memcpy_from_scatterwalk);
|
|
|
|
inline void memcpy_to_scatterwalk(struct scatter_walk *walk, const void *buf,
|
|
unsigned int nbytes)
|
|
{
|
|
do {
|
|
unsigned int to_copy;
|
|
|
|
to_copy = scatterwalk_next(walk, nbytes);
|
|
memcpy(walk->addr, buf, to_copy);
|
|
scatterwalk_done_dst(walk, to_copy);
|
|
buf += to_copy;
|
|
nbytes -= to_copy;
|
|
} while (nbytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(memcpy_to_scatterwalk);
|
|
|
|
void memcpy_from_sglist(void *buf, struct scatterlist *sg,
|
|
unsigned int start, unsigned int nbytes)
|
|
{
|
|
struct scatter_walk walk;
|
|
|
|
if (unlikely(nbytes == 0)) /* in case sg == NULL */
|
|
return;
|
|
|
|
scatterwalk_start_at_pos(&walk, sg, start);
|
|
memcpy_from_scatterwalk(buf, &walk, nbytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(memcpy_from_sglist);
|
|
|
|
void memcpy_to_sglist(struct scatterlist *sg, unsigned int start,
|
|
const void *buf, unsigned int nbytes)
|
|
{
|
|
struct scatter_walk walk;
|
|
|
|
if (unlikely(nbytes == 0)) /* in case sg == NULL */
|
|
return;
|
|
|
|
scatterwalk_start_at_pos(&walk, sg, start);
|
|
memcpy_to_scatterwalk(&walk, buf, nbytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(memcpy_to_sglist);
|
|
|
|
void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
|
|
unsigned int nbytes)
|
|
{
|
|
struct scatter_walk swalk;
|
|
struct scatter_walk dwalk;
|
|
|
|
if (unlikely(nbytes == 0)) /* in case sg == NULL */
|
|
return;
|
|
|
|
scatterwalk_start(&swalk, src);
|
|
scatterwalk_start(&dwalk, dst);
|
|
|
|
do {
|
|
unsigned int slen, dlen;
|
|
unsigned int len;
|
|
|
|
slen = scatterwalk_next(&swalk, nbytes);
|
|
dlen = scatterwalk_next(&dwalk, nbytes);
|
|
len = min(slen, dlen);
|
|
memcpy(dwalk.addr, swalk.addr, len);
|
|
scatterwalk_done_dst(&dwalk, len);
|
|
scatterwalk_done_src(&swalk, len);
|
|
nbytes -= len;
|
|
} while (nbytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(memcpy_sglist);
|
|
|
|
struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
|
|
struct scatterlist *src,
|
|
unsigned int len)
|
|
{
|
|
for (;;) {
|
|
if (!len)
|
|
return src;
|
|
|
|
if (src->length > len)
|
|
break;
|
|
|
|
len -= src->length;
|
|
src = sg_next(src);
|
|
}
|
|
|
|
sg_init_table(dst, 2);
|
|
sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
|
|
scatterwalk_crypto_chain(dst, sg_next(src), 2);
|
|
|
|
return dst;
|
|
}
|
|
EXPORT_SYMBOL_GPL(scatterwalk_ffwd);
|