2023年全國碩士研究生考試考研英語一試題真題(含答案詳解+作文范文)_第1頁
已閱讀1頁,還剩26頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、<p>  操作系統(tǒng)課程設(shè)計(jì)說明書</p><p>  題 目:GeekOS操作系統(tǒng)的研究與實(shí)現(xiàn)</p><p>  系 別: 計(jì)算機(jī)科學(xué)與工程學(xué)院 </p><p><b>  目錄</b></p><p>  1 GeekOS概述3</p><p>  1.1

2、GeekOS系統(tǒng)源代碼結(jié)構(gòu)3</p><p><b>  2 實(shí)驗(yàn)環(huán)境5</b></p><p><b>  3 項(xiàng)目實(shí)現(xiàn)5</b></p><p>  3.1 project05</p><p>  3.11項(xiàng)目設(shè)計(jì)目的5</p><p>  3.12項(xiàng)目設(shè)計(jì)要求

3、5</p><p>  3.13項(xiàng)目設(shè)計(jì)原理5</p><p>  3.13項(xiàng)目具體實(shí)現(xiàn)6</p><p>  3.14調(diào)試運(yùn)行結(jié)果7</p><p>  3.2 project18</p><p>  3.21項(xiàng)目設(shè)計(jì)目的8</p><p>  3.22項(xiàng)目設(shè)計(jì)要求8</p

4、><p>  3.23項(xiàng)目設(shè)計(jì)原理9</p><p>  3.23項(xiàng)目具體實(shí)現(xiàn)10</p><p>  3.24調(diào)試運(yùn)行結(jié)果11</p><p>  3.3 project212</p><p>  3.31項(xiàng)目設(shè)計(jì)目的12</p><p>  3.32項(xiàng)目設(shè)計(jì)要求12</p>

5、;<p>  3.33項(xiàng)目設(shè)計(jì)原理13</p><p>  3.23項(xiàng)目具體實(shí)現(xiàn)15</p><p>  3.24調(diào)試運(yùn)行結(jié)果25</p><p>  4 遇到問題及解決方法26</p><p><b>  5 學(xué)習(xí)總結(jié)27</b></p><p><b>  參

6、考文獻(xiàn)27</b></p><p>  1 GeekOS概述</p><p>  GeekOS是一個(gè)基于X86架構(gòu)的PC上運(yùn)行的微操作系統(tǒng)內(nèi)核。由美國馬理蘭大學(xué)的教師開發(fā),是一個(gè)用C語言開發(fā)的操作系統(tǒng)。主要用于操作系統(tǒng)課程設(shè)計(jì),目的是使學(xué)生能夠?qū)嶋H動(dòng)手參與到一個(gè)操作系統(tǒng)的開發(fā)工作中。出于教學(xué)目的,這個(gè)系統(tǒng)內(nèi)核設(shè)計(jì)簡(jiǎn)單,卻又兼?zhèn)鋵?shí)用性,它可以運(yùn)行在真正的X86 PC硬件平臺(tái)。作

7、為一個(gè)課程設(shè)計(jì)平臺(tái),GeekOS由一個(gè)基本的操作系統(tǒng)內(nèi)核作為基礎(chǔ),提供了操作系統(tǒng)與硬件之間的所有必備接口,實(shí)現(xiàn)了系統(tǒng)引導(dǎo)、實(shí)模式到保護(hù)模式的轉(zhuǎn)換、中斷調(diào)用及異常處理、基于段式的內(nèi)存管理,F(xiàn)IFO進(jìn)程調(diào)度算法以及內(nèi)核進(jìn)程、基本的輸入輸出(鍵盤作為輸入設(shè)備、顯示器作為輸出設(shè)備),以及一個(gè)用于存放用戶程序的只讀文件系統(tǒng)PFAT。學(xué)生可以在Linux或Unix環(huán)境下對(duì)其進(jìn)行功能擴(kuò)充,且其針對(duì)進(jìn)程、文件系統(tǒng)、存儲(chǔ)管理等操作系統(tǒng)核心內(nèi)容分別設(shè)計(jì)了7

8、個(gè)難度逐漸增加的項(xiàng)目供學(xué)生選擇 </p><p>  1.1GeekOS系統(tǒng)源代碼結(jié)構(gòu) </p><p>  GeekOS操作系統(tǒng)源文件geekos-0.3.0.zip可以從http://geekos.sourceforge.net下載。解壓后的GeekOS目錄結(jié)構(gòu)如圖1-3所示:</p><p>  在doc目錄下文件hacking.pdf和index.htm是G

9、eekOS系統(tǒng)的參考文檔。Scripts目錄下有startProject和removeEmptyConflicts兩個(gè)腳本文件。GeekOS系統(tǒng)的源文件在src目錄下,分為7個(gè)項(xiàng)目:Project0, Project1, Project2, Project3, Project4, Project5, Project6。每個(gè)項(xiàng)目的文件結(jié)構(gòu)都類似,以Project0為例,結(jié)構(gòu)如圖1-4所示:</p><p>  在b

