操作系统课设报告桂林电子科技大学_第1页
操作系统课设报告桂林电子科技大学_第2页
操作系统课设报告桂林电子科技大学_第3页
操作系统课设报告桂林电子科技大学_第4页
操作系统课设报告桂林电子科技大学_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、桂林电子科技大学综合设计说明书用纸GeekOSGeekOS 操作系统操作系统课程设计说明书课程设计说明书题题 目:目: GeekOSGeekOS 操作系统的研究与实验操作系统的研究与实验 学学 院:院: 计算机科学与工程学院计算机科学与工程学院 专专 业业: 信息安全信息安全 姓姓 名名: 学 号: 指导教师:指导教师: 2015 年年 06 月月 12 日日桂林电子科技大学综合设计说明书用纸目 录1 GEEKOS 简介简介 .11.1 GEEKOS 系统源代码结构.12 课程设计环境课程设计环境 .23 项目项目 0 的设计实现的设计实现 .33.1 项目设计目的 .33.2 项目设计要求.

2、33.3 项目实现原理.33.4 项目实现过程.33.5 运行结果.54 项目项目 1 的设计实现的设计实现 .64.1 项目设计目的 .64.2 项目设计要求.64.3 项目实现原理 .64.4 项目实现过程 .84.5 运行结果.95 项目项目 2 的设计实现的设计实现 .105.1 项目设计目的 .105.2 项目设计目的 .105.3 项目实现原理 .115.4 项目实现过程 .135.5 运行结果 .236 遇到问题及解决方法遇到问题及解决方法 .237 课程设计总结课程设计总结 .24桂林电子科技大学综合设计说明书用纸 第 1 页 1 GeekOS 简介GeekOS 是一个基于 X

3、86 架构的 PC 上运行的微操作系统内核,由美国马理兰大学的教师开发,主要用于操作系统课程设计,目的是使学生能够实际动手参与到一个操作系统的开发工作中。出于教学目的,这个系统内核设计简单,却又兼备实用性,它可以运行在真正的 X86 PC 硬件平台。作为一个课程设计平台,GeekOS 由一个基本的操作系统内核作为基础,提供了操作系统与硬件之间的所有必备接口,实现了系统引导,实模式到保护模式的转换,中断调用及异常处理,基于段式的内存管理,FIFO 进程调度算法以及内核进程,基本的输入输出(键盘作为输入设备,显示器作为输出设备),以及一个用于存放用户程序的只读文件系统PFAT。学生可以在 Linu

4、x 或 Unix 环境下对其进行功能扩充,且其针对进程、文件系统、存储管理等操作系统核心内容分别设计了 7 个难度逐渐增加的项目供学生选择 。1.1 GeekOS 系统源代码结构GeekOS 操作系统源文件 geekos-0.3.0.zip 可以从 http:/下载。图 1.1 GeekOS 系统主目录在 doc 目录里的文件 hacking.pdf 和 index.htm 是 GeekOS 系统的参考文档。Scripts目录下有 startProject 和 removeEmptyConflicts 两个脚本文件。GeekOS 系统的源文件在src 目录下,分为 7 个项目:Project0

5、 到 Project7。在 build 文件夹中,包含系统编译后的可执行文件的文件、软盘镜像或是硬盘镜像、makefile 项目管理文件。在 include 文件夹中有 GeekOS 和 libc 两个子目录,在 GeekOS 子目录中有 kthread.h、keyboard.h 等文件。桂林电子科技大学综合设计说明书用纸 第 2 页 图 1.2 项目文件结构图2 课程设计环境1. 虚拟机软件:VMware Workstation 10.0。2. 虚拟系统:linux 系统 CentOS 6.0。3. NASM 汇编器。4. GNU gcc 编译器。5. GNU gdb 调试器。6. Sour

6、se Insight:程序编辑器和代码浏览器。7. Bochs:GeekOS 运行于 Windows(或 Linux)下的 Bochs PC 模拟器,Bochs 是用 C+ 开发的可移植的 IA-32 (x86) PC 模拟器,它包括对 Intel x86 CPU 、通用 I/O 设备和可定制的 BIOS 的模拟,几乎可以运行在所有流行的平台上。在本次课设中使用的是 bochs 2.6。图 2.1 课设环境桂林电子科技大学综合设计说明书用纸 第 3 页 3 项目 0 的设计实现3.1 项目设计目的熟悉 GeekOS 的项目编译、调试和运行环境,掌握 GeekOS 运行工作过程。3.2 项目设计

