桂林电子科技大学综合设计说明书用纸 第 9 页
{
exeFormat->segmentList[i].offsetInFile=proHeader->offset; exeFormat->segmentList[i].lengthInFile=proHeader->fileSize; exeFormat->segmentList[i].startAddress=proHeader->vaddr; exeFormat->segmentList[i].sizeInMemory=proHeader->memSize; exeFormat->segmentList[i].protFlags=proHeader->flags; proHeader++; } return 0; }
2. 编译GeekOS项目project0 (1)执行make depend shell>># make depend 生成depend.mak文件 (2)执行make shell>># make
成功之后再build目录下生成fd.img和disk.img文件。 3. 配置启动Bochs
(1)创建bochs配置文件 shell>># gedit bochsrc (2)在编辑器输入一下配置内容
romimage:file=$BXSHARE/BIOS-bochs-latest megs: 8 boot: a
floppya: 1_44=fd.img, status=inserted
ata0-master:type=disk, mode=flat, path=\log: ./bochs.out
(3)保存,直接退出gedit 4.5 运行结果 (1)启动bochs
shell>># bochs –f bochsrc
(2)选择begin simulation (3)结果:
桂林电子科技大学综合设计说明书用纸 第 10 页
图 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”文件中的函数Parse_ELF_Executable()。该函数的实现要求和项目1相同。
4.“src/GeekOS/userseg.c”文件中主要是实现一些为实现对“src/GeekOS/user.c”中高层操作支持的函数。
Destroy_User_Context()函数的功能是释放用户态进程占用的内存资源。
Load_User_Program()函数的功能通过加载可执行文件镜像创建新进程的User_Context结构。
Copy_From_User()和Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管理模式下,只要段有效,调用memcpy函数就可以实现这两个函数的功能。
Switch_To_Address_Space()函数的功能是通过将进程的LDT装入到LDT寄存器来激活
桂林电子科技大学综合设计说明书用纸 第 11 页
用户的地址空间;
5.“src/GeekOS/kthread.c”文件中的Start_User_Thread函数和Setup_User_Thread函数。
Setup_User_Thread()函数的功能是为进程初始化内核堆栈,堆栈中是为进程首次进入用户态运行时设置处理器状态要使用的数据。
Start_User_Thread()是一个高层操作,该函数使用User_Context对象开始一个新进程。
6.“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 GeekOS进程转换
GeekOS系统最早创建的内核进程有Idle、Reaper和Main三个进程,它们由Init_Scheduler函数创建:最先初始化一个核态进程mainThread,并将该进程作为当前运行进程,函数最后还调用Start_Kernel_Thread 函数创建了两个系统进程Idle和Reaper。 所以,Idle、Reaper和Main三个进程是系统中最早存在的进程。 2.GeekOS的用户态进程
在GeekOS中为了区分用户态进程和内核进程,在Kernel_Thread结构体中设置了一个字段 userContext,指向用户态进程上下文。对于内核进程来说,这个指针为空,而用户态进程都拥有自己的用户上下文(User_Context)。因此,在GeekOS中要判断一个进程是内核进程还是用户态进程,只要通过userContext字段是否为空来判断就可以了。
桂林电子科技大学综合设计说明书用纸 第 12 页
图 5.2 用户进程
3.用户进程空间
每个用户态进程都拥有属于自己的内存段空间,如:代码段、数据段、堆栈段等,每个段有一个段描述符(segment descriptor),并且每个进程有一个段描述符表(Local Descriptor Table),用于保存该进程的所有段描述符。操作系统中还设置一个全局描述符表(GDT,Global Descriptor Table),用于记录了系统中所有进程的ldt描述符。
图 5.3 用户进程空间
4. 用户态进程创建LDT的步骤
(1)调用函数Allocate_Segment_Descriptor()新建一个LDT描述符; (2)调用函数Selector()新建一个LDT选择子;
(3)调用函数Init_Code_Segment_Descriptor()新建一个文本段描述符; (4)调用函数Init_Data_Segment_Descriptor()新建一个数据段; (5)调用函数Selector()新建一个数据段选择子;
(6)调用函数Selector()新建一个文本(可执行代码)段选择子。
桂林电子科技大学综合设计说明书用纸 第 13 页
图 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文件主要是实现一些为实现对src/GeekOS/user.c中高层操作支持的函数。
Destroy_User_Context()函数的功能是释放用户态进程占用的内存资源。
Load_User_Program()函数的功能通过加载可执行文件镜像创建新进程的User_Context结构。 Copy_From_User()和Copy_To_User()函数的功能是在用户地址空间和内核地址空间之间复制数据,在分段存储器管理模式下,只要段有效,调用memcpy函数就可以实现这两个函数的功能。 Switch_To_Address_Space()函数的功能是通过将进程的LDT装入到LDT寄存器来激活用户的地址空间