亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
12下一頁(yè)
最近訪問(wèn)板塊 發(fā)新帖
查看: 24964 | 回復(fù): 17
打印 上一主題 下一主題

do_page_fault函數(shù)處理流程 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2011-05-28 00:58 |只看該作者 |倒序?yàn)g覽
本帖最后由 cluter 于 2011-05-28 01:01 編輯

只解釋下關(guān)鍵代碼的流程,附件里是關(guān)于缺頁(yè)處理思路更清晰的一個(gè)整理,無(wú)代碼的。
  1. //*********************************缺頁(yè)異常處理函數(shù)*******************************************
  2. do_page_fault(struct pt_regs *regs, unsigned long error_code)
  3. {

  4.        
  5.         //獲取當(dāng)前cpu正在運(yùn)行的進(jìn)程的進(jìn)程描述符
  6.         //然后獲取該進(jìn)程的內(nèi)存描述符
  7.         tsk = current;
  8.         mm = tsk->mm;

  9.         /* Get the faulting address: */
  10.         //獲取出錯(cuò)的地址
  11.         address = read_cr2();


  12.         /*
  13.          * We fault-in kernel-space virtual memory on-demand. The
  14.          * 'reference' page table is init_mm.pgd.
  15.          *
  16.          * NOTE! We MUST NOT take any locks for this case. We may
  17.          * be in an interrupt or a critical region, and should
  18.          * only copy the information from the master page table,
  19.          * nothing more.
  20.          *
  21.          * This verifies that the fault happens in kernel space
  22.          * (error_code & 4) == 0, and that the fault was not a
  23.          * protection error (error_code & 9) == 0.
  24.          */
  25.          //頁(yè)訪問(wèn)出錯(cuò)地址address在內(nèi)核空間
  26.         if (unlikely(fault_in_kernel_space(address))) {
  27.                 //檢查標(biāo)志位確定訪問(wèn)發(fā)生在"內(nèi)核態(tài)"
  28.                 if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) {
  29.                         //如果是內(nèi)核空間"非連續(xù)內(nèi)存"的訪問(wèn),
  30.                         //則直接拷貝"內(nèi)核頁(yè)表項(xiàng)"到"用戶頁(yè)表項(xiàng)"
  31.                         //如果"內(nèi)核頁(yè)表項(xiàng)"為null,說(shuō)明內(nèi)核有BUG,返回-1
  32.                         if (vmalloc_fault(address) >= 0)
  33.                                 return;
  34.                 }

  35.                 //如果在"用戶態(tài)"則直接進(jìn)入"非法訪問(wèn)"處理函數(shù)
  36.                 //如果vmalloc_fault返回-1,則表示內(nèi)核BUG
  37.                 bad_area_nosemaphore(regs, error_code, address);
  38.                 //錯(cuò)誤處理函數(shù)
  39.                 // 1 "用戶態(tài)"錯(cuò)誤-->直接終止進(jìn)程
  40.                 // 2 "內(nèi)核態(tài)"錯(cuò)誤
  41.                 //                       系統(tǒng)調(diào)用參數(shù)錯(cuò)誤 ---->終止進(jìn)程/返回系統(tǒng)調(diào)用錯(cuò)誤碼
  42.                 //                       內(nèi)核BUG                            ---->內(nèi)核panic
  43.                 return;
  44.         }


  45.         /*
  46.          * If we're in an interrupt, have no user context or are running
  47.          * in an atomic region then we must not take the fault:
  48.          */
  49.          // 1 在中斷中,此時(shí)沒(méi)有進(jìn)程上下文
  50.          // 2 在原子操作流程中
  51.          // 都不允許處理缺頁(yè)異常
  52.         if (unlikely(in_atomic() || !mm)) {
  53.                 bad_area_nosemaphore(regs, error_code, address);
  54.                 return;
  55.         }

  56.         /*
  57.          * When running in the kernel we expect faults to occur only to
  58.          * addresses in user space.  All other faults represent errors in
  59.          * the kernel and should generate an OOPS.  Unfortunately, in the
  60.          * case of an erroneous fault occurring in a code path which already
  61.          * holds mmap_sem we will deadlock attempting to validate the fault
  62.          * against the address space.  Luckily the kernel only validly
  63.          * references user space from well defined areas of code, which are
  64.          * listed in the exceptions table.
  65.          *
  66.          * As the vast majority of faults will be valid we will only perform
  67.          * the source reference check when there is a possibility of a
  68.          * deadlock. Attempt to lock the address space, if we cannot we then
  69.          * validate the source. If this is invalid we can skip the address
  70.          * space check, thus avoiding the deadlock:
  71.          */
  72.          //此時(shí)可以確定缺頁(yè)地址address在"用戶空間"了
  73.         if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
  74.                 //錯(cuò)誤發(fā)生在"內(nèi)核態(tài)",查看異常表
  75.                 //如果在內(nèi)核態(tài)引起缺頁(yè),則引起缺頁(yè)的"指令地址"一定在"異常表"中
  76.                 //如果"異常表"中返回指令地址,則說(shuō)明可能是"請(qǐng)求調(diào)頁(yè)",也可能是"非法訪問(wèn)"
  77.                 //如果"異常表"中無(wú)地址,則肯定是內(nèi)核錯(cuò)誤
  78.                 if ((error_code & PF_USER) == 0 &&
  79.                     !search_exception_tables(regs->ip)) {
  80.                        //內(nèi)核panic
  81.                         bad_area_nosemaphore(regs, error_code, address);
  82.                         return;
  83.                 }
  84.                 down_read(&mm->mmap_sem);
  85.         } else {
  86.                 /*
  87.                  * The above down_read_trylock() might have succeeded in
  88.                  * which case we'll have missed the might_sleep() from
  89.                  * down_read():
  90.                  */
  91.                 might_sleep();
  92.         }
  93.         //尋找address所在的vma
  94.         vma = find_vma(mm, address);
  95.         //如果address之后無(wú)vma,則肯定是非法訪問(wèn)
  96.         if (unlikely(!vma)) {
  97.                 bad_area(regs, error_code, address);
  98.                 return;
  99.         }
  100.         // 1 如果vma->start_address<=address,則直接跳到 "合法訪問(wèn)"階段
  101.         // 2 如果vma->start_address>address,則也有可能是用戶的"入棧行為"導(dǎo)致缺頁(yè)
  102.         if (likely(vma->vm_start <= address))
  103.                 goto good_area;
  104.         // "入棧"操作,則該vma的標(biāo)志為 "向下增長(zhǎng)"
  105.         if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
  106.                 bad_area(regs, error_code, address);
  107.                 return;
  108.         }
  109.         // 確定缺頁(yè)發(fā)生在"用戶態(tài)"
  110.         if (error_code & PF_USER) {
  111.                 /*
  112.                  * Accessing the stack below %sp is always a bug.
  113.                  * The large cushion allows instructions like enter
  114.                  * and pusha to work. ("enter $65535, $31" pushes
  115.                  * 32 pointers and then decrements %sp by 65535.)
  116.                  */
  117.                  //驗(yàn)證缺頁(yè)address和棧頂sp的關(guān)系
  118.                 if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
  119.                         bad_area(regs, error_code, address);
  120.                         return;
  121.                 }
  122.         }
  123.         //擴(kuò)展棧
  124.         if (unlikely(expand_stack(vma, address))) {
  125.                 bad_area(regs, error_code, address);
  126.                 return;
  127.         }

  128.         /*
  129.          * Ok, we have a good vm_area for this memory access, so
  130.          * we can handle it..
  131.          */
  132. good_area:
  133.         write = error_code & PF_WRITE;
  134.         // 再次驗(yàn)證"權(quán)限"
  135.         if (unlikely(access_error(error_code, write, vma))) {
  136.                 bad_area_access_error(regs, error_code, address);
  137.                 return;
  138.         }

  139.         /*
  140.          * If for any reason at all we couldn't handle the fault,
  141.          * make sure we exit gracefully rather than endlessly redo
  142.          * the fault:
  143.          */
  144.          //分配新"頁(yè)框"
  145.         fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);

  146.         up_read(&mm->mmap_sem);
  147. }


  148. //*******************************訪問(wèn)權(quán)限驗(yàn)證函數(shù)********************************************
  149. access_error(unsigned long error_code, int write, struct vm_area_struct *vma)
  150. {       
  151.         //如果是"寫操作"引起的缺頁(yè),則該vma必須可寫
  152.         if (write) {
  153.                 /* write, present and write, not present: */
  154.                 if (unlikely(!(vma->vm_flags & VM_WRITE)))
  155.                         return 1;
  156.                 return 0;
  157.         }

  158.         /* read, present: */
  159.         //檢查該頁(yè)是否已經(jīng)在RAM中,如果"特權(quán)位"置位表示頁(yè)框在RAM中
  160.         //表示進(jìn)程訪問(wèn)"有特權(quán)" 頁(yè)框
  161.         if (unlikely(error_code & PF_PROT))
  162.                 return 1;

  163.         /* read, not present: */
  164.         //如果該頁(yè)不在內(nèi)存中,該線性區(qū)必須可"讀"
  165.         if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))))
  166.                 return 1;

  167.         return 0;
  168. }
