前面的一篇文章中簡單的描述了一下內存映射的內容,http://blog.csdn.net/codectq/article/details/25658813,這篇文章作爲用戶把內存規劃好之後,在用戶空間使用IOCTL對設備進行控制時的常用函數的代碼摘錄。後續我會把這部分完善起來。
#ifdefCONFIG_MMU
externunsigned long __must_check __copy_from_user(void *to, const void __user *from,unsigned long n);
externunsigned long __must_check __copy_to_user(void __user *to, const void *from,unsigned long n);
externunsigned long __must_check __copy_to_user_std(void __user *to, const void*from, unsigned long n);
externunsigned long __must_check __clear_user(void __user *addr, unsigned long n);
externunsigned long __must_check __clear_user_std(void __user *addr, unsigned longn);
#else
#define__copy_from_user(to,from,n)
(memcpy(to, (void __force *)from, n),0)
#define__copy_to_user(to,from,n)
(memcpy((void __force *)to, from, n),0)
#define__clear_user(addr,n)
(memset((void __force *)addr, 0, n), 0)
#endif
externunsigned long __must_check __strncpy_from_user(char *to, const char __user*from, unsigned long count);
externunsigned long __must_check __strnlen_user(const char __user *s, long n);
staticinline unsigned long __must_check copy_from_user(void *to, const void __user*from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n))
n = __copy_from_user(to, from, n);
else /* security hole - plug it */
memset(to, 0, n);
return n;
}
staticinline unsigned long __must_check copy_to_user(void __user *to, const void*from, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
return n;
}
在新的內核中,修改了這部分代碼。部分網上能夠查到的資料還一直以很老的內核版本在說明。實在受不了有些對新內核講解的文章不負責任的添加鏈接。
./arch/arm/lib/uaccess.S:288:/*Prototype: unsigned long __copy_from_user(void *to,const void *from,unsignedlong n);
./arch/arm/lib/uaccess.S:307:ENTRY(__copy_from_user)
./arch/arm/lib/uaccess.S:547:ENDPROC(__copy_from_user)
copy_to_user與mmap的工作原理
copy_to_user在每次拷貝時需要檢測指針的合法性,也就是用戶空間的指針所指向的地址的確是一段該進程本身的地址,而不是指向了不屬於它的地方,而且每次都會拷貝一次數據,頻繁訪問內存,由於虛擬地址連續,物理地址不一定會連續,從而造成CPU的CACHE頻繁失效,從而使速度降低
mmap僅在第一次使用時爲進程建立頁表,也就是將一段物理地址映射到一段虛擬地址上,以後操作時不再檢測其地址的合法性(合法性交由CPU頁保護異常來做),另一方面是內核下直接操作mmap地址,可以不用頻繁拷貝,也就是說在內核下直接可用指針向該地址操作,而不再在內核中專門開一個緩衝區,然後將緩衝區中的數據拷貝一次進來,mmap一般是將一段連續的物理地址映射成一段虛擬地址,當然,也可以將每段連續,但各段不連續的物理地址映射成一段連續的虛擬地址,無論如何,其物理地址在每段之中是連續的,這樣一來,就不會造成CPU的CACHE頻繁失效,從而大大節約時間。