7、要求1.搭建 GeekOS 的编译和调试平台,掌握 GeekOS 的内核进程工作原理。2.熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接收键盘输入的字符并显示到屏幕上,当输入 ctrl+d 时,结束进程的运行。3.3 项目实现原理项目 0 主要要求设计一个函数对键盘的中断进行响应。这主要通过使用 GeekOS 提供的键盘响应函数 Wait_Kernel_Thread 进行键盘中断的响应和返回键值。该函数首先检查键盘缓冲区是否有按键,如果有,就读取一个键码,如果此时键盘缓冲区没有键值,就将线程放入键盘事件等待队列。于是可分为两步完成:1.编写函数 EchoCount,函输功能是:接受

8、键盘输入的按键,并将键值显示在显示器,当输入 Ctrl+D 退出。2.在 Main 函数体内调用 Start_Kernel_Thread 函数,将编写的函数地址传递给startFunc,建立一个内核进程。3.4 项目实现过程1.添加代码(1)在 Main 函数中编写一个函数,函数功能是:接收键盘输入的按键,并将键值显示到显示器的函数,当输入 Ctrl+D 就退出。void project0()Print(To Exit hit Ctrl + d.n); Keycode keycode; while(1) if( Read_Key(&keycode) ) /读取键盘按键状态if(!( (

9、keycode & KEY_SPECIAL_FLAG) | (keycode & KEY_RELEASE_FLAG) ) /只处理非特殊按键的按下事件 int asciiCode = keycode & 0 xff; /低 8 位为 Ascii 码 if( (keycode & KEY_CTRL_FLAG)=KEY_CTRL_FLAG & asciiCode=d) /按下 Ctrl 键 Print(n-BYE!-n); Exit(1); else Print(%c,(asciiCode=r) ? n : keycode);桂林电子科技大学综合设计说明书用

10、纸 第 4 页 /放在 main 函数之前(2) 在 Main 函数体内调用 Start_Kernel_Thread 函数,将步骤 1 编写的函数地址传递给参数 startFunc,建立一个内核级进程。 void Main(struct Boot_Info* bootInfo) /TODO(Start a kernel thread to echo pressed keys and print counts); struct Kernel_Thread *thread; thread = Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,f

11、alse); 2.编译 GeekOS 项目 project0(1)shell# cd /geekos-0.3.0/src/project0/build(2)shell# make depend生成 depend.mak 文件。图 3.1 make depend 执行过程(3)shell# make成功之后在 build 目录下生成 fd.img 文件。桂林电子科技大学综合设计说明书用纸 第 5 页 图 3.2 make 执行过程3.配置启动 Bochs(1)创建 bochs 配置文件shell# gedit bochsrc(2)在编辑器中输入一下配置内容gdbstub: enabled=1,

12、port=1234, text_base=0, data_base=0, bss_base=0romimage:file=$BXSHARE/BIOS-bochs-latestmegs: 8boot: afloppya:1_44=fd.img, status=insertedlog: ./bochs.out(3)保存,直接退出 gedit3.5 运行结果(1)启动 bochsshell# bochs - bochsrc(2)选择 begin simulation(3)结果:桂林电子科技大学综合设计说明书用纸 第 6 页 图 3.3 项目 0 运行结果4 项目 1 的设计实现4.1 项目设计目的熟

13、悉 ELF 文件格式,了解 GeekOS 系统如何将 ELF 格式的可执行程序装入到内存,建立内核进程并运行的实现技术。4.2 项目设计要求1.修改/geekos/elf.c 文件:在函数 Parse_ELF_Executable( )中添加代码,分析 ELF 格式的可执行文件(包括分析得出 ELF 文件头、程序头,获取可执行文件长度,代码段、数据段等信息) ,并填充 Exe_Format 数据结构中的域值。2.在 Linux 环境下编译系统得到 GeekOS 镜像文件。3.编写一个相应的 bochs 配置文件。4.在 bochs 中运行 GeekOS 系统显示结果。4.3 项目实现原理1.E