10、uild文件夾中,包含系統(tǒng)編譯后的可執(zhí)行文件的文件、軟盤鏡像或是硬盤鏡像、makefile項(xiàng)目管理文件。在inculde文件夾中有g(shù)eekOS和libc兩個(gè)子目錄,在geekOS子目錄中有kthread.h,keyboard.h等頭文件,在libc中包含有g(shù)eekOS支持的C語言標(biāo)準(zhǔn)函數(shù)string.H頭文件。在scripts文件夾是項(xiàng)目編譯時(shí)要用到的一些腳本文件。Src文件夾中存放系統(tǒng)內(nèi)核源代碼,用戶修改geekOS系統(tǒng)時(shí)要修改的源代

11、碼如main.c都位于這個(gè)目錄中。在User子目錄中一般是用來存放用戶的測(cè)試文件,在tools子目錄中的代碼是用來建立PFAT測(cè)試文件系統(tǒng)的。</p><p><b>  2 實(shí)驗(yàn)環(huán)境</b></p><p> ?。?)硬件環(huán)境:本次課設(shè)是在虛擬機(jī)上安裝Linux進(jìn)行開發(fā)調(diào)試,具體安裝使用方法如下: <1>、安裝linux虛擬機(jī) 本次課設(shè)的虛擬機(jī)是運(yùn)行在o

12、racle VM Virtualbox上的,下載Linux鏡像文件后,即可按提示即可安裝。 </p><p>  <2>、GeekOS:是一個(gè)基于X86架構(gòu)的PC機(jī)上運(yùn)行的微操作系統(tǒng)內(nèi)核,由美國 馬理蘭大學(xué)的教師開發(fā),是一個(gè)用C語言開發(fā)的操作系統(tǒng), GeekOS主要 用于操作系統(tǒng)課程設(shè)計(jì),目的是使學(xué)生能夠?qū)嶋H動(dòng)手參與到一個(gè)操作系統(tǒng)的 開發(fā)工作中。 GeekOS的使用:打開linux虛擬機(jī),直接解壓G

13、eekOS壓縮包就可使用, 無需安裝。</p><p>  <3>、Bochs安裝和使用:在Linux系統(tǒng)中需先解壓軟件包,然后再配置編譯生成系統(tǒng)文件。</p><p> ?。?)軟件環(huán)境:標(biāo)準(zhǔn)C語言</p><p><b>  3 項(xiàng)目實(shí)現(xiàn)</b></p><p>  3.1 project0</p&

14、gt;<p>  3.11項(xiàng)目設(shè)計(jì)目的</p><p>  熟悉GeekOS的項(xiàng)目編譯、調(diào)試和運(yùn)行環(huán)境,掌握GeekOS運(yùn)行工作過程。</p><p>  3.12項(xiàng)目設(shè)計(jì)要求</p><p> ?。?)搭建GeekOS的編譯和調(diào)試平臺(tái),掌握GeekOS的內(nèi)核進(jìn)程工作原理。</p><p> ?。?)熟悉鍵盤操作函數(shù),編程實(shí)現(xiàn)一

15、個(gè)內(nèi)核進(jìn)程。該進(jìn)程的功能是:接受鍵盤輸入的字符并顯示到屏幕上,當(dāng)輸入Ctrl+D時(shí),結(jié)束進(jìn)程的運(yùn)行。</p><p>  3.13項(xiàng)目設(shè)計(jì)原理</p><p>  項(xiàng)目要求從鍵盤輸入,因此要用到鍵盤處理函數(shù) 。GeekOS的鍵盤處理函數(shù)定義在keyboard.h與keyboard.c 文件中。鍵盤的初始化是在Main函數(shù)中調(diào)用Init_Keyboard進(jìn)行的,Init_Keyboard主要

16、功能是設(shè)置初始狀態(tài)下存放鍵盤掃描碼的緩沖區(qū),并為鍵盤中斷設(shè)置處理函數(shù)。而鍵盤中斷處理過程是:首先從相應(yīng)的I/O端口讀取鍵盤掃描碼,根據(jù)是否按下Shift鍵,分別在鍵值表中尋找掃描碼對(duì)應(yīng)的按鍵值,經(jīng)過處理后將鍵值放入鍵盤緩沖區(qū),最后通知系統(tǒng)重新調(diào)度進(jìn)程。若用戶進(jìn)程需要從鍵盤輸入信息,可調(diào)用Wait_For_Key()函數(shù),進(jìn)程調(diào)用該函數(shù)后,會(huì)阻塞進(jìn)入按鍵操作的等待隊(duì)列,直到按鍵操作結(jié)束,進(jìn)程才會(huì)被喚醒。Start_Kernel_Threa

