44 lines
		
	
	
	
		
			815 B
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			44 lines
		
	
	
	
		
			815 B
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * 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); |