版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
前言操作系統(tǒng)是一種簡(jiǎn)潔的系統(tǒng)軟件。本書(shū)通過(guò)介紹操作系統(tǒng)的根本概念和原理,并結(jié)合操作系統(tǒng)原理來(lái)分析一個(gè)小型但全面的操作系統(tǒng)xv6,并進(jìn)一步進(jìn)展各種基于xv6操作系統(tǒng)的試驗(yàn),來(lái)讓讀者了解和把握操作系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)。xv6x86架構(gòu)的計(jì)算機(jī)系統(tǒng)上UNIX的教學(xué)用操作系統(tǒng)。xv6起源于MIT2023年秋季,F(xiàn)ransKaashoek,JoshCates,andEmilSitMIT開(kāi)設(shè)了一門(mén)的試驗(yàn)型課程“操作系統(tǒng)工程”,英文名稱是“OperatingSystemsEngineering”,課程代號(hào)是“6.097”,后改為“6.828”,在此課程上,一開(kāi)頭承受了“萊昂UNIX源代碼分析”〔英文書(shū)名是“Lion”CornmentaryonUNIX6thEditionWithSourceCode”〕UNIXv6〔V6〕PDP-11計(jì)算機(jī)系統(tǒng)上。為了讓學(xué)生更好地理解V6的實(shí)現(xiàn),F(xiàn)ransKaashoek等從2023年夏季開(kāi)頭,參考V6的架構(gòu),x86計(jì)算機(jī)系統(tǒng)上重實(shí)現(xiàn)了一個(gè)支持多處理器計(jì)算機(jī)系統(tǒng)的類(lèi)似UNIX的教學(xué)用操作系統(tǒng),xv6MIT本科生課程“6.828:OperatingSystemsEngineering中,xv6主要exokernelJOSxv6MIT的網(wǎng)址在“:///6.828/xv6/“:///6.828/xv6/第零章安裝使用LinuxFUbuntuLinuxUbuntuLinux下編程。編譯[needupdate]UbuntuLinux8.10Capt工具進(jìn)一步安裝相關(guān)軟件包$sudoapt-getinstallgccbinutilslibc6-devgdbxv6軟件包,到某一名目,然后到此名目下執(zhí)行$make就可以生成相關(guān)執(zhí)行文件和鏡像,包括xv6.img(bootloaderxv6kernel)fs.img(包含應(yīng)用程序)運(yùn)行[needupdate]UbuntuLinux8.10apt工具進(jìn)一步安裝相關(guān)軟件包$sudoapt-getinstallqemubochsbiosvgabioslibsdl1.2debiankvmqemu執(zhí)行,可執(zhí)行如下命令qemu-smp4-parallelstdio-hdbfs.img-hdaxv6.imgkvm執(zhí)行,可執(zhí)行如下命令kvm-smp4-parallelstdio-hdbfs.imgxv6.imgqemukvmB。調(diào)試[needupdate]qemuqemudebugger調(diào)試〔patch并qemuC源碼級(jí)調(diào)試〕和gdb遠(yuǎn)程調(diào)試〔C源碼級(jí)調(diào)試,缺點(diǎn)是可能會(huì)有驚異的問(wèn)題,對(duì)硬件把握不夠。gdb遠(yuǎn)程調(diào)試的方法如下:aqemu調(diào)試方式啟動(dòng)qemu-S-s -smp2-monitorstdio-hdbfs.img-hdaxv6.imgbgdb啟動(dòng)并調(diào)試gdbkernel(gdb)targetremote:1234(gdb)breakFUNCTION-NAME(gdb)continue...(gdb)quitqemuinternaldebugger調(diào)試aqemu啟動(dòng)命令qemu-smp2-monitorstdio-hdbfs.img-hdaxv6.imgqemu的monitor中可執(zhí)行如下命令進(jìn)展調(diào)試分析x/fmtaddr--virtualmemorydumpstartingat”addr”infocpus--showinfosforeachCPUinforegisters--showthecpuregisterssinglestepsinglestap_enabled--togglesinglestepmodebreakpoint_insertaddr--insertbreakpointbreakpoint_removeaddr--removebreakpointbreakpoint_show--showbreakpointwatchpoint_insertaddrtype--insertwatchpointtype0=read1=writewatchpoint_removeaddr--removewatchpointwatchpoint_show--showwatchpointwhere--showcallsstack第一章總體構(gòu)造和系統(tǒng)組成本章將給出xv6啟動(dòng)實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:操作系統(tǒng)是什么?xv6是如何產(chǎn)生的?xv6的總體構(gòu)造是什么?xv6包含哪些重要的組成局部?操作系統(tǒng)是一種軟件,操作系統(tǒng)沒(méi)有一個(gè)準(zhǔn)確和統(tǒng)一的定義。操作系統(tǒng)是一種比較簡(jiǎn)潔的軟件,我們可以從多種角度來(lái)了解操作系統(tǒng)。從操作系統(tǒng)的任務(wù)來(lái)看,操作系統(tǒng)的任務(wù)主要是把握和治理計(jì)算機(jī)系統(tǒng)中的硬件資源并對(duì)應(yīng)用軟件和用戶供給各種便利使用計(jì)算機(jī)的功能。通過(guò)操作系統(tǒng),能有效地組織和治理計(jì)算機(jī)系統(tǒng)中的硬件資源和其他軟件資源,向用戶和應(yīng)用軟件供給各種效勞功能,使得用戶和應(yīng)用軟件能夠靈敏、便利、有效地使用計(jì)算機(jī),并使整個(gè)計(jì)算機(jī)系統(tǒng)能高效地運(yùn)行。從操作系統(tǒng)在計(jì)算機(jī)系統(tǒng)中的實(shí)現(xiàn)層次上看,操作系統(tǒng)位于計(jì)算機(jī)硬件之上,應(yīng)用軟件之下。由于操作系統(tǒng)是一個(gè)簡(jiǎn)潔的軟件系統(tǒng),為了能夠更好地設(shè)計(jì)和實(shí)現(xiàn)操作系統(tǒng),我們可以從功能上對(duì)操作系統(tǒng)進(jìn)展分解,可把操作系統(tǒng)分解為系統(tǒng)調(diào)用、進(jìn)程調(diào)度、內(nèi)存治理、中斷處理、文件系統(tǒng)和設(shè)備治理等功能模塊,在具體實(shí)現(xiàn)上可承受模塊化、層次化和面對(duì)對(duì)象等設(shè)計(jì)方法來(lái)設(shè)計(jì)實(shí)現(xiàn)操作系統(tǒng)。OS組成構(gòu)造圖[needtoupdate]。要了解xv6,首先我們需要了解操作系統(tǒng)的一些根本概念(請(qǐng)參考A)xv6〔xv6-rev2版本〕是一個(gè)支持對(duì)稱多處理器(SMP)的類(lèi)Unix系統(tǒng)。它包含操作系統(tǒng)一些最根本的要素,包括系統(tǒng)調(diào)用、進(jìn)程調(diào)度、內(nèi)存治理、中斷處理和文件系統(tǒng)等。xv6xv6UNIX操作系統(tǒng)設(shè)計(jì)思路。簡(jiǎn)潔地說(shuō),xv6基于扁平內(nèi)存治理的層次型單體內(nèi)核,應(yīng)用程序和操作系統(tǒng)是處于不同的特權(quán)狀態(tài)和地址空間。代表應(yīng)用程序的用戶態(tài)進(jìn)程運(yùn)行在CPU的用戶態(tài)〔又稱非特權(quán)模式,用戶模式,無(wú)法直接訪問(wèn)系統(tǒng)硬件和操作系統(tǒng)中的系統(tǒng)數(shù)據(jù),而操作系統(tǒng)運(yùn)行在CPU的核心態(tài)〔又稱特權(quán)模式,內(nèi)核模式,可以訪問(wèn)系統(tǒng)硬件和核心數(shù)據(jù)。下面分別從系統(tǒng)調(diào)用接口、進(jìn)程/文件系統(tǒng)、I/O系統(tǒng)調(diào)用是應(yīng)用程序訪問(wèn)操作系統(tǒng)的接口。在系統(tǒng)調(diào)用接口上,通用操作系統(tǒng)與基于此操作系統(tǒng)的應(yīng)用程序處于兩個(gè)不同的CPU特權(quán)態(tài),操作系統(tǒng)處于核心態(tài),而應(yīng)用程序處于用戶態(tài)。在核心態(tài)可以執(zhí)行CPU特權(quán)指令,而用戶態(tài)無(wú)法執(zhí)行特權(quán)指令,且只能通過(guò)特定的指令或中斷來(lái)訪問(wèn)操作系統(tǒng)供給的各種功能。這在確定程度上保證了系統(tǒng)整體的安全,避開(kāi)應(yīng)用程序?qū)Σ僮飨到y(tǒng)可能的破壞。在內(nèi)存治理方面,通用操作系統(tǒng)承受了虛擬內(nèi)存治理方式,這樣可以讓內(nèi)存需求超過(guò)實(shí)際物理內(nèi)存的進(jìn)程/線程能夠執(zhí)行,其主要思想是把重要和常用的數(shù)據(jù)和執(zhí)行代碼放在物理內(nèi)存中,把不常用的數(shù)據(jù)和執(zhí)行代碼放到二級(jí)存儲(chǔ)〔這里主要指的是硬盤(pán)等可在掉電后保存數(shù)據(jù)的存儲(chǔ)介質(zhì)同內(nèi)存區(qū)域的保護(hù),不同進(jìn)程之間,或者應(yīng)用程序和操作系統(tǒng)之間的地址空間相對(duì)隔離。這樣一般狀況下不同進(jìn)程的地址空間不能直接訪問(wèn),且應(yīng)用程序不能直接訪問(wèn)內(nèi)核地址空間。所以一個(gè)與錯(cuò)誤的應(yīng)用程序不會(huì)導(dǎo)致系統(tǒng)的崩潰,從而增加了系統(tǒng)的牢靠性。xv6操作系統(tǒng)沒(méi)有承受X86段模式的單一地址空間治理方式。在內(nèi)存安排和釋放的治理上,xv6相對(duì)實(shí)現(xiàn)得比較簡(jiǎn)潔,承受基于可變分區(qū)安排的首次適配算法,簡(jiǎn)潔產(chǎn)生內(nèi)存碎片。在進(jìn)程/線程治理方面,當(dāng)前通用操作系統(tǒng)結(jié)合虛存治理,承受進(jìn)程和線程結(jié)合的治理方式。進(jìn)程代表了一個(gè)程序執(zhí)行的過(guò)程以及其所占用的計(jì)算機(jī)資源〔包括CPU、內(nèi)存、文件等,進(jìn)程的執(zhí)行流可用線程來(lái)表示。操作系統(tǒng)的調(diào)度單位可以是進(jìn)程或線程。一個(gè)進(jìn)程可以包含多個(gè)線程,屬于同一進(jìn)程的多個(gè)線程共享進(jìn)程治理的資源,比方屬于同一進(jìn)程的多個(gè)線程共享進(jìn)程所治理的內(nèi)存,這樣這些線程可以直接訪問(wèn)屬于進(jìn)程的全局地址空間。xv6操作系統(tǒng)實(shí)現(xiàn)了一個(gè)基于進(jìn)程〔沒(méi)有實(shí)現(xiàn)線程〕的簡(jiǎn)潔進(jìn)程治理機(jī)制。在文件系統(tǒng)治理方面,當(dāng)前通用操作系統(tǒng)結(jié)合虛存治理,實(shí)現(xiàn)了多種簡(jiǎn)潔、高效且牢靠的文件系統(tǒng),且建立了一個(gè)統(tǒng)一的虛擬文件系統(tǒng)層,屏蔽不同文件系統(tǒng)的差異,對(duì)上層供給統(tǒng)一的接口。且與用戶治理和進(jìn)程治理結(jié)合,可實(shí)現(xiàn)安全治理,保證對(duì)文件的安全訪問(wèn)。xv6操作系統(tǒng)inode索引方式的文件系統(tǒng)。在I/O治理方面,xv6操作系統(tǒng)與通用操作系統(tǒng)〔特別是類(lèi)UNIX操作系統(tǒng)〕差異不是特別大,都把設(shè)備“看成”是一種特別的設(shè)備文件,有設(shè)備號(hào),用文件的訪問(wèn)接口來(lái)進(jìn)展翻開(kāi)、關(guān)閉、讀、寫(xiě)和把握等操作。在靈敏性方面,xv6驅(qū)動(dòng)程序不能象通用操作系統(tǒng)那樣依據(jù)硬件狀況動(dòng)態(tài)加載,而是在編譯時(shí)候就靜態(tài)確定的。xv6總體架構(gòu)從操作系統(tǒng)模型上來(lái)看,xv6是一個(gè)單地址空間的層次式單體內(nèi)核,不是微內(nèi)核〔microkernel〕模型的操作系統(tǒng)〔如Mach,QNX,與通用操作系統(tǒng)〔如Linux〕空間和特權(quán)模式上也有確定的差異。下面主要分進(jìn)程調(diào)度、內(nèi)存治理、同步互斥、文件系統(tǒng)幾xv6進(jìn)展介紹。同步互斥SMPCPU中都是共享的,所以在需要某xv6spinlock,從而可以對(duì)共享CPU數(shù)量。內(nèi)存治理在內(nèi)存治理方面,xv6承受了段式虛擬內(nèi)存的治理方式。每個(gè)用戶進(jìn)程所占用的內(nèi)存都是在一個(gè)連續(xù)的段中。用戶進(jìn)程內(nèi)存的分布為:代碼段、靜態(tài)變量段、固定大小的棧和可變大小的堆空間。由于進(jìn)程內(nèi)存是依據(jù)段治理的,因此在每次安排進(jìn)程內(nèi)存時(shí),xv6進(jìn)程治理SMPCPU執(zhí)行CPUCPU的操作系統(tǒng)治理問(wèn)題,具體包括假設(shè)創(chuàng)立進(jìn)程、如何刪除進(jìn)程、選擇哪個(gè)進(jìn)程占用哪個(gè)CPU,何時(shí)進(jìn)展進(jìn)程切換,進(jìn)程能夠持續(xù)占用CPU的時(shí)間片段的大小設(shè)定等。在xv6中,首先其進(jìn)程是基于時(shí)間片來(lái)調(diào)度的。每次進(jìn)程的調(diào)度是由時(shí)鐘中斷產(chǎn)生的,或者是因當(dāng)CPU之間都共享一個(gè)進(jìn)程池〔具體實(shí)現(xiàn)為一個(gè)全局?jǐn)?shù)組,其中有全部待運(yùn)行的進(jìn)程。在每個(gè)時(shí)間片中,CPU文件系統(tǒng)xv6中供給了一個(gè)簡(jiǎn)潔的文件系統(tǒng),這個(gè)文件系統(tǒng)供給了大多數(shù)POSIX標(biāo)準(zhǔn)的接口。由于這個(gè)文件系統(tǒng)比較簡(jiǎn)潔,其中一個(gè)文件最多由(12+128)也被限制在(12+128)*512Bytes。在這個(gè)文件系統(tǒng)中供給了一個(gè)Buf層,用來(lái)緩存磁盤(pán)上的數(shù)據(jù)。但是此文件系統(tǒng)是寫(xiě)直達(dá)的,因此每次更都會(huì)直接寫(xiě)到磁盤(pán)上。中斷治理和系統(tǒng)調(diào)用治理[NTU]外設(shè)治理[NTU](boot)概述本章將給出xv6啟動(dòng)實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:bootloader是什么?bootloader做了哪些事情?xv6是如何被加載并啟動(dòng)的?xv6的初始內(nèi)存治理是如何實(shí)現(xiàn)的?xv6的初始中斷治理是如何實(shí)現(xiàn)的?xv6如何實(shí)現(xiàn)內(nèi)核態(tài)到用戶態(tài)的轉(zhuǎn)變的?xv6啟動(dòng)用戶態(tài)進(jìn)程前需要完成哪些事情?xv6如何創(chuàng)立并啟動(dòng)第一個(gè)用戶態(tài)進(jìn)程?當(dāng)計(jì)算機(jī)加電后,一般不直接執(zhí)行操作系統(tǒng),而是執(zhí)行引導(dǎo)加載程序。簡(jiǎn)潔地說(shuō),引導(dǎo)加載程序就是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行的一段小程序。通過(guò)這段小程序,我們可以初始化硬件設(shè)備、建立系統(tǒng)的內(nèi)存空間映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)適宜的狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核預(yù)備好正確的環(huán)境。最終引導(dǎo)加載程序把操作系統(tǒng)內(nèi)核映像加載到RAM中,并將系統(tǒng)把握權(quán)傳遞給它。對(duì)于絕大多數(shù)計(jì)算機(jī)系統(tǒng)而言,操作系統(tǒng)和應(yīng)用軟件是存放在磁盤(pán)〔硬盤(pán)/軟盤(pán)、光盤(pán)、EPROM、ROM、Flash等可在掉電后連續(xù)保存數(shù)據(jù)的存儲(chǔ)介質(zhì)上。計(jì)算機(jī)啟動(dòng)后,CPU一開(kāi)頭會(huì)到一個(gè)特定的地址開(kāi)頭執(zhí)行指令,這個(gè)特定的地址存放了系統(tǒng)軟件〔不僅是操作系統(tǒng),還可能是引導(dǎo)加載程序等。引導(dǎo)加載程序(bootloader)PC386PCBIOS(BasicInputOutputSystem,即根本輸入/輸出系統(tǒng),其本質(zhì)Flash/CMOS上的軟件)和位于軟盤(pán)/OSBootLoader一起組成。BIOS實(shí)際上是被固化在計(jì)算機(jī)ROM〔只讀存儲(chǔ)器〕芯片上的一個(gè)特別的軟件,為上層軟件BIOS就是PC計(jì)算機(jī)硬件與上層軟件程序之間的一個(gè)“橋梁“,負(fù)責(zé)訪問(wèn)和把握硬件。以PC386為例,計(jì)算機(jī)加電后,CPU從物理地址0xFFFFFFF0〔由初始化的CS:EIP確定,此時(shí)CSIP0xF0000xFFF0)〕開(kāi)頭執(zhí)行。在0xFFFFFFF0這里只是存放了一條跳轉(zhuǎn)指令,通過(guò)跳轉(zhuǎn)指令跳到BIOS例行程序起始點(diǎn)。BIOS做完計(jì)算機(jī)硬件自檢和初始化后,會(huì)選擇一個(gè)啟動(dòng)設(shè)備〔例如軟盤(pán)、硬盤(pán)、光盤(pán)等個(gè)特定的地址0x7c00處,然后CPU把握權(quán)會(huì)轉(zhuǎn)移到那個(gè)地址連續(xù)執(zhí)行。至此BIOS的初始化工作xv6。xv6系統(tǒng)的啟動(dòng)流程大致是這樣的:做為多處理系統(tǒng),啟動(dòng)是首先從一個(gè)CPU的啟動(dòng)CPUBIOSOSBootLoader從磁盤(pán)上〔一般是位于第一個(gè)扇區(qū)〕拷貝到內(nèi)存當(dāng)中。當(dāng)BIOSBootLoaderBootLoaderCPUCPU將把啟動(dòng)代碼拷貝到內(nèi)存中,然后喚起其他CPU執(zhí)行這一段代碼,完成它們的初始化過(guò)程。xv6的源碼中,整個(gè)啟動(dòng)過(guò)程主要牽涉到如下幾個(gè)文件:bootloaderbootasm.Sbootmain.cxv6初始化模塊main.cbootother.S下面將針對(duì)這些文件進(jìn)展分析,對(duì)啟動(dòng)過(guò)程分成兩局部進(jìn)展介紹。代碼分析bootloader代碼分析bootloader的組成makefile50行~56行有如下語(yǔ)句50: bootblock:bootasm.Sbootmain.c51: $(CC)$(CFLAGS)-O-nostdinc-I.-cbootmain.c52: $(CC)$(CFLAGS)-nostdinc-I.-cbootasm.S53: -N-estart-Ttext0x7C00-obootblock.obootasm.obootmain.o54: $(OBJDUMP)-Sbootblock.o>bootblock.asm55: $(OBJCOPY)-S-Obinarybootblock.obootblock56: ./sign.plbootblockbootloader包含兩個(gè)文件,bootasm.Sbootmain.c。生成的bootloader會(huì)寫(xiě)到一個(gè)主引導(dǎo)扇區(qū)上面。作為主引導(dǎo)扇區(qū),其位置在軟盤(pán)或硬盤(pán)的第一個(gè)扇區(qū),其大小為512個(gè)字節(jié),在此扇區(qū)的最終兩個(gè)字節(jié)是一個(gè)主引導(dǎo)扇區(qū)特征碼為”55AA”。Makefile的51行和52gccbootmain.cbootasm.Sbootmain.obootasm.o。Makefile53ldbootmain.obootasm.o鏈接成目標(biāo)文件bootblock.o,且定義了起始執(zhí)行的點(diǎn)〔也稱入口點(diǎn)〕為start函數(shù),具體的代碼段起始地址為0x7C00[Q]大家還0x7C00這個(gè)特別的地址的含義嗎?Makefile54行是通過(guò)objdumpbootblock.obootlock.asm。Makefile55objcopy程序把bootblock.o變成二進(jìn)制碼bootlock。[Q]bootlock的大小可以大于512字節(jié)嗎?Makefile的56sign.pl程序把bootlock512個(gè)字節(jié),并把最終兩個(gè)字節(jié)寫(xiě)成”55AA”。[小試驗(yàn)]xv6.img512個(gè)字節(jié)取出來(lái),反匯編它的內(nèi)容,并與bootasm.S和bootmain.c的內(nèi)容〔bootblock.asm〕進(jìn)展比較,512個(gè)字節(jié)的最終兩個(gè)字節(jié)的內(nèi)容是否是“55AA”代碼分析bootloader的啟動(dòng)主要涉及到bootasm.S、bootmain.c。其中bootasm.S的主要作用是從實(shí)模bootmain的作用是把內(nèi)核從磁盤(pán)拷貝到內(nèi)存中。bootasm.S在進(jìn)入實(shí)模式向保護(hù)模式切換之前,首先需要把中斷關(guān)閉(“cli“atline15),保證轉(zhuǎn)換過(guò)程不被硬件中斷打斷。19~22DS,ES,SS進(jìn)展清零。20~42(A20地址線)[歷史]在8086年月,8086供給了20跟地址線,那么供給的可尋址空間范圍即0~2^20(00000H~FFFFFH)的1M8086的數(shù)據(jù)處理位寬位16位,8086供給了段地址加偏移地址的地址轉(zhuǎn)換機(jī)制,就是我們常見(jiàn)的”段地址:偏移地址(或有效地址)”,實(shí)際的計(jì)算方法為:”段地址*10H+偏移地址”,作為段地址的數(shù)據(jù)是放在段存放器中的(16位),而座位偏移地址的數(shù)據(jù)則是通過(guò)8086供給的尋址方式來(lái)計(jì)算而來(lái)的(16位)。而“段值:偏移”這種表示法能夠表示的最大內(nèi)存為10FFEEh(FFFF0 + FFFF),所以當(dāng)尋址到超過(guò)1MB的內(nèi)存時(shí),會(huì)發(fā)生“回卷”〔不會(huì)發(fā)生特別。但是到了80286供給了24根地址線,cpu的尋址范圍變?yōu)?^24=16M,同時(shí)也供給了保護(hù)模式,真的可以訪問(wèn)到1MB以上的內(nèi)存了,此時(shí)假設(shè)遇到“尋址超過(guò)1MB”的狀況,系統(tǒng)不會(huì)再“回卷”了,這就造成了向上不兼容。為了保持完全的兼容性,IBM打算在PCAT系統(tǒng)上加個(gè)規(guī)律,來(lái)仿照以上的繚繞特征。他們的方法就是把A20和鍵盤(pán)把握器的一個(gè)輸出進(jìn)展AND,這樣來(lái)把握A20的翻開(kāi)和關(guān)閉。一開(kāi)頭時(shí)A20是被屏蔽的〔總為0,直到系統(tǒng)軟件去翻開(kāi)它。留意A20而非A20~A31被把握,所以在A20關(guān)閉時(shí)會(huì)發(fā)生一些好玩的副作用。就是在訪問(wèn)奇當(dāng)A20Gate制止時(shí),則程序就像在8086中運(yùn)行,100000h~100FFEFh的地是不行訪問(wèn)的。A20Gate是要翻開(kāi)的。為了使能全部地址位的尋址力氣當(dāng)A20Gate制止時(shí),則程序就像在8086中運(yùn)行,100000h~100FFEFh的地是不行訪問(wèn)的。A20Gate是要翻開(kāi)的。為了使能全部地址位的尋址力氣,必需向鍵盤(pán)把握器8042發(fā)送一個(gè)命令。鍵盤(pán)把握器8042將會(huì)將它的的某個(gè)輸出引腳的輸出置高電平,作為A20門(mén)的輸入。一旦設(shè)置成功之后,內(nèi)存將不會(huì)再被繞回(memorywrapping),這樣我們就可以尋址整個(gè)286的16M內(nèi)存,或者是尋址803864G內(nèi)存了。8042IO0x60~0x6fIBMPC/AT使用的只有0x60和0x64兩個(gè)端口〔0x61、0x62和0x63用于與XT兼容目的。8042通過(guò)這些端口給鍵盤(pán)把握器或鍵盤(pán)發(fā)送命令或讀取狀態(tài)。輸出端口P2用于特定目的。位0〔P20引腳〕用于實(shí)現(xiàn)CPU復(fù)位操作,位1〔P21引腳〕用戶把握A20信號(hào)線的開(kāi)啟與否。系統(tǒng)向輸入緩沖〔端口0x64〕寫(xiě)入一個(gè)字節(jié),即發(fā)送一個(gè)鍵盤(pán)把握器命令??梢詭б粋€(gè)參數(shù)。參數(shù)是通過(guò)0x60端口發(fā)送的。命令的返回值也從端口0x60去讀。圖Intel8042芯片或其兼容芯片的規(guī)律示意圖28~31I/O0x64I/O0x641位〔0位〕00x64busy10為止。33~340xd1I/O0x64;0xd1命令是寫(xiě)輸出端口,bit0是復(fù)位,bit1是GateA20.36~39I/O0x64I/O0x641位〔最低位為第0位〕00x64busy10為止。41~420xdfI/O0x60;0xdfA20至此,A20地址線已經(jīng)使能。48行,“l(fā)gdtgdtdesc“gdtdesc中給出了段表有效大小,和所在地址(gdt)gdt01段是21、2段的范圍都是0x0~0xffffffff。在第49~51行中,通過(guò)將CR0的第0位置1,把保護(hù)模式設(shè)置為翻開(kāi)。但此時(shí)段模式并沒(méi)有55ljmpcs變成$PROT_MODE_CSEG所指向的段〔8>>3=1,gdt1段,即代碼段ljmp后,32位模式。59~65gdt2段,即數(shù)據(jù)段。bootmain.c68行,將棧頂指針指向$start坐在位置即(0x7c00)69bootmain過(guò)程,進(jìn)展內(nèi)核的加載。bootmain.c在這個(gè)文件中主要有四個(gè)函數(shù):bootmain、waitdisk、readsect和readseg。其中bootmain是加載內(nèi)核,其余三個(gè)都是對(duì)磁盤(pán)進(jìn)展訪問(wèn)的程序。waitdisk、readsectreadsegreadsegoffset處開(kāi)頭countvareadsect以扇區(qū)為單位進(jìn)展的。因此在88行保證va是從一個(gè)扇區(qū)起始位置開(kāi)頭,因此要對(duì)va進(jìn)展對(duì)齊。readsect是對(duì)磁盤(pán)進(jìn)展讀取,waitdisk等待磁盤(pán)的預(yù)備過(guò)程,一旦磁盤(pán)預(yù)備好后就可以進(jìn)展讀取了。然后看一下bootmain過(guò)程。bootmain的目的是從磁盤(pán)中加載內(nèi)核到內(nèi)存中,其中內(nèi)核是以ELF執(zhí)行文件格式存在磁盤(pán)上的。首先將從磁盤(pán)讀取一頁(yè)大小(8*512B=4KB)的信息,其中包含了ELF(34~37行。當(dāng)完成拷貝后,bootmain獵取內(nèi)核入口程序的地址(見(jiàn)40~41行,然后進(jìn)入該入口(即main.c中的main函數(shù))。操作系統(tǒng)初始化模塊代碼分析操作系統(tǒng)初始化模塊代碼分析操作系統(tǒng)的啟動(dòng)局部包含如下文件main.cbootother.Smain.cmain.c的作用是進(jìn)展對(duì)系統(tǒng)各方面的初始化工作,然后喚起其他CPU的初始化。首先我們看processtablebuffercachePICinterruptcontrollerIOAPICinterruptcontrollerphysicalmemoryallocatortrapvectorsfiletableinodecacheconsoledevice&interruptIDEprocesstablebuffercachePICinterruptcontrollerIOAPICinterruptcontrollerphysicalmemoryallocatortrapvectorsfiletableinodecacheconsoledevice&interruptIDEdevice&interrupttimer〔onlyforuniprocessor〕firstuserprocess這些將在后面的文章具體介紹。在初始話內(nèi)存、中斷表、文件系統(tǒng)、I/O設(shè)備等之后,第一個(gè)CPUbootothersCPUbootothers之前,第一個(gè)用戶進(jìn)程將通過(guò)userint進(jìn)展初始化。在初始化其他AP后,將進(jìn)入scheduler過(guò)程。scheduler過(guò)程CPU的進(jìn)展進(jìn)程調(diào)度的,這將在以后進(jìn)展?fàn)幷?。bootothersbootstrapCPUCPU進(jìn)展啟動(dòng)。啟動(dòng)時(shí)這樣進(jìn)展的,首先把bootother.S的代碼拷貝到0x7000起始的這塊內(nèi)存里。bootother.S然后在0x7000-4、0x7000-8兩個(gè)內(nèi)存單元記錄下bootother.S中將要進(jìn)展跳轉(zhuǎn)的內(nèi)核棧位置以及mpmainCPUbootother.Smpmain過(guò)程。在mpmain中,每個(gè)CPU將進(jìn)展中斷表和段表的初始化,然后翻開(kāi)中斷進(jìn)入scheduler過(guò)程。bootother.Sbootother.SCPUMakefile5862行:58:bootother:bootother.S59: $(CC)$(CFLAGS)-nostdinc-I.-cbootother.S60: $(LD)$(LDFLAGS)-N-estart-Ttext0x7000-obootother.outbootother.o61: $(OBJCOPY)-S-Obinarybootother.outbootother62: $(OBJDUMP)-Sbootother.o>bootother.asm可以了解到:Makefile59gccbootother.Sbootother.o。Makefile60ldbootother.o進(jìn)展地址重定位,start,起始地0x7000bootother.out。Makefile61objcopy把bootother.outbootother。Makefile62objdumpbootother.obootother.asm。bootother.S的執(zhí)行內(nèi)容格外類(lèi)似之前的bootasm.S。在這個(gè)文件中晚啟動(dòng)的CPU將會(huì)進(jìn)展從實(shí)模式到保護(hù)模式的轉(zhuǎn)化〔4249行。然后重設(shè)段存放器〔5459行kernelmpmain〔61-63行[Q]這個(gè)棧的內(nèi)容是什么?(spinlock)概述本章將給出xv6同步互斥實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:什么是競(jìng)爭(zhēng)狀態(tài)?什么是互斥?什么是同步?[NUD]xv6中的臨界區(qū)代碼是什么?xv6是怎樣處理臨界區(qū)代碼的?當(dāng)兩個(gè)或多個(gè)線程在執(zhí)行一些關(guān)鍵性的臨界區(qū)代碼時(shí)〔如對(duì)共享資源的訪問(wèn)們不會(huì)相互阻礙?當(dāng)線程之間存在著某種依存關(guān)系時(shí),如何來(lái)調(diào)整它們的運(yùn)行次序?當(dāng)線程經(jīng)常需要與其它線程進(jìn)展通信,那么如何依據(jù)需要供給有效的通信手段?這實(shí)際上需要操作系統(tǒng)供給同步互斥與通信的手段才能解決上述問(wèn)題。任何為進(jìn)程所占用的實(shí)體都可稱為資源。資源可以是CPU、內(nèi)存,也可以是I/O設(shè)備,還可以是一個(gè)變量,一個(gè)構(gòu)造或一個(gè)數(shù)組等。可以被一個(gè)以上進(jìn)程使用的資源叫做共享資源。為了防止數(shù)據(jù)被任憑訪問(wèn)〔特別是執(zhí)行寫(xiě)操作這叫做互斥〔mutualexclusion。需要互斥訪問(wèn)的共享資源稱為臨界資源。假設(shè)兩個(gè)或多個(gè)進(jìn)程對(duì)同一共享資源同時(shí)進(jìn)展讀寫(xiě)操作,而最終的結(jié)果是不行推想的,該結(jié)果取決于各個(gè)進(jìn)程具體運(yùn)行狀況。則稱此狀態(tài)為競(jìng)爭(zhēng)狀態(tài)〔racecondition問(wèn),可能導(dǎo)致競(jìng)爭(zhēng)狀態(tài)的消滅。我們把可能消滅競(jìng)爭(zhēng)態(tài)的程序片斷稱為程序臨界區(qū)。程序臨界區(qū)在處理時(shí)不行以被中斷,要保證其操作的原子性。為確保臨界區(qū)程序執(zhí)行過(guò)程中不被中斷,在進(jìn)入臨界區(qū)之前要屏蔽中斷,而臨界區(qū)代碼執(zhí)行完以后要馬上使能中斷,以削減對(duì)中斷處理延遲的影響。Spinlock的引入是為了進(jìn)展資源的互斥訪問(wèn)。在SMP架構(gòu)下,每個(gè)CPU的權(quán)限都是一樣的,但是某些狀況下,一個(gè)CPU需要對(duì)資源進(jìn)展獨(dú)占,此時(shí)就可以通過(guò)spinlock來(lái)進(jìn)展。spinlockCPUxchg完成的。具體的實(shí)現(xiàn)方法如下。2.2.代碼分析spinlock.hspinlock構(gòu)造的定義如下:structspinlock{structspinlock{uintlocked;//Isthelockheld?//Fordebugging:char*name;intlock.cpu;//Nameoflock.//Thenumberofthecpuholdingtheuintpcs[10]; //Thecallstack(anarrayofprogramcounters)//thatlockedthelock.};locked變量,這個(gè)用來(lái)表示當(dāng)前鎖是否被鎖上。其他的變量name,cpu和pcsname記錄鎖的用途,cpucpu取得了這把鎖,pcs記錄了獲得這把鎖時(shí)的棧的內(nèi)容。spinlock.cspinlock.cspinlock的各種操作:初始化、獵取鎖,釋放鎖等。我們依次閱讀文件中的每個(gè)過(guò)程。初始化鎖initlockname、lockedcpu三個(gè)域。cpu0xffffffff,cpu全部。獵取鎖acquire過(guò)程是獵取鎖(lock)28~29pushcli屏蔽中斷,檢查當(dāng)前鎖是否CPUcliCPU的中斷關(guān)閉(CPU的中斷并不受到影響,而且其他軟中斷也并沒(méi)有被關(guān)閉35while將直到成功獵取鎖為止。在35cmpxchg去獵取鎖。其指令格式為:xchg(va,newvalue)。作用是交換內(nèi)存地址vanewvaluevaxchglocked=0表示這把xchg(va,1)0whilewhile循環(huán)中打轉(zhuǎn)。跳出while表示獲得了鎖,42CPUID。43getcallerpcs記錄獲得鎖時(shí)的函數(shù)調(diào)用棧。釋放鎖releaseCPU拿到這把鎖,假設(shè)不是,則報(bào)錯(cuò);假設(shè)是,那CPUCPU已經(jīng)沒(méi)有拿popcli將中斷翻開(kāi)。第四章內(nèi)存治理概述本章將給出xv6內(nèi)存治理實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:xv6如何進(jìn)展內(nèi)存治理初始化的?xv6的靜態(tài)內(nèi)存安排的空間包括什么?xv6的動(dòng)態(tài)內(nèi)存安排的空間包括什么?xv6的動(dòng)態(tài)內(nèi)存安排是如何實(shí)現(xiàn)的?xv6的動(dòng)態(tài)內(nèi)存安排的空間??jī)?nèi)存治理機(jī)制是實(shí)時(shí)操作系統(tǒng)的重要組成局部。xv6不支持虛擬存儲(chǔ)治理,不支持簡(jiǎn)潔的段頁(yè)式的保護(hù)機(jī)制,而承受線性編址方式,即規(guī)律地址和物理地址一一對(duì)應(yīng)的平面模式。這樣沒(méi)有虛擬存儲(chǔ)治理供給的不受限于物理內(nèi)存大小的大地址空間、地址保護(hù)等功能。xv6同時(shí)支持靜態(tài)內(nèi)存安排和動(dòng)態(tài)內(nèi)存安排兩種治理方式。靜態(tài)內(nèi)存安排是指在編譯或鏈接時(shí)將應(yīng)用所需的內(nèi)存空間安排好。承受這種安排方案的xv6內(nèi)核映像所占內(nèi)存空間〔代碼段和數(shù)據(jù)段等〕的大小一般在編譯時(shí)就能夠確定,中斷向量表等其它區(qū)域所占用的內(nèi)存空間大小是個(gè)定值。這樣承受靜態(tài)的內(nèi)存安排機(jī)制,在編譯時(shí)就可以確定xv6而動(dòng)態(tài)內(nèi)存安排是指系統(tǒng)運(yùn)行時(shí)依據(jù)應(yīng)用需要?jiǎng)討B(tài)地安排內(nèi)存。動(dòng)態(tài)內(nèi)存安排的實(shí)現(xiàn)機(jī)制靈敏,給程序?qū)崿F(xiàn)帶來(lái)極大的便利,有的應(yīng)用環(huán)境中動(dòng)態(tài)內(nèi)存安排甚至是必不行少的。xv6xv6.img所在內(nèi)存的末尾開(kāi)頭,增加一塊1MB1MBxv6中動(dòng)態(tài)安排和釋放。在初始化完動(dòng)態(tài)內(nèi)存空間后的內(nèi)存布局如下:代碼分析kalloc.c動(dòng)態(tài)內(nèi)存治理初始化內(nèi)存空間初始化工作由函數(shù)kini完成,執(zhí)行完kinit后,內(nèi)存布局如下所示:bootloaderx0x10000mainkalloc.c文件中的kinit函數(shù)對(duì)內(nèi)存進(jìn)展初始化。其執(zhí)行流程如下:initlockkalloc_lock〔32行〕endstartstart指針startxv6所治理的空閑區(qū)域的起始地址〔3334行〕2564Kkfreestart指針指向的地址為256*4*1024〔3537行〕動(dòng)態(tài)內(nèi)存安排與釋放kalloc.ckfree是回收一段內(nèi)存,而kalloc是安排一段內(nèi)存。xv6的內(nèi)存治理是格外簡(jiǎn)潔的。由于內(nèi)存安排是以連續(xù)的段的方式進(jìn)展的,通過(guò)單鏈表方式鏈接空閑的段。因此經(jīng)過(guò)確定時(shí)間的安排,空閑空間將由一個(gè)個(gè)地址不連續(xù)的段組成。xv6用freelist將其按起始地址從左至右排列串起來(lái)。每次回收時(shí),將回收的段參與段序列中。假設(shè)覺(jué)察參與段之后能夠合并,則將其合并成一個(gè)段。當(dāng)進(jìn)展安排時(shí),則遍歷整個(gè)鏈表,直到找到一個(gè)比需求大的段,則將相應(yīng)的段安排出去。初始化后第一次安排N次安排和釋放后第五章進(jìn)程治理與調(diào)度概述本章將給出xv6進(jìn)程治理實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:什么是進(jìn)程?xv6的進(jìn)程治理數(shù)據(jù)構(gòu)造〔進(jìn)程把握塊,PCB〕包含哪些內(nèi)容?xv6是如何組織進(jìn)程治理數(shù)據(jù)構(gòu)造?xv6如何進(jìn)展進(jìn)程治理初始化的?xv6怎樣啟動(dòng)多進(jìn)程的(即需要做哪些初始化工作)?xv6何時(shí)進(jìn)展進(jìn)程調(diào)度?xv6是如何調(diào)度進(jìn)程的〔CPU運(yùn)行〕?xv6是如何完成進(jìn)程切換的?xv6如何啟動(dòng)并執(zhí)行用戶態(tài)的進(jìn)程的?進(jìn)程的概念程序與進(jìn)程的概念是不行分的。當(dāng)用戶在計(jì)算機(jī)上運(yùn)行一個(gè)程序時(shí),此程序?qū)?yīng)的進(jìn)程就誕生了,并實(shí)際完成各種程序供給的功能,而用戶關(guān)閉一個(gè)程序時(shí),進(jìn)程也隨之終止。程序是為了完成某項(xiàng)任務(wù)編排的語(yǔ)句序列,它要告知計(jì)算機(jī)如何執(zhí)行,因此程序是需要通過(guò)CPU來(lái)運(yùn)行的,且在程序的運(yùn)行過(guò)程中需要占有計(jì)算機(jī)的各種資源〔比方內(nèi)存等〕才能運(yùn)行下去。假設(shè)計(jì)算機(jī)系統(tǒng)在任一時(shí)刻限制只有一個(gè)程序在運(yùn)行,則程序在整個(gè)運(yùn)行過(guò)程中獨(dú)占計(jì)算機(jī)中的全部資源,這樣整個(gè)程序運(yùn)行和治理就簡(jiǎn)潔了。就象在一個(gè)家中只住了一個(gè)人A,他想看書(shū)就到書(shū)房去看書(shū),想睡覺(jué)就到睡房的床上去睡覺(jué),想看電視就到電視廳看電視,想吃飯就去餐廳吃飯,沒(méi)人和他搶占資源。但為了提高計(jì)算機(jī)系統(tǒng)的資源利用率,需要支持多個(gè)程序并發(fā)執(zhí)行。這就會(huì)帶來(lái)很多的問(wèn)題,如資源的共享與競(jìng)爭(zhēng),同步與互斥等。比方此人與B成家并有了小孩C,那就是三口之家同時(shí)住一套房,當(dāng)A想去看足球競(jìng)賽直播電視節(jié)目的時(shí)候,假設(shè)覺(jué)察電視廳已經(jīng)有B在坐著看連續(xù)劇電視節(jié)目了,A就得等待或干別的事情。除非A并在另外一個(gè)房間看他的球競(jìng)賽直播。由于程序是靜態(tài)的,我們看到的程序是存儲(chǔ)在存儲(chǔ)介質(zhì)〔如硬盤(pán)、光盤(pán)等〕上的,它無(wú)法反映出程序執(zhí)行過(guò)程中的動(dòng)態(tài)特性,而且程序在執(zhí)行過(guò)程中會(huì)不斷申請(qǐng)資源或釋放資源,這樣讓程序作為共享資源的根本單位是不適宜的,所以需要引入一個(gè)概念,它能描述程序的執(zhí)行過(guò)程而且可以作為共享資源的根本單位,這個(gè)概念就是進(jìn)程。簡(jiǎn)潔地說(shuō),一個(gè)進(jìn)程是一個(gè)具有確定獨(dú)立功能的程序在一個(gè)數(shù)據(jù)集合上的一次動(dòng)態(tài)執(zhí)行過(guò)程。每個(gè)進(jìn)程都是整個(gè)應(yīng)用的某一局部。操作系統(tǒng)在規(guī)律上維護(hù)了進(jìn)程的運(yùn)行狀態(tài)信息,即與進(jìn)程CPU存放器和棧空間〔只有這樣才能實(shí)現(xiàn)進(jìn)程切換。操作系統(tǒng)依據(jù)當(dāng)前進(jìn)程的狀況設(shè)置進(jìn)程的狀態(tài),并依據(jù)進(jìn)程的狀態(tài)〔比方優(yōu)先級(jí)〕CPU并運(yùn)行,這個(gè)過(guò)程成為調(diào)度。進(jìn)程的狀態(tài)進(jìn)程從誕生到死亡要經(jīng)受假設(shè)干個(gè)階段,也會(huì)有生老病死。簡(jiǎn)潔地說(shuō),進(jìn)程有三種狀態(tài):就緒、執(zhí)行、等待。多種緣由可以導(dǎo)致創(chuàng)立一個(gè)進(jìn)程,比方,當(dāng)操作系統(tǒng)把一個(gè)程序從硬盤(pán)調(diào)入內(nèi)存后,在開(kāi)頭執(zhí)行前,操作系統(tǒng)就要為此程序創(chuàng)立一個(gè)對(duì)應(yīng)的進(jìn)程。又比方,一個(gè)進(jìn)程可以自己創(chuàng)立一個(gè)子進(jìn)程,子進(jìn)程被創(chuàng)立后就是在內(nèi)存中,處于就緒態(tài),所謂就緒態(tài)就是萬(wàn)事具備,只CPUCPU,就可以執(zhí)行實(shí)際的工作了,其狀態(tài)就變成了執(zhí)行態(tài);進(jìn)程在執(zhí)行中假設(shè)需要等待某個(gè)資源〔如等硬盤(pán)輸入數(shù)據(jù)CPU,且其狀態(tài)就變?yōu)榈却龖B(tài),這時(shí)操作系統(tǒng)又會(huì)從處于就緒態(tài)的另一個(gè)進(jìn)程中選擇一個(gè)進(jìn)程占有CPU,則這另一個(gè)進(jìn)程的狀態(tài)就變成了執(zhí)行態(tài)。當(dāng)前一個(gè)進(jìn)程所等到數(shù)據(jù)到來(lái)后,處于等待態(tài)的前一個(gè)進(jìn)程又被喚醒,并把狀態(tài)變成為就緒態(tài)。xv6中,進(jìn)程具有多種狀態(tài),包括:EMBRO,SLEEPING,RUNNABLE,RUNNINGZOMBIEproc.h文件中:enumproc_state{UNUSED,EMBRYO,SLEEPING,RUNNABLE,RUNNING,ZOMBIE};狀態(tài)的含義如下:UNUSED:進(jìn)程未被創(chuàng)立〔即進(jìn)程把握塊空閑〕時(shí)的狀態(tài);EMBRYO:需要安排一個(gè)進(jìn)程把握塊且找到一個(gè)處于UNUSED狀態(tài)的進(jìn)程把握塊時(shí),把此進(jìn)程把握塊狀態(tài)設(shè)置為要使用的狀態(tài);SLEEPING:進(jìn)程由于等待某資源等緣由無(wú)法執(zhí)行,進(jìn)入睡眠狀態(tài),即等待態(tài);RUNNABLE:進(jìn)程獲得了除CPU之外的全部資源,處于可運(yùn)行狀態(tài),即就緒態(tài);RUNNINGCPU,正在運(yùn)行的狀態(tài),即執(zhí)行態(tài);ZOMBIE:進(jìn)程完畢的狀態(tài)5.1〔左〕SMPCPU獵取進(jìn)程調(diào)度的權(quán)利是一樣的。CPUscheduler里面進(jìn)展輪詢操作,每次從線程池中選擇一個(gè)RUNNABLE的進(jìn)程進(jìn)展運(yùn)行。直到運(yùn)行完畢,或一單位時(shí)間片完畢,或者進(jìn)程主動(dòng)yield或sleep。CPU5.1〔右〕所示。5.1狀態(tài)轉(zhuǎn)換的過(guò)程[即哪些大事促使了狀態(tài)的轉(zhuǎn)換TODO]進(jìn)程把握塊程序的運(yùn)行是通過(guò)進(jìn)程表達(dá)的,操作系統(tǒng)對(duì)進(jìn)程進(jìn)展治理和把握,那么操作系統(tǒng)怎么了解到CPU的現(xiàn)場(chǎng)保存在那呢?這實(shí)際是通過(guò)進(jìn)程把握快〔ProcessControlBlock,簡(jiǎn)稱PCB。PCB是進(jìn)程的唯一標(biāo)志,在PCB感知進(jìn)程的存在,通過(guò)PCBxv6CPU共享一個(gè)進(jìn)程把握塊池,即源代碼proc.cproc〔即進(jìn)程把握塊〕類(lèi):一類(lèi)是未使用的進(jìn)程把握塊構(gòu)造,另一類(lèi)是正在使用的進(jìn)程把握塊構(gòu)造。每次要?jiǎng)?chuàng)立一個(gè)進(jìn)程時(shí),只需要從進(jìn)程把握塊數(shù)組中取得一個(gè)未使用進(jìn)程把握塊構(gòu)造進(jìn)展相應(yīng)的處理即可。代碼分析構(gòu)造與變量構(gòu)造與變量proc.h文件中定義了幾個(gè)關(guān)鍵的數(shù)據(jù)構(gòu)造。其中context是在內(nèi)核進(jìn)展上下文切換需要保存的存放器〔定義在proc.h中:structcontext{inteip;intesp;intebx;intecx;intedx;intesi;intedi;intebp;};[Q]eax?proc構(gòu)造描述了進(jìn)程運(yùn)行需要的數(shù)據(jù):structproc{char*mem;processmemory(kerneladdress)uintsz;ofprocessmemory(bytes)char*kstack;kernelstackforthisprocessenumproc_statestate;intpid;ProcessID
//Processstate
//Startof//Size//Bottomof//structproc*parent;void*chan;zero,sleepingonchanintkilled;Ifnon-zero,havebeenkilledstructfile*ofile[NOFILE];structinode*cwd;structcontextcontext;structtrapframe*tf;interruptcharname[16];(debugging)};
//Parentprocess//Ifnon-////Openfiles//Currentdirectory//Switchheretorunprocess//Trapframeforcurrent//Processname其中:其中:memmem記錄了進(jìn)程在內(nèi)核的起始地址;sz是記錄進(jìn)程所占有的內(nèi)存空間大小;kstack是進(jìn)程在內(nèi)核態(tài)的棧;state是進(jìn)程的狀態(tài);pidID;chanNULL時(shí),是進(jìn)程睡眠時(shí)所掛的睡眠隊(duì)列;killed0時(shí),表示進(jìn)程被殺死了;ofile數(shù)組是進(jìn)程翻開(kāi)的文件數(shù)組;cwd是進(jìn)程運(yùn)行時(shí)所處的當(dāng)前名目;context是切換進(jìn)程需要維護(hù)的硬件存放器內(nèi)容;tf是中斷進(jìn)程后,需要恢復(fù)進(jìn)程連續(xù)執(zhí)行所保存的存放器內(nèi)容;name保存了進(jìn)程的名字〔用于調(diào)試。進(jìn)程在內(nèi)存中的布局如下:expandableheapexpandableheap〔堆〕fixed-sizestack〔?!硂riginaldataandbss〔數(shù)據(jù)〕Text〔代碼〕proc[NPROC]數(shù)組〔proc.c11行〕xv6所能夠支持的進(jìn)程所需的相關(guān)數(shù)據(jù),NPROCxv6可支持進(jìn)程個(gè)數(shù)。cpuCPU的相關(guān)信息:structcpu{ucharapicid;LocalAPICIDstructproc*curproc;running.structcontextcontext;schedulerstructtaskstatets;tofindstackforinterrupt////Processcurrently//Switchheretoenter//Usedbyx86structsegdescgdt[NSEGS];volatileuintbooted;started?intncli;//Depthofpushcliintena;//x86globaldescriptortable//HastheCPU//Wereinterruptsenabledbeforepushcli?};其中:apicidCPUid編號(hào);curprocCPU上運(yùn)行的進(jìn)程把握塊;context[] ;ts是Taskstatesegment,用于在中斷時(shí)找到棧[] ;gdt是此CPU的全局描述符表〔GDT;bootedCPU已經(jīng)啟動(dòng)了;nclipushcli函數(shù)的次數(shù);intena表示[] ;全局變量進(jìn)程數(shù)組proc[NPROC]數(shù)組就是進(jìn)程池。進(jìn)程池訪問(wèn)鎖proc_table_lockspinlock是用來(lái)保護(hù)對(duì)進(jìn)程池的臨界區(qū)訪問(wèn)。當(dāng)前運(yùn)行進(jìn)程curproccpu當(dāng)前運(yùn)行的進(jìn)程。第一個(gè)進(jìn)程initproc是記錄第一個(gè)創(chuàng)立的進(jìn)程。這個(gè)進(jìn)程格外特別,它將托管全部沒(méi)有父進(jìn)程的進(jìn)程〔也就是父進(jìn)程先于子進(jìn)程完畢。下一進(jìn)程號(hào)nextid是用來(lái)產(chǎn)生進(jìn)程號(hào)的,在系統(tǒng)啟動(dòng)后會(huì)始終保持遞增。處理過(guò)程與進(jìn)程相關(guān)的處理函數(shù)集中在proc.c中,下面將依次介紹相關(guān)處理過(guò)程。進(jìn)程治理初始化pinitproc_table_lock鎖。初始化用戶進(jìn)程inituserinit是初始化第一個(gè)用戶進(jìn)程init。其處理過(guò)程如下所示:156copyproccopyproc0,這表示是第一個(gè)用戶進(jìn)程。由于是第一個(gè)進(jìn)程,因此在copyproc中沒(méi)有進(jìn)展內(nèi)存等相關(guān)構(gòu)造的初始化;156~173是對(duì)相關(guān)構(gòu)造〔包括內(nèi)存、當(dāng)前名目cwd、trapframe〕進(jìn)展初始化。留意的是,161~162行將進(jìn)程的段加上了用戶態(tài)權(quán)限而不是內(nèi)核態(tài)權(quán)限;p->tf->eip=0表0地址。p->tf->esp=p->sz的含義是174~176行是將第一個(gè)用戶進(jìn)程的代碼〔initcode.S〕拷貝到進(jìn)程的內(nèi)存中,然后把進(jìn)程名字指定為“initcoe設(shè)置進(jìn)程狀態(tài)為RUNNABLE;178pinitproc。創(chuàng)立子進(jìn)程在xv6中,可以通過(guò)sys_fork來(lái)復(fù)制父進(jìn)程內(nèi)容并創(chuàng)立一個(gè)的子進(jìn)程。其處理過(guò)程如下所示:11copyproc函數(shù)創(chuàng)立一個(gè)的進(jìn)程,留意這里調(diào)用copyproc函數(shù)的參數(shù)是p,p的相關(guān)內(nèi)容來(lái)創(chuàng)立子進(jìn)程;把創(chuàng)立的子進(jìn)程狀態(tài)設(shè)置為RUNNABLE,返回子進(jìn)程的pid。留意這也是fork返回后,確定是父進(jìn)程還是子進(jìn)程返回的一個(gè)標(biāo)志。復(fù)制進(jìn)程copyprocsys_forkcopyproc函數(shù),完成對(duì)userinitcopyproc函數(shù),完成對(duì)第一個(gè)用戶態(tài)進(jìn)程的創(chuàng)立。其處理過(guò)程如下所示:108~109PCB復(fù)制;112~115np開(kāi)拓內(nèi)核棧空間;116行是將其trapframe所占的空間放在內(nèi)核棧棧頂,大小位sizeof(structtrapframe),np->tf指向棧頂-sizeof(structtrapframe)的位置;p〔即父進(jìn)程〕非空,119~121npparentpp中的狀態(tài)復(fù)制到nptrapframe中;p〔即父進(jìn)程〕非空,124psz〔進(jìn)程空間大小〕npmem內(nèi)存空間;p〔即父進(jìn)程〕非空,131pmemnpmem;p〔即父進(jìn)程〕非空,133~135filedup函數(shù)復(fù)制父進(jìn)程翻開(kāi)的文件給子進(jìn)np;p〔即父進(jìn)程〕非空,136idupnp;139~142shedulereipforkretscheduler中加上的鎖給釋放。esp指向安排的棧地址;144~145fork產(chǎn)生的,因此其作為子進(jìn)程0。進(jìn)程構(gòu)造的空間安排allocproc是進(jìn)展進(jìn)程安排,也就是在進(jìn)程池中找出一個(gè)狀態(tài)為UNUSED的進(jìn)程返回。選出來(lái)EMBRYOproc_table_lock。增加進(jìn)程的地址空間growprocsbrk調(diào)用。xv6的內(nèi)存治理格外簡(jiǎn)潔。當(dāng)要增大n時(shí),假設(shè)原內(nèi)存空間為sz,xv6將首先嘗試開(kāi)拓一個(gè)為sz+n的空間(55~57行)。假設(shè)(58~63行)。設(shè)置內(nèi)核空間和用戶空間段描述符setupsegstaskstatep0時(shí),IDLE進(jìn)程,只運(yùn)行在內(nèi)核態(tài),并且是在初始化生成的。因此對(duì)于這個(gè)進(jìn)程不TSesp00xffffffff81~85CPU設(shè)置段描述符,TSS87~88為用戶端,段的基址和大小由當(dāng)前進(jìn)程打算。設(shè)置完成后,lgdtltr進(jìn)展加載。調(diào)度進(jìn)程scheduler對(duì)每個(gè)CPU進(jìn)展進(jìn)程調(diào)度。CPU到?jīng)]有運(yùn)行用戶進(jìn)程時(shí),就會(huì)進(jìn)入這個(gè)過(guò)程中。這個(gè)過(guò)程不停的從進(jìn)程中選出一個(gè)RUNNABLE的進(jìn)程,然后運(yùn)行這個(gè)進(jìn)程〔通過(guò)swtch.S中的swtch函數(shù)進(jìn)展。[TODO]schedschedulerswtch進(jìn)展上下文切換即可。CPUyield是用戶進(jìn)程用來(lái)主動(dòng)放棄當(dāng)前CPUschedulerscheduler需要加鎖所proc_table_lock加上。設(shè)置用戶進(jìn)程返回forkretforksys_fork創(chuàng)立的進(jìn)程是通過(guò)shcedulerproc_table_lock鎖釋放。睡眠進(jìn)程sleep功能是讓進(jìn)程休眠。首先獲得proc_table_lockchan,也就是說(shuō)只有相關(guān)的chanschedchan等記錄清proc_table_locklk鎖。喚醒進(jìn)程wakeup功能是喚醒進(jìn)程。先獵取proc_table_lock,然后調(diào)用函數(shù)wakeup1,然后釋放proc_table_lock。wakeup1chanSLEEPINGRUNNABLE。殺死進(jìn)程killIDkilled狀態(tài)置1即可。假設(shè)目標(biāo)進(jìn)程出于sleeping狀態(tài)則將其設(shè)置成RUNNABLE使其盡早被殺掉。退出進(jìn)程exit的是用于用戶進(jìn)程退出。在退出之前,用戶進(jìn)程需要關(guān)閉翻開(kāi)的文件(351~356行,將翻開(kāi)的文件夾關(guān)閉(358~359)wait狀態(tài)。并將其子進(jìn)程托管init。然后轉(zhuǎn)變其狀態(tài)為ZOMBIE〔等待父進(jìn)程進(jìn)展回收schedCPU。等待進(jìn)程完畢wait是用于父進(jìn)程等待子進(jìn)程完畢只用的。做法是不斷的循環(huán)知道找到一個(gè)子進(jìn)程變成ZOMBIE狀態(tài),則釋放ZOMBIE子進(jìn)程〔回收其資源,然后完畢循環(huán)返回其子進(jìn)程的進(jìn)程ID在循環(huán)的時(shí)候需要推斷是否被外部進(jìn)程Kill,或有無(wú)活潑子進(jìn)程,假設(shè)被殺死或無(wú)活潑子進(jìn)程,則推出循環(huán)。進(jìn)程上下文切換在操作系統(tǒng)中通常也把上下文切換稱為進(jìn)程切換〔processswitch。當(dāng)操作系統(tǒng)打算運(yùn)行另外的進(jìn)程時(shí),它需要保存當(dāng)前正在運(yùn)行進(jìn)程的當(dāng)前上下文〔Context,也可稱“運(yùn)行狀態(tài)信息”,即CPU存放器中的全部?jī)?nèi)容。這些內(nèi)容保存在進(jìn)程的堆??臻g或特定的上下文保存區(qū)。完成保存工作后,操作系統(tǒng)就可以把下一個(gè)將要運(yùn)行進(jìn)程的當(dāng)前上下文從該進(jìn)程的?;蛏舷挛腃PU一般有兩種狀況的上下文切換:高優(yōu)先級(jí)的進(jìn)程由于需要某種臨界資源,主動(dòng)懇求堵塞,讓出處理器,此時(shí)將調(diào)度就緒狀態(tài)的低優(yōu)先級(jí)進(jìn)程獲得執(zhí)行。這種切換稱為進(jìn)程級(jí)的上下文切換。進(jìn)程由于時(shí)鐘中斷或其它中斷到來(lái)而被打斷,在中斷效勞例程處理完畢后,內(nèi)核覺(jué)察有更高優(yōu)先級(jí)進(jìn)程處于就緒態(tài),則在中斷處理完畢后直接切換到高優(yōu)先級(jí)進(jìn)程執(zhí)行。這種調(diào)度也稱為中斷級(jí)的上下文切換。swtch.S這個(gè)程序是進(jìn)展上下文切換。9oldcontext11~18行將當(dāng)前的context存入。留意:eipnewcontext的指針,將全部存放器復(fù)原,然后將要運(yùn)行的eip壓入棧,利用ret切換到的進(jìn)程。留意,在切換回去后,的進(jìn)程仍處于內(nèi)核態(tài)。(trap&systemcall)概述本章將給出xv6中斷處理和系統(tǒng)調(diào)用實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:什么是中斷?什么是系統(tǒng)調(diào)用?中斷與系統(tǒng)調(diào)用有何關(guān)系?xv6如何處理中斷?xv6的時(shí)鐘中斷處理有何特別的作用?xv6的各種實(shí)現(xiàn)功能?xv6如何處理系統(tǒng)調(diào)用?操作系統(tǒng)需要對(duì)計(jì)算機(jī)系統(tǒng)中的各種外設(shè)進(jìn)展治理,這就需要CPU和外設(shè)能夠相互通信才行。一般外設(shè)的速度遠(yuǎn)慢于CPU的速度。假設(shè)讓操作系統(tǒng)通過(guò)CPU“主動(dòng)關(guān)心”外設(shè)的大事,即承受通常的輪詢〔polling〕機(jī)制,則太鋪張CPU資源了。所以需要操作系統(tǒng)和CPU能夠一起供給某種機(jī)制,讓外設(shè)在需要操作系統(tǒng)處理外設(shè)相關(guān)大事的時(shí)候,能夠“主動(dòng)通知”操作系統(tǒng),即打斷操作系統(tǒng)和應(yīng)用的正常執(zhí)行,讓操作系統(tǒng)完成外設(shè)的相關(guān)處理,然后在恢復(fù)操作系統(tǒng)和應(yīng)用的正常執(zhí)行。在操作系統(tǒng)中,這種機(jī)制稱為中斷機(jī)制。中斷機(jī)制給操作系統(tǒng)供給了處理意外狀況的力氣,同時(shí)它也是實(shí)現(xiàn)進(jìn)程/線程搶占式調(diào)度的一個(gè)重要基石。在操作系統(tǒng)中,把三種特別的中斷大事。由CPU外部設(shè)備引起的外部大事如I/O中斷、時(shí)鐘中斷、把握臺(tái)中斷等是異步產(chǎn)生的,與CPU的執(zhí)行無(wú)關(guān),我們稱之為異步中斷〔asynchronousinterrupt〕也稱外部中斷,簡(jiǎn)稱中斷(interrupt)。而把在CPU執(zhí)行指令期間檢測(cè)到不正常的或非法的條件〔如除零錯(cuò)、地址訪問(wèn)越界〕所引起的內(nèi)部大事稱作同步中斷〔synchronousinterrupt,也稱內(nèi)部中斷,簡(jiǎn)稱特別〔exception。把在程序中使用懇求系統(tǒng)效勞的系統(tǒng)調(diào)用而引發(fā)的大事,稱作陷入中斷(trapinterrupt,也稱軟中斷〔softinterrupt〔systemcall〕trap。在后面的表達(dá)中,假設(shè)沒(méi)有特別指出,我們將用簡(jiǎn)稱中斷、特別、陷入來(lái)表示這三種特別的中斷大事。2.源碼分析trap.cxv6對(duì)不同的中斷的處理過(guò)程以及中斷表的初始化。中斷初始化tvinit2.源碼分析trap.cxv6對(duì)不同的中斷的處理過(guò)程以及中斷表的初始化。中斷初始化tvinit過(guò)程中主要是對(duì)idt表進(jìn)展初始化。其中vectors中存放的是每個(gè)中斷處理程序的入口地址。vectorsvectors.Sperlvectors.pl2223可以看到,Systemcall中斷權(quán)限為用戶權(quán)限,也就是說(shuō)只能int0x30tickslock這個(gè)鎖進(jìn)展初始化,這個(gè)鎖是用來(lái)處理時(shí)鐘中斷的。idtinitidt表的。idtinittvinitidtinitCPU調(diào)用。而tvinit過(guò)程只需要被調(diào)用一次。vectors.S&vectors.plvectors.Svectors.pl生成的。其中定義了每個(gè)中斷的入口程序和入口地址〔存儲(chǔ)在vecotrs數(shù)組中。可以留意到,中斷分成兩類(lèi):一類(lèi)是壓入錯(cuò)誤編碼的(errorcode)另一類(lèi)不會(huì)壓入錯(cuò)誤編碼。因此對(duì)于其次類(lèi),vectors.S將壓入一個(gè)0。此外vectors.S還會(huì)將中斷號(hào)壓入棧。在壓完兩個(gè)必要的值之后,全部中斷都將統(tǒng)一的跳轉(zhuǎn)進(jìn)入alltraps入口程序。中斷處理過(guò)程trap函數(shù)的實(shí)現(xiàn)trap過(guò)程便是對(duì)中斷進(jìn)展處理的。全部的中斷在經(jīng)過(guò)中斷入口程序(trapasm.S中定義〕后,都會(huì)最終跳轉(zhuǎn)到這里。其處理過(guò)程如下:在37~45行,假設(shè)中斷是系統(tǒng)調(diào)用,則通過(guò)syscall過(guò)程完成系統(tǒng)調(diào)用的處理。值得留意的是,這里進(jìn)展了當(dāng)前進(jìn)程是否被其他進(jìn)程kill的狀況。也就是說(shuō),假設(shè)一個(gè)進(jìn)程被Kill,那么此進(jìn)程將在進(jìn)入或退出內(nèi)核態(tài)時(shí)被切斷。48~56行是對(duì)不同的中斷進(jìn)展處理。caseIRQ_OFFSET+IRQ_TIMER是處理時(shí)鐘中CPU0CPUtickssleeping狀態(tài)的進(jìn)程進(jìn)展檢查〔通過(guò)wakeup)。在wakeup則RUNNABLE;57~60ide_intr完成磁盤(pán)中斷處理;61~64kbd_intr完成鍵盤(pán)中斷處理;6~69行打印出產(chǎn)生的IRQ_SPURIOUS[]72~82行,推斷假設(shè)是在內(nèi)核執(zhí)行時(shí)產(chǎn)生的中斷,則系統(tǒng)掛起;假設(shè)是在用戶態(tài)執(zhí)行p->killed=1,表示要?dú)⑺来诉M(jìn)程84~88行,將檢查當(dāng)前進(jìn)程的p->killed,假設(shè)是非零且在用戶態(tài)引起的中斷,則調(diào)用exit函數(shù)退出此進(jìn)程;9~93行,推斷假設(shè)當(dāng)前進(jìn)程占用了CPU〔即cp->state==RUNNING,且是時(shí)鐘中斷,則調(diào)用yield函數(shù),讓當(dāng)前進(jìn)程放棄所在CPU,選擇其他進(jìn)程占用當(dāng)前CPU。trapasm.Strapasm.S在這個(gè)文件中,主要是將存放器進(jìn)展保存。9~11行都是將相關(guān)存放器壓入到棧。存放器值在棧中的布局可以參考x86.h中trapframe的定義。需要留意到的是棧底是在內(nèi)存的高地址位置,trapframe構(gòu)造是從低到高放置的。14~16trap.c中traptraptrapframeesp存放器壓入棧,其正好是trapframe的地址。在從trap返回之后,將開(kāi)頭保存的全部存放器恢復(fù)〔26~28行,然后將中斷編號(hào)和錯(cuò)誤號(hào)彈出棧即可。然后調(diào)用iret進(jìn)展返回。syscall.c這個(gè)文件的主要目的是處理系統(tǒng)調(diào)用,依據(jù)系統(tǒng)調(diào)用的編號(hào)安排到不同的處理函數(shù)中去。其中文件中還供給了提取參數(shù)的過(guò)程。fetchintfetchstr是從進(jìn)程〔p)addrkernelip。由于addr是進(jìn)程中的地址,其對(duì)應(yīng)的物理地址在內(nèi)核態(tài)的虛擬地址是不同的,因此需要轉(zhuǎn)換。轉(zhuǎn)換是十paddrp->mem+addrpp->memp->sz大小的連續(xù)空間。需要留意的是,fetchintfetchstr都需要推斷參數(shù)給出的內(nèi)存地址是否超過(guò)了進(jìn)程所安排的內(nèi)存范圍。argint,argptrargstrsystemcall中傳入的參數(shù)。進(jìn)程在進(jìn)程調(diào)用前,都會(huì)把參數(shù)壓入fetchintfetchstr獵取參argintnncp->tf->esp+4+4*n。syscall過(guò)程是將系統(tǒng)調(diào)用安排到不同的處理函數(shù)。處理后的返回結(jié)果存到cp->tf->eax中。這eax〔trapasm.S)。sysproc.cproc.c中的函數(shù)sys_sleep。一進(jìn)入這個(gè)函數(shù)時(shí),ticksticks0中。接著始終ticks-ticks0即實(shí)際睡眠時(shí)間超過(guò)預(yù)定的時(shí)間后就返回。由于不能始終占用CPU,sleepSleeping狀態(tài),參與休眠隊(duì)列。(filesystem)概述本章將給出xv6文件系統(tǒng)實(shí)現(xiàn)的概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:什么是文件系統(tǒng)?什么是文件?什么是名目?I/OBuffer有何作用?xv6的文件系統(tǒng)有哪些重要局部組成?xv6如何實(shí)現(xiàn)創(chuàng)立一個(gè)文件?xv6如何實(shí)現(xiàn)讀寫(xiě)文件?很多應(yīng)用需要對(duì)數(shù)據(jù)進(jìn)展長(zhǎng)期保存和訪問(wèn),這樣就需要文件系統(tǒng)的支持。操作系統(tǒng)中負(fù)責(zé)治理和存儲(chǔ)文件信息的軟件機(jī)構(gòu)稱為文件治理系統(tǒng),簡(jiǎn)稱文件系統(tǒng)。文件系統(tǒng)由三局部組成:與文件治理有關(guān)的軟件、被治理的文件以及實(shí)施文件治理所需的數(shù)據(jù)構(gòu)造。從系統(tǒng)角度來(lái)看,文件系統(tǒng)是對(duì)文件存儲(chǔ)器空間進(jìn)展組織和安排,負(fù)責(zé)文件的存儲(chǔ)并對(duì)存入的文件進(jìn)展保護(hù)和檢索的系統(tǒng)。具體地說(shuō),它負(fù)責(zé)為用戶建立文件,存入、讀出、修改、轉(zhuǎn)儲(chǔ)文件,把握文件的存取,當(dāng)用戶不再使用時(shí)刪除文件等。xv6的文件系統(tǒng)是整個(gè)操作系統(tǒng)中代碼量最大的一局部了,但照舊只是一個(gè)格外簡(jiǎn)潔的實(shí)現(xiàn)。UnixUNIX文件系統(tǒng)種類(lèi)具有類(lèi)似的通用構(gòu)造,其中心概念是超級(jí)塊〔superblock〕,i節(jié)點(diǎn)〔inode〕,數(shù)據(jù)塊〔datablock〕名目塊〔directoryblock〕,和間接塊〔indirectionblock。超級(jí)塊包括文件系統(tǒng)的總體信息,比方大小(其準(zhǔn)確信息依靠文件系統(tǒng))。i節(jié)點(diǎn)包括除了名字外的一個(gè)文件的全部信息,名字與i節(jié)點(diǎn)數(shù)目一起存在名目中,名目條目包括文件名和文件的i節(jié)點(diǎn)數(shù)目。i節(jié)點(diǎn)包括幾個(gè)數(shù)據(jù)塊的數(shù)目,用于存儲(chǔ)文件的數(shù)據(jù)。i節(jié)點(diǎn)中只有少量數(shù)據(jù)塊數(shù)的空間,假設(shè)需要更多,會(huì)動(dòng)態(tài)安排指向數(shù)據(jù)塊的指針空間。這些動(dòng)態(tài)安排的塊是間接塊;為了找到數(shù)據(jù)塊,這名字指出它必需先找到間接塊的號(hào)碼。xv6API、文件系統(tǒng)、BufI/O通訊。FDFileRead和Write等函數(shù)與硬件設(shè)備進(jìn)展交互,從而隱蔽了很多實(shí)現(xiàn)的細(xì)節(jié),簡(jiǎn)化了很多上層程序的操作。Buf緩存構(gòu)造是用來(lái)緩存需要寫(xiě)入硬件設(shè)備的數(shù)據(jù)和從硬件設(shè)備上讀出的數(shù)據(jù)。Buf可以對(duì)硬件設(shè)備的操作進(jìn)展統(tǒng)一的調(diào)度,從而提高效率。最底層的便是直接對(duì)硬件設(shè)備進(jìn)展調(diào)度。7.1xv6文件系統(tǒng)構(gòu)造FD文件描述符,F(xiàn)ile文件構(gòu)造和源碼分析sysfile.c此文件定義了很多有關(guān)文件系統(tǒng)的系統(tǒng)調(diào)用。xv6中的系統(tǒng)調(diào)用是針對(duì)文件描述符進(jìn)展的。每File。有可能多個(gè)文件描述指向同一個(gè)文件。每個(gè)文件描ofile記錄了其指向的文件構(gòu)造。下面對(duì)每個(gè)過(guò)程進(jìn)展介紹。argfdnn個(gè)參數(shù)讀取出來(lái)(20行)ofile找到相應(yīng)的文件構(gòu)造〔22行。ofile數(shù)組中查找一個(gè)沒(méi)有使用的文件描述符,然后返回即可。sys_readosfile讀取出文件描述符所指向文件構(gòu)造fileread進(jìn)展文件讀取。sys_writesys_read類(lèi)似,只需要找到相應(yīng)的文件構(gòu)造,調(diào)用filewrite對(duì)文件構(gòu)造進(jìn)展寫(xiě)操作。同樣,sys_dup、sys_closesys_fstat都是API進(jìn)展操作,這里就不再贅述了。sys_linkxv6中,一個(gè)名目中存儲(chǔ)的是一個(gè)個(gè)文inodeinodeinode。sys_link就是用來(lái)建立這種指向的。為了避開(kāi)形成大于1的環(huán),dir的link只能指向一個(gè)文件,而不能是名目(122~124行116~128inode1。然后在130~136sys_unlink是用來(lái)取消一個(gè)硬鏈接。就是在名目中找到相應(yīng)的表項(xiàng),進(jìn)展刪除。create過(guò)程是用于建立相應(yīng)的file.h每個(gè)文件構(gòu)造都對(duì)應(yīng)著一個(gè)磁盤(pán)設(shè)備上的真實(shí)文件、或一個(gè)硬件設(shè)備、或者通訊管道。從File的構(gòu)造定義可以看出,F(xiàn)ile構(gòu)造主要分成兩種類(lèi)型,一種是INODE(可能是磁盤(pán)上的文件,也可能是硬件設(shè)備,另一種是Pip〔管道。假設(shè)是INODE型,則ip指針則指向其對(duì)應(yīng)的pipePIPEreadablewritable是用來(lái)加ref則是表示被整個(gè)系統(tǒng)的用戶進(jìn)程應(yīng)用了多少次(TODO:不同進(jìn)程INODE層?)。file.c此文件中供給了對(duì)FILE構(gòu)造的一些根本操作,例如FILE文件構(gòu)造的安排〔filealloc的復(fù)制〔filedup、文件構(gòu)造的關(guān)閉(fileclose)、文件讀取(fileread)和文件寫(xiě)入(filewrite)。全部FILE文件構(gòu)造在系統(tǒng)中都有一個(gè)統(tǒng)一的列表保存,這個(gè)列表的大小限制了整個(gè)系統(tǒng)可以SMP構(gòu)造,在訪問(wèn)這個(gè)列表時(shí)需要加上鎖來(lái)保證互斥的資源訪問(wèn)。filealloc是用來(lái)安排一個(gè)FILE構(gòu)造的,也就是從文件列表中選取一個(gè)狀態(tài)為FD_CLOSED的FD_NONE1。fork中。fileclose是將一個(gè)文件的引用計(jì)數(shù)減一。比方某個(gè)用戶進(jìn)程將此文件構(gòu)造關(guān)閉了。當(dāng)引用計(jì)數(shù)變?yōu)?時(shí),說(shuō)明系統(tǒng)中沒(méi)有任何一處翻開(kāi)此文件,此時(shí)可以收回此文件構(gòu)造。在回收時(shí),同時(shí)要調(diào)用文件構(gòu)造下層構(gòu)造(PIPEINODE)的關(guān)閉。filestat是返回一個(gè)文件構(gòu)造的統(tǒng)計(jì)信息。只有當(dāng)此文件構(gòu)造類(lèi)型是INODEC時(shí)才有效。返回的統(tǒng)計(jì)信息有文件大小,文件鏈接數(shù)等等。分別是通文件構(gòu)造讀取和寫(xiě)入數(shù)據(jù)。兩個(gè)函數(shù)都是調(diào)用下層構(gòu)造相應(yīng)的函數(shù)file_table_lock鎖。但全部的下層構(gòu)造都有其自身的加鎖機(jī)制。磁盤(pán)文件系統(tǒng)和源碼分析文件系統(tǒng)主要是以INODE構(gòu)造進(jìn)展操作的。INODE可以是一個(gè)文件,也可以是一個(gè)文件夾。用戶進(jìn)程通過(guò)文件路徑來(lái)進(jìn)展對(duì)INODE的查詢和訪問(wèn)。INODE在xv6文件系統(tǒng)中有兩種類(lèi)型,一種是在系統(tǒng)實(shí)際運(yùn)行時(shí)在內(nèi)存中的INODE〔即fsvar.h中的inode構(gòu)造,另一種是在磁盤(pán)上INODE〔fs.hdinode)INODE是用于操作系統(tǒng)對(duì)文件訪問(wèn)進(jìn)展控INODEdinode則是用于組織這個(gè)文件系統(tǒng)在磁盤(pán)上的存儲(chǔ)構(gòu)造。fsvar.h&fs.hxv6文件系統(tǒng)在磁盤(pán)上的組織構(gòu)造。xv6對(duì)磁盤(pán)空間的劃分是以塊〔block)為單dinodeblock組成。在磁盤(pán)上,xv6文件系統(tǒng)從低地址到高地址(即從0塊到最終一塊〕的布局為:超級(jí)塊(superblock)、dinode構(gòu)造列表(inodes)用狀況的統(tǒng)計(jì)表(blockin-use-bitmap)和數(shù)據(jù)塊。其中超級(jí)塊的作用是給出磁盤(pán)文件系統(tǒng)的根本信息,包括文件系統(tǒng)總的塊數(shù),數(shù)據(jù)塊的數(shù)目以及dinode的數(shù)目。超級(jí)塊只占一個(gè)塊〔blockdinodedinodedinode都有自己的編號(hào)。dinode構(gòu)造中記錄的文件類(lèi)型(文件或名目、設(shè)備、硬鏈接數(shù)、文件大小和此文件所占用的數(shù)據(jù)塊。占用數(shù)據(jù)塊的編號(hào)存在addrs中,其中addrs[0]~addrs[NDIRECT-1]直接指向一個(gè)數(shù)據(jù)塊;而addrs[INDIRECT]指向一個(gè)塊,塊里存放的都是其他被此文件占用的數(shù)據(jù)塊的地址,因此是addrs[INDIRECT]是間接指針。磁盤(pán)塊使用狀況統(tǒng)計(jì)表是一段連續(xù)的磁盤(pán)空間,其中每一比特對(duì)應(yīng)了整個(gè)盤(pán)上某塊的使用狀況。假設(shè)第ibit為1,則表示磁盤(pán)上的第0塊被占用。磁盤(pán)中剩下的塊都為數(shù)據(jù)塊。留意:以上每一局部都占用整數(shù)個(gè)塊,有些構(gòu)造可能沒(méi)有把其最終一0。fs.creadsbsuperblock。bzero,balloc,bfree都是數(shù)據(jù)塊相關(guān)的操作。在操作中都是對(duì)有bufblockballoc,bfree在操作之后都需要修改磁盤(pán)塊使用狀況統(tǒng)計(jì)相應(yīng)的比特位。inode操作相關(guān)的函數(shù)。在文件系統(tǒng)中,icache構(gòu)造緩存當(dāng)前系統(tǒng)中全部inodeinodeFile文件構(gòu)造或者是進(jìn)程所處的當(dāng)前名目cwdinode0時(shí),inodeinode都有一個(gè)inumdinode的列表的編號(hào)。igeticacheinuminodeicacheinode,則inoderef1。idupinodeforkFile文件構(gòu)造被復(fù)制是會(huì)發(fā)生這個(gè)狀況。ilockinodeinodeI_BUSY,同inodeinode使用權(quán)時(shí),假設(shè)覺(jué)察已被其他進(jìn)程SLEEP狀態(tài)。知道其他進(jìn)程放棄使用權(quán)后,用wakeup將其喚醒。需要留意的是在搶inode使用權(quán)時(shí),照舊可能消滅RACE狀態(tài)(TODO)。搶到使用權(quán)后,假設(shè)覺(jué)察ip->flagsI_VALID,則從磁盤(pán)上讀入。iunlockinode的使用權(quán),同時(shí)喚醒等待這把鎖的進(jìn)程。iput1inode。iallocinode進(jìn)展安排。這個(gè)算法對(duì)磁盤(pán)進(jìn)展挨次查找空閑的inode,速度實(shí)際上比較慢。iupdate是將內(nèi)存中的內(nèi)容更到磁盤(pán)。bmapinoden個(gè)塊(block)n塊是直接塊,則可以馬上返回。否則要加載block然后讀到相應(yīng)的塊,然后返回。itrunc、stati、readiwriteiinode的數(shù)據(jù)訪問(wèn)。dirlookup、dirlink、skipelem、_namei都是對(duì)文件路徑進(jìn)展處理,相比照較簡(jiǎn)潔,這里便不再贅述。需要留意的是,dirinodedirent項(xiàng),描述了文件夾inode編號(hào)。I/O緩存Buf構(gòu)造和源碼分析xv6bufblock塊進(jìn)展緩存。bufLRUbuf總是放在鏈表的首部。bio.cbinitbuf鏈表初始化,并將其鏈成一個(gè)表。bgetbuf。首先在bufbufbuf存儲(chǔ)扇區(qū)。bread是bgetbufB_VALID,則通過(guò)ide_rw進(jìn)展磁盤(pán)同步。bwritebufbwrite之前需要在外部對(duì)buf,從而保證全都性。brelsebufbuf訪問(wèn)完畢時(shí)調(diào)用的。此時(shí)基于LRUbufbuf鏈表的頭部。ide.cide磁盤(pán)進(jìn)展讀寫(xiě)操作。I/O讀寫(xiě)是異步的。ide_rwide_queue進(jìn)展排隊(duì)。在ide_rwide_queuedisk沒(méi)有開(kāi)頭讀寫(xiě),則喚起disk讀寫(xiě)。(141~142行145~146進(jìn)展輪詢等待讀寫(xiě)進(jìn)程的完成。輪詢中并不是盲sleep當(dāng)前進(jìn)程,等待進(jìn)程完成是被喚起。ide_start_requestbufb進(jìn)程懇求發(fā)送到磁盤(pán)。當(dāng)進(jìn)程完成時(shí),磁盤(pán)將發(fā)出完成的硬件中斷。ide_intr則是相應(yīng)此中斷的過(guò)程。ide_intr106~108行去除狀態(tài),并喚醒等待此bufide_queue有后繼進(jìn)程,則啟動(dòng)此進(jìn)程。第八章對(duì)稱多處理〔SMP/MultiCore〕支持概述本章將給出xv6多處理器支持的實(shí)現(xiàn)概貌。讀者將學(xué)習(xí)以下一些內(nèi)容:SMP系統(tǒng)?什么是PIC,LAPIC,IOAPIC?xv6CPU的?xv6CPU之間的中斷信息傳遞的?xv6如何初始化主處理器〔BP〕和從處理器
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年國(guó)際旅游環(huán)境影響因素探討與實(shí)踐題目
- 2026年動(dòng)物科學(xué)知識(shí)理解與實(shí)驗(yàn)設(shè)計(jì)試題集
- 2026年生物醫(yī)學(xué)實(shí)驗(yàn)室操作考試實(shí)驗(yàn)設(shè)計(jì)與實(shí)驗(yàn)記錄規(guī)范題目
- 2026年數(shù)據(jù)庫(kù)管理與系統(tǒng)開(kāi)發(fā)試題集
- 2026年體育教練員專(zhuān)業(yè)能力綜合評(píng)估試題
- 2026年環(huán)境治理從業(yè)考試環(huán)境保護(hù)法實(shí)施細(xì)則與案例分析
- 2026年環(huán)境工程師認(rèn)證試題污染治理與生態(tài)保護(hù)
- 2026年電子電路設(shè)計(jì)與分析數(shù)字信號(hào)處理題庫(kù)
- 2026年人工智能技術(shù)與應(yīng)用考試題集
- 2026年社會(huì)學(xué)理論在現(xiàn)實(shí)中的應(yīng)用社會(huì)問(wèn)題調(diào)研實(shí)踐題集
- 2026年山東藥品食品職業(yè)學(xué)院?jiǎn)握芯C合素質(zhì)考試備考試題含詳細(xì)答案解析
- GB/T 46878-2025二氧化碳捕集、運(yùn)輸和地質(zhì)封存地質(zhì)封存
- 雷波縣糧油貿(mào)易總公司 2026年面向社會(huì)公開(kāi)招聘?jìng)淇伎荚囋囶}及答案解析
- 2026年1月浙江省高考(首考)歷史試題(含答案)
- 療養(yǎng)院?jiǎn)T工勞動(dòng)保護(hù)制度
- 2026浙江溫州市蒼南縣城市投資集團(tuán)有限公司招聘19人考試參考試題及答案解析
- 2026年廣州中考化學(xué)創(chuàng)新題型特訓(xùn)試卷(附答案可下載)
- 2025司法鑒定人資格考試考點(diǎn)試題及答案
- 保健用品生產(chǎn)管理制度
- 檔案計(jì)件工資管理制度
- 浙江省杭州市拱墅區(qū)2024-2025學(xué)年八年級(jí)上學(xué)期語(yǔ)文期末試卷(含答案)
評(píng)論
0/150
提交評(píng)論