17、d函數(shù)主要功能就是建立一個(gè)內(nèi)核線程。</p><p>  本項(xiàng)目主要要求設(shè)計(jì)一個(gè)函數(shù)對(duì)鍵盤的中斷進(jìn)行響應(yīng)。這主要通過使用Geekos提供的鍵盤響應(yīng)函數(shù)Wait_For_Key()進(jìn)行鍵盤中斷的響應(yīng)及返回鍵值。該函數(shù)首先檢查鍵盤緩沖區(qū)是否有按鍵,如果有,就讀取一個(gè)鍵碼,如果此時(shí)鍵盤緩沖區(qū)中沒有按鍵,就將線程放入鍵盤事件等待隊(duì)列。于是可分兩步完成:</p><p>  1 編寫函數(shù),函數(shù)功能是

18、:接受鍵盤輸入的按鍵,并將鍵值顯示到顯示器,當(dāng)輸入Ctrl+D退出。</p><p>  2 在Main函數(shù)體內(nèi)調(diào)用Start_User_Thread函數(shù),將編寫的函數(shù)地址傳遞給startFunc,建立一個(gè)內(nèi)核進(jìn)程。</p><p>  3.13項(xiàng)目具體實(shí)現(xiàn)</p><p><b>  編寫的函數(shù)</b></p><p>

19、;  static void keyin(void){ Keycode keycode;Print("\n--------Wait for your input,Ctrl+d to exit--------\n");while(1){keycode=Wait_For_Key(); //讀取鍵盤按鍵狀態(tài)if(!( (keycode & 0x0100) || (keycode & 0x800

20、0)) ) //處理非特殊按鍵的按下事件{ int asciiCode = keycode & 0x03ff; //低8位為Ascii碼if( (keycode & 0x4000)==0x4000 && asciiCode=='d') //按下Ctrl鍵{Print("\n-----------------Bye-----------------\n");E

21、xit(1); }else{Print("%c",(asciiCode=='\r') ? '\n' : asciiCode);}} }}</p><p>  (2) 首先注釋Main()函數(shù)中TODO宏,并調(diào)用Start_Kernel_Thread函數(shù),將步驟1編寫的函數(shù)地址傳遞給參數(shù),建立一個(gè)內(nèi)核級(jí)進(jìn)程</p><p>

22、  struct Kernel_Thread *thread; thread = Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,false);</p><p>  (3) 執(zhí)行make depend及make命令,此時(shí)會(huì)在build目錄下生成fd.img</p><p>  (4) 編寫brochs 配置文件</p&g

23、t;<p>  vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest</p><p>  romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000</p><p><b>  megs: 8</b></p>&

24、lt;p><b>  boot: a</b></p><p>  floppya: 1_44=fd.img, status=inserted</p><p>  #floppya: 1_44=fd_aug.img, status=inserted</p><p>  log: ./bochs.out</p><p>

25、;  keyboard_serial_delay: 200</p><p>  floppy_command_delay: 500</p><p>  vga_update_interval: 300000</p><p>  ips: 1000000</p><p>  mouse: enabled=0</p><p&

26、gt;  private_colormap: enabled=0</p><p>  i440fxsupport: enabled=0</p><p>  3.14調(diào)試運(yùn)行結(jié)果</p><p>  進(jìn)入/os/ project0/build目錄</p><p>  執(zhí)行 make depend</p><p><

27、b>  執(zhí)行 make</b></p><p>  成功之后在build 目錄下生成fd.img文件。</p><p><b>  啟動(dòng)bochs</b></p><p>  在build目錄中執(zhí)行</p><p>  bochs –f bochsrc</p><p><b

28、>  成功后,運(yùn)行結(jié)果:</b></p><p>  3.2 project1</p><p>  3.21項(xiàng)目設(shè)計(jì)目的</p><p>  熟悉ELF文件格式,了解GeekOS系統(tǒng)如何將ELF格式的用戶可執(zhí)行程序裝入內(nèi)存,建立內(nèi)核進(jìn)程并運(yùn)行的實(shí)現(xiàn)技術(shù)。</p><p>  3.22項(xiàng)目設(shè)計(jì)要求</p><

29、;p>  (1)修改/geekos/elf.c文件:在函數(shù)Parse_ELF_Executable()中添加代碼,分析ELF格式的可執(zhí)行文件(包括分析得出ELF文件頭、程序頭,獲取可執(zhí)行文件長度,代碼段、數(shù)據(jù)段等信息),并填充Exe_Format數(shù)據(jù)結(jié)構(gòu)的域值。</p><p>  (2)掌握GeekOS在核心態(tài)運(yùn)行用戶程序的原理,為項(xiàng)目2的實(shí)現(xiàn)做準(zhǔn)備。</p><p>  3.23

30、項(xiàng)目設(shè)計(jì)原理</p><p>  ELF是UNIX系統(tǒng)實(shí)驗(yàn)室作為應(yīng)用程序二進(jìn)制接口而開發(fā)和發(fā)布的。有兩個(gè)平行視圖。</p><p>  GeekOS中的用戶程序全部在系統(tǒng)的編譯階段完成編譯和連接,形成可執(zhí)行文件,用戶可執(zhí)行文件保存在PFAT文件系統(tǒng)中。本項(xiàng)目要完成的就是在系統(tǒng)啟動(dòng)后,從PFAT文件系統(tǒng)將可執(zhí)行文件裝入內(nèi)存,建立進(jìn)程并運(yùn)行得到相應(yīng)的輸出。在磁盤中的ELF文件的映像和在內(nèi)存中執(zhí)