復(fù)制代碼


順便提出幾個(gè)問(wèn)題:
                                在"內(nèi)核態(tài)"訪問(wèn)非連續(xù)內(nèi)存時(shí),為何要拷貝“內(nèi)核頁(yè)表項(xiàng)”到用“戶頁(yè)表項(xiàng)”,為何不直接使用“內(nèi)核頁(yè)表”?
                                對(duì)于一個(gè)4G的機(jī)器,用戶進(jìn)程的頁(yè)框大部分分布在物理內(nèi)存的哪個(gè)范圍?
                                為什么當(dāng)物理內(nèi)存大于1G的時(shí)候,就開始劃分出”高端內(nèi)存“?
                                64bit的機(jī)器上不需要”高端內(nèi)存“,這是為什么?

論壇徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16賽季CBA聯(lián)賽之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金雞報(bào)曉
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年紀(jì)念徽章
日期:2016-11-09 13:19:1015-16賽季CBA聯(lián)賽之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-12-03 06:20:002015七夕節(jié)徽章
日期:2015-08-21 11:06:17IT運(yùn)維版塊每日發(fā)帖之星
日期:2015-08-09 06:20:002015亞冠之吉達(dá)阿赫利
日期:2015-07-03 08:39:42
2 [報(bào)告]
發(fā)表于 2011-05-28 07:24 |只看該作者
高端內(nèi)存的作用是訪問(wèn)內(nèi)核空間1g不能直接尋址之外的內(nèi)存
折衷的辦法就是
把1G劃為直接映射的一部分和高端內(nèi)存