14、LF 文件格式。连接程序视图 执行程序视图 ELF 头部ELF 头部 程序头部表(可选) 程序头部表 节区 1 段 1 桂林电子科技大学综合设计说明书用纸 第 7 页 节区 n 段 2 节区头部表 节区头部表(可选) 表 4.1 ELF 目标文件格式2. 内存中的可执行文件镜像GeekOS 中的用户进程全部在系统的编译阶段完成编译和链接,形成可执行文件,用户可执行文件保存在 PFAT 文件系统中。项目 1 要完成的事系统启动后,从 PFAT 文件系统将可执行文件装入内存,建立进程并运行得到相应的输出。如下图:图 4.1 文件镜像3. 内核线程的建立流程该过程主要由 Spawner 函数实现,其

15、主要经过:调用 Read_Fully 函数将文件读入内存,后调用 Parse_ELF_Executable 函数分析 ELF 文件,最后调用 Spawn_Program 函数将可执行程序的代码段和数据段等装入内存,此后便可以开始运行一个内核级进程了。如下图:桂林电子科技大学综合设计说明书用纸 第 8 页 图 4.2 建立流程4.4 项目实现过程1.添加代码修改/geekos/elf.c 文件。在函数 Parse_ELF_Executalbe()中添加代码,分析 ELF 格式的可执行文件(包括分析得出ELF 文件头、程序头,获取可执行文件长度,代码段、数据段等信息) ,并填充 Exe_Forma

16、t数据结构中的域值。int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat) /TODO(Parse an ELF executable image); int i; elfHeader *head=(elfHeader*)exeFileData; programHeader *proHeader=(programHeader *)(exeFileData+head-phoff); KASSERT(exeFileData!=NULL); KASSERT(exe

17、FileLengthhead-ehsize+head-phentsize*head-phnum); KASSERT(head-entry%4=0);桂林电子科技大学综合设计说明书用纸 第 9 页 exeFormat-numSegments=head-phnum; exeFormat-entryAddr=head-entry; for(i=0;iphnum;i+) exeFormat-segmentListi.offsetInFile=proHeader-offset; exeFormat-segmentListi.lengthInFile=proHeader-fileSize; exeForm

18、at-segmentListi.startAddress=proHeader-vaddr; exeFormat-segmentListi.sizeInMemory=proHeader-memSize; exeFormat-segmentLtFlags=proHeader-flags; proHeader+;return 0;2. 编译 GeekOS 项目 project0(1)执行 make dependshell# make depend生成 depend.mak 文件(2)执行 makeshell# make成功之后再 build 目录下生成 fd.img 和 disk.i

19、mg 文件。3. 配置启动 Bochs(1)创建 bochs 配置文件shell# gedit bochsrc(2)在编辑器输入一下配置内容romimage:file=$BXSHARE/BIOS-bochs-latestmegs: 8boot: afloppya: 1_44=fd.img, status=insertedata0-master:type=disk, mode=flat, path=diskc.img, cylinders=0log: ./bochs.out桂林电子科技大学综合设计说明书用纸 第 10 页 (3)保存,直接退出 gedit4.5 运行结果(1)启动 bochssh

20、ell# bochs f bochsrc(2)选择 begin simulation(3)结果:图 4.3 项目 1 运行结果5 项目 2 的设计实现5.1 项目设计目的扩充 GeekOS 操作系统内核,使得系统能够支持用户级进程的动态创建和执行。5.2 项目设计目的1.“src/GeekOS/user.c”文件中的函数 Spawn() ,其功能是生成一个新的用户级进程;2.“src/GeekOS/user.c”文件中的函数 Switch_To_User_Context() ,调度程序在执行一个新的进程前调用该函数以切换用户地址空间;3.“src/GeekOS/elf.c”文件中的函数 Par

21、se_ELF_Executable() 。该函数的实现要求和项目 1 相同。4.“src/GeekOS/userseg.c”文件中主要是实现一些为实现对“src/GeekOS/user.c”中高层操作支持的函数。 Destroy_User_Context()函数的功能是释放用户态进程占用的内存资源。 Load_User_Program()函数的功能通过加载可执行文件镜像创建新进程的桂林电子科技大学综合设计说明书用纸 第 11 页 User_Context 结构。 Copy_From_User()和 Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管