31、行程序鏡像間的對(duì)應(yīng)關(guān)系如下圖所示</p><p>  而此過程主要由Spawner函數(shù)實(shí)現(xiàn),其主要經(jīng)過簡(jiǎn)要概述為:先調(diào)用Read_Fully函數(shù)將文件讀入內(nèi)存,后調(diào)用Parse_ELF_Executable函數(shù)分析ELF文件,最后調(diào)用Spawn_Program函數(shù)將可執(zhí)行程序的代碼段和數(shù)據(jù)段等裝入內(nèi)存,此后便可以開始運(yùn)行一個(gè)內(nèi)核級(jí)進(jìn)程了。如下圖所示:</p><p>  在本項(xiàng)目中,我們要

32、完成Parse_ELF_Executable函數(shù),此函數(shù)的作用為根據(jù)ELF文件格式,從exeFileData指向的內(nèi)容中得到ELF文件頭,繼續(xù)分析可得到程序頭和程序代碼段等信息。</p><p>  3.23項(xiàng)目具體實(shí)現(xiàn)</p><p>  修改project/project1/src/geekos/elf.c文件:在函數(shù)Parse_ELF_Executable( )中添加代碼,分析 &l

33、t;/p><p>  ELF格式的可執(zhí)行文件(包括分析得出ELF文件頭、程序頭,獲取可執(zhí)行文</p><p>  件長度,代碼段、數(shù)據(jù)段等信息),并填充Exe_Format數(shù)據(jù)結(jié)構(gòu)中的域值</p><p>  1、elf.c:將ELF格式的可執(zhí)行程序裝入到內(nèi)存,建立內(nèi)核進(jìn)程并運(yùn)行.</p><p>  ================== elf

34、.c ====================</p><p>  int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat)</p><p><b>  {</b></p><p><b>  int

35、 i;</b></p><p>  elfHeader *head=(elfHeader*)exeFileData;</p><p>  programHeader *proHeader=(programHeader *)(exeFileData+head->phoff);</p><p>  KASSERT(exeFileData!=NULL);

36、</p><p>  KASSERT(exeFileLength>head->ehsize+head->phentsize*head->phnum);</p><p>  KASSERT(head->entry%4==0);</p><p>  exeFormat->numSegments=head->phnum;</

37、p><p>  exeFormat->entryAddr=head->entry;</p><p>  for(i=0;i<head->phnum;i++)</p><p><b>  {</b></p><p>  exeFormat->segmentList[i].offsetInFile=

38、proHeader->offset;</p><p>  exeFormat->segmentList[i].lengthInFile=proHeader->fileSize;</p><p>  exeFormat->segmentList[i].startAddress=proHeader->vaddr;</p><p>  exe

39、Format->segmentList[i].sizeInMemory=proHeader->memSize;</p><p>  exeFormat->segmentList[i].protFlags=proHeader->flags;</p><p>  proHeader++;</p><p><b>  }</b>

40、;</p><p><b>  return 0;</b></p><p><b>  }</b></p><p>  =========================================</p><p>  2、編譯,成功后生成兩個(gè)鏡像文件:fd.img和diskc.img。其中,D

41、iskc.img為模擬器能引導(dǎo)的操作系統(tǒng)鏡像 。</p><p>  3、編寫相應(yīng)的bochs配置文件</p><p>  由于生成了diskc.img,因此配置文件需加上以下內(nèi)容</p><p>  config_interface: textconfig</p><p><b>  megs: 8</b></p

42、><p>  vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest</p><p>  romimage: file=$BXSHARE/BIOS-bochs-latest</p><p>  floppya: 1_44=./fd.img, status=inserted</p><p>  ata0: en

43、abled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14</p><p>  ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15</p><p>  #ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11</p><p> 

44、 #ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9</p><p>  ata0-master: type=disk, path="diskc.img", mode=flat, cylinders=40, heads=8, spt=64</p><p>  #ata0-slave: type=cdrom, pat

45、h="/dev/cdrom", status=inserted</p><p><b>  boot: a</b></p><p>  ips: 1000000</p><p>  log:./bochs.out</p><p>  vga_update_interval: 300000</p&

46、gt;<p>  keyboard_serial_delay: 250</p><p>  keyboard_paste_delay: 100000</p><p>  private_colormap: enabled=0 </p><p><b>  }</b></p><p>  3.24調(diào)試運(yùn)行結(jié)果

47、</p><p>  進(jìn)入/os/ project1/build目錄</p><p>  執(zhí)行 make depend</p><p><b>  執(zhí)行 make</b></p><p>  成功之后在build 目錄下生成fd.img、diskc.img文件。</p><p><b>

