| /* | |
| * 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); |