




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第3页操作系统实验报告目录TOC\o"1-3"\h\u10181.实验目的 1170192.开发环境的搭建 2211332.1在虚拟机上安装Linux 2207432.2安装VMwareTools和实现文件共享 2218192.3BochsPC模拟器的安装 2262803.项目具体实现 2167603.1项目0 221003.1.1项目设计要求 3248723.1.2项目设计原理 3304003.1.3项目设计的具体实现 473713.1.4系统编译运行的原理及结果 5239693.2项目1 630533.2.1项目设计要求 6208853.2.2项目设计原理 6261513.2.3项目设计的具体实现 7128633.2.4系统编译运行的原理及结果 9167043.3项目2 10185083.3.1项目设计要求 10115613.3.2项目设计原理 1035853.3.3项目设计的具体实现 1112473.3.4系统编译运行的原理及结果 18156204.遇到的问题及解决办法 19172875.实验总结 19实验目的操作系统是管理系统软件,硬件资源,控制程序运行,改善人机界面及交互,提供各种服务,合理组织计算机工作流程和为用户有效地使用计算机提供良好运行环境的系统软件,它为用户使用计算机提供了一个方便,灵活,安全,可靠的工作环境,它也是其他运用软件赖以存在的基础。操作系统是计算机科学与技术专业核心的课程,涉及到很多方面的知识,概念和原理抽象。在课程学习过程中,主要是学习理论知识,而操作系统实验则从理论转向实践,让我们亲自去编写一个操作系统内核,从而可以更加深入的理解操作系统软件的实现过程,增强了实践动手能力。本实验主要要求我们熟悉GeekOs的项目编译、调试和运行环境,掌握GeekOs运行工作过程。熟悉ELF文件格式,了解GeekOs系统如何将ELF格式的用户可执行程序装入到内存,建立内核线程并运行的实现技术。扩充GeekOs操作系统内核,使得系统能过支持用户级进程的动态创建和执行。开发环境的搭建在实现这个过程中。由于Geekos是开源的基于linux系统开发的操作系统,我们需要用到linux下的编译环境。所以需要搭建linux环境。为了实现与Windows下的文件进行共享,需要安装VMwareTools软件包。在运行的时候需要bochspc模拟器来模拟操作系统,所以也需要安装bochspc模拟器。2.1在虚拟机上安装Linux本次环境的搭建是采用在Windows环境下先安装一个PC虚拟机,然后在虚拟机上安装Linux操作系统。本次实验选择安装的虚拟机软件VMware,安装过程则为首先在相应的网站下载此安装软件,然后其根据提示安装。安装完成后就会在桌面上显示一个虚拟机图标VMware-workstation。VMware安装完成后,可以开始建立虚拟机,每新建一个虚拟机都会要求建立一个配置文件,这个配置文件相当于电脑中的硬件配置表,用户可以在配置文件中决定虚拟机的硬盘如何配置,内在多大,准备运行哪种操作系统,是否有网络等。其中中安装的过程中要选取实验需要的相应组件进行安装,其中本次实验必须需要的组件是:AWK、Diff3、Egrep、gcc、GNUbinutils、GNUMake、Perl、NASM。2.2安装VMwareTools在虚拟机上安装VMwareTools,就相当于给Linux安装各种驱动程序。此步的主要目的就是为了以后的工程运行时能够实现与Windows下的文件进行共享,因为bochsPC模拟器要在Windows下运行,所以这里的文件就只能通过这一步的共享,从而达到在Linux下工程运行后得到的build下的镜像文件替代源文件,从而使得bochsPC模拟器能够得到所需的镜像文件。2.3安装BochsPC模拟器BochsPC模拟器:用来运行GeekOS系统。安装此软件只需设定好想安装到的文件目录后一直点下一步就可以安装成功。最后设置bochsrc.txt文件。根据实验的需要,一般只需要修改以下几项:(1)vgaromimage:$BXSHARE/VGABIOS-lgpl-latest(2)romimage:file=$BXSHARE/BIOS-bochs-latest,address=0xf0000(3)floppya:1_44=fdx.img,status=insertedboot:floppy(4)做Project1的时候,需要添加一个磁盘镜像ata0-master:type=disk,mode=flat,path=diskx.img,cylinders=615,heads=6,spt=17配置完bochsrc.txt以后,而且有了从工程生成的操作系统Geekos就可以用bochs软件模拟了。到bochs的安装目录下,输入bochs命令,选择6开始模拟。如果你的操作系统编译成功,就可以得到想要的结果。项目具体实现3.1项目0本项目主要目的是要熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。3.1.1项目设计要求(1)搭建GeekOS的编译和调试平台,掌握GeekOS的内核进程工作原理。(2)熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接收键盘输入的字符并显示到屏幕上,当输入Ctrl+D时,结、束进程的运行。3.1.2项目设计原理在这个项目里面主要了解两部分的内容:内核线程和键盘处理,相应的文件是thread.c和keyboard.c。Geekos系统的默认内核只支持内核态的线程,在系统初始化的时候,main函数分别执行了4个内核函数,一个内核函数负责软驱中断,一个复杂键盘中断,还有两个负责进程调度。函数Start_Kernel_Thread()其可以生成一个内核线程:1.内核线程结构的定义如下:structKernel_Thread{unsignedlongesp;volatileunsignedlongnumTicks;intpriority;DEFINE_LINK(Thread_Queue,Kernel_Thread);void*stackPage;structUser_Context*userContext;structKernel_Thread*owner;intrefCount;Booleanalive;structMutexjoinLock;structConditionjoinCond;};esp字段用来存放一个线程挂起的堆栈指针;stackPage字段指向内核线程的堆栈页面numTicks和priority分别被调度程序用来实现基于先占权和基于优先权的时间片调度。DEFINE_LINK宏定义一个内核线程在线程队列上时的前一个和后一个字段。userContext字段如果不为空,则指向一个线程用户环境,它是一个允许线程执行用户模式的代码和数据的组合段。内核线程有两种方式创建。在内核里独立运行的线程可通过Start_Kernel_Thread()函数来创建,该函数通过一个指针指向一个执行线程体的启动函数。线程所执行的用户模式的程序由Start_User_Thread()函数创建,并且用一指针指向一个用户环境和用户环境内存中代码入口点的地址。调用Exit()函数销毁内核线程。入口参数分别为:函数地址,函数参数(无参数就写0),优先级设定,线程属性(false为内核线程,true为用户线程),返回值Mythread的数据类型是staticstructKernel_Thread*thread2.Start_Kernel_Thread完成的工作:Create_Thread(priority,detached)//根据优先级创建一条线程kthread=Alloc_Page()//为线程分配内存空间stackPage=Alloc_Page()Init_Thread(kthread,stackPage,priority,detached)Add_To_Back_Of_All_Thread_List(&s_allThreadList,kthread)Setup_Kernel_Thread(kthread,startFunc,arg)//配置内核线程的初始化Make_Runnable_Atomic(kthread);//设置线程运行的原子性操作Disable_Interrupts();//禁止中断Make_Runnable(kthread);//线程运行Enable_Interrupts();//使能中断3.Geekos处理键盘代码在keyboard.c里面提供了一个功用函数KeycodeWait_For_Key(void),循环等待一个键盘事件,然后返回一个16位的数据Keycode型的,在keyboard.h里定义了所有的键盘代码。Read_Key(Keycode*keycode)函数可以处理队列键盘按键,可以保存到队列中并输出。关于Keycode的定义是:低8位用来表示键盘值,通过s_scanTableNoShift和s_scanTableWithShift这两个数组来转换相应的键盘码为所表示字符的ASCII码,高六位分别是:KEY_SPECIAL_FLAG(特殊键,比如F1,F2)用返回的值key&0x0100就可以判断是否按下特殊健,1为有效,说明是特殊健,0则不是,以下的几种情况类似KEY_KEYPAD_FLAG(小键盘键)0x0200KEY_SHIFT_FLAG(左,右SHIFT)0x1000KEY_ALT_FLAG(左,右ALT)0x2000KEY_CTRL_FLAG(左,右CTRL)0x4000KEY_RELEASE_FLAG(键弹起来标志位)0x80003.1.3项目设计的具体实现projcet0项目主要是对main.c文件中的键盘相应的实现。我们创建函数keyboard()。下面是具体的代码。voidkeyboard(ulong_targ){Keycodekey;Print("PleaseEnterthecharacters.press'Ctrl+d'toexit\n\n");while(true){Set_Current_Attr(ATTRIB(BLACK,RED|BRIGHT));key=Wait_For_Key();if(key==(KEY_CTRL_FLAG+'d')){Print("\n\nKeyEnd\n");break;}if(!(key&KEY_RELEASE_FLAG)&&!(key&KEY_SPECIAL_FLAG)){Print("%c",key);}}}voidMain(structBoot_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("\n\nWelcometosutingting'sGeekOS!\n\n");Start_Kernel_Thread(keyboard,0,5,1);Set_Current_Attr(ATTRIB(BLACK,GRAY));TODO("Startakernelthreadtoechopressedkeysandprintcounts");Exit(0);}3.1.4系统编译运行的原理及结果I.编译源代码在linux的终端中:(1)输入:cd+空格+路径(project0文件下的build文件所在的路径)(2)终端进入build目录$makedepend$make 如果没有问题就会自动生成一个镜像文件fd.img。II修改bochsrc.txt配置文件其具体的文件bochsrc.txt内容如下:#配置模拟器的BIOS和显示系统的BIOS文件vgaromimage:$BXSHARE/VGABIOS-lgpl-latestromimage:file=$BXSHARE/BIOS-bochs-latest,address=0xf0000#配置模拟器内存大小megs:8#配置模拟器从软盘引导系统boot:a#这是对模拟器硬盘的描述,其中disk.img是硬盘的映像文件,将其注释掉,因为项目0#不需要硬盘。#软盘A的描述,其中fd.img为软盘映像文件floppya:1_44=fd.img,status=inserted#floppya:1_44=fd_aug.img,status=inserted#这是配置模拟器的系统文件keyboard_serial_delay:200floppy_command_delay:500vga_update_interval:300000ips:1000000mouse:enabled=0private_colormap:enabled=0i440fxsupport:enabled=0#配置模拟器的日志文件log:./bochs.outIII.运行bochs终端运行bochs选择6即的运行结果如下图1所示:图1project0的运行结果3.2项目1本项目主要是为了让学生熟悉ELF文件格式,了解Geekos系统如何将ELF
格式的用户可执行程式装入到内存,建立内核进程并运行的实现技术。3.2.1项目设计要求分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件的长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。(1)修改/geekos/elf.c文件:在函数Parse_ELF_Executable()中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。(2)在Linux环境下编译系统得到GeekOS镜像文件。(3)编写一个相应的bochs配置文件。(4)在bochs中运行GeekOS系统显示结果。3.2.2项目设计原理项目的主要内容是在文件elf.c中函数Parse_ELF_Executable()添加代码,实现对ELF文件的解释,装入到内存运行,得到指定的结果.主要是分析ELF文件。为以后的工程执行应用程序做准备,需要理解的是ELF的一下原理性。需要关注以下几个数据结构:具体代码在\project1include\geekos\elf.h中:typedef struct{unsignedcharident[16];unsignedshorttype;unsignedshortmachine;unsignedintversion;unsignedintentry;unsignedintphoff; //programheader偏移量unsignedintsphoff; //sectionheader的偏移unsignedintflags; //指示具体的进程unsignedshortehsize; //elf头部的大小unsignedshortphentsize; //programheader的大小 unsignedshortphnum; //programheader的个数unsignedshortshentsize; unsignedshortshnum;unsignedshortshstrndx;}elfHeader;structExe_Format{structExe_SegmentsegmentList[EXE_MAX_SEGMENTS];//段的定义intnumSegments; //可执行文件中段的个数ulong_tentryAddr; //代码入口};structExe_Segment{ulong_toffsetInFile; //段在可执行文件中的偏移ulong_tlengthInFile; //段在可执行文件中的长度 ulong_tstartAddress; //段在内存中的起始地址ulong_tsizeInMemory; //段在内存中的大小intprotFlags; //VM保护标志};typedefstruct{unsignedinttype;unsignedintoffset;unsignedintvaddr;unsignedintpaddr;unsignedintfileSize; unsignedintmemSize;unsignedintflags;unsignedintalignment;}programHeader;offset 表示该成员给出了该段的驻留位置相对于文件开始处的偏移。fileSize表示该成员给出了文件映像中该段的字节数;它可能是0。memSize表示该成员给出了内存映像中该段的字节数;它可能是0。vaddr 表示该成员给出了该段在内存中的首字节地址。flags表示该成员给出了和该段相关的标志。这是编程实现过程主要部分,对linux下ELF有一定了解之后,就能顺利的完成工程项目设计的具体实现下面是project1\src\geekos下的elf.c中的代码。#include<geekos/errno.h>#include<geekos/kassert.h>#include<geekos/ktypes.h>#include<geekos/screen.h>/*fordebugPrint()statements*/#include<geekos/pfat.h>#include<geekos/malloc.h>#include<geekos/string.h>#include<geekos/elf.h>intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat){inti;elfHeader*head=(elfHeader*)exeFileData;programHeader*proHeader=(programHeader*)(exeFileData+head->phoff);Set_Current_Attr(ATTRIB(BLACK,BLUE|BRIGHT));Print("ident=%s,",head->ident);Print("type=%d,",head->type);Print("machine=%d,",head->machine);Print("version=%d\n",head->version);Print("entry=%d,",head->entry);Print("phoff=%d,",head->phoff);Print("sphoff=%d,",head->sphoff);Print("flags=%d\n",head->flags);Print("ehsize=%d,",head->ehsize);Print("phentsize=%d,",head->phentsize);Print("phnum=%d,",head->phnum);Print("shentsize=%d\n",head->shentsize);Print("shnum=%d,",head->shnum);Print("shstrndx=%d\n",head->shstrndx);Set_Current_Attr(ATTRIB(BLACK,RED|BRIGHT));Print("type=%d,",proHeader->type);Print("offset=%d,",proHeader->offset);Print("vaddr=%d,",proHeader->vaddr);Print("paddr=%d\n",proHeader->paddr);Print("fileSize=%d,",proHeader->fileSize);Print("memSize=%d,",proHeader->memSize);Print("flags=%d,",proHeader->flags);Print("alignment=%d\n",proHeader->alignment);Set_Current_Attr(ATTRIB(BLACK,GREEN|BRIGHT));for(i=0;i<head->phnum;i++)//programheadertablenumber{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++;}exeFormat->numSegments=head->phnum;exeFormat->entryAddr=head->entry;return0;}3.2.4系统编译运行的原理及结果I.编译源代码在linux的终端中:(1)输入:cd+空格+路径(project1文件下的build文件所在的路径)(2)终端进入build目录$makedepend$make 如果没有问题就会自动生成两个镜像文件fd.img和diskc.img。II修改.bochsrc.txt配置文件其具体的文件bochsrc.txt内容如下:vgaromimage:$BXSHARE/VGABIOS-lgpl-latestromimage:file=$BXSHARE/BIOS-bochs-latest,address=0xf0000megs:8boot:a#diskc:file=diskc.img,cyl=40,heads=8,spt=64#这是对模拟器硬盘的描述,其中disk.img是硬盘的映像文件。ata0:enabled=1,ioaddr1=0x1f0,ioaddr2=0x3f0,irq=14ata0-master:type=disk,mode=flat,path=diskc.img,cylinders=40,heads=8,spt=64floppya:1_44=fd.img,status=inserted#floppya:1_44=fd_aug.img,status=insertedkeyboard_serial_delay:200floppy_command_delay:500vga_update_interval:300000ips:1000000mouse:enabled=0private_colormap:enabled=0i440fxsupport:enabled=0log:./bochs.outIII.运行bochs终端运行bochs选择6即的运行结果如下图2所示:图2project1的运行结果3.3项目2本项目主要的任务是扩展Geekos操作系统内核,使得系统能够支持用户级进程的动态创建和执行。3.3.1项目设计要求(1)修改user.c中的函数Spawn(),其功能是生成一个新的用户级进程。(2)修改user.c中函数Switch_To_UserContext(),调度程序在执行一个新的进程前调用该函数以切换用户地址空间。(3)修改文件elf.c文件中的函数Parse_ELF_Executable()。这个在项目一已经实现。(4)修改userseg.c文件中的Destroy_User_Context()、Load_User_Program()、Copy_From_User()、Copy_To_User()和Switch_To_Address_Space()。(5)修改kthread.c文件中的Start_User_Thread()和Setup_User_Thread()函数(6)实现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)。3.3.2项目设计原理项目2需要实现用户进程,其实用户进程就是基于内核进程的一个改进。内核进程控制块结构Kernel_Thread中有一个字段User_Context,而在初始化内核进程的函数时系统将其初始化为零;User_Context字段其实就是上下文数据结构,定义如下:StructUser_Context{#defineNUM_USER_LDT_ENTRIES3StructSegment_Descriptorldt[NUM_USRE_LDT_ENTRIES];Structsegment_Descriptor*ldtDsecriptor;Char*memory;Ulong_tsize;Ushort_tldtSelector;Ushort_tcsSelector;Ushort_tdsSelector;Pde_t*pageDir;Ulong_tentryAddr;Ulong_targBlockAddr;Ulong_tstackPointerAddr;IntrefCount;#if0Int*semaphores#endif};StructSegmentDescriptorldt[NUM_USER_LDT_ENTRIES]:是SegmentDescriptor数组,这里只有两个元素,一个Segment用于用户进程的数据,一个Segment用于用户进程的代码。ldtDescriptor是LDT的描述SegmentDescriptor,memory是用户内存空间的其实地址。Size是用户空间的大小。entryAddr是用户代码的其实地址,进程就是从这个地址开始运行的。3.3.3项目设计的具体实现主要修改以下文件中的函数:User.c中intSpawn(constchar*program,constchar*command,structKernel_Thread**pThread){
intrc;
char*exeFileData=0;
ulong_texeFileLength;
structUser_Context*userContext=0;
structKernel_Thread*process=0;
structExe_FormatexeFormat;
if((rc=Read_Fully(program,(void**)&exeFileData,&exeFileLength))!=0||
(rc=Parse_ELF_Executable(exeFileData,exeFileLength,&exeFormat))!=0||
(rc=Load_User_Program(exeFileData,exeFileLength,&exeFormat,command,&userContext))!=0)
gotofail;
Free(exeFileData);
exeFileData=0;
/*开始用户进程*/
process=Start_User_Thread(userContext,false);
if(process!=0){
KASSERT(process->refCount==2);
/*返回核心进程的指针*/
*pThread=process;
}else
rc=ENOMEM;
returnrc;fail:
if(exeFileData!=0)
Free(exeFileData);
if(userContext!=0)
Destroy_User_Context(userContext);
returnrc;}voidSwitch_To_User_Context(structKernel_Thread*kthread,structInterrupt_State*state){
staticstructUser_Context*s_currentUserContext;
/*lastusercontextused*/
externintuserDebug;
structUser_Context*userContext=kthread->userContext;
KASSERT(!Interrupts_Enabled());
if(userContext==0){
/*核心态进程,无需改变地址空间.*/
return;
}
if(userContext!=s_currentUserContext){
ulong_tesp0;
if(userDebug)Print("A[%p]\n",kthread);
Switch_To_Address_Space(userContext);
esp0=((ulong_t)kthread->stackPage)+PAGE_SIZE;
if(userDebug)Print("S[%lx]\n",esp0);
/*新进程的核心栈.*/
Set_Kernel_Stack_Pointer(esp0);
/*Newusercontextisactive*/
s_currentUserContext=userContext;
}}Elf.c中intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,
structExe_Format*exeFormat){
inti; elfHeader*head=(elfHeader*)exeFileData; programHeader*proHeader=(programHeader*)(exeFileData+head->phoff); KASSERT(exeFileData!=NULL); KASSERT(exeFileLength>head->ehsize+head->phentsize*head->phnum); KASSERT(head->entry%4==0); exeFormat->numSegments=head->phnum; exeFormat->entryAddr=head->entry; for(i=0;i<head->phnum;i++) { 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++; } return0;}Userseg.c中voidDestroy_User_Context(structUser_Context*userContext){
Free_Segment_Descriptor(userContext->ldtDescriptor); userContext->ldtDescriptor=0; //释放内存空间 Free(userContext->memory); userContext->memory=0; //释放userContext本身占用的内存 Free(userContext); userContext=0;}intLoad_User_Program(char*exeFileData,ulong_texeFileLength,
structExe_Format*exeFormat,constchar*command,
structUser_Context**pUserContext){
inti; ulong_tmaxva=0;//要分配的最大内存空间 unsignednumArgs;//进程数目 ulong_targBlockSize;//参数块的大小 ulong_tsize,argBlockAddr;//参数块地址 structUser_Context*userContext=0; //计算用户态进程所需的最大内存空间 for(i=0;i<exeFormat->numSegments;++i) { //elf.h structExe_Segment*segment=&exeFormat->segmentList[i]; ulong_ttopva=segment->startAddress+segment->sizeInMemory;/*FIXME:rangecheck*/ if(topva>maxva) { maxva=topva; } } Get_Argument_Block_Size(command,&numArgs,&argBlockSize);//获取参数块信息 size=Round_Up_To_Page(maxva)+DEFAULT_USER_STACK_SIZE;//用户进程大小=参数块总大小+进程堆栈大小(8192) argBlockAddr=size; size+=argBlockSize; userContext=Create_User_Context(size);//按相应大小创建一个进程 if(userContext==0)//如果为核心态进程 { return-1; } for(i=0;i<exeFormat->numSegments;++i) { structExe_Segment*segment=&exeFormat->segmentList[i]; //根据段信息将用户程序中的各段内容复制到分配的用户内存空间 memcpy(userContext->memory+segment->startAddress,exeFileData+segment->offsetInFile,segment->lengthInFile); } //格式化参数块 Format_Argument_Block(userContext->memory+argBlockAddr,numArgs,argBlockAddr,command); //初始化数据段,堆栈段及代码段信息 userContext->entryAddr=exeFormat->entryAddr; userContext->argBlockAddr=argBlockAddr; userContext->stackPointerAddr=argBlockAddr; //将初始化完毕的User_Context赋给*pUserContext *pUserContext=userContext; return0;//成功}boolCopy_From_User(void*destInKernel,ulong_tsrcInUser,ulong_tbufSize){
structUser_Context*current=g_currentThread->userContext;
if(!Validate_User_Memory(current,srcInUser,bufSize))
returnfalse;
memcpy(destInKernel,User_To_Kernel(current,srcInUser),bufSize);
returntrue;}boolCopy_To_User(ulong_tdestInUser,void*srcInKernel,ulong_tbufSize){
structUser_Context*current=g_currentThread->userContext;
if(!Validate_User_Memory(current,destInUser,bufSize))
returnfalse;
memcpy(User_To_Kernel(current,destInUser),srcInKernel,bufSize);
returntrue;}voidSwitch_To_Address_Space(structUser_Context*userContext){
//TODO("Switchtouseraddressspaceusingsegmentation/LDT"); ushort_tldtSelector=userContext->ldtSelector;/*SwitchtotheLDTofthenewusercontext*/ __asm____volatile__("lldt%0"::"a"(ldtSelector));
}Kthread.c中Start_User_Thread(structUser_Context*userContext,booldetached){
structKernel_Thread*kthread=Create_Thread(PRIORITY_USER,detached);
if(kthread!=0){
Setup_User_Thread(kthread,userContext);
Make_Runnable_Atomic(kthread);
}
returnkthread;}voidSetup_User_Thread(
structKernel_Thread*kthread,structUser_Context*userContext){
//TODO("Createanewthreadtoexecuteinusermode");ulong_teflags=EFLAGS_IF;unsignedcsSelector=userContext->csSelector;//CS选择子unsigneddsSelector=userContext->dsSelector;//DS选择子Attach_User_Context(kthread,userContext); //初始化用户态进程堆栈,使之看上去像刚被中断运行一样 //分别调用Push函数将以下数据压入堆栈Push(kthread,dsSelector);//数据选择子Push(kthread,userContext->stackPointerAddr);//堆栈指针Push(kthread,eflags);//EflagsPush(kthread,csSelector);//文本选择子Push(kthread,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);/*edi*/Push(kthread,0);/*ebp*///初始化数据段寄存单元Push(kthread,dsSelector);/*ds*/Push(kthread,dsSelector);/*es*/Push(kthread,dsSelector);/*fs*/Push(kthread,dsSelector);/*gs*/}Syscall.c中staticintSys_Exit(structInterrupt_State*state){
Exit(state->ebx);}staticintSys_PrintString(structInterrupt_State*state){
intrc=0;
uint_tlength=state->ecx;
uchar_t*buf=0;
if(length>0){
/*Copystringintokernel.*/
if((rc=Copy_User_String(state->ebx,length,1023,(char**)&buf))!=0)
gotodone;
/*Writetoconsole.*/
Put_Buf(buf,length);
}done:
if(buf!=0)
Free(buf);
returnrc;}staticintSys_GetKey(structInterrupt_State*state){
returnWait_For_Key();}staticintSys_SetAttr(structInterrupt_State*state){
Set_Current_Attr((uchar_t)state->ebx);
return0;}staticintSys_GetCursor(structInterrupt_State*state){
introw,col;
Get_Cursor(&row,&col);
if(!Copy_To_User(state->ebx,&row,sizeof(int))||
!Copy_To_User(state->ecx,&col,sizeof(int)))
{return-1;}
return0;}staticintSys_PutCursor(structInterrupt_State*state){
returnPut_Cursor(state->ebx,state->ecx)?0:-1;}staticintSys_Spawn(structInterrupt_State*state){
intrc;
char*program=0;
char*command=0;
structKernel_Thread*process;
/*Copyprogramnameandcommandfromuserspace.*/
if((rc=Copy_User_String(state->ebx,state->ecx,VFS_MAX_PATH_LEN,&program))!=0||
(rc=Copy_User_String(state->edx,state->esi,1023,&command))!=0)
gotodone;
Enable_Interrupts();
rc=Spawn(program,command,&process);
if(rc==0){
KASSERT(process!=0);
rc=process->pid;
}
Disable_Interrupts();done:
if(program!=0)
Free(program);
if(command!=0)
Free(command);
returnrc;}staticintSys_Wait(structInterrupt_State*state){
intexitCode;
structKer
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 度合同制速记服务与保密全文
- 水产养殖合同范本专业版
- 租赁合同范本:车辆租赁协议
- 建筑设计服务合同样本版
- 生态林地保护承包合同书样本
- 企业贷款合同、利息计算标准
- 企业风险控制反担保合同模板
- 公租房解除合同范本
- 化工原料采购合同范本大全
- 演艺人才培养合作合同范本
- GB/T 3452.2-2007液压气动用O形橡胶密封圈第2部分:外观质量检验规范
- GB/T 30797-2014食品用洗涤剂试验方法总砷的测定
- GB/T 20057-2012滚动轴承圆柱滚子轴承平挡圈和套圈无挡边端倒角尺寸
- GB/T 19808-2005塑料管材和管件公称外径大于或等于90mm的聚乙烯电熔组件的拉伸剥离试验
- GB/T 12771-2019流体输送用不锈钢焊接钢管
- 工程验收及移交管理方案
- 班组建设工作体系课件
- 图片编辑概述课件
- 第章交通调查与数据分析课件
- 2023年岳阳职业技术学院单招职业技能考试笔试题库及答案解析
- 北师大版八年级数学上册《认识无理数(第2课时)》参考课件2
评论
0/150
提交评论