64位機(jī)的內(nèi)核空間能夠足夠大到尋址所有內(nèi)存(虛擬地址空間不止4G)、

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2011-05-28 07:54 |只看該作者
回復(fù) 2# amarant


    LS起這么早。。。關(guān)于為何使用高端內(nèi)存,閣下理解的很透徹。。,第一個(gè)問(wèn)題LS怎么看?

論壇徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16賽季CBA聯(lián)賽之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金雞報(bào)曉
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年紀(jì)念徽章
日期:2016-11-09 13:19:1015-16賽季CBA聯(lián)賽之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-12-03 06:20:002015七夕節(jié)徽章
日期:2015-08-21 11:06:17IT運(yùn)維版塊每日發(fā)帖之星
日期:2015-08-09 06:20:002015亞冠之吉達(dá)阿赫利
日期:2015-07-03 08:39:42
4 [報(bào)告]
發(fā)表于 2011-05-28 09:27 |只看該作者
回復(fù) 3# cluter


    這個(gè)問(wèn)題我說(shuō)不準(zhǔn),就不敢胡說(shuō)了。。

論壇徽章:
2
CU十二周年紀(jì)念徽章
日期:2013-10-24 15:41:34處女座
日期:2013-12-27 22:22:41
5 [報(bào)告]
發(fā)表于 2011-05-28 12:51 |只看該作者
第一個(gè)問(wèn)題我還真沒(méi)看懂是什么意思

第二個(gè)問(wèn)題,我沒(méi)有仔細(xì)研究過(guò)代碼,這應(yīng)該取決于內(nèi)核向Buddy System索要內(nèi)存時(shí)傳入的flag參數(shù)。新版的代碼已經(jīng)改的亂七八糟了,我在ULK上看過(guò)的代碼片斷里參數(shù)好像包括了GFP_HIGHUSER,也就是說(shuō),優(yōu)先在大于896M的物理內(nèi)存里拿。

第三第四個(gè)問(wèn)題,內(nèi)核使用高端內(nèi)存是因?yàn)閮?nèi)核擁有的虛擬地址大于物理內(nèi)存。訪問(wèn)物理內(nèi)存必需先將其映射于某一塊虛擬地址段之上,而大多體系結(jié)構(gòu)中,內(nèi)核是與進(jìn)程共用地址空間的。Linux下內(nèi)核一般只占頂1G,資源有些緊張,能映射到的物理也就緊張。因此在其1G的虛擬地址空間之中,開辟一個(gè)小窗口動(dòng)態(tài)映射“夠不著”的那些物理內(nèi)存。所以說(shuō),高端內(nèi)存的出現(xiàn)是因?yàn)椤皟?nèi)核虛擬地址空間 <  物理內(nèi)存大小”。