22、理模式下,只要段有效,调用 memcpy 函数就可以实现这两个函数的功能。 Switch_To_Address_Space()函数的功能是通过将进程的 LDT 装入到 LDT 寄存器来激活用户的地址空间;5.“src/GeekOS/kthread.c”文件中的 Start_User_Thread 函数和 Setup_User_Thread 函数。 Setup_User_Thread()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据。 Start_User_Thread()是一个高层操作,该函数使用 User_Context 对象开始一个新进程。6

23、.“src/GeekOS/kthread.c”文件中主要是实现用户程序要求内核进行服务的一些系统调用函数定义。要求用户实现的有 Sys_Exit()函数、Sys_PrintString()函数、Sys_GetKey() 、Sys_SetAttr() 、Sys_GetCursor() 、Sys_PutCursor() 、Sys_Spawn()函数、Sys_Wait()函数和 Sys_GetPID( )函数。7.在 main.c 文件中改写生成第一个用户态进程的函数调用:Spawn_Init_Process(void) 。5.3 项目实现原理1. GeekOS 进程状态及转换图 5.1 GeekO

24、S 进程转换GeekOS 系统最早创建的内核进程有 Idle、Reaper 和 Main 三个进程,它们由Init_Scheduler 函数创建:最先初始化一个核态进程 mainThread,并将该进程作为当前运行进程,函数最后还调用 Start_Kernel_Thread 函数创建了两个系统进程 Idle 和桂林电子科技大学综合设计说明书用纸 第 12 页 Reaper。 所以,Idle、Reaper 和 Main 三个进程是系统中最早存在的进程。2. GeekOS 的用户态进程 在 GeekOS 中为了区分用户态进程和内核进程,在 Kernel_Thread 结构体中设置了一个字段 use

25、rContext,指向用户态进程上下文。对于内核进程来说,这个指针为空,而用户态进程都拥有自己的用户上下文(User_Context) 。因此,在 GeekOS 中要判断一个进程是内核进程还是用户态进程,只要通过 userContext 字段是否为空来判断就可以了。 图 5.2 用户进程3.用户进程空间每个用户态进程都拥有属于自己的内存段空间,如:代码段、数据段、堆栈段等,每个段有一个段描述符(segment descriptor) ,并且每个进程有一个段描述符表(Local Descriptor Table) ,用于保存该进程的所有段描述符。操作系统中还设置一个全局描述符表(GDT,Glob

26、al Descriptor Table) ,用于记录了系统中所有进程的 ldt 描述符。图 5.3 用户进程空间4. 用户态进程创建 LDT 的步骤(1)调用函数 Allocate_Segment_Descriptor()新建一个 LDT 描述符;桂林电子科技大学综合设计说明书用纸 第 13 页 (2)调用函数 Selector()新建一个 LDT 选择子;(3)调用函数 Init_Code_Segment_Descriptor()新建一个文本段描述符;(4)调用函数 Init_Data_Segment_Descriptor()新建一个数据段;(5)调用函数 Selector()新建一个数据段

