中國(guó)科學(xué)院大學(xué)操作系統(tǒng)考試思考題答案.docx_第1頁(yè)
中國(guó)科學(xué)院大學(xué)操作系統(tǒng)考試思考題答案.docx_第2頁(yè)
中國(guó)科學(xué)院大學(xué)操作系統(tǒng)考試思考題答案.docx_第3頁(yè)
中國(guó)科學(xué)院大學(xué)操作系統(tǒng)考試思考題答案.docx_第4頁(yè)
中國(guó)科學(xué)院大學(xué)操作系統(tǒng)考試思考題答案.docx_第5頁(yè)
已閱讀5頁(yè),還剩6頁(yè)未讀 繼續(xù)免費(fèi)閱讀

付費(fèi)下載

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

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

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論