如果“內(nèi)核虛擬地址空間 >  物理內(nèi)存大小”,就不會(huì)出現(xiàn)高端內(nèi)存了。這時(shí)還可以分為兩種情況,一為“內(nèi)核虛擬地址空間太大”,比如64位操作系統(tǒng);一為“物理內(nèi)存太小”,比如32位操作系統(tǒng)時(shí)物理內(nèi)存小于896M。

論壇徽章:
0
6 [報(bào)告]
發(fā)表于 2011-05-28 14:44 |只看該作者
回復(fù) 5# tempname2


    呵呵,ls 2 3 問(wèn)題都理解的很深刻。給進(jìn)程分配的頁(yè)框和進(jìn)程的頁(yè)表都優(yōu)先在高端內(nèi)存索。!

   第一個(gè)問(wèn)題其實(shí)就是:當(dāng)進(jìn)程系統(tǒng)調(diào)用進(jìn)入內(nèi)核態(tài),為何不使用內(nèi)核頁(yè)表,而是把內(nèi)核頁(yè)表項(xiàng)拷貝到進(jìn)程頁(yè)表,然后繼續(xù)訪問(wèn)。

論壇徽章:
0
7 [報(bào)告]
發(fā)表于 2011-05-29 21:27 |只看該作者
回復(fù) 4# amarant


    其實(shí),只需要逆向思考下就可以了,如果切換頁(yè)表,系統(tǒng)必須做其他什么事情?

論壇徽章:
0
8 [報(bào)告]
發(fā)表于 2011-05-29 22:29 |只看該作者
對(duì)第一個(gè)問(wèn)題我的理解是:
每個(gè)進(jìn)程都有一個(gè)頁(yè)表,頁(yè)表既有內(nèi)核地址空間的,也有用戶地址空間的。
但是,有些內(nèi)核空間的只在 init_mm的頁(yè)表中有,而當(dāng)前進(jìn)程沒(méi)有,當(dāng)訪問(wèn)這些地址的時(shí)候,就出現(xiàn)頁(yè)中斷,
這里把 init_mm的頁(yè)表中的相關(guān)項(xiàng)拷貝到當(dāng)前進(jìn)程的頁(yè)表中。這樣再訪問(wèn)的時(shí)候,就不會(huì)頁(yè)中斷了。

論壇徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16賽季CBA聯(lián)賽之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金雞報(bào)曉
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年紀(jì)念徽章
日期:2016-11-09 13:19:1015-16賽季CBA聯(lián)賽之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-12-03 06:20:002015七夕節(jié)徽章
日期:2015-08-21 11:06:17IT運(yùn)維版塊每日發(fā)帖之星
日期:2015-08-09 06:20:002015亞冠之吉達(dá)阿赫利
日期:2015-07-03 08:39:42
9 [報(bào)告]
發(fā)表于 2011-05-30 10:53 |只看該作者
我不了解X86頁(yè)表在內(nèi)存中的儲(chǔ)存結(jié)構(gòu),如果X86中的頁(yè)全局表項(xiàng)必須是以數(shù)組的方式順序存儲(chǔ)。那么就很好理解為什么要多此一舉復(fù)制內(nèi)核頁(yè)表過(guò)來(lái)了。

論壇徽章:
0
10 [報(bào)告]
發(fā)表于 2011-05-30 13:52 |只看該作者
看代碼是從init_mm.pgd上拷貝過(guò)去的,如果不拷貝而直接切換到init_mm_pgd上,那至少存在這個(gè)問(wèn)題,內(nèi)核中使用copy_from_user等訪問(wèn)進(jìn)程用戶地址空間的時(shí)候必然出錯(cuò)。另外執(zhí)行signal處理函數(shù)時(shí)要利用程序在用戶空間的棧來(lái)保存被沖掉的內(nèi)核棧保存的內(nèi)容,也必然出錯(cuò)。其原因在于init_mm.gpd上沒(méi)有當(dāng)前進(jìn)程在用戶地址空間的映射表。呵呵,不知俺說(shuō)的對(duì)不對(duì)。
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP