在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > linux內(nèi)核中的get_user和put_user

            linux內(nèi)核中的get_user和put_user

            作者: 時間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
            內(nèi)核版本:2.6.14

            CPU平臺:arm

            本文引用地址:http://www.biyoush.com/article/201611/319994.htm

            在內(nèi)核空間和用戶空間交換數(shù)據(jù)時,get_userput_user是兩個兩用的函數(shù)。相對于copy_to_user和copy_from_user(將在另一篇博客中分析),這兩個函數(shù)主要用于完成一些簡單類型變量(char、int、long等)的拷貝任務(wù),對于一些復(fù)合類型的變量,比如數(shù)據(jù)結(jié)構(gòu)或者數(shù)組類型,get_user和put_user函數(shù)還是無法勝任,這兩個函數(shù)內(nèi)部將對指針指向的對象長度進(jìn)行檢查,在arm平臺上只支持長度為1,2,4,8的變量。下面我具體分析,首先看get_user的定義(linux/include/asm-arm/uaccess.h):

            [plain]view plaincopy
            print?
            1. externint__get_user_1(void*);
            2. externint__get_user_2(void*);
            3. externint__get_user_4(void*);
            4. externint__get_user_8(void*);
            5. externint__get_user_bad(void);
            6. #define__get_user_x(__r2,__p,__e,__s,__i...)
            7. __asm____volatile__(
            8. __asmeq("%0","r0")__asmeq("%1","r2")//進(jìn)行判斷(#define__asmeq(x,y)".ifnc"x","y";.err;.endifnt")
            9. "bl__get_user_"#__s//根據(jù)參數(shù)調(diào)用不同的函數(shù),此時r0=指向用戶空間的指針,r2=內(nèi)核空間的變量
            10. :"=&r"(__e),"=r"(__r2)
            11. :"0"(__p)
            12. :__i,"cc")
            13. #defineget_user(x,p)
            14. ({
            15. constregistertypeof(*(p))__user*__pasm("r0")=(p);//__p的數(shù)據(jù)類型和*(p)的指針數(shù)據(jù)類型是一樣的,__p=p,且存放在r0寄存器中
            16. registertypeof(*(p))__r2asm("r2");//__r2的數(shù)據(jù)類型和*(p)的數(shù)據(jù)類型是一樣的,且存放在r2寄存器中
            17. registerint__easm("r0");//定義__e,存放在寄存器r0,作為返回值
            18. switch(sizeof(*(__p))){//對__p所指向的對象長度進(jìn)行檢查,并根據(jù)長度調(diào)用響應(yīng)的函數(shù)
            19. case1:
            20. __get_user_x(__r2,__p,__e,1,"lr");
            21. break;
            22. case2:
            23. __get_user_x(__r2,__p,__e,2,"r3","lr");
            24. break;
            25. case4:
            26. __get_user_x(__r2,__p,__e,4,"lr");
            27. break;
            28. case8:
            29. __get_user_x(__r2,__p,__e,8,"lr");
            30. break;
            31. default:__e=__get_user_bad();break;//默認(rèn)處理
            32. }
            33. x=__r2;
            34. __e;
            35. })

            上面的源碼涉及到gcc的內(nèi)聯(lián)匯編,不太了解的朋友可以參考前面的博客(http://blog.csdn.net/ce123/article/details/8209702)。繼續(xù),跟蹤__get_user_1等函數(shù)的執(zhí)行,它們的定義如下(linux/arch/arm/lib/getuser.S)。

            [plain]view plaincopy
            print?
            1. .global__get_user_1
            2. __get_user_1:
            3. 1:ldrbtr2,[r0]
            4. movr0,#0
            5. movpc,lr
            6. .global__get_user_2
            7. __get_user_2:
            8. 2:ldrbtr2,[r0],#1
            9. 3:ldrbtr3,[r0]
            10. #ifndef__ARMEB__
            11. orrr2,r2,r3,lsl#8
            12. #else
            13. orrr2,r3,r2,lsl#8
            14. #endif
            15. movr0,#0
            16. movpc,lr
            17. .global__get_user_4
            18. __get_user_4:
            19. 4:ldrtr2,[r0]
            20. movr0,#0
            21. movpc,lr
            22. .global__get_user_8
            23. __get_user_8:
            24. 5:ldrtr2,[r0],#4
            25. 6:ldrtr3,[r0]
            26. movr0,#0
            27. movpc,lr
            28. __get_user_bad_8:
            29. movr3,#0
            30. __get_user_bad:
            31. movr2,#0
            32. movr0,#-EFAULT
            33. movpc,lr
            34. .section__ex_table,"a"
            35. .long1b,__get_user_bad
            36. .long2b,__get_user_bad
            37. .long3b,__get_user_bad
            38. .long4b,__get_user_bad
            39. .long5b,__get_user_bad_8
            40. .long6b,__get_user_bad_8
            41. .previous

            這段代碼都是單條匯編指令實現(xiàn)的內(nèi)存操作,就不進(jìn)行詳細(xì)注解了。如果定義__ARMEB__宏,則是支持EABI的大端格式代碼(http://blog.csdn.net/ce123/article/details/8457491),關(guān)于大端模式和小端模式的詳細(xì)介紹,可以參考http://blog.csdn.net/ce123/article/details/6971544。這段代碼在.section __ex_table, "a"之前都是常規(guī)的內(nèi)存拷貝操縱,特殊的地方在于后面定義“__ex_table”section 。

            標(biāo)號1,2,...,6處是內(nèi)存訪問指令,如果mov的源地址位于一個尚未被提交物理頁面的空間中,將產(chǎn)生缺頁異常,內(nèi)核會調(diào)用do_page_fault函數(shù)處理這個異常,因為異常發(fā)生在內(nèi)核空間,do_page_fault將調(diào)用search_exception_tables在“__ex_table”中查找異常指令的修復(fù)指令,在上面這段帶面的最后,“__ex_table”section 中定義了如下數(shù)據(jù):

            [plain]view plaincopy
            print?
            1. .section__ex_table,"a"
            2. .long1b,__get_user_bad//其中1b對應(yīng)標(biāo)號1處的指令,__get_user_bad是1處指令的修復(fù)指令。
            3. .long2b,__get_user_bad
            4. .long3b,__get_user_bad
            5. .long4b,__get_user_bad
            6. .long5b,__get_user_bad_8
            7. .long6b,__get_user_bad_8
            當(dāng)標(biāo)號1處發(fā)生缺頁異常時,系統(tǒng)將調(diào)用do_page_fault提交物理頁面,然后跳到__get_user_bad繼續(xù)執(zhí)行。get_user函數(shù)如果成果執(zhí)行則返回1,否則返回-EFAULT。

            put_user用于將內(nèi)核空間的一個簡單類型變量x拷貝到p所指向的用戶空間。該函數(shù)可以自動判斷變量的類型,如果執(zhí)行成功則返回0,否則返回-EFAULT。下面給出它們的定義(linux/include/asm-arm/uaccess.h)。

            [plain]view plaincopy
            print?
            1. externint__put_user_1(void*,unsignedint);
            2. externint__put_user_2(void*,unsignedint);
            3. externint__put_user_4(void*,unsignedint);
            4. externint__put_user_8(void*,unsignedlonglong);
            5. externint__put_user_bad(void);
            6. #define__put_user_x(__r2,__p,__e,__s)
            7. __asm____volatile__(
            8. __asmeq("%0","r0")__asmeq("%2","r2")
            9. "bl__put_user_"#__s
            10. :"=&r"(__e)
            11. :"0"(__p),"r"(__r2)
            12. :"ip","lr","cc")
            13. #defineput_user(x,p)
            14. ({
            15. constregistertypeof(*(p))__r2asm("r2")=(x);
            16. constregistertypeof(*(p))__user*__pasm("r0")=(p);
            17. registerint__easm("r0");
            18. switch(sizeof(*(__p))){
            19. case1:
            20. __put_user_x(__r2,__p,__e,1);
            21. break;
            22. case2:
            23. __put_user_x(__r2,__p,__e,2);
            24. break;
            25. case4:
            26. __put_user_x(__r2,__p,__e,4);
            27. break;
            28. case8:
            29. __put_user_x(__r2,__p,__e,8);
            30. break;
            31. default:__e=__put_user_bad();break;
            32. }
            33. __e;
            34. })
            __put_user_1等函數(shù)的的定義如下(linux/arch/arm/lib/putuser.S)。

            [plain]view plaincopy
            print?
            1. .global__put_user_1
            2. __put_user_1:
            3. 1:strbtr2,[r0]
            4. movr0,#0
            5. movpc,lr
            6. .global__put_user_2
            7. __put_user_2:
            8. movip,r2,lsr#8
            9. #ifndef__ARMEB__
            10. 2:strbtr2,[r0],#1
            11. 3:strbtip,[r0]
            12. #else
            13. 2:strbtip,[r0],#1
            14. 3:strbtr2,[r0]
            15. #endif
            16. movr0,#0
            17. movpc,lr
            18. .global__put_user_4
            19. __put_user_4:
            20. 4:strtr2,[r0]
            21. movr0,#0
            22. movpc,lr
            23. .global__put_user_8
            24. __put_user_8:
            25. 5:strtr2,[r0],#4
            26. 6:strtr3,[r0]
            27. movr0,#0
            28. movpc,lr
            29. __put_user_bad:
            30. movr0,#-EFAULT
            31. movpc,lr
            32. .section__ex_table,"a"
            33. .long1b,__put_user_bad
            34. .long2b,__put_user_bad
            35. .long3b,__put_user_bad
            36. .long4b,__put_user_bad
            37. .long5b,__put_user_bad
            38. .long6b,__put_user_bad
            39. .previous
            put_user函數(shù)就不具體分析了。get_user和put_user僅能完成一些簡單類型變量的拷貝任務(wù),后面我們將分析copy_to_user和copy_from_user。


            評論


            技術(shù)專區(qū)

            關(guān)閉