中國科學院大學操作系統(tǒng)考試思考題答案.docx
《中國科學院大學操作系統(tǒng)考試思考題答案.docx》由會員分享,可在線閱讀,更多相關《中國科學院大學操作系統(tǒng)考試思考題答案.docx(11頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1. 為什么計算機啟動最開始的時候執(zhí)行的是BIOS代碼而不是操作系統(tǒng)自身的代碼? 答:通常我們用C語言寫的用戶程序,必須在操作系統(tǒng)的平臺上執(zhí)行,即操作系統(tǒng)為應用程序創(chuàng)建進程并把應用程序的可執(zhí)行代碼加載到內存。計算機啟動的時候,操作系統(tǒng)并沒有在內存中,我們首先要把操作系統(tǒng)加載到內存,而這個工作最開始的部分,就是由bios 程序來實現(xiàn)的。所以計算機啟動最開始執(zhí)行的是 bios 代碼 2. 為什么BIOS只加載了一個扇區(qū),后續(xù)扇區(qū)卻是由bootsect代碼加載?為什么BIOS沒有把所有需要加載的扇區(qū)都加載? 答:對 BIOS 而言,“約定”在接到啟動操作系統(tǒng)的命令后,“定位識別”只從啟動扇區(qū)把代碼加載到 0x7c00 這個位置。后續(xù)扇區(qū)則由 bootsect 代碼加載,這些代碼由編寫系統(tǒng)的用戶負責,與 BIOS 無關。這樣構建的好處是站在整個體系的高度,統(tǒng)一設計和統(tǒng)一安排,簡單而有效。BIOS 和操作系統(tǒng)的開發(fā)都可以遵循這一約定,靈活地進行各自的設計。例如, BIOS可以不用知道內核鏡像的大小以及其在軟盤的分布等等信息,減輕了 BIOS 程序的復雜度,降低了硬件上的開銷。而操作系統(tǒng)的開發(fā)者也可以按照自己的意愿,內存的規(guī)劃,等等都更為靈活。另外,如果要使用BIOS進行加載,而且加載完成之后再執(zhí)行,則需要很長的時間,因此Linux采用的是邊執(zhí)行邊加載的方法。 3. 為什么BIOS把bootsect加載到0x07c00,而不是0x00000?加載后又馬上挪到0x90000處,是何道理?為什么不一次加載到位? 答:因為BIOS首先會把中斷向量表加載到0x00000-0x003ff的1KB的內存空間,在加載bootsect時約定加載到0x07c00處,符合內存布局,如下。 加載之后挪到0x90000處的原因如下:首先內核會使用啟動扇區(qū)中的一些數(shù)據(jù),如第 508、509 字節(jié)處的 ROOT_DEV;其次,依據(jù)系統(tǒng)對內存的規(guī)劃,內核占用 0x0000 開始的空間,因此 0x7c00 可能會被覆蓋。因為加載到0x07c00是BIOS約定好的,操作系統(tǒng)只能遵守這個約定。 4. bootsect、setup、head程序之間是怎么銜接的?給出代碼證據(jù)。 答:bootsect首先利用int 0x13中斷分別加載setup程序及system模塊,待bootsect程序的任務完成之后,執(zhí)行 jmpi 0,SETUPSEG 由于 bootsect 將 setup 段加載到了 SETUPSEG:0 的地方,在實模式下,該指令跳轉到setup段的第一條指令。 setup 執(zhí)行了之后,內核被移到了0x00000處,系統(tǒng)進入了保護模式,并加載了中斷描述符表和全局描述符表 lidt idt_48 lgdt gdt_48 在保護模式下,一個重要的特征就是根據(jù)GDT決定后續(xù)執(zhí)行哪里的程序。開啟保護模式后,執(zhí)行 jmpi 0, 8 根據(jù)保護模式的機制,該指令執(zhí)行后跳轉到以GDT第2項中的 base_addr 為基地址,以0為偏移量的地方,其中base_addr為0。由于head放置在內核的頭部,因此程序跳轉到head中執(zhí)行 5. setup程序里的cli是為了什么? 答:cli是關中斷指令。因為此時需要由16位實模式向32位保護模式轉變,即將進行實模式下的中斷向量表和保護模式下中斷描述符表的交接工作,在保護模式的中斷機制尚未完成時不允許響應中斷,以免發(fā)生未知的錯誤。 6. setup程序的最后是jmpi 0,8 為什么這個8不能簡單的當作阿拉伯數(shù)字8看待? 答:這里 8 要看成二進制 1000,最后兩位00表示內核特權級,第三位0表示 GDT 表,第四位1表示根據(jù)GDT中的第2項來確定代碼段的段基址和段限長等信息。這樣,我們可以得到代碼是從段基址 0x00000000、偏移為 0 處開始執(zhí)行的,即 head 的開始位置。注意到已經(jīng)開啟了保護模式的機制,這里的8是保護模式下的段選擇符,而不能當成簡單的阿拉伯數(shù)字8來看待。 7. 打開A20和打開pe究竟是什么關系,保護模式不就是32位的嗎?為什么還要打開A20?有必要嗎? 答:有必要。A20是cpu的第 21 位地址線,A20 未打開的時候,實模式下的最大尋址為 1MB+64KB,而第21根地址線被強制為0,所以相當于 cpu“回滾”到內存地址起始處尋址。打開A20僅僅意味著CPU可以進行32位尋址,且最大尋址空間是4GB,而打開PE是使能保護模式。打開A20是打開PE的必要條件;而打開A20不一定非得打開PE。打開PE是說明系統(tǒng)處于保護模式下,如果不打開A20的話,可以訪問的內存只能是奇數(shù)1M段,若要真正在保護模式下工作,必須打開A20,實現(xiàn)32位尋址。 8. Linux是用C語言寫的,為什么沒有從main還是開始,而是先運行3個匯編程序,道理何在? 答:通常用 C 語言編寫的程序都是用戶應用程序,這類程序的執(zhí)行必須在操作系統(tǒng)上執(zhí)行,也就是說要由操作系統(tǒng)為應用程序創(chuàng)建進程,并把應用程序的可執(zhí)行代碼從硬盤加載到內存。 而在計算機剛剛加電時,內存中沒有操作系統(tǒng)程序,只有BIOS 程序在運行,需要借助BIOS分別加載bootsect、setup及system模塊,然后利用這3個程序來完成內存規(guī)劃、建立IDT和GDT、設置分頁機制等等,并實現(xiàn)從開機時的16位實模式到 main 函數(shù)執(zhí)行需要的32位保護模式之間的轉換。 當計算機處在32 位的保護模式狀態(tài)下時,調用main的條件才算準備完畢。 9. 為什么不用call,而是用ret“調用”main函數(shù)?畫出調用路線圖,給出代碼證據(jù)。 答:CALL 指令會將 EIP 的值自動壓棧,保護返回現(xiàn)場,然后執(zhí)行被調函數(shù),檔執(zhí)行到被調函數(shù)的ret指令時,自動出棧給 EIP 并還原現(xiàn)場,繼續(xù)執(zhí)行CALL 的下一行指令。在由head程序向main函數(shù)跳轉時,是不需要main函數(shù)返回的;同時由于main函數(shù)已經(jīng)是最底層的函數(shù)了,沒有更底層的支撐函數(shù)支持其返回。所以要達到既調用 main又不需返回,就不采用 call 而是選擇了 ret“調用”了。 調用線路圖見P42 圖1-46。 代碼如下: (見P36 最下面) setup_paging: … ret 10. 保護模式的“保護”體現(xiàn)在哪里? 答:打開了保護模式后,CPU 的尋址模式發(fā)生了變化,需要依賴于 GDT 去獲取代碼或數(shù)據(jù)段的基址。從 GDT 可以看出,保護模式除了段基址外,還有段限長,這樣相當于增加了一個段位寄存器。既有效地防止了對代碼或數(shù)據(jù)段的覆蓋,又防止了代碼段自身的訪問超限,明顯增強了保護作用。 同時,保護模式中特權級的引入對于操作系統(tǒng)內核提供了強有力的保護。Intel 從硬件上禁止低特權級代碼段使用一些關鍵性指令,還提供了機會允許操作系統(tǒng)設計者通過一些特權級的設置,禁止用戶進程使用 cli、sti 等對掌控局面至關重要的指令。有了這些基礎,操作系統(tǒng)可以把內核設計成最高特權級,把用戶進程設計成最低特權級。這樣,操作系統(tǒng)可以訪問 GDT、LDT、TR,而 GDT、LDT 是邏輯地址形成線性地址的關鍵,因此操作系統(tǒng)可以掌控線性地址。物理地址是由內核將線性地址轉換而成的,所以操作系統(tǒng)可以訪問任何物理地址,而用戶進程只能使用邏輯地址。 11. 特權級的目的和意義是什么?為什么特權級是基于段的? 答:特權級是操作系統(tǒng)為了更好地管理內存空間及其訪問控制而設的,提高了系統(tǒng)的安全性。 保護模式中特權級的引入對于操作系統(tǒng)內核提供了強有力的保護。Intel 從硬件上禁止低特權級代碼段使用一些關鍵性指令,還提供了機會允許操作系統(tǒng)設計者通過一些特權級的設置,禁止用戶進程使用 cli、sti 等對掌控局面至關重要的指令。有了這些基礎,操作系統(tǒng)可以把內核設計成最高特權級,把用戶進程設計成最低特權級。這樣,操作系統(tǒng)可以訪問 GDT、LDT、TR,而 GDT、LDT 是邏輯地址形成線性地址的關鍵,因此操作系統(tǒng)可以掌控線性地址。物理地址是由內核將線性地址轉換而成的,所以操作系統(tǒng)可以訪問任何物理地址,而用戶進程只能使用邏輯地址。 在操作系統(tǒng)設計中,一般一個段實現(xiàn)的功能相對完整,可以把代碼放在一個段,數(shù)據(jù)放在一個段,并通過段選擇符(包括 CS、SS、DS、ES、FS 和 GS)獲取段的基址和特權級等信息。特權級基于段,這樣當段選擇子具有不匹配的特權級時,按照特權級規(guī)則判斷是否可以訪問。特權級基于段,是結合了程序的特點和硬件實現(xiàn)的一種考慮。 12. 在setup程序里曾經(jīng)設置過一次gdt,為什么在head程序中將其廢棄,又重新設置了一個?為什么折騰兩次,而不是一次搞好? 答:見P33 點評。 13. 在head程序執(zhí)行結束的時候,在idt的前面有184個字節(jié)的head程序的剩余代碼,剩余了什么?為什么要剩余? 答:在idt前面有184個字節(jié)的剩余代碼,包含了after_page_tables、 ignore_int 和 setup_paging代碼段,其中after_page_tables往棧中壓入了些參數(shù),ignore_int 用做初始化中斷時的中斷處理函數(shù),setup_paging 則是初始化分頁。 剩余的原因: after_page_tables 中壓入了一些參數(shù),為內核進入 main 函數(shù)的跳轉做準備。為了謹慎起見,設計者在棧中壓入了 L6,以使得系統(tǒng)可能出錯時,返回到 L6 處執(zhí)行。 ignore_int 為中斷處理函數(shù),使用 ignore_int 將 idt 全部初始化,因此如果中斷開啟后,可能使用了未設置的中斷向量,那么將默認跳轉到 ignore_int 處執(zhí)行。這樣做的好處是使得系統(tǒng)不會跳轉到隨機的地方執(zhí)行錯誤的代碼,所以 ignore_int 不能被覆蓋。 setup_paging 用于分頁,在該函數(shù)中對 0x0000 和 0x5000 的進行了初始化操作。該代碼需要“剩余”用于跳轉到 main,即執(zhí)行”ret ”指令。 14. 進程0的task_struct在哪?具體內容是什么?給出代碼證據(jù)。 答:進程0的task_struct是操作系統(tǒng)設計者事先寫好的,位于內核數(shù)據(jù)區(qū),存儲在user_stack中。(因為在進程0未激活之前,使用的是boot階段的user_stack。) static union task_union init_task={INIT_TASK}; 具體內容如下: 包含了進程 0 的進程狀態(tài)、進程 0 的 LDT、進程 0 的 TSS 等等。其中 ldt 設置了代碼段和堆棧段的基址和限長(640KB),而 TSS 則保存了各種寄存器的值,包括各個段選擇符。 代碼如下: INIT_TASK的定義見P68。 15. 進程0創(chuàng)建進程1時,為進程1建立了自己的task_struct、內核棧,第一個頁表,分別位于物理內存16MB的頂端倒數(shù)第一頁、第二頁。請問,這個了頁究竟占用的是誰的線性地址空間,內核、進程0、進程1、還是沒有占用任何線性地址空間(直接從物理地址分配)?說明理由并給出代碼證據(jù)。 答:占用的是內核的線性地址空間。(先理解清楚,稍后補充) 16. 假設:經(jīng)過一段時間的運行,操作系統(tǒng)中已經(jīng)有5個進程在運行,且內核分別為進程4、進程5分別創(chuàng)建了第一個頁表,這兩個頁表在誰的線性地址空間?用圖表示這兩個頁表在線性地址空間和物理地址空間的映射關系。 答:在內核的線性地址空間。(圖片自己畫,參考如下圖) 17. 進程0開始創(chuàng)建進程1,調用了fork(),跟蹤代碼時我們發(fā)現(xiàn),fork代碼執(zhí)行了兩次,第一次,跳過init()直接執(zhí)行了for(;;) pause(),第二次執(zhí)行fork代碼后,執(zhí)行了init()。奇怪的是,我們在代碼中并沒有看見向后的goto語句,也沒有看到循環(huán)語句,是什么原因導致反復執(zhí)行?請說明理由,并給出代碼證據(jù)。 答:進程 0 創(chuàng)建進程1采用了中斷機制,在中斷發(fā)生時由硬件將 ss,esp,eflags,cs,eip的值壓入了內核棧,其中 eip 的值指向了 int 0x80 的下一條指令。在執(zhí)行fork時,通過0x80號系統(tǒng)調用,內核執(zhí)行copy_process函數(shù),為進程1準備其管理結構(task_struct),設置進程1的線性地址空間及物理頁面,其中設置了進程1的 TSS 中 eax 的值為 0,狀態(tài)為TASK_RUNNING,以及利用中斷壓棧的寄存器值設置進程 1 的 ss,esp,eflags,cs,eip。 copy_process: p->pid = last_pid; … p->tss.eip = eip; p->tss.eflags = eflags; p->tss.eax = 0; … p->tss.esp = esp; … p->tss.cs = cs & 0xffff; p->tss.ss = ss & 0xffff; … p->state = TASK_RUNNING; return last_pid; 函數(shù)copy_process的返回值是last_pid,即進程1的pid(pid不為0)。在fork返回到進程0后,進程0判斷返回值非 0,因此執(zhí)行代碼 for(;;) pause(); 在sys_pause函數(shù)中,內核設置了進程0的狀態(tài)為 TASK_INTERRUPTIBLE,并進行進程調度。由于只有進程1處于就緒態(tài),因此調度執(zhí)行進程1的指令。由于進程1在TSS中設置了eip等寄存器的值,因此從 int 0x80 的下一條指令開始執(zhí)行,且設定返回 eax 的值作為 fork 的返回值(值為 0),因此進程1執(zhí)行了 init 的函數(shù)。導致反復執(zhí)行,主要是利用了兩個系統(tǒng)調用 sys_fork 和 sys_pause 對進程狀態(tài)的設置,以及利用了進程調度機制。 18. copy_process函數(shù)的參數(shù)最后五項是:long eip,long cs,long eflags,long esp,long ss。查看棧結構確實有這五個參數(shù),奇怪的是其他參數(shù)的壓棧代碼都能找得到,確找不到這五個參數(shù)的壓棧代碼,反匯編代碼中也查不到,請解釋原因。 答:在fork()中,當執(zhí)行“int $0x80”時產(chǎn)生一個軟中斷,該中斷使 CPU硬件自動將SS、ESP、EFLAGS、CS、EIP這5個寄存器的數(shù)值按照這個順序壓入進程0的內核棧。利用硬件進行壓棧,可以確保 eip 的值指向正確的指令,以使在中斷返回后,程序能夠繼續(xù)執(zhí)行。 19. 為什么static inline _syscall0(type,name)中需要加上關鍵字inline? 答:inline一般是用于定義內聯(lián)函數(shù),內聯(lián)函數(shù)結合了函數(shù)以及宏的優(yōu)點,在定義時和函數(shù)一樣,編譯器會對其參數(shù)進行檢查;在使用時和宏類似,內聯(lián)函數(shù)的代碼會被直接嵌入在它被調用的地方,這樣省去了函數(shù)調用時的一些額外開銷,比如保存和恢復函數(shù)返回地址等,可以加快速度。 20. 根據(jù)代碼詳細說明copy_process函數(shù)的所有參數(shù)是如何形成的? 答:一般在應用程序中,一個函數(shù)的參數(shù)是由函數(shù)定義的,而在操作系統(tǒng)底層中,函數(shù)參數(shù)可以由函數(shù)定義以外的程序通過壓棧的方式“做”出來。 copy_process函數(shù)的所有參數(shù)正是通過壓棧形成的。代碼見P83頁、P85頁、P86頁。 21. 根據(jù)代碼詳細分析,進程0如何根據(jù)調度第一次切換到進程1的。 答:通過fork(),進程0創(chuàng)建進程1,并將其狀態(tài)設為TASK_RUNNING,fork()函數(shù)執(zhí)行完畢后返回,進入 for(;;) pause(); 在sys_pause()中,將當前進程(進程0)的狀態(tài)設置為TASK_INTERRUPTBLE,然后執(zhí)行schedule(),遍歷task[]數(shù)組,找到唯一的一個處于TASK_RUNNING的進程(進程1),然后切換到進程1執(zhí)行,即switch_to(1)。 代碼見P106 22. 內核的線性地址空間是如何分頁的?畫出從0x000000開始的7個頁(包括頁目錄表、頁表所在頁)的掛接關系圖,就是頁目錄表的前四個頁目錄項、第一個個頁表的前7個頁表項指向什么位置?給出代碼證據(jù)。 答:先把頁目錄表和4個頁表放在物理內存的起始地址,從內存起始位置開始的5頁空間內容全部清零(每頁4KB)。然后設置頁目錄表的前4項,使之分別指向4個頁表,將第4個頁表的最后一個頁表項指向尋址范圍的最后一個頁面,將第4個頁表的倒數(shù)第二個頁表項指向尋址范圍的倒數(shù)第二個頁面,從高地址向低地址方向填寫4個頁面,依次指向內存從高地址向低地址方向的各個頁面。 圖見P39(注意要畫出7個頁,參考如下) 代碼見P39 最下面 23. 用文字和圖說明中斷描述符表是如何初始化的,可以舉例說明(比如:set_trap_gate(0,÷_error)),并給出代碼證據(jù)。 答:以set_trap_gate(0,÷_error)為例,其中,n是0,gate_addr是&idt[0],也就是idt的第一項中斷描述符的地址;type是15,dpl(描述符特權級)是0;addr是中斷服務程序divide_error(void)的入口地址。 見P54 圖2-9 P53 代碼 24. 進程0 fork進程1之前,為什么先要調用move_to_user_mode()?用的是什么方法?解釋其中的道理。 答:因為在Linux-0.11中,除進程0之外,所有進程都是由一個已有進程在用戶態(tài)下完成創(chuàng)建的。但是此時進程0還處于內核態(tài),因此要調用move_to_user_mode()函數(shù),模仿中斷返回的方式,實現(xiàn)進程0的特權級從內核態(tài)轉化為用戶態(tài)。又因為在Linux-0.11中,轉換特權級時采用中斷和中斷返回的方式,調用系統(tǒng)中斷實現(xiàn)從3到0的特權級轉換,中斷返回時轉換為3特權級。因此,進程0從0特權級到3特權級轉換時采用的是模仿中斷返回。 設計者首先手工寫壓棧代碼模擬int(中斷)壓棧,當執(zhí)行iret指令時,CPU自動將這5個寄存器的值(SS,ESP,EFLAGS,CS,EIP)按序恢復給CPU,CPU就會翻轉到3特權級去執(zhí)行代碼。 25. 進程0創(chuàng)建進程1時調用copy_process函數(shù),在其中直接、間接調用了兩次get_free_page函數(shù),在物理內存中獲得了兩個頁,分別用作什么?是怎么設置的?給出代碼證據(jù)。 答:第一次調用get_free_page函數(shù)申請的空閑頁面用于進程1 的task_struct及內核棧。首先將申請到的頁面清0,然后復制進程0的task_struct,再針對進程1作個性化設置,其中esp0 的設置,意味著設置該頁末尾為進程 1 的堆棧的起始地址。代碼見P90 及 P92。 第二次調用get_free_page函數(shù)申請的空閑頁面用于進程1的頁表。在創(chuàng)建進程1執(zhí)行copy_process中,執(zhí)行copy_mem(nr,p)時,內核為進程1拷貝了進程 0的頁表(160 項),同時修改了頁表項的屬性為只讀。代碼見P98。 26. 在IA-32中,有大約20多個指令是只能在0特權級下使用,其他的指令,比如cli,并沒有這個約定。奇怪的是,在Linux0.11中,在3特權級的進程代碼并不能使用cli指令,會報特權級錯誤,這是為什么?請解釋并給出代碼證據(jù)。 答: cli指令用于復位IF標志位,其執(zhí)行與CPL(當前特權級)和EFLAGS[IOPL]標志位有關。只有當CPL小于或等于IOPL時才可以執(zhí)行該指令。如果在CPL大于IOPL的情況下執(zhí)行,將會產(chǎn)生一個一般性保護異常,如下: set_trap_gate(13, &general_protection); 由于在內核IOPL的初始值為0,且未經(jīng)改變。進程0在 move_to_user_mode 中,繼承了內核的 eflags,如下: move_to_user_mode() … "pushfl\n\t" \ … "iret\n" \是否正確? 在TSS中明確設置了eflags的iopl為0 在進程0的TSS中,設置了eflags中的 IOPL 位為 0,代碼見P68,后續(xù)進程 如果沒有改動的話也是0,即IOPL=0。因此,通過設置 IOPL,可以限制3特權級的進程代碼使用 cli 指令。 27. 根據(jù)代碼詳細分析操作系統(tǒng)是如何獲得一個空閑頁的。 答:代碼見P90 get_free_page函數(shù)。 過程: (1)將EAX 設置為0,EDI 設置指向mem_map 的最后一項(mem_map+PAGING_PAGES-1),std設置掃描是從高地址向低地址。從mem_map的最后一項反向掃描,找出引用次數(shù)為0(AL)的頁,如果沒有則退出;如果找到,則將找到的頁設引用數(shù)為1; (2) ECX左移12位得到頁的相對地址,加LOW_MEM得到物理地址,將此頁最后一個字節(jié)的地址賦值給EDI(LOW_MEM+4092); (3) stosl將EAX的值設置到ES:EDI所指內存,即反向清零1024*32bit,將此頁清空; (4) 將頁的地址(存放在EAX)返回。 28. 用戶進程自己設計一套LDT表,并與GDT掛接,是否可行,為什么? 答:不可行。GDT和LDT放在內核數(shù)據(jù)區(qū),屬于0特權級,3特權級的用戶進程無權訪問修改。此外,如果用戶進程可以自己設計LDT的話,表明用戶進程可以訪問其他進程的LDT,則會削弱進程之間的保護邊界,容易引發(fā)問題。 29. 保護模式下,線性地址到物理地址的轉化過程是什么? 答:保護模式下,線性地址到物理地址的轉化是借助頁目錄表及頁表完成的。其轉化過程如圖所示(見P97 圖3-9)。Linux 0.11中僅有一個頁目錄表,其地址存放在CR3寄存器中,通過線性地址中的“頁目錄項”數(shù)據(jù)及CR3寄存器就可以找到頁目錄表中對應的頁目錄項,通過該頁目錄項可以找到對應的頁表,結合線性地址中的“頁表項”數(shù)據(jù)就可以找到對應的頁表項,通過該頁表項可以找到對應的物理頁面,最后通過線性地址中的“頁內偏移”落實到實際的物理地址值。 30. 為什么get_free_page()將新分配的頁面清0? 答:Linux在回收頁面時并沒有將頁面清0,只是將mem_map中與該頁對應的位置0。在使用get_free_page申請頁時,也是遍歷mem_map尋找對應位為0的頁,但是該頁可能存在垃圾數(shù)據(jù),如果不清0的話,若將該頁用做頁表,則可能導致錯誤的映射,引發(fā)錯誤,所以要將新分配的頁面清0。 31. 內核和普通用戶進程并不在一個線性地址空間內,為什么仍然能夠訪問普通用戶進程的頁面? 答:雖然內核與普通進程并不在一個線性地址空間內,但是用戶進程的頁面最終要從物理內存上分配,而內核的分頁機制即頁目錄表、頁表等,正好管理著16M物理內存,所以內核可以訪問普通用戶進程的頁面。 32. 詳細分析一個進程從創(chuàng)建、加載程序、執(zhí)行、退出的全過程。 答:可以參考課本P273頁,其中的核心部分課上都進行了介紹,包括fork()、copy_process()、do_execve()及do_exit等。 參考: 首先,shell調用fork開始創(chuàng)建進程,產(chǎn)生int 0x80軟中斷,最終映射到sys_fork(),調用find_empty_process(),為str1申請可用的pid和task[64]空閑位置,接著調用copy_process()為str1申請用來承載進程task_struct和內核棧的一個頁面,shell把自己的task_struct復制給str1進程,然后修改str1的task_struct的部分數(shù)據(jù),包括時間片,TSS字段等。接著調用copy_mem()為進程分段(確定段基址和段限長等),然后調用copy_page_tables為str1進程另起一套頁目錄項和頁表項,并指向shell的頁面。還要解決文件繼承的問題,然后將str1進程TSS和LDT掛接在GDT的指定位置,完成這些后,將str1設為就緒態(tài)。接下來加載用戶程序:首先要做一些檢查工作,如可執(zhí)行文件的數(shù)據(jù)長度和代碼長度等;然后調用free_page_tables解除與shell的頁面共享關系,接著根據(jù)程序的長度重新設置LDT,調整str1的task_struct,最后調整EIP和ESP。用戶程序被調度執(zhí)行,產(chǎn)生缺頁中斷,調用do_no_page為str1申請一個內存頁面,并把它登記在mem_map中,將str1程序從硬盤加載到新分配的頁面中,把它的物理地址映射到進程的線性地址空間內。執(zhí)行加載到的程序,產(chǎn)生壓棧動作,若??臻g不夠,則產(chǎn)生缺頁中斷繼續(xù)申請頁面。最后,用戶進程調用exit退出,釋放程序所占頁面,解除與文件有關的內容,并調用tell_father給父進程發(fā)信號,退出后執(zhí)行調度,shell進程收到用戶進程發(fā)送的信號設置為就緒態(tài),待其執(zhí)行時,釋放掉用戶進程task_struct所占用的頁面,解除與task[64]的關系,這時用戶進程徹底退出。 33. 詳細分析多個進程(無父子關系)共享一個可執(zhí)行程序的完整過程。 答:依次創(chuàng)建3個用戶進程,每個進程都有自己的task。假設進程1先執(zhí)行,需要壓棧產(chǎn)生缺頁中斷,內核為其申請空閑物理頁面,并映射到進程1的線性地址空間。這時產(chǎn)生時鐘中斷,輪到進程2執(zhí)行,進程2也執(zhí)行同樣邏輯的程序。之后,又輪到進程3執(zhí)行,也是壓棧,并設置text??梢?,三個進程雖程序相同,但數(shù)據(jù)獨立,用TSS和LDT實現(xiàn)對進程的保護。 34. 缺頁中斷是如何產(chǎn)生的,頁寫保護中斷是如何產(chǎn)生的,操作系統(tǒng)是如何處理的? 答:缺頁中斷:每個頁目錄項和頁表項都有個標志位P,如果和一個頁面建立了映射關系,P位置1,否則置0。MMU在解析線性地址時,若發(fā)現(xiàn)某個表項的P位為零,說明沒有對應頁面,就會產(chǎn)生缺頁中斷。操作系統(tǒng)會調用_do_no_page為進程申請空閑頁面,將程序加載到新分配的頁面中,并建立頁目錄表-頁表-頁面的三級映射管理關系。 頁寫保護異常:假設兩個進程共享一個頁面,該頁面處于寫保護狀態(tài)即只讀,此時若某一進程執(zhí)行寫操作,就會產(chǎn)生“頁寫保護”異常。操作系統(tǒng)會調用_do_wp_page,為該進程申請空閑頁面,將該進程的頁表指向新申請的頁面,然后將原頁表的數(shù)據(jù)復制到新頁面中,同時將原頁面的引用計數(shù)減1。該進程得到自己的頁面,就可以執(zhí)行寫操作。 35. 為什么要設計緩沖區(qū),有什么好處? 答:緩沖區(qū)的作用主要體現(xiàn)在兩方面: (1) 形成所有塊設備數(shù)據(jù)的統(tǒng)一集散地,操作系統(tǒng)的設計更方便,更靈活; (2) 數(shù)據(jù)塊復用,提高對塊設備文件操作的運行效率。在計算機中,內存間的數(shù)據(jù)交換速度是內存與硬盤數(shù)據(jù)交換速度的2個量級,如果某個進程將硬盤數(shù)據(jù)讀到緩沖區(qū)之后,其他進程剛好也需要讀取這些數(shù)據(jù),那么就可以直接從緩沖區(qū)中讀取,比直接從硬盤讀取快很多。如果緩沖區(qū)的數(shù)據(jù)能夠被更多進程共享的話,計算機的整體效率就會大大提高。同樣,寫操作類似。 36. 操作系統(tǒng)如何利用buffer_head中的 b_data,b_blocknr,b_dev,b_uptodate,b_dirt,b_count,b_lock,b_wait管理緩沖塊的? 答:b_data指向緩沖塊,用于找到緩沖塊的位置。 進程與緩沖區(qū)及緩沖區(qū)與硬盤之間都是以緩沖塊為單位進行數(shù)據(jù)交互的,而b_blocknr,b_dev唯一標識一個塊,用于保證數(shù)據(jù)交換的正確性。另外緩沖區(qū)中的數(shù)據(jù)被越多進程共享,效率就越高,因此要讓緩沖區(qū)中的數(shù)據(jù)塊停留的時間盡可能久,而這正是由b_blocknr,b_dev決定的,內核在hash表中搜索緩沖塊時,只看設備號與塊號,只要緩沖塊與硬盤數(shù)據(jù)的綁定關系還在,就認定數(shù)據(jù)塊仍停留在緩沖塊中,就可以直接用。 b_uptodate與b_dirt,是為了解決緩沖塊與數(shù)據(jù)塊的數(shù)據(jù)正確性問題而存在的。b_uptodate針對進程方向,如果b_uptodate為1,說明緩沖塊的數(shù)據(jù)已經(jīng)是數(shù)據(jù)塊中最新的,可以支持進程共享緩沖塊中的數(shù)據(jù);如果b_uptodate為0,提醒內核緩沖塊并沒有用綁定的數(shù)據(jù)塊中的數(shù)據(jù)更新,不支持進程共享該緩沖塊。 b_dirt是針對硬盤方向的,b_dirt為1說明緩沖塊的內容被進程方向的數(shù)據(jù)改寫了,最終需要同步到硬盤上;b_dirt為0則說明不需要同步 b_count記錄每個緩沖塊有多少進程共享。b_dirt大于0表明有進程在共享該緩沖塊,當進程不需要共享緩沖塊時,內核會解除該進程與緩沖塊的關系,并將b_count數(shù)值減1,為0表明可以被當作新緩沖塊來申請使用。 b_lock為1說明緩沖塊正與硬盤交互,內核會攔截進程對該緩沖塊的操作,以免發(fā)生錯誤,交互完成后,置0表明進程可以操作該緩沖塊。 b_wait記錄等待緩沖塊的解鎖而被掛起的進程,指向等待隊列前面進程的task_struct。- 配套講稿:
如PPT文件的首頁顯示word圖標,表示該PPT已包含配套word講稿。雙擊word圖標可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國旗、國徽等圖片,僅作為作品整體效果示例展示,禁止商用。設計者僅對作品中獨創(chuàng)性部分享有著作權。
- 關 鍵 詞:
- 中國科學院 大學 操作系統(tǒng) 考試 思考題 答案
裝配圖網(wǎng)所有資源均是用戶自行上傳分享,僅供網(wǎng)友學習交流,未經(jīng)上傳用戶書面授權,請勿作他用。
鏈接地址:http://www.820124.com/p-12750812.html