MIT jos 6.828 Fall 2014 训练记录(lab 3)
注:源代码参见我的github: https://github.com/YaoZengzeng/jos
Part A : User Environments and Exception Handling
User Exception:
1、kernel维护了以下三个全局变量和environment有关的全局变量
struct Env *envs = NULL; // All environments
struct Env *curenv = NULL; // The current env -->在启动过程中,curenv被初始化为NULL
static struct Env *env_free_list; // Free environment list 数据结构Env定义在inc/env.h中,如下所示:
struct Env {
struct Trapframe env_tf; // Saved registers
struct Env *env_link; // Next free Env
envid_t env_id; // Unique environment identifier
envid_t env_parent_id; // env_id of this env's parent
enum EnvType env_type; // Indicates special system environments
unsigned env_status; // Status of the environment
uint32_t env_runs; // Number of times environment has run
// Address space
pde_t *env_pgdir; // Kernel virtual address of page dir
};
env_id:Kernel用一个唯一的id来标示当前正在使用这个Env数据结构的进程(或者说正在使用envs中这个特定的slot的environment)。当一个用户进程终止的时候,kernel可能会将同一个Env数据结构
重新分配给另一个不同的environment。但是,新的environment仍然会有一个完全不同的env_id,虽然它和旧的environment使用在envs中相同的slot。
env_status:
ENV_FREE:该Env inactive,该结构正在env_free_list中
ENV_RUNNABLE:该Env正在等待CPU运行
ENV_RUNNING:该Env正在CPU上运行
ENV_NOT_RUNNABLE:该Env是active的,但是并不能运行,原因可能是它在等待来自其他environment的IPC
ENV_DYING:僵尸进程,它在下一次陷入kernel的时候会被释放
2、和Unix process类似,JOS的environment结合了"thread"和"address space"。thread由保存在env_tf中的寄存器定义,而address space则由env_pgdir指向的page directory和page table 定义。
在JOS中,不像xv6,每个进程都有单独的kernel stacks。因为在JOS中,每次仅仅只能有一个environment处于kernel中,因此JOS只需要一个kernel stack。
3、
(1)void env_init(void):将envs中的所有environment设置为free,将它们的env_ids设置为0,并且将它们插入到env_free_list
(2)static int env_setup_vm(struct Env *e):初始化environment e的内核部分的virtual memory,分配一个page作为e->env_pgdir的page directory,因为每个environment的kernel部分的
(3)virtual memmory的布局是一致的,因此只需要将kern_pgdir索引高于PDX(UTOP)的部分直接拷贝到e->env_pgdir的相应部分即可。
(4)static void region_alloc(struct Env *e, void *va, size_t len): 为environment e分配len个字节的physical memory,并且将它映射到该environment address space的va处。并且
将va向下对齐,(va+len)向上对齐(对齐即能被PGSIZE整除)
(5)static void load_icode(struct Env *e, uint8_t *binary):为environment e初始化程序,堆栈和处理器标志,简单地说就是将kernel中硬编码写入的程序加载到environment e的地址空间内。
并且为该程序映射一个one page大小的初始栈。
注:类似于boot loader从磁盘中加载加载内核,首先需要读取ELF header,这里将binary做强制类型转换即可
接着将类型为ELF_PROG_LOAD的segment载入内存,其实最快的方法是直接利用memcpy的方法进行内存的拷贝,但是这里存在一个问题,因为此时的page directory依旧是kernel的kern_pgdir,而我们需要将
数据拷贝到environment e自己的address space中,所以这里的操作比较tricky,需要先执行指令"lcr3(PADDR(e->env_pgdir));"进入e的address space,再进行memcpy,之后再"lcr3(PADDR(kern_pgdir));"
转换回来即可。最后,我们需要制定environment e的执行入口,其实就是初始化e->env_tf.tf_eip,一般该值为0x800020。
(6)void env_create(uint8_t *binary, enum EnvType type): 利用env_alloc获取一个新的environment,并且利用load_inode将binary载入该env的address space,最后设置environment的type。
(7)void env_run(struct Env *e):切换上下文,将当前运行的environment设置为e。
(8)env_pop_tf(struct Trapframe *tf): 将tf的内容载入寄存器,当'iret'指令执行时,离开kernel,开始执行environment的代码。
Exception Handling:
1、exception和interrupt都是受保护的控制转换(protected control transfer),它能让处理器从用户模式转换到内核模式(CPL=0),从而能够避免用户态的代码影响到kernel或者其他environment的代码。
在x86体系中,interrupt是由处理器之外异步的事件导致的控制转换,例如外设IO的消息等等,而exception是由当前正在运行的代码导致的控制转换,例如访问非法内存等等。
2、为了保证exception/interrupt导致的控制转换确实是受到保护的,那么处理器必须保证在严格控制的条件下才能进入kernel。在x86中,下面两种机制确保了这一切:
(1)The Interrupt Descriptor Table:x86规定了256种不同的interrupt和exception能进入kernel,它们每一个都有自己的interrupt vector。一个vector是一个0到255的数字。CPU使用vector作为
处理器interrupt descriptor table (IDX)的索引,而IDX存放在内核私有的内存里,通过IDX的每个表项,处理器能够得到:
一、EIP:指向处理该类型exception的内核代码。二、CS寄存器的值,其中的0-1位指定了exception handler运行的级别。
(2)The Task State Segment:在处理interrupt和exception之前,处理器需要将当前正在运行代码的状态保存起来,例如寄存器EIP和CS的值,并且为了防止恶意代码的攻击这些状态值存放的地方不能被用户态的代码访问。
因此,当x86执行interrupt或trap之前,运行等级会从用户态转化为内核态,并且会切换到内核内存中的一个stack。一个叫做task state segment(TSS)的数据结构标示了这个stack的segment selector和address。
当执行异常处理的时候,处理器先将SS,ESP,EFLAGS,CS,EIP以及一个可选的error code压栈,接着从interrupt descriptor中加载CS和EIP,最后将ESP和SS指向上述的stack。
3、在x86中所有的synchronous exception使用0到31的interrupt vectors,对应IDT的0到31,例如缺页异常就是vector 14。interrupt vector大于31的,只能被software interrupts,通常由int指令引起,或者
其他一些asynchronous hardware interrupts引起。
4、
(1)、处理器切换到TSS中SS0和ESP0指定stack。在JOS它们的值分别为GD_KD,KSTAKTOP
(2)、将SS,ESP,EFLAGS,CS,EIP一次入栈(有些exception可能会将error code入栈)
(3)、处理器从相应的IDT中获取CS:EIP,执行相应异常处理的代码
5、当系统执行一个嵌套的异常时,此时已经处在内核模式,因此它不需要切换堆栈,并且不用保存老的SS和ESP寄存器,只需要将老的EFLAGS,CS,EIP(如果还有error code)入栈即可。
MIT jos 6.828 Fall 2014 训练记录(lab 3)的更多相关文章
- MIT jos 6.828 Fall 2014 训练记录(lab 6)
源代码参见我的github: https://github.com/YaoZengzeng/jos 在这个实验中将实现一个基于Intel 82540M(又称E1000)的网卡驱动.不过,一个网卡驱动还 ...
- MIT jos 6.828 Fall 2014 训练记录(lab 4)
源代码参见我的github: https://github.com/YaoZengzeng/jos Part A: Multiprocessor Support and Cooperative Mul ...
- MIT jos 6.828 Fall 2014 训练记录(lab 2)
注: 源代码参见我的github:https://github.com/YaoZengzeng/jos Part1 : Physical Page Management mem_init函数: /*该 ...
- MIT jos 6.828 Fall 2014 训练记录(lab 1)
注: 源代码参见我的github:https://github.com/YaoZengzeng/jos Part 1: PC Bootstrap +------------------+ <- ...
- MIT jos 6.828 Fall 2014 训练记录(lab 5)
源代码参见我的github: https://github.com/YaoZengzeng/jos File system perliminaries 我们开发的是一个单用户的操作系统,只提供了足够的 ...
- MIT 操作系统实验 MIT JOS lab2
MIT JOS lab2 首先把内存分布理清楚,由/boot/main.c可知这里把kernel的img的ELF header读入到物理地址0x10000处 这里能够回想JOS lab1的一个小问.当 ...
- 台州学院maximum cow训练记录
前队名太过晦气,故启用最大牛 我们的组队大概就是18年初,组队阵容是17级生詹志龙.陶源和16级的黄睿博. 三人大学前均无接触过此类竞赛,队伍十分年轻.我可能是我们队最菜的,我只是知道的内容最多,靠我 ...
- MIT 操作系统实验 MIT JOS lab1
JOS lab1 首先向MIT还有K&R致敬! 没有非常好的开源环境我不可能拿到这么好的东西. 向每个与我一起交流讨论的programmer致谢!没有道友一起死磕.我也可能会中途放弃. 跟丫死 ...
- MIT JOS学习笔记03:kernel 02(2016.11.08)
未经许可谢绝以任何形式对本文内容进行转载! 本篇接着上一篇对kernel的分析. (5)pte_t * pgdir_walk(pde_t *pgdir, const void *va, int cre ...
随机推荐
- 【poj 3461】Oulipo(字符串--KMP)
题意:求子串在文本串中出现了多少次. 解法:使用KMP的next[ ]和tend[ ]数组计数. #include<cstdio> #include<cstdlib> #inc ...
- 机器学习实战 - 读书笔记(07) - 利用AdaBoost元算法提高分类性能
前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习笔记,这次是第7章 - 利用AdaBoost元算法提高分类性能. 核心思想 在使用某个特定的算法是, ...
- centos下完全卸载mysql
版权声明:本文为博主原创文章,未经博主允许不得转载. yum方式安装的MySQL 1.yum remove mysql mysql-server mysql-libs compat-mysql51 2 ...
- Angular 核心概念
module(模块) 作用 通过模块对页面进行业务上的划分,根据不同的功能划分不同的模块. 将重复使用的指令或者过滤器之类的代码做成模块,方便复用 注意必须指定第二个参数,否则变成找到已经定义的模块 ...
- IOS6学习笔记(二)
四.使用关联引用为分类添加数据 虽然不能在分类中创建实例变量,但是可以创建关联引用(associative reference).通过关联引用,你可以向任何对象中添加键-值(key-value)数据. ...
- 初学Node(三)模块系统
模块系统 Node根据CommonJS规范实现了一套自己的模块机制,可以使用require()导入一个模块,使用module.exports导出一个模块. require使用 在Node中我们可以使用 ...
- 初学Node(二)package.json文件
package.json简介 package.json在Node项目中用于描述项目的一些基本信息,以及依赖的配置,一般每一个Node项目的根目录下都有一个package.json文件. 在项目的根目录 ...
- 解决C#导出excel异常来自 HRESULT:0x800A03EC的方法 .
解决C#导出excel异常来自 HRESULT:0x800A03EC的方法 . xlBook.SaveAs(FilePath,Microsoft.Office.Interop.Excel.XlFi ...
- Instruments指南:如何调试内存泄露
Instruments指南:如何调试内存泄露 开篇 现在,你应该使用的ARC,而不是原来我们使用的MRC或者其他.但是我们在使用ARC的时候也会出现内存泄露的情况. 幸运的是,苹果为我们提供了Inst ...
- 博客建议(Suggestions)
I don't know if you will like the music. But I am sure there are some songs which are really wonderf ...