操作系統(tǒng)課程設(shè)計(jì)_第1頁
操作系統(tǒng)課程設(shè)計(jì)_第2頁
操作系統(tǒng)課程設(shè)計(jì)_第3頁
操作系統(tǒng)課程設(shè)計(jì)_第4頁
操作系統(tǒng)課程設(shè)計(jì)_第5頁
已閱讀5頁,還剩23頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、 課程設(shè)計(jì)說明書學(xué) 院: 計(jì)算機(jī)科學(xué)與工程學(xué)院 專 業(yè): 計(jì)算機(jī)科學(xué)與技術(shù) 姓 名: 楊天駒 學(xué) 號: 0900310327 指導(dǎo)教師: 黃廷輝 2012年 3 月 5 日操作系統(tǒng)課程設(shè)計(jì)報(bào)告GeekOS操作系統(tǒng)的研究與實(shí)現(xiàn)(項(xiàng)目0-項(xiàng)目2)一、 實(shí)驗(yàn)?zāi)康模菏煜eekOS項(xiàng)目編譯運(yùn)行環(huán)境、核態(tài)進(jìn)程的實(shí)現(xiàn)、用戶態(tài)進(jìn)程的實(shí)現(xiàn)、進(jìn)程調(diào)度策略和算法實(shí)現(xiàn)、分頁存儲管理的實(shí)現(xiàn)和文件系統(tǒng)的實(shí)現(xiàn)等。二、 項(xiàng)目設(shè)計(jì)要求:GeekOS設(shè)計(jì)項(xiàng)目0:1. 搭建GeekOS的編譯和調(diào)試平臺,掌握GeekOS的內(nèi)核進(jìn)程工作原理。2. 熟悉鍵盤操作函數(shù),編程實(shí)現(xiàn)一個(gè)內(nèi)核進(jìn)程。該進(jìn)程的功能是:接受鍵盤輸入的字符并顯示到屏幕

2、上,當(dāng)輸入Ctrl+D時(shí),結(jié)束進(jìn)程的運(yùn)行。GeekOS設(shè)計(jì)項(xiàng)目1:1.修改/geekos/elf.c文件:在函數(shù)Parse_ELF_Executable()中添加代碼,分析ELF格式的可執(zhí)行文件(包括分析得出ELF文件頭、程序頭,獲取可執(zhí)行文件長度、代碼段、數(shù)據(jù)段等信息),并填充Exe_Format數(shù)據(jù)結(jié)構(gòu)中的域值。2.掌握GeekOS在核心態(tài)運(yùn)行用戶程序的原理,為項(xiàng)目2的實(shí)現(xiàn)做準(zhǔn)備。GeekOS設(shè)計(jì)項(xiàng)目2:本項(xiàng)目要求用戶對以下幾個(gè)文件進(jìn)行修改:1. src/GeekOS/user.c文件中的函數(shù)Spawn(),其功能是生成一個(gè)新的用戶級進(jìn)程。2. src/GeekOS/usre.c文件中的函

3、數(shù)Switch_To_User_Context(),調(diào)度程序在執(zhí)行一個(gè)新的進(jìn)程前調(diào)用該函數(shù)以切換用戶地址空間。3. src/GeekOS/elf.c文件中的函數(shù)Parse_ELF_Executable()。該函數(shù)的實(shí)現(xiàn)要求和項(xiàng)目1相同。4. src/GeekOS/userseg.c文件中主要是實(shí)現(xiàn)一些為實(shí)現(xiàn)對src/GeekOS/user.c中高層操作支持的函數(shù)。(1)Destroy_User_Context()函數(shù)的功能是釋放用戶態(tài)進(jìn)程占用的內(nèi)存資源。 (2)Load_User_Program()函數(shù)的功能是通過加載可執(zhí)行文件鏡像創(chuàng)建新進(jìn)程的User_Context結(jié)構(gòu)。 (3)Copy_F

