Commit | Line | Data |
---|---|---|
1ac2e6ca RR |
1 | /* |
2 | * User address space access functions. | |
3 | * | |
4 | * For licencing details see kernel-base/COPYING | |
5 | */ | |
6 | ||
7 | #include <linux/highmem.h> | |
8 | #include <linux/module.h> | |
9 | ||
92ae03f2 | 10 | #include <asm/word-at-a-time.h> |
db0dc75d | 11 | #include <linux/sched.h> |
92ae03f2 | 12 | |
1ac2e6ca RR |
13 | /* |
14 | * best effort, GUP based copy_from_user() that is NMI-safe | |
15 | */ | |
16 | unsigned long | |
17 | copy_from_user_nmi(void *to, const void __user *from, unsigned long n) | |
18 | { | |
19 | unsigned long offset, addr = (unsigned long)from; | |
20 | unsigned long size, len = 0; | |
21 | struct page *page; | |
22 | void *map; | |
23 | int ret; | |
24 | ||
25f42985 | 25 | if (__range_not_ok(from, n, TASK_SIZE)) |
db0dc75d AS |
26 | return len; |
27 | ||
1ac2e6ca RR |
28 | do { |
29 | ret = __get_user_pages_fast(addr, 1, 0, &page); | |
30 | if (!ret) | |
31 | break; | |
32 | ||
33 | offset = addr & (PAGE_SIZE - 1); | |
34 | size = min(PAGE_SIZE - offset, n - len); | |
35 | ||
36 | map = kmap_atomic(page); | |
37 | memcpy(to, map+offset, size); | |
38 | kunmap_atomic(map); | |
39 | put_page(page); | |
40 | ||
41 | len += size; | |
42 | to += size; | |
43 | addr += size; | |
44 | ||
45 | } while (len < n); | |
46 | ||
47 | return len; | |
48 | } | |
49 | EXPORT_SYMBOL_GPL(copy_from_user_nmi); |