48、  啟動(dòng)bochs</b></p><p>  在build目錄中執(zhí)行</p><p><b>  成功后,運(yùn)行結(jié)果:</b></p><p>  3.3 project2</p><p>  3.31項(xiàng)目設(shè)計(jì)目的</p><p>  擴(kuò)充GeekOS操作系統(tǒng)內(nèi)核,使得系統(tǒng)能夠支持用戶

49、級(jí)進(jìn)程的動(dòng)態(tài)創(chuàng)建和執(zhí)行。</p><p>  3.32項(xiàng)目設(shè)計(jì)要求</p><p>  開始本項(xiàng)目前需要閱讀/src/geekos目錄中的entry.c、lowlevel.asm、kthread.c、userseg.c,其中在userseg.c中主要關(guān)注Destroy_User_Context()和Load_User_Program()兩個(gè)函數(shù)。本項(xiàng)目要求用戶對(duì)以下幾個(gè)文件進(jìn)行修改:<

50、;/p><p>  1)“src/GeekOS/user.c”文件中的函數(shù)Spawn(),其功能是生成一個(gè)新的用戶級(jí)進(jìn)程;</p><p>  2)“src/GeekOS/user.c”文件中的函數(shù)Switch_To_User_Context(),調(diào)度程序在執(zhí)行一個(gè)新的進(jìn)程前調(diào)用該函數(shù)以切換用戶地址空間;</p><p>  3)“src/GeekOS/elf.c”文件

51、中的函數(shù)Parse_ELF_Executable()。該函數(shù)的實(shí)現(xiàn)要求和項(xiàng)目1相同。</p><p>  4)“src/GeekOS/userseg.c”文件中主要是實(shí)現(xiàn)一些為實(shí)現(xiàn)對(duì)“src/GeekOS/user.c”中高層操作支持的函數(shù)。 Destroy_User_Context()函數(shù)的功能是釋放用戶態(tài)進(jìn)程占用的內(nèi)存資源。 Load_User_Program()函數(shù)的功能通過加載可執(zhí)行文件鏡像創(chuàng)建新進(jìn)程的U

52、ser_Context結(jié)構(gòu)。 Copy_From_User()和Copy_To_User()函數(shù)的功能是在用戶地址空間和內(nèi)核地址空間之間復(fù)制數(shù)據(jù),在分段存儲(chǔ)器管理模式下,只要段有效,調(diào)用memcpy函數(shù)就可以實(shí)現(xiàn)這兩個(gè)函數(shù)的功能。 Switch_To_Address_Space()函數(shù)的功能是通過將進(jìn)程的LDT裝入到LDT寄存器來激活用戶的地址空間;</p><p>  5)“src/GeekOS/kthread

53、.c”文件中的Start_User_Thread函數(shù)和Setup_User_Thread函數(shù)。 Setup_User_Thread()函數(shù)的功能是為進(jìn)程初始化內(nèi)核堆棧,堆棧中是為進(jìn)程首次進(jìn)入用戶態(tài)運(yùn)行時(shí)設(shè)置處理器狀態(tài)要使用的數(shù)據(jù)。 Start_User_Thread()是一個(gè)高層操作,該函數(shù)使用User_Context對(duì)象開始一個(gè)新進(jìn)程。</p><p>  6)“src/GeekOS/kthread.c”文件中

54、主要是實(shí)現(xiàn)用戶程序要求內(nèi)核進(jìn)行服務(wù)的一些系統(tǒng)調(diào)用函數(shù)定義。要求用戶實(shí)現(xiàn)的有Sys_Exit()函數(shù)、Sys_PrintString()函數(shù)、Sys_GetKey()、Sys_SetAttr()、Sys_GetCursor()、Sys_PutCursor()、Sys_Spawn()函數(shù)、Sys_Wait()函數(shù)和Sys_GetPID( )函數(shù)。</p><p>  7)在main.c文件中改寫生成第一個(gè)用戶態(tài)進(jìn)程的

55、函數(shù)調(diào)用:Spawn_Init_Process(void) 。</p><p>  3.33項(xiàng)目設(shè)計(jì)原理</p><p>  Geekos的初始系統(tǒng)不支持用戶態(tài)進(jìn)程,但提供了用戶態(tài)進(jìn)程上下文接口和實(shí)現(xiàn)用戶態(tài)進(jìn)程需要用到的數(shù)據(jù)結(jié)構(gòu)。所以,用戶態(tài)進(jìn)程及相關(guān)函數(shù)都要開發(fā)者實(shí)現(xiàn)。在Geekos中為了區(qū)分用戶態(tài)進(jìn)程和內(nèi)核進(jìn)程,在Kernel_Thread結(jié)構(gòu)體中設(shè)置了一個(gè)字段userContext,

56、指向用戶態(tài)進(jìn)程上下文。對(duì)于內(nèi)核進(jìn)程來說,這個(gè)指針為空,而用戶態(tài)進(jìn)程都擁有自己的用戶上下文。因此在Geekos中要判斷一個(gè)進(jìn)程是內(nèi)核進(jìn)程還是用戶態(tài)進(jìn)程,只要通過userContext字段是否為空來判斷就可以了。GeekOS的進(jìn)程結(jié)構(gòu)圖如10-1所示:</p><p>  圖10.1 用戶態(tài)進(jìn)程結(jié)構(gòu)</p><p>  每個(gè)用戶態(tài)進(jìn)程都擁有屬于自己的內(nèi)存段空間,如:代碼段、數(shù)據(jù)段、堆棧段等,