4、rom_User()和Copy_To_User()函數(shù)的功能是在用戶地址空間和內(nèi)核地址空間之間復(fù)制函數(shù),在分段存儲器管理模式下,只要段有效,調(diào)用memcpy函數(shù)就可以實(shí)現(xiàn)這兩個(gè)函數(shù)的功能。 (4)Switch_To_Address_Space()函數(shù)的功能是通過將進(jìn)程的LDT裝入到LDT寄存器來激活用戶的地址空間。5. src/GeekOS/kthread.c文件中的Start_User_Thread函數(shù)和Setup_User_Thread函數(shù)。 (1)Setup_User_Thread()函數(shù)的功能是為進(jìn)程初始化內(nèi)核堆棧,堆棧中是為進(jìn)程首次進(jìn)入用戶態(tài)運(yùn)行時(shí)設(shè)置處理器狀態(tài)要使用的數(shù)據(jù)。 (2)

5、Start_User_Thread()是一個(gè)高層操作,該函數(shù)使用User_Context對象開始一個(gè)新進(jìn)程 6. src/GeekOS/Syscall.c文件中主要是實(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()函數(shù)、Sys_Wait()函數(shù)和Sys_GetPID()函數(shù)。這些函數(shù)在文件中有詳細(xì)的注釋,按照提示用戶可以很好實(shí)現(xiàn)它們的功能。 最后,需要在main.c文件中改寫生成第一個(gè)用戶態(tài)進(jìn)程

6、的函數(shù)調(diào)用:Spawn_Init_Process(void)。需要注意的是:作為與用戶溝通的界面,GeekOS提供了一個(gè)簡單的Shell,保存在PFAT文件系統(tǒng)內(nèi),所以GeekOS系統(tǒng)啟動后,應(yīng)啟動shell程序/c/shell.exe運(yùn)行,所以需要將/c/shell.exe作為可執(zhí)行文件傳遞給Spawn函數(shù)的program參數(shù),創(chuàng)建第一個(gè)用戶態(tài)進(jìn)程,然后由它來創(chuàng)建其他進(jìn)程。 添加代碼運(yùn)行成功后,GeekOS就可以掛載shell,并能運(yùn)行測試文件c.exe和b.exe。三、 如何建立開發(fā)環(huán)境:(一) 利用linux安裝盤安裝了ubuntu10.10版本的linux操作系統(tǒng)環(huán)境;(二) 聯(lián)網(wǎng)后通

7、過系統(tǒng)里的更新管理器更新了系統(tǒng),并安裝了語言包和必要的驅(qū)動。(三) 在ubuntu軟件中心下載安裝了NASM匯編器、Bochs PC模擬器以及bochs-x插件(保證ubuntu10.10環(huán)境下的bochs正常運(yùn)行)。四、 項(xiàng)目設(shè)計(jì)原理:Make工作原理:在默認(rèn)的方式下,只要輸入make命令就可以工作。具體的處理過程如下:(1)make會在當(dāng)前目錄下找文件名為“Makefile”或“makefile”的文件。 (2)如果找到,它會找文件中的第一個(gè)目標(biāo)文件(target),在上面的例子中,它會找到“edit”這個(gè)文件,并把這個(gè)文件作為最終的目標(biāo)文件。 (3)如果edit文件不存在,或是edit所

8、依賴的后面的.o文件的修改時(shí)間要比edit這個(gè)文件新,那么,就會執(zhí)行后面所定義的命令來生成edit這個(gè)文件。 (4)如果edit所依賴的.o文件也不存在,那么make會在當(dāng)前文件中找目標(biāo)為.o文件的依賴性,如果找到則再根據(jù)那一個(gè)規(guī)則生成.o文件(這有點(diǎn)像一個(gè)堆棧的過程)。 (5)如果指定的C文件和H文件是存在的, make會生成.o文件,然后再用.o文件生成make的最終任務(wù),也就是鏈接生成執(zhí)行文件edit。 GeekOS的makefile文件功能:(1) 指定GeekOS如何被編譯,哪些源文件被編譯,哪些用戶程序被編譯等等。通常不同項(xiàng)目的編譯僅僅需要修改這一部分。(2) 定義了編譯GeekO

9、S要用到的工具程序。(3) 指定規(guī)則:描述系統(tǒng)如何編譯源程序。(4) 指定系統(tǒng)編譯生成的指定文件 。GeekOS項(xiàng)目的開發(fā)流程:1. 開始一個(gè)GeekOS項(xiàng)目,第一步是添加相應(yīng)的代碼 。2. 在Linux下利用make命令編譯系統(tǒng),生成系統(tǒng)鏡像文件。 $ cd /project0/build $ make depend $ make 3. 編寫每個(gè)項(xiàng)目相應(yīng)的Bochs的配置文件。4. 運(yùn)行Bochs模擬器,執(zhí)行GeekOS內(nèi)核。 $ cd /bochs $ bochs 運(yùn)行后,屏幕上會有一些提示。運(yùn)行GeekOS選擇Begin simulation,如果GeekOS 編譯成功,并且bochs的

10、配置也沒問題,將會看到一個(gè)模擬VGA的文本窗口,Geekos就能運(yùn)行程序輸出相應(yīng)信息 (每個(gè)環(huán)境具體運(yùn)行的命令格式會有一些不同)內(nèi)核線程的建立流程: 用戶態(tài)進(jìn)程創(chuàng)建流程 五、 項(xiàng)目設(shè)計(jì)的具體實(shí)現(xiàn)(程序代碼):GeekOS設(shè)計(jì)項(xiàng)目0:Main.c文件:#include #include #include #include #include #include #include #include #include #include #include /* * Kernel C code entry point. * Initializes kernel subsystems, mounts file

11、systems, * and spawns init process. */void Main(struct Boot_Info* bootInfo) Init_BSS(); Init_Screen(); Init_Mem(bootInfo); Init_CRC32(); Init_TSS(); Init_Interrupts(); Init_Scheduler(); Init_Traps(); Init_Timer(); Init_Keyboard(); Set_Current_Attr(ATTRIB(BLACK, GREEN|BRIGHT); Print(Welcome to GeekOS

12、!n); Set_Current_Attr(ATTRIB(BLACK, GRAY); void EchoCount() Keycode keycode; int count; count=0; while (1) if ( Read_Key( &keycode ) ) if(keycode & 0x4000) = 0x4000) if(Wait_For_Key() & 0x00ff) = d) /Print(%c,Wait_For_Key(); Set_Current_Attr(ATTRIB(BLACK, RED); Print(Ctrl+d Is Entered! Program Ended

13、!); Exit(1); else if ( !(keycode & KEY_SPECIAL_FLAG) & !(keycode & KEY_RELEASE_FLAG) ) keycode &= 0xff; count=count+1; Set_Current_Attr(ATTRIB(BLACK, CYAN); Print( %c, (keycode = r) ? n : keycode ); if(keycode=r) count=count-1; Set_Current_Attr(ATTRIB(AMBER, BLUE); Print(The counnts is %d ,count); P

14、rint(n); count=0; struct Kernel_Thread *kerThd;kerThd = Start_Kernel_Thread(&EchoCount, 0 , PRIORITY_NORMAL, false); /* Now this thread is done. */ Exit(0);GeekOS設(shè)計(jì)項(xiàng)目1:Elf.c文件:#include #include #include #include /* for debug Print() statements */#include #include #include #include /* * From the data

15、 of an ELF executable, determine how its segments * need to be loaded into memory. * param exeFileData buffer containing the executable file * param exeFileLength length of the executable file in bytes * param exeFormat structure describing the executables segments * and entry address; to be filled

16、in * return 0 if successful, phoff); KASSERT(exeFileData!=NULL); KASSERT(exeFileLengthhead-ehsize+head-phentsize*head-phnum); KASSERT(head-entry%4=0); exeFormat-numSegments=head-phnum; exeFormat-entryAddr=head-entry; for(i=0;iphnum;i+) exeFormat-segmentListi.offsetInFile=proHeader-offset; exeFormat-

17、segmentListi.lengthInFile=proHeader-fileSize; exeFormat-segmentListi.startAddress=proHeader-vaddr; exeFormat-segmentListi.sizeInMemory=proHeader-memSize; exeFormat-segmentLtFlags=proHeader-flags; proHeader+;return 0;GeekOS設(shè)計(jì)項(xiàng)目2:Src/GeekOS/user.c文件中的函數(shù)Spawn():int Spawn(const char *program, co

18、nst char *command, struct Kernel_Thread *pThread) /* * Hints: * - Call Read_Fully() to load the entire executable into a memory buffer * - Call Parse_ELF_Executable() to verify that the executable is * valid, and to populate an Exe_Format data structure describing * how the executable should be load

19、ed * - Call Load_User_Program() to create a User_Context with the loaded * program * - Call Start_User_Thread() with the new User_Context * * If all goes well, store the pointer to the new thread in * pThread and return 0. Otherwise, return an error code. */ int rc; char *exeFileData = 0; ulong_t ex

20、eFileLength; struct User_Context *userContext = 0; struct Kernel_Thread *process = 0; struct Exe_Format exeFormat; /* * Load the executable file data, parse ELF headers, * and load code and data segments into user memory. */ if (rc = Read_Fully(program, (void*) &exeFileData, &exeFileLength) != 0 | (

21、rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat) != 0 | (rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &userContext) != 0) goto fail; /* * User program has been loaded, so we can free the * executable file data now. */ Free(exeFileData); exeFileData = 0; /*

22、 Start the process! */ process = Start_User_Thread(userContext, false); if (process != 0) KASSERT(process-refCount = 2); /* Return Kernel_Thread pointer */ *pThread = process; else rc = ENOMEM; return rc;fail: if (exeFileData != 0) Free(exeFileData); if (userContext != 0) Destroy_User_Context(userCo

23、ntext); return rc;Src/GeekOS/user.c文件中的函數(shù)Switch_To_User_Context():void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state) /* * Hint: Before executing in user mode, you will need to call * the Set_Kernel_Stack_Pointer() and Switch_To_Address_Space() * functions. */ s

24、tatic struct User_Context* s_currentUserContext; /* last user context used */ struct User_Context* userContext = kthread-userContext; /* * FIXME: could avoid resetting ss0/esp0 if not returning * to user space. */ KASSERT(!Interrupts_Enabled(); if (userContext = 0) /* Kernel mode thread: no need to

25、switch address space. */ return; /* Switch only if the user context is indeed different */ if (userContext != s_currentUserContext) ulong_t esp0; /* Switch to address space of user context */ Switch_To_Address_Space(userContext); /* * By definition, when returning to user mode there is no * context

26、remaining on the kernel stack. */ esp0 = (ulong_t) kthread-stackPage) + PAGE_SIZE; /* Change to the kernel stack of the new process. */ Set_Kernel_Stack_Pointer(esp0); /* New user context is active */ s_currentUserContext = userContext; src/GeekOS/elf.c文件中的函數(shù)Parse_ELF_Executable():int Parse_ELF_Exec

27、utable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat) elfHeader *hdr; programHeader *phdr; int i; hdr = (elfHeader *) exeFileData; /* * FIXME: when checking offsets, we really ought to be * checking overflow cases. Need to use functions from * range.h (which needs to be impl

28、emented, too) */ if (exeFileLength phnum EXE_MAX_SEGMENTS) if (elfDebug) Print(Too many segments (%d) in ELF executablen, hdr-phnum); return ENOEXEC; if (exeFileLength phoff + (hdr-phnum * sizeof(programHeader) if (elfDebug) Print(Not enough room for program headern); return ENOEXEC; exeFormat-numSe

29、gments = hdr-phnum; exeFormat-entryAddr = hdr-entry; phdr = (programHeader *) (exeFileData + hdr-phoff); for (i = 0; i phnum; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; /* * Fill in segment offset, length, address * FIXME: should check that segments are valid */ segment-offsetInFile

30、= phdri.offset; segment-lengthInFile = phdri.fileSize; segment-startAddress = phdri.vaddr; segment-sizeInMemory = phdri.memSize; if (segment-lengthInFile segment-sizeInMemory) if (elfDebug) Print(Segment %d: length in file (%lu) exceeds size in memory (%lu)n, i, segment-lengthInFile, segment-sizeInM

31、emory); return ENOEXEC; /* Groovy */ return 0;src/GeekOS/userseg.c文件中的函數(shù)Destroy_User_Context()void Destroy_User_Context(struct User_Context* userContext) /* * Hints: * - you need to free the memory allocated for the user process * - dont forget to free the segment descriptor allocated * for the proc

32、esss LDT */ / TODO(Destroy a User_Context); /* Free the contexts LDT descriptor */ Free_Segment_Descriptor(userContext-ldtDescriptor);userContext-ldtDescriptor=0; /* Free the contexts memory */ Free(userContext-memory);userContext-memory=0; Free(userContext);userContext=0;src/GeekOS/userseg.c文件中的函數(shù)L

33、oad_User_Program()int Load_User_Program(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat, const char *command, struct User_Context *pUserContext) /* * Hints: * - Determine where in memory each executable segment will be placed * - Determine size of argument block and where it m

34、emory it will * be placed * - Copy each executable segment into memory * - Format argument block in memory * - In the created User_Context object, set code entry point * address, argument block address, and initial kernel stack pointer * address */ int i; ulong_t maxva = 0; unsigned numArgs; ulong_t

35、 argBlockSize; ulong_t size, argBlockAddr; struct User_Context *userContext = 0; /* Find maximum virtual address */ for (i = 0; i numSegments; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; ulong_t topva = segment-startAddress + segment-sizeInMemory; /* FIXME: range check */ if (topva ma

36、xva) maxva = topva; /* Determine size required for argument block */ Get_Argument_Block_Size(command, &numArgs, &argBlockSize); /* * Now we can determine the size of the memory block needed * to run the process. */ size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE; argBlockAddr = size; size +

37、= argBlockSize; /* Create User_Context */ userContext = Create_User_Context(size); if (userContext = 0) return -1; /* Load segment data into memory */ for (i = 0; i numSegments; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; memcpy(userContext-memory + segment-startAddress, exeFileData +

38、 segment-offsetInFile, segment-lengthInFile); /* Format argument block */ Format_Argument_Block(userContext-memory + argBlockAddr, numArgs, argBlockAddr, command); /* Fill in code entry point */ userContext-entryAddr = exeFormat-entryAddr; /* * Fill in addresses of argument block and stack * (They h

39、appen to be the same) */ userContext-argBlockAddr = argBlockAddr; userContext-stackPointerAddr = argBlockAddr; *pUserContext = userContext; return 0;src/GeekOS/kthread.c文件中的函數(shù)Setup_User_Thread()void Setup_User_Thread( struct Kernel_Thread* kthread, struct User_Context* userContext) /* * Hints: * - C

40、all Attach_User_Context() to attach the user context * to the Kernel_Thread * - Set up initial thread stack to make it appear that * the thread was interrupted while in user mode * just before the entry point instruction was executed * - The esi register should contain the address of * the argument

41、block */ /* * Interrupts in user mode MUST be enabled. * All other EFLAGS bits will be clear. */ ulong_t eflags = EFLAGS_IF; unsigned csSelector = userContext-csSelector; unsigned dsSelector = userContext-dsSelector; Attach_User_Context(kthread, userContext); /* * Make the threads stack look like it

42、 was interrupted * while in user mode. */ /* Stack segment and stack pointer within user mode. */ Push(kthread, dsSelector); /* user ss */ Push(kthread, userContext-stackPointerAddr); /* user esp */ /* eflags, cs, eip */ Push(kthread, eflags); Push(kthread, csSelector); Push(kthread, userContext-ent

43、ryAddr); Print(Entry addr=%lxn, userContext-entryAddr); /* Push fake error code and interrupt number. */ Push(kthread, 0); Push(kthread, 0); /* * Push initial values for general-purpose registers. * The only important register is esi, which we use to * pass the address of the argument block. */ Push

44、(kthread, 0); /* eax */ Push(kthread, 0); /* ebx */ Push(kthread, 0); /* edx */ Push(kthread, 0); /* edx */ Push(kthread, userContext-argBlockAddr); /* esi */ Push(kthread, 0); /* edi */ Push(kthread, 0); /* ebp */ /* Push initial values for the data segment registers. */ Push(kthread, dsSelector);

45、/* ds */ Push(kthread, dsSelector); /* es */ Push(kthread, dsSelector); /* fs */ Push(kthread, dsSelector); /* gs */src/GeekOS/kthread.c文件中的函數(shù)Start_User_Thread()struct Kernel_Thread*Start_User_Thread(struct User_Context* userContext, bool detached) /* * Hints: * - Use Create_Thread() to create a new raw thread object * - Call Setup_User_Thread() to get the thread ready to * execute in user mode * - Call Make_Runnable_Atomic() to schedule the process * for execution */ struct Kernel_Thread* kthread = Create_Thread(PRI

溫馨提示

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

評論

0/150

提交評論