《Geekos操作系统的研究与实现操作系统课程设计报告书.docx》由会员分享,可在线阅读,更多相关《Geekos操作系统的研究与实现操作系统课程设计报告书.docx(23页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、操作系统课程设计报告题目:Geekos操作系统的研究与实现 专业:学生编号:学生:讲师:据。在分段内存管理模式下,只要段有效,就可以通过调用men1cpy函数来实现这两个函数 的功能。函数的作用是通过将进程的LDT加载到LDT寄存器中来激活用户的地址空间。(5) src/geek OS/kthread . c 文件中的 Start_User Thread 函数和 SetupJJser Thread 函 数。Setup_User_Thread()函数的作用是为进程初始化内核堆栈,堆栈中包含了进程第一次进入 用户模式时用来设置处理器状态的数据。Start_User_Thread()是一个高级操作,
2、它使用User_Context对象来启动一个新进程。(6) src/geek OS/kthread . c 相关功能的修改。(7) src/geek OS/syscall . c文件主要定义了用户程序需要内核服务的一些系统调用 函数。要求用户实现 Sys_Exit ()函数、Sys_PrintString()函数、Sys_GetKey () Sys_SetAttr () Sys_PutCursor ()、Sys_Spawn ()函数、Sys_Wait ()函数和 Sys_GetPID (8)在main, c文件中,重写函数调用,生成第一个用户态进程:Spawn Init_Process (vo
3、id)= user , c= 生成流程(用户状态)int Spawn(const char *program, const char *command, struct Kernel_Thread *pThread) (TODO(通过从文件系统读取可执行文件来生成进程);标记每个函数的返回值,0表示成功,否那么失败。 char * exeFileData二0; 存储在内存缓冲区中的用户程序的可执行文件ulong _ t exeFileLength可执行文件的长度struct User _ Context * User Context = 0; 指向 User_Conetxt 的指针 struct
4、内核一线程*进程=0; 指向内核线程*pThread的指针struct Exe _ Format exeFormat调用 Parse_ELF Executab 1 e 函数得到的可执行文件信息 if (rc = Read Fully (program, (void*) &exeFileData, &exeFileLength) ! = 0)调用 Read Fully 函 数将所有名为program的可执行文件读入内存缓冲区。Print (无法读取文件%s! n ,程序);调用Parse_ELF_Executable函数来分析ELF格式文件。Print (解析ELF文件失败! n );调用Loa
5、d_User_Program将可执行程序的程序段和数据段加载到内 存中。Print(加载用户程序失败! n );在堆分配模式下,释放内存并再次初始化exeFileData启动用户进 程,调用Start_User_Thread函数创立一个进程并使其进入准备运行队列*/非核心级进程(即用户级进程) 并返回核心进程的指针*/记录当前进程的ID超过内存project 2 include geek OS errno . h如 果新进程创立失败,注销UsejContext对象。 if (exeFileData! = 0)释放内存 if (userContext! = 0)销毁流程对象 返回RC;Destr
6、oy User Context (用户上下文);/ 免费(exeFileData) ; / rc = ENOMEM 返回RC; 失败: else/* pThread = processrc =过程-PID; /ka sert (process- ref count = = 2);/*process = Start _ User Thread (User context, false);如果(过程! = 0) /免费(exeFileData);exeFileData = 0;/*goto失败;)/goto失败;)if(RC = Load _ User _ Program(exe file dat
7、a , exeFileLength , &exeFormat , command, &userContext)! = 0) / goto失败;)if(RC = Parse _ ELF _ Executable(exe file data, exeFileLength, &exeFormat)!= 0 ) /int rc/)切换到用户上下文void Switch To_User_Context(结构内核线程* kthread,结构中断状态*状态) 指向User_Conetxt的指针,初始化为要切换的进程。卡塞特(! interrupts _ Enabled(); 0表示这个进程处于核心状态,所以
8、不需要切换地址空间。返回;当进程处于用户状态时,地址空间被切换。espO =(ulong _ t)kthread- stack PAGE) +PAGE _ SIZE;新流程的核心堆栈。*/设置核心堆栈指针 /*新用户上下文处于活动状态*/s _ currentUserContext = user context;set _ Kernel _ Stack _ Pointer (espO); /if (userDebug)/ Print(S%lxn , espO);/*)if (userContext!= s_currentUserContext) long _ t espO/if (userDe
9、bug) Print (z,A%p n ,kthread);Switch To_Address_Space (用户上下文);/if (user context =0)/user contextTODO(如有必要,切换到新的用户地址空间);静态结构User _ Context * s _ currentuser Context; /*上次使用的用户上下文*/ /extern int user debug;struct User _ Context * User Context = kthread- User Context; /)= elf . c=复制工程1= user seg . c=需要在
10、这个文件中的每个函数前面添加一个函数。这个函数的作用是根据给定的大小创立一个用户级的 流程上下文。具体实现如下:函数Function:根据给定的大小创立用户级流程上下文统计结构 user _ context * create _ user _ context (ulong _ t size)是一个用户状态进程。if (UserContext! = 0)是核心进程。Else为空。If (0 = UserContext-memory)为用户模式进程创立的LDT (段描述符表)创立一个新的LDT描述符。user context- Idt Descriptor = Al locate _ Segmen
11、t _ Descriptor ();初始化段描述符init _ LDT _描述符(UserContext-ldtDescriptor, UserContext-ldt, NUM _ USER _ LDT _ ENTRIES); 创立新的LDT选择器user context- Idt Selector = Selector(KERNEL _ PRIVILEGE , true , Get _ Descriptor _ Index (user context- Idt Descriptor);创立新的文本段描述符。初始化代码段描述符(创立一个新的数据段初始化数据段描述符(新数据段和文本段选择器USE
12、R context-CSS elector = Selector (USER PRIVILEGE, false, 0);将参考号清除为 0。user context- ref count = 0;返回 UserContext失败:if (UserContext! = 0) if (UserContext-memory! = 0)Free (UserContext-内存);)免费(user context);)返回0;)USER context- ds Selector = Selector (USER _ PRIVILEGE, false, 1);/&UserContext-ldt1,(ulo
13、ng_t) UserContext-内存,size / PAGE_SIZE,用户权限);/&UserContext-ldt0,(ulong_t) UserContext-内存,size / PAGE_SIZE,用户权限);/if(0 = = user context- Idt descriptor)goto失败;/goto失败;memset(UserContext-memory, 0 , size);user context- size = size;/goto失败;/user context-memory = Malloc(size);/ struct User _ Context * Us
14、er Context;size = Round _ Up To _ Page(size);User Context =(struct User _ Context *)Malloc(sizeof(struct User _ Context); /销毁用户上下文void Destroy_User_Context(结构用户上下文*用户上下文)/T0D0(,z Destroy a User _ Context );/ka sert(user context- ref count 二二 0);/*释放上下文的LDT描述符*/Free Segment Descriptor (user context-I
15、dtDescriptor);/*释放上下文的内存*/Disable _ Interrupts();/Free(user context- memory);/Free(user context);/Enable Interrupts();释放被占用的LDT内存空间Free(userContext-)内存);释放userContext本身占用的内存免费(user context);user context = 0;usercontext- memory0;/ freeuserSegment Descriptor (user context- IdtDescriptor); context- Idt
16、 descriptor = 0; /-要分配的最大存储空间。未签名的numArgs进程的数量ulong _ t argBlockSize参数块的大小ulong_t size, argBlockAddr参数块地址struct User Context pUserContext 返回0; / user context- user context- /struct User Context pUserContext 返回0; / user context- user context- / User Context = 0;int Load _ User _ Program (char * Exe f
17、ile data, ulong_t exeFileLength, struct ExeFormat *exeFormat, const char *command, struct User _ Context * * puser Context) /TODO (使用分段将用户可执行文件加载到用户内存空间);int I;ulong _ t maxva = 0; /计算用户态进程需要的最大内存空间。for(I = 0; I num segments; + I) 获取参数块信息。SIZE = Round Up To _ Page(maxva) +DEFAULT _ USER STACK SIZE;
18、用户进程大小二总参数块 大小+进程栈大小(8192)根据对应的大小创立一个进程If (userContext = 0)如果是核心进程return-1;根据段信息,将用户程序中的每个段复制到分配的用户内存空间中。memcpy(user context- memory+segment- start address , exeFileData+segment- offsetlnFile , segment- length infile);格式参数块format Argument Block(user context- memory+argBlockAddr , numArgs , argblock
19、addr , command);初始化数据段、堆栈段和代码段信息user context- entryAddr = exe format- entryAddr ;将初始化的 User_Context 分配给 *pUserContext 成功)arg block addr;argblock addr;userContextarg block addr =stackPointerAddr/for(I = 0; I numstruct Exe _ Segment * Segment /argBlockAddr = sizesize+= argBlockSize;segments; +i) & Exe
20、 format- Segment list I;User Context = Create _ User _ Context (size); / /elf.hstruct Exe _ Segment * Segment = & Exe format- Segment listI;ulong _ t top va = segment- start address+segment- size in memory; /* FIXME: 范围检查*/if (topva maxva) maxva = topva )Get_Argunient_Block_Size (命令,fenumArgs, & arg
21、BlockSize) ; /将用户状态的进程复制到核心缓冲区。bool Copy From User (void * destlnKernel, ulong t srcInUser, ulong t bufSize) TODO(将内存从用户缓冲区复制到内核缓冲区);struct User _ Context * User Context = g _ current thread- User Context; / -:检查内存是否有效如果(! validate _ User _ Memory (User context, srcInUser, bufSize) 返回false / -:用户-内核
22、memcpy(destlnKernel, UserContext-memory + srcInUser, bufSize); 返回true将内核状态的进程复制到用户状态。bool Copy _ To _ User(ulong _ t destlnUser, void* srcInKernel, ulong_t bufSize) TODO(将内存从内核缓冲区复制到用户缓冲区)struct User _ Context * User Context = g _ current thread- User Context; / -:检查内存是否有效如果(! validate _ User _ Memo
23、ry (User context, destlnUser, bufSize) 返回false/ -:内核-用户memcpy(user context-memory+destInUser, srcInKernel, bufSize); 返回true切换到用户地址空间void Switch To Address Space(结构用户上下文*用户上下文)( T0D0(使用分段/LDT切换到用户地址空间);ushort _ t Idt selector = user context- Idt selector; /*切换到新用户上下文的 LDT */ ASM volatile ( lldt % 0 :
24、 a (ldt selector); )= kthread . c-添加头文件#include 创立用户进程/* static */void setup _ user _ thread (struct kernel _ thread * kthread , struct user _ context * user context)选择器unsigned ds selector = user context-ds selector; /DS 选择器Attach_User_Context (kthread, User Context);初始化用户模式进程堆栈,使其看起来好像刚刚被中断。Push(k
25、thread, Push(kthread, Push (kthread, Push (kthread, Push(kthread, Push(kthrcad, Push (kthread,分别调用Push函数将以下数据推入堆栈 ds selector); 数据选择器user context- stackPointerAddr); 堆栈指针e flags) ; /Eflags 文本选择器user context- entryAddr); 程序计数器0); 错误代码(0)中断号(0)初始化通用寄存器单元,并将ESI用户传输到参数块地址。0) ; /* eax */初始化数据段寄存器单元Push(k
26、thread,Push(kthread,Push(kthread,Push(kthread,Push(kthread,Push(kthread,dsdsdsselector); /*selector); /*selector); /*es */ fs */ gs */ds selector); /* ds */Push (kthread, Push(kthread, Push(kthread, Push(kthread, Push(kthread, Push (kthread,0);0);0);/* ebx */* edx */* edx */ user context- argblock a
27、ddr); /* esi */0); /* edi */0); /* ebp */ /Push(kthread, 0); /Push(kthread, csSelector); /( T0D0(创立一个在用户模式下执行的新线程); ulong t eflags = EFLAGS IFunsigned cs selector = user context- cs selector; /CS启动用户进程struct kernel _ thread * start _ user _ thread (struct user _ context * user context, bool detached
28、)是一个用户态进程。if (kthread! = 0) Setup_User_Thread(kthread, User context); make _ Runnable _ Atomic(kthread);返回 kthread TODO(启动用户线程);struct Kernel _ Thread * kthread = Create _ Thread(PRIORITY _ USER, detached); / )= syscall . c=你需要在这个文件中的其他函数之前添加一个名为Copy_User_String的函数,由函数 Sys PrintString调用。具体实现如下:stati
29、c int copy _ user _ string(ulong _ tu addr, ulong _ tlen, ulong _ tmaxlen, char * * pstr)超过了最大长度。If (len maxLen) 为字符串分配空间str =(char *)Malloc(len+l);从用户空间复制数据如果(! Copy _ from _ user (str, uaddr, len) 成功* pStr = str 失败: 返回RC;)rc 二 EINVALID 免费(str); goto失败; )strlen= 0 ;/if (0 = str) rc = ENOMEM goto失败;
30、 ) /返回 EINVALID / int RC = 0; char * str /静态 int Sys _ Exit (struct Interrupt State * State) TODO(退出系统调用); 退出(状态-ebx); )static int sys printstring (struct interrupt _ state * state)返回值 uint _ t length = state-ecx; 字符串长度uchar _ t * buf=0;将字符串复制到核心*/将字符串打印到屏幕*/PutBuf(buf, length);完成:如果(buf!= 0)免费(buf)
31、;返回RC;if (RC = Copy _ User _ String (state-ebx, length, 1023, (char*) &buf) ! = 0) 转到完成;/*写入控制台。如果(长度0) (/*将字符串复制到内核中。 T0D0 (Printstring 系统调用);int RC = 0; /static int sys _ getkey (struct interrupt _ state * state)返回键码 keyboard. c/Wait_For_Key () /TODO (GetKey 系统调用);返回 Wait _ For _ Key () ; /)静态int
32、Sys_SetAttr (结构中断状态*状态) /T0D0(SetAttr 系统调用);set _ Current _ Attr (uchar _ t)state-ebx);返回0;)静态 int Sys get cursor (struct Interrupt _ State * State) /TODO(,zGetCursor 系统调用);int row, colGet Cursor(&row, & col);如果(! Copy_To_User (state-ebx, &r ow, sizeof (int) | | ! CopyTo User (state-ecx, &col, sizeo
33、f(int)return-1;返回0;)静态 int Sys put cursor (struct Interrupt _ State * State) /TODO (,zPutCursor 系统调用);返回 Put Cursor (state-ebx, state-ecx) ? 0 : -1;)-函数返回值char * program = 0; 进程名称char * command = 0; /用户命令struct内核一线程*进程;从用户空间复制进程名goto失败;从用户空间复制用户命令goto失败;if(RC = Copy _ User _ String(state- EDX, state
34、-esi, 1023, &command)! = 0) /*从用户空间复制程序名和命令。*/if (RC = Copy _ User _ String(state- ebx, state-ecx, VFS 最大路径_长度, feprogram)!= 0)/静态 int Sys _ Spawn (struct Interrupt _ State * State) /TODO (Spawn 系统调用);int rc/enable _ Interrupts () ; /翻开中断rc = Spawn(程序、命令和进程);得到进程名和用户命令后,可以生成一个新的进程。If (rc = 0) 如果成功,返
35、回新的进程II)号KASSERT (过程! = 0);关闭中断失败:返回小于0的错误代码如果(程序!=0)免费(程序);如果(命令! = 0)免费(命令);返回RC;rc 二过程-PID;)disable _ Interrupts (); /)静态 int Sys _ Wait (struct Interrupt _ State * State) TODO(等待系统调用);int exitCodestruct Kernel _ Thread * kthread = Lookup _ Thread (state- ebx);如果(kthread = 0)return-12;enable _ In
36、terrupts();exit code = Join(kthread);disable _ Interrupts();返回 exitCode)静态int Sys_GetPID(结构中断状态*状态) /T0D0(GetPID 系统调用);返回 g _ current thread- PID;)目录一、实验目的2二、工程设计要求3三、开发环境的建立4.开发环境的介绍41 .开发环境的构建4四、工程设计原理5五、工程设计的实现6Project。工程的具体实现61. Projectl工程的具体实现8Project2工程的具体实现9六、系统编译运行的结果20七、遇到的问题和解决方法23八、课程设计总结
37、24静态 void Spawn lnit Process (void)/TODO(,Z Spawn init process ); struct Kernel _ Thread * pThreadSpawn(/z/c/she 11. exe , z,/c/shell. exe , & pThread);3.编译 GeekOS 工程 project2进入 geek 0S-0 . 3 . O/src/project 2/build 目录。# cd /. ./geek 0S_0 . 3 . O/src/project 2/build执行make依赖。构建#使依赖生成 depend, mak 文件。1
38、) 执行制作构建#制造之后在构建目录下成功生成了 fd. img和disk. img文件。3.配置启动Bochslo 创立 bochs 配置文件:输入 gedit bochsrcobuild# gedit bochsrc注意:这是bochs在geek OS-O . 3 . O/src/project 2/build目录下创立的配置文件bochsrc。2 .在编辑器中输入以下配置容量vgaromimage:file = $ bx share/VGA BlOS-lgpl-latestrom image:file 二 $ bx share/BIOS-bochs-latest, address=0xf
39、0000梅格:8靴子:aflop ya: 1 _ 44 = FD . img,状态二已插入日志:。/bochs. out键盘串行延迟:200软盘命令延迟:500vga更新间隔:300000ips: 100 万鼠标:启用=0private_co1ormap: enabled、。i440fxsupport: enabled=0ata0:enabled=l, ioaddrl=0xlf0, ioaddr2=0x3f0, irq=14ataO-master:type=disk, mode二flat, path=diskc. img,柱面二40,磁头二8, spt=64.保存、退出gedit并启动boch
40、s:在构建目录中执行bochs -f bochsrc3 .build# bochs -f bochsrc.选择开始模拟六、系统编译和运行的结果1. 0工程0运行结果:翻开终端:$ geek 0S-0 . 3 . O/src/project O/build$ make$ make依赖美元bochs请选择一个:5 5工Bochs x86 emulator, _ x工Bochs x86 emulator, _ x819ZKB memory detected, 1675 pages in freelist, 1048576 bytes in kerne 1 heap Initializing IDT.
41、Initializing timer.Delay loop: 3656 iterations per tick Initializing keyboard.Ue 1come to GeekOS!Exit with ctr1+d wewerrrrrrrgrg_回wsws:/桌面廉作系统课设/geekos0.3.0/src/project0/bu“d一 n文件(E)编辑(E)查看(V)搜索(S) 终端(工)帮助出)configuration file (typically called bochsrc.txt) and loaded it if it could be found. When yo
42、u are satisfied with the configuration, go ahead and start the simulation./ou can also start bochs with the -q option to skip these menus.1. Restore factory default configurationRead options from.2. Edit options4 Save options to.5. Begin simulation5. Quit nowPlease choose 300000000001 30000000000131
43、92KB memoryone: 5 5installing x module as the Bochs GUIusing log file ./bochs.outdetected, 1675 pages in freelist, 1048576 bytes in kernel heapInitializing IDT.Initializing timer.Delay loop: 3656 iterations per tick Initializing keyboard.Welcome to GeekOS! Exit with ctrl+d ewerrrrrrrgrg|. 1工程1运行结果:翻
44、开终端:$ geek 0S_0 . 3 . O/src/project 1/build$ make$ make依赖 美元bochs 请选择一个:5 5工Bochs x86 emulator, USER Opy 奇 I 1_臼USER Opy 奇 I 1_臼USHB819ZKB memory detected, 1670 pages in freelist, 1048576 bytes in kerne 1 Initializing IDT.Initializing timer.Delay loop: 3656 iterations per tickInitializing keyboard.I
45、nitializing DMA Contro1ler.Initializing floppy controIler.fd0: cy1=80, heads=Z, sectors=18Initializing IDE controIler.ide0: cy1=ZQ, heads=16, sectors=63Mounted /c f ilesystem?Welcome to GeekOS?Starting the Spawner thread.Hi ? This is the f irst stringHi ! This is the third (and last) stringIf you see this youre happywsws:/桌面既作系统课设/geekos文件(E)编辑(日 查看(V)搜索(S) 终端(工)帮助坦)Please choose one: 5 5000000000001 installing x module as the Bochs GUI000000000001 using log file ./bochs.out8192KB memory detected, 1670 pages in freelist, 1048576 bytes in kernel
限制150内