57、每個(gè)段有一個(gè)段描述符(segment descriptor),并且每個(gè)進(jìn)程有一個(gè)段描述符表(Local Descriptor Table),用于保存該進(jìn)程的所有段描述符。操作系統(tǒng)中還設(shè)置一個(gè)全局描述符表(GDT,Global Descriptor Table),用于記錄了系統(tǒng)中所有進(jìn)程的ldt描述符。GDT、LDT和User_Context的關(guān)系如圖10-2所示</p><p>  圖10-2 GDT、LDT和U

58、ser_Context的關(guān)系</p><p><b>  程序流程圖:</b></p><p>  GeekOS的用戶級(jí)進(jìn)程創(chuàng)建過程可以描述如下:</p><p>  (1)Spawn函數(shù)導(dǎo)入用戶程序并初始化:調(diào)用Load_User_Program進(jìn)行User_Context的初始化及用戶級(jí)進(jìn)程空間的分配及用戶程序各段的裝入;</p>

59、;<p>  (2)Spawn函數(shù)調(diào)用Start_User_Thread(),初始化一個(gè)用戶態(tài)進(jìn)程,包括初始化進(jìn)程Kernel_Thread結(jié)構(gòu)以及調(diào)用Setup_User_Thread初始化用戶級(jí)進(jìn)程內(nèi)核堆棧;</p><p>  (3)最后Spawn函數(shù)退出,這時(shí)用戶級(jí)進(jìn)程已被添加至系統(tǒng)運(yùn)行進(jìn)程隊(duì)列,可以被調(diào)度了。</p><p>  3.23項(xiàng)目具體實(shí)現(xiàn)</p&g

60、t;<p><b>  1、添加代碼</b></p><p>  ================== user.c ===============</p><p>  //產(chǎn)生一個(gè)進(jìn)程(用戶態(tài))</p><p>  int Spawn(const char *program, const char *command, stru