27、选择子;(6)调用函数 Selector()新建一个文本(可执行代码)段选择子。图 5.4 用户进程创建流程5.4 项目实现过程1.添加代码(1)修改 src/GeekOS/user.c 文件中的函数 Spawn(),其功能是生成一个用户级进程。(2)src/GeekOS/user.c 文件中的函数 Switch_To_User_Contex(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间。(3)src/GeekOS/elf.c 文件中的函数 Prase_ELF_Executable()。该函数的实现要求和项目 1 相同。(4)src/GeekOS/userseg.c 文件主要是

28、实现一些为实现对 src/GeekOS/user.c 中高层操作支持的函数。 Destroy_User_Context()函数的功能是释放用户态进程占用的内存资源。桂林电子科技大学综合设计说明书用纸 第 14 页 Load_User_Program()函数的功能通过加载可执行文件镜像创建新进程的 User_Context 结构。 Copy_From_User()和 Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管理模式下,只要段有效,调用 memcpy 函数就可以实现这两个函数的功能。 Switch_To_Address_Space()函数的功能

29、是通过将进程的 LDT 装入到 LDT 寄存器来激活用户的地址空间(5)src/GeekOS/kthread.c 文件中 Start_User_Thread 函数和 Setup_User_Thread 函数。 Setup_User_Thread()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据。 Start_User_Thread()是一个高层操作,该函数使用 User_Context 对象开始一个新进程。(6)src/GeekOS/kthread.c 相关函数的修改。(7)src/GeekOS/syscall.c”文件中主要是实现用户程序要求内

30、核进行服务的一些系统调用函数定义。 要求用户实现的有 Sys_Exit()函数、Sys_PrintString()函数、Sys_GetKey() 、Sys_SetAttr() 、Sys_GetCursor() 、Sys_PutCursor() 、Sys_Spawn()函数、Sys_Wait()函数和 Sys_GetPID( )函数。(8)在 main.c 文件中改写生成第一个用户态进程的函数调用:Spawn_Init_Process(void) = user.c =/产生一个进程(用户态)int Spawn(const char *program, const char *command, s

31、truct Kernel_Thread *pThread) /TODO(Spawn a process by reading an executable from a filesystem); int rc; /标记各函数的返回值,为 0 则表示成功,否则失败 char *exeFileData = 0;/保存在内存缓冲中的用户程序可执行文件 ulong_t exeFileLength;/可执行文件的长度 struct User_Context *userContext = 0;/指向 User_Conetxt 的指针 struct Kernel_Thread *process = 0;/指向

32、 Kernel_Thread *pThread 的指针 struct Exe_Format exeFormat;/调用 Parse_ELF_Executable 函数得到的可执行文件信息 if (rc = Read_Fully(program, (void*) &exeFileData, &exeFileLength) != 0 ) /调用 Read_Fully 函数将名为 program 的可执行文件全部读入内存缓冲区 Print(Failed to Read File %s!n, program); goto fail; if(rc = Parse_ELF_Executab

33、le(exeFileData, exeFileLength, &exeFormat) != 0 ) /调用 Parse_ELF_Executable 函数分析 ELF 格式文件 Print(Failed to Parse ELF File!n); goto fail; if(rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &userContext) != 桂林电子科技大学综合设计说明书用纸 第 15 页 0) /调用 Load_User_Program 将可执行程序的程序段和

34、数据段装入内存 Print(Failed to Load User Program!n); goto fail; /在堆分配方式下释放内存并再次初始化 exeFileData Free(exeFileData); exeFileData = 0;/* 开始用户进程,调用 Start_User_Thread 函数创建一个进程并使其进入准备运行队列*/ process = Start_User_Thread(userContext, false); if (process != 0) /不是核心级进程(即为用户级进程) KASSERT(process-refCount = 2);/* 返回核心进程

35、的指针 */ *pThread = process; rc = process-pid;/记录当前进程的 ID else/超出内存 project2includegeekoserrno.h rc = ENOMEM; return rc;fail: /如果新进程创建失败则注销 User_Context 对象 if (exeFileData != 0) Free(exeFileData);/释放内存 if (userContext != 0) Destroy_User_Context(userContext);/销毁进程对象 return rc;-/切换至用户上下文void Switch_To_U

36、ser_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state) /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 = kthread-userContext;/指向 User_Con

37、etxt 的指针,并初始化为准备切换的进程 KASSERT(!Interrupts_Enabled(); if (userContext = 0) /userContext 为 0 表示此进程为核心态进程就不用切换地址空间 return; if (userContext != s_currentUserContext) ulong_t esp0; /if (userDebug) Print(A%pn, kthread); Switch_To_Address_Space(userContext);/为用户态进程时则切换地址空间 esp0 = (ulong_t) kthread-stackPage

38、) + PAGE_SIZE; /if (userDebug) / Print(S%lxn, esp0);/* 新进程的核心栈. */桂林电子科技大学综合设计说明书用纸 第 16 页 Set_Kernel_Stack_Pointer(esp0);/设置内核堆栈指针/* New user context is active */ s_currentUserContext = userContext; = elf.c =copy project1 = userseg.c =/需在此文件各函数前增加一个函数,此函数的功能是按给定的大小创建一个用户级进程上下文,具体实现如下:/函数功能:按给定的大小创建

