diff options
Diffstat (limited to 'arch/x86/lib/usercopy.c')
| -rw-r--r-- | arch/x86/lib/usercopy.c | 43 | 
1 files changed, 43 insertions, 0 deletions
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c new file mode 100644 index 000000000000..97be9cb54483 --- /dev/null +++ b/arch/x86/lib/usercopy.c @@ -0,0 +1,43 @@ +/* + * User address space access functions. + * + *  For licencing details see kernel-base/COPYING + */ + +#include <linux/highmem.h> +#include <linux/module.h> + +/* + * best effort, GUP based copy_from_user() that is NMI-safe + */ +unsigned long +copy_from_user_nmi(void *to, const void __user *from, unsigned long n) +{ +	unsigned long offset, addr = (unsigned long)from; +	unsigned long size, len = 0; +	struct page *page; +	void *map; +	int ret; + +	do { +		ret = __get_user_pages_fast(addr, 1, 0, &page); +		if (!ret) +			break; + +		offset = addr & (PAGE_SIZE - 1); +		size = min(PAGE_SIZE - offset, n - len); + +		map = kmap_atomic(page); +		memcpy(to, map+offset, size); +		kunmap_atomic(map); +		put_page(page); + +		len  += size; +		to   += size; +		addr += size; + +	} while (len < n); + +	return len; +} +EXPORT_SYMBOL_GPL(copy_from_user_nmi);  |