61、ct Kernel_Thread **pThread)</p><p><b>  {</b></p><p>  //TODO("Spawn a process by reading an executable from a filesystem"); int rc; //標(biāo)記各函數(shù)的返回值,為0則表示成功,否則失敗 char *exeFi

62、leData = 0;//保存在內(nèi)存緩沖中的用戶程序可執(zhí)行文件 ulong_t exeFileLength;//可執(zhí)行文件的長度 struct User_Context *userContext = 0;//指向User_Conetxt的指針 struct Kernel_Thread *process = 0;//指向Kernel_Thread *pThread的指針 struct Exe_Format exeFormat;//

63、調(diào)用Parse_ELF_Executable函數(shù)得到的可執(zhí)行文件信息 if ((rc = Read_Fully(program, (void**) &exeFileData, &exeFileLength)) != 0 ) {//調(diào)用Read_Fully函數(shù)將名為program的可執(zhí)行文件全部讀入內(nèi)存緩沖區(qū) Print</p><p><b>  }</b></

64、p><p>  -------------------------------------</p><p>  //切換至用戶上下文</p><p>  void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state)</p><p&g

65、t;  { //TODO("Switch to a new user address space, if necessary"); static struct User_Context* s_currentUserContext; /* last user context used */ //extern int userDebug; struct User_Context* userContext

66、= kthread->userContext;//指向User_Conetxt的指針,并初始化為準(zhǔn)備切換的進(jìn)程 KASSERT(!Interrupts_Enabled()); if (userContext == 0) { //userContext為0表示此進(jìn)程為核心態(tài)進(jìn)程就不用切換地址空間 return; } if (userContext != s_currentUserContext) { ulong_t

67、 esp0; //if (userDebug) Print("A[%p]\n", kthread); Switch_To_Address_Spac</p><p><b>  } </b></p><p>  ================== elf.c ====================同 project1</p>

68、<p>  =================== userseg.c ===================</p><p>  //需在此文件各函數(shù)前增加一個(gè)函數(shù),此函數(shù)的功能是按給定的大小創(chuàng)建一個(gè)用戶級(jí)進(jìn)程上下文,具體實(shí)現(xiàn)如下://函數(shù)功能:按給定的大小創(chuàng)建一個(gè)用戶級(jí)進(jìn)程上下文static struct User_Context* Create_User_Context(ulong_t s

69、ize){ struct User_Context * UserContext; size = Round_Up_To_Page(size); UserContext = (struct User_Context *)Malloc(sizeof(struct User_Context)); //為用戶態(tài)進(jìn)程 if (UserContext != 0) UserContext->m

70、emory = Malloc(size); //為核心態(tài)進(jìn)程 else goto fail; //內(nèi)存為空 if (0 == UserContext->memory) goto fail; memset(UserContex</p><p>  --------------------------------------------&l

71、t;/p><p><b>  //摧毀用戶上下文</b></p><p>  void Destroy_User_Context(struct User_Context* userContext)</p><p>  { //TODO("Destroy a User_Context");</p><p

72、>  //釋放占用的LDT Free_Segment_Descriptor(userContext->ldtDescriptor); userContext->ldtDescriptor=0; //釋放內(nèi)存空間 Free(userContext->memory); userContext->memory=0; //釋放userContext本身占用的內(nèi)

73、存 Free(userContext); userContext=0;}</p><p>  ----------------------------------------------int Load_User_Program(char *exeFileData, ulong_t exeFileLength,struct Exe_Format *exeFormat, const char *

74、command, struct User_Context **pUserContext){ //TODO("Load a user executable into a user memory space using segmentation"); int i; ulong_t maxva = 0;//要分配的最大內(nèi)存空間 unsigned numArgs;//進(jìn)程數(shù)目 ulong_t argB

75、lockSize;//參數(shù)塊的大小 ulong_t size, argBlockAddr;//參數(shù)塊地址 struct User_Context *userContext = 0;</p><p>  //計(jì)算用戶態(tài)進(jìn)程所需的最大內(nèi)存空間 for (i = 0; i < exeFormat->numSegments; ++i) { //elf.h struct Exe_Segment *

76、segment = &exeFormat->segmentList[i]; ulong_t topva = segment->startAddress + segment->sizeInMemory; /* FIXME: range check */ if (topva > maxva) maxva = topva; } Get_Argument_Block_Size(command,

77、 &numArgs, &argBlockSize);//獲取參數(shù)塊信息 size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE;//用戶進(jìn)程大小=參數(shù)塊總大小 + 進(jìn)程堆棧大小(8192) argBlockAddr = size; size += argBlockSize; userContext = Create_User_</p><

78、;p>  ----------------------------------------------</p><p>  //將用戶態(tài)的進(jìn)程復(fù)制到內(nèi)核緩沖區(qū)</p><p>  bool Copy_From_User(void* destInKernel, ulong_t srcInUser, ulong_t bufSize)</p><p>  {

79、 //TODO("Copy memory from user buffer to kernel buffer"); struct User_Context * UserContext = g_currentThread->userContext;</p><p>  //--: check if memory if validated if (!Validate_User_Memo

80、ry(UserContext,srcInUser, bufSize)) return false;</p><p>  //--:user->kernel memcpy(destInKernel, UserContext->memory + srcInUser, bufSize); return true;}</p><p>  ---------------

81、--------------------------</p><p>  //將內(nèi)核態(tài)的進(jìn)程復(fù)制到用戶態(tài)</p><p>  bool Copy_To_User(ulong_t destInUser, void* srcInKernel, ulong_t bufSize)</p><p>  { //TODO("Copy memory from

82、kernel buffer to user buffer") struct User_Context * UserContext = g_currentThread->userContext;</p><p>  //--: check if memory if validated if (!Validate_User_Memory(UserContext, destInUser, bufS

83、ize)) return false; //--:kernel->user memcpy(UserContext->memory + destInUser, srcInKernel, bufSize);</p><p>  return true;}</p><p>  ----------------------------------------</p&

84、gt;<p>  //切換到用戶地址空間</p><p>  void Switch_To_Address_Space(struct User_Context *userContext){ //TODO("Switch to user address space using segmentation/LDT"); ushort_t ldtSelector= userCo

85、ntext->ldtSelector;/* Switch to the LDT of the new user context */ __asm__ __volatile__ ("lldt %0"::"a"(ldtSelector));</p><p><b>  }</b></p><p>  ============

86、===== kthread.c ===============</p><p>  添加頭文件 #include <geekos/user.h></p><p>  ----------------------------------</p><p>  //創(chuàng)建一個(gè)用戶進(jìn)程</p><p>  /*static*/ void S

87、etup_User_Thread(struct Kernel_Thread* kthread, struct User_Context* userContext){ //TODO("Create a new thread to execute in user mode"); ulong_t eflags = EFLAGS_IF; unsigned csSelector=userContext-

88、>csSelector;//CS選擇子 unsigned dsSelector=userContext->dsSelector;//DS選擇子 Attach_User_Context(kthread, userContext); //初始化用戶態(tài)進(jìn)程堆棧,使之看上去像剛被中斷運(yùn)行一樣 //分別調(diào)用Push函數(shù)將以下數(shù)據(jù)壓入堆棧 Push(kthread, dsSelector);

89、 //數(shù)據(jù)選擇子 Push(kthread, userContext->stackP</p><p>  //開始用戶進(jìn)程struct Kernel_Thread* Start_User_Thread(struct User_Context* userContext, bool detached){ //TODO("Start user thread&qu

90、ot;); struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached); //為用戶態(tài)進(jìn)程 if (kthread != 0){ Setup_User_Thread(kthread, userContext); Make_Runnable_Atomic(kthread); } return kthread;</p><