39、一个用户级进程上下文static struct User_Context* Create_User_Context(ulong_t size) struct User_Context * UserContext; size = Round_Up_To_Page(size); UserContext = (struct User_Context *)Malloc(sizeof(struct User_Context); /为用户态进程 if (UserContext != 0) UserContext-memory = Malloc(size); /为核心态进程 else goto fail;

40、/内存为空 if (0 = UserContext-memory) goto fail; memset(UserContext-memory, 0, size); UserContext-size = size; /以下为用户态进程创建 LDT(段描述符表) /新建一个 LDT 描述符 UserContext-ldtDescriptor = Allocate_Segment_Descriptor(); if (0 = UserContext-ldtDescriptor) goto fail; /初始化段描述符 Init_LDT_Descriptor(UserContext-ldtDescrip

41、tor, UserContext-ldt, NUM_USER_LDT_ENTRIES); /新建一个 LDT 选择子 UserContext-ldtSelector = Selector(KERNEL_PRIVILEGE, true, Get_Descriptor_Index(UserContext-ldtDescriptor); /新建一个文本段描述符 Init_Code_Segment_Descriptor( &UserContext-ldt0, (ulong_t) UserContext-memory, size / PAGE_SIZE, USER_PRIVILEGE );桂林电

42、子科技大学综合设计说明书用纸 第 17 页 /新建一个数据段 Init_Data_Segment_Descriptor( &UserContext-ldt1, (ulong_t) UserContext-memory, size / PAGE_SIZE, USER_PRIVILEGE ); /新建数据段和文本段选择子 UserContext-csSelector = Selector(USER_PRIVILEGE, false, 0); UserContext-dsSelector = Selector(USER_PRIVILEGE, false, 1); /将引用数清 0 UserC

43、ontext-refCount = 0; return UserContext;fail: if (UserContext != 0) if (UserContext-memory != 0) Free(UserContext-memory); Free(UserContext); return 0;-/摧毁用户上下文void Destroy_User_Context(struct User_Context* userContext) /TODO(Destroy a User_Context);/ KASSERT(userContext-refCount = 0);/* Free the co

44、ntexts LDT descriptor */ Free_Segment_Descriptor(userContext-ldtDescriptor);/* Free the contexts memory */ Disable_Interrupts();/ Free(userContext-memory);/ Free(userContext);/ Enable_Interrupts(); /释放占用的 LDT Free_Segment_Descriptor(userContext-ldtDescriptor); userContext-ldtDescriptor=0; /释放内存空间 Fr

45、ee(userContext-memory); userContext-memory=0; /释放 userContext 本身占用的内存 Free(userContext); userContext=0;桂林电子科技大学综合设计说明书用纸 第 18 页 -int Load_User_Program(char *exeFileData, ulong_t exeFileLength,struct Exe_Format *exeFormat, const char *command, struct User_Context *pUserContext) /TODO(Load a user exec

46、utable into a user memory space using segmentation); int i; ulong_t maxva = 0;/要分配的最大内存空间 unsigned numArgs;/进程数目 ulong_t argBlockSize;/参数块的大小 ulong_t size, argBlockAddr;/参数块地址 struct User_Context *userContext = 0; /计算用户态进程所需的最大内存空间 for (i = 0; i numSegments; +i) /elf.h struct Exe_Segment *segment =

47、&exeFormat-segmentListi; ulong_t topva = segment-startAddress + segment-sizeInMemory; /* FIXME: range check */ if (topva maxva) maxva = topva; Get_Argument_Block_Size(command, &numArgs, &argBlockSize);/获取参数块信息 size = Round_Up_To_Page(maxva) + DEFAULT_USER_STACK_SIZE;/用户进程大小=参数块总大小 + 进程堆栈

48、大小(8192) argBlockAddr = size; size += argBlockSize; userContext = Create_User_Context(size);/按相应大小创建一个进程 if (userContext = 0)/如果为核心态进程 return -1; for (i = 0; i numSegments; +i) struct Exe_Segment *segment = &exeFormat-segmentListi; /根据段信息将用户程序中的各段内容复制到分配的用户内存空间 memcpy(userContext-memory + segmen

49、t-startAddress, exeFileData + segment-offsetInFile,segment-lengthInFile); /格式化参数块 Format_Argument_Block(userContext-memory + argBlockAddr, numArgs, argBlockAddr, command); /初始化数据段,堆栈段及代码段信息 userContext-entryAddr = exeFormat-entryAddr; userContext-argBlockAddr = argBlockAddr; userContext-stackPointer

50、Addr = argBlockAddr; /将初始化完毕的 User_Context 赋给*pUserContext *pUserContext = userContext; return 0;/成功-/将用户态的进程复制到内核缓冲区bool Copy_From_User(void* destInKernel, ulong_t srcInUser, ulong_t bufSize)桂林电子科技大学综合设计说明书用纸 第 19 页 /TODO(Copy memory from user buffer to kernel buffer); struct User_Context * UserCon

51、text = g_currentThread-userContext; /-: check if memory if validated if (!Validate_User_Memory(UserContext,srcInUser, bufSize) return false; /-:user-kernel memcpy(destInKernel, UserContext-memory + srcInUser, bufSize); return true;-/将内核态的进程复制到用户态bool Copy_To_User(ulong_t destInUser, void* srcInKerne

52、l, ulong_t bufSize) /TODO(Copy memory from kernel buffer to user buffer) struct User_Context * UserContext = g_currentThread-userContext; /-: check if memory if validated if (!Validate_User_Memory(UserContext, destInUser, bufSize) return false; /-:kernel-user memcpy(UserContext-memory + destInUser,

53、srcInKernel, bufSize); return true;-/切换到用户地址空间void Switch_To_Address_Space(struct User_Context *userContext) /TODO(Switch to user address space using segmentation/LDT); ushort_t ldtSelector= userContext-ldtSelector;/* Switch to the LDT of the new user context */ _asm_ _volatile_ (lldt %0:a(ldtSelect

54、or); = kthread.c =添加头文件 #include -/创建一个用户进程/*static*/ void Setup_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-csSelector;/CS 选择子 unsigned dsSelector=userCon

55、text-dsSelector;/DS 选择子 Attach_User_Context(kthread, userContext); /初始化用户态进程堆栈,使之看上去像刚被中断运行一样 /分别调用 Push 函数将以下数据压入堆栈 Push(kthread, dsSelector); /数据选择子 Push(kthread, userContext-stackPointerAddr); /堆栈指针 Push(kthread, eflags); /Eflags Push(kthread, csSelector); /文本选择子桂林电子科技大学综合设计说明书用纸 第 20 页 Push(kthr

56、ead, userContext-entryAddr); /程序计数器 Push(kthread, 0); /错误代码(0) Push(kthread, 0); /中断号(0) /初始化通用寄存单元,将 ESI 用户传递参数块地址 Push(kthread, 0); /* eax */ Push(kthread, 0); /* ebx */ Push(kthread, 0); /* edx */ Push(kthread, 0); /* edx */ Push(kthread, userContext-argBlockAddr); /* esi */ Push(kthread, 0); /*

57、edi */ Push(kthread, 0); /* ebp */ /初始化数据段寄存单元 Push(kthread, dsSelector); /* ds */ Push(kthread, dsSelector); /* es */ Push(kthread, dsSelector); /* fs */ Push(kthread, dsSelector); /* gs */ /开始用户进程struct Kernel_Thread* Start_User_Thread(struct User_Context* userContext, bool detached) /TODO(Start u

58、ser thread); struct Kernel_Thread* kthread = Create_Thread(PRIORITY_USER, detached); /为用户态进程 if (kthread != 0) Setup_User_Thread(kthread, userContext); Make_Runnable_Atomic(kthread); return kthread; = syscall.c =/需在此文件别的函数前增加一个函数,函数名为 Copy_User_String,它被函数 Sys_PrintString 调用,具体实现如下:static int Copy_U

59、ser_String(ulong_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) rc = ENOMEM;桂林电子科技大学综合设计说明书用纸 第 21 页 goto fail; /从用户空间中复制数据 if (!Copy_From_User(str, uaddr, len) rc = EINVALID; Free(

60、str); goto fail; strlen = 0; /成功 *pStr = str;fail: return rc;-static int Sys_Exit(struct Interrupt_State* state) /TODO(Exit system call); Exit(state-ebx);-static int Sys_PrintString(struct Interrupt_State* state) /TODO(PrintString system call); int rc = 0;/返回值 uint_t length = state-ecx;/字符串长度 uchar_t* buf = 0; if (length 0) /* Copy string into kernel. 将字符串复制到内核*/ if (rc = Copy_User_String(st

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论