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