91、p><b>  }</b></p><p>  ================ syscall.c =================</p><p>  //需在此文件別的函數(shù)前增加一個(gè)函數(shù),函數(shù)名為Copy_User_String,它被函數(shù)Sys_PrintString調(diào)用,具體實(shí)現(xiàn)如下:static int Copy_User_String(ulong

92、_t uaddr, ulong_t len, ulong_t maxLen, char **pStr){ int rc = 0; char *str; if (len > maxLen){ //超過最大長度 return EINVALID; } str = (char*) Malloc(len+1); //為字符串分配空間 if (0 == str){

93、 rc = ENOMEM; goto fail; } if (!Copy_From_User(str, uaddr, len)){ //從用戶空間中復(fù)制數(shù)據(jù) rc = EINVALID; Free(str); goto fail; } str[len] = '</p><p>  -------------

94、----------------------------</p><p>  static int Sys_Exit(struct Interrupt_State* state){ //TODO("Exit system call"); Exit(state->ebx);</p><p><b>  }</b></p>

95、<p>  -----------------------------------------</p><p>  static int Sys_PrintString(struct Interrupt_State* state){ //TODO("PrintString system call"); int rc = 0;//返回值 uint_t length = s

96、tate->ecx;//字符串長度 uchar_t* buf = 0; if (length > 0) {/* Copy string into kernel. 將字符串復(fù)制到內(nèi)核*/ if ((rc = Copy_User_String(state->ebx, length, 1023, (char**) &buf)) != 0) goto done;/* Write to console.

97、 將字符串打印到屏幕 */ Put_Buf(buf, length); }done: if (buf != 0) Free(buf); return rc;}</p><p>  ----------------------------------------------</p><p>  static int Sys_GetKey(struct Interru

98、pt_State* state){ //TODO("GetKey system call"); return Wait_For_Key(); //返回按鍵碼keyboard.c/Wait_For_Key()</p><p><b>  }</b></p><p>  ------------------------------------

99、---------static int Sys_SetAttr(struct Interrupt_State* state){ //TODO("SetAttr system call"); Set_Current_Attr((uchar_t) state->ebx); return 0;</p><p><b>  }</b></p>&

100、lt;p>  ---------------------------------------------</p><p>  static int Sys_GetCursor(struct Interrupt_State* state){ //TODO("GetCursor system call"); int row, col; Get_Cursor(&row, &

101、amp;col); if (!Copy_To_User(state->ebx, &row, sizeof(int)) ||!Copy_To_User(state->ecx, &col, sizeof(int))) return -1; return 0;</p><p><b>  }</b></p><p>  ---------

102、--------------------------------------</p><p>  static int Sys_PutCursor(struct Interrupt_State* state){ //TODO("PutCursor system call"); return Put_Cursor(state->ebx, state->ecx) ? 0 :

103、-1;</p><p><b>  }</b></p><p>  -----------------------------------------------static int Sys_Spawn(struct Interrupt_State* state){ //TODO("Spawn system call"); int

104、 rc; //函數(shù)返回值 char *program = 0; //進(jìn)程名稱 char *command = 0; //用戶命令 struct Kernel_Thread *process;/* Copy program name and command from user space. */ if ((rc = Copy_User_String(state-&g

105、t;ebx, state->ecx, VFS_MAX_PATH_LEN, &program)) != 0) {//從用戶空間復(fù)制進(jìn)程名稱 goto fail; } if(rc = Copy_User_String(state->edx, state->esi, 1023, </p><p>  Enable_Interrupts(); //開中斷 rc = Spawn(pr

106、ogram, command, &process);//得到進(jìn)程名稱和用戶命令后便可生成一個(gè)新進(jìn)程 if (rc == 0) {//若成功則返回新進(jìn)程ID號(hào) KASSERT(process != 0); rc = process->pid; } Disable_Interrupts();//關(guān)中斷fail://返回小于0的錯(cuò)誤代碼 if (program != 0) Free(program); i

107、f (command != 0) Free(command); return rc;</p><p><b>  }</b></p><p>  -----------------------------------------static int Sys_Wait(struct Interrupt_State* state){ //TODO("

108、;Wait system call"); int exitCode; struct Kernel_Thread *kthread = Lookup_Thread(state->ebx); if (kthread == 0) return -12; Enable_Interrupts(); exitCode = Join(kthread); Disable_Interrupts(); return exi

109、tCode;}</p><p>  ---------------------------------------</p><p>  static int Sys_GetPID(struct Interrupt_State* state){ //TODO("GetPID system call"); return g_currentThread->p

110、id;</p><p><b>  }</b></p><p>  ================= main.c ==================static void Spawn_Init_Process(void){ //TODO("Spawn the init process"); struct Kernel_Thr

111、ead *pThread; Spawn("/c/shell.exe","/c/shell.exe",&pThread);</p><p><b>  }</b></p><p>  2、編譯,成功之后生成fd.img和disk.img及depend.mak文件。</p><p>  3、.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫僅提供信息存儲(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)論