geekos project 2
GeekOS进程状态及转换
GeekOS系统最早创建的内核进程有Idle、Reaper和Main三个进程,它们由Init_Scheduler函数创建:最先初始化一个核态进程mainThread,并将该进程作为当前运行进程,函数最后还调用Start_Kernel_Thread 函数创建了两个系统进程Idle和Reaper。 所以,Idle、Reaper和Main三个进程是系统中最早存在的进程。
GeekOS的用户态进程
在GeekOS中为了区分用户态进程和内核进程,在Kernel_Thread结构体中设置了一个字段 userContext,指向用户态进程上下文。对于内核进程来说,这个指针为空,而用户态进程都拥有自己的用户上下文(User_Context)。因此,在GeekOS中要判断一个进程是内核进程还是用户态进程,只要通过userContext字段是否为空来判断。
User_Context结构结构
User_Context结构结构c
struct User_Context {
#define NUM_USER_LDT_ENTRIES 3
struct Segment_Descriptor ldt[NUM_USER_LDT_ENTRIES]; // 用户LDT
struct Segment_Descriptor* ldtDescriptor; // LDT描述符
char* memory; // 指向用户空间
ulong_t size; // 用户空间的大小
ushort_t ldtSelector; // ldt选择子
ushort_t csSelector; // cs选择子
ushort_t ssSelector; // ss选择子
ushort_t dsSelector; // ds选择子
pde_t *pageDir; // 页表指针
ulong_t entryAddr; // 用户程序入口地址
ulong_t argBlockAddr; // 参数块地址
ulong_t stackPointerAddr; // 用户态进程的栈指针
int refCount; // 引用数
struct File *fileList[USER_MAX_FILES]; // 打开文件列表
int fileCount; // 打开文件计数
};
用户态进程空间
每个用户态进程都拥有属于自己的内存段空间,如:代码段、数据段、栈段等,每个段有一个段描述符(segment descriptor),并且每个进程有一个段描述符表(Local Descriptor Table),用于保存该进程的所有段描述符。操作系统中还设置一个全局描述符表(GDT,Global Descriptor Table),用于记录了系统中所有进程的ldt描述符。
用户态进程创建LDT的步骤
- 调用函数Allocate_Segment_Descriptor()新建一个LDT描述符;
- 调用函数Selector()新建一个LDT选择子;
- 调用函数Init_Code_Segment_Descriptor()初始化一个文本段描述符;
- 调用函数Init_Data_Segment_Descriptor()初始化一个数据段描述符;
- 调用函数Selector()新建一个数据段选择子;
- 调用函数Selector()新建一个文本(可执行代码)段选择子。