mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
![Herbert Xu](/assets/img/avatar_default.png)
This patch prepares the scatterwalk code for use by the new block cipher type. Firstly it halves the size of scatter_walk on 32-bit platforms. This is important as we allocate at least two of these objects on the stack for each block cipher operation. It also exports the symbols since the block cipher code can be built as a module. Finally there is a hack in scatterwalk_unmap that relies on progress being made. Unfortunately, for hardware crypto we can't guarantee progress to be made since the hardware can fail. So this also gets rid of the hack by not advancing the address returned by scatterwalk_map. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
105 lines
2.4 KiB
C
105 lines
2.4 KiB
C
/*
|
|
* 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>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/module.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/scatterlist.h>
|
|
|
|
#include "internal.h"
|
|
#include "scatterwalk.h"
|
|
|
|
enum km_type crypto_km_types[] = {
|
|
KM_USER0,
|
|
KM_USER1,
|
|
KM_SOFTIRQ0,
|
|
KM_SOFTIRQ1,
|
|
};
|
|
EXPORT_SYMBOL_GPL(crypto_km_types);
|
|
|
|
static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
|
|
{
|
|
void *src = out ? buf : sgdata;
|
|
void *dst = out ? sgdata : buf;
|
|
|
|
memcpy(dst, src, nbytes);
|
|
}
|
|
|
|
void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
|
|
{
|
|
walk->sg = sg;
|
|
|
|
BUG_ON(!sg->length);
|
|
|
|
walk->offset = sg->offset;
|
|
}
|
|
EXPORT_SYMBOL_GPL(scatterwalk_start);
|
|
|
|
void *scatterwalk_map(struct scatter_walk *walk, int out)
|
|
{
|
|
return crypto_kmap(scatterwalk_page(walk), out) +
|
|
offset_in_page(walk->offset);
|
|
}
|
|
EXPORT_SYMBOL_GPL(scatterwalk_map);
|
|
|
|
static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
|
|
unsigned int more)
|
|
{
|
|
if (out)
|
|
flush_dcache_page(scatterwalk_page(walk));
|
|
|
|
if (more) {
|
|
walk->offset += PAGE_SIZE - 1;
|
|
walk->offset &= PAGE_MASK;
|
|
if (walk->offset >= walk->sg->offset + walk->sg->length)
|
|
scatterwalk_start(walk, sg_next(walk->sg));
|
|
}
|
|
}
|
|
|
|
void scatterwalk_done(struct scatter_walk *walk, int out, int more)
|
|
{
|
|
if (!offset_in_page(walk->offset) || !more)
|
|
scatterwalk_pagedone(walk, out, more);
|
|
}
|
|
EXPORT_SYMBOL_GPL(scatterwalk_done);
|
|
|
|
void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
|
|
size_t nbytes, int out)
|
|
{
|
|
for (;;) {
|
|
unsigned int len_this_page = scatterwalk_pagelen(walk);
|
|
u8 *vaddr;
|
|
|
|
if (len_this_page > nbytes)
|
|
len_this_page = nbytes;
|
|
|
|
vaddr = scatterwalk_map(walk, out);
|
|
memcpy_dir(buf, vaddr, len_this_page, out);
|
|
scatterwalk_unmap(vaddr, out);
|
|
|
|
if (nbytes == len_this_page)
|
|
break;
|
|
|
|
buf += len_this_page;
|
|
nbytes -= len_this_page;
|
|
|
|
scatterwalk_pagedone(walk, out, 1);
|
|
}
|
|
|
|
scatterwalk_advance(walk, nbytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(scatterwalk_copychunks);
|