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 ...
随机推荐
- 泛函编程(8)-数据结构-Tree
上节介绍了泛函数据结构List及相关的泛函编程函数设计使用,还附带了少许多态类型(Polymorphic Type)及变形(Type Variance)的介绍.有关Polymorphism的详细介绍会 ...
- IIS在默认情况并不支持对PUT和DELETE请求的支持
IIS在默认情况并不支持对PUT和DELETE请求的支持: IIS拒绝PUT和DELETE请求是由默认注册的一个名为:“WebDAVModule”的自定义HttpModule导致的.WebDAV的全称 ...
- linux环形buff模拟多线程信号量操作
互斥锁mutex变量的值非0即1,只能用来表示两种状态下的临界资源.而信号量是与之类似的,用来表示可用资源的,区别在于,信号量可以表示多个可用资源的. --值为2的信号量也就是特殊的互斥锁了. 那么下 ...
- winform(多窗体、菜单和工具栏)
一.多窗体 1.哪个是主窗体 利用From1的button将From2打开 private void button1_Click(object sender, EventArgs e) { Form2 ...
- Angular 核心概念2
自定义指令 指令增强了 HTML,提供额外的功能 内置的指令基本上已经可以满足我们的绝大多数需要了 少数情况下我们有一些特殊的需要,可以通过自定义指令的方式实现 普通指令 语法 <div hel ...
- Javascript面向对象编程(二)--- 构造函数的继承
这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例 今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动 ...
- Java反射中的getClass()方法
Java反射学习 所谓反射,可以理解为在运行时期获取对象类型信息的操作.传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代 ...
- Windows环境下利用github快速配置git环境
在windows环境下利用github客户端我们可以直接拥有可视化的界面来管理工程,当然你也可以选择你喜欢的命令行工具来做.今天我分享一个比较快速的方式来配置git环境. 先去下载github的win ...
- Unable to execute dex: Multiple dex files define Lcom/kenai/jbosh/AbstractAttr
出现该问题应该是导入项目的android版本问题. 编译的时候把build path 下 source选项卡中的libs去掉就正常了. http://blog.csdn.net/e421083 ...
- Android项目实战(十五):自定义不可滑动的ListView和GridView
不可滑动的ListView (RecyclweView类似) public class NoScrollListView extends ListView { public NoScrollListV ...