温故而知新,几个点,有必要记一下:
1. 在执行C语言对应的程序前(boot loader),汇编部分(entry.S)已经设置好了ebp & esp。如此,C语言执行函数时即有了栈环境。
2. 内存管理是黑魔法…
分段机制(segment)无法取消,即使分页机制(paging)开启依然作用。变化只是从初始的-0xF000 0000变为了0x0;
为什么是256M? 不知道和bochs有关?不过如果物理内存是1个G的话,初始的段offset就不是-0xF000 0000而该是-0xC000 0000;
pgdir_walk()一直比较困扰我…因为涉及到stack variable,segment offset,physical address,virtual address,还涉及到段基址以及MMU自动的地址转换。我一度很分裂…而且现在依然不是很清醒…说一下理解:
分页机制开始前,因为segment offset是-0xF000 0000,所以地址我们首先手动的对其进行KADDR转换,接下来系统会自动为该虚地址+(offset=-0xF000 0000),得到其物理地址并访问;
分页机制启动后,segment offset重置为0。仍然需要进行KADDR的转换是因为页目录的映射关系,参看之前的映射Map all of physical memory at KERNBASE。
3.1 进程:将执行状态(Trapframe)与地址空间(virtual address)结合在一起(补一句,EFLAG, CR0 ~ CR3真是存了不少东西);
加载映像image的时候(就是load .text, .data segment时),记得要切换page dir,因为…你需要加载到自己的地址空间,而非操作系统的地址空间。
vpt是在kern/entry.S里设置的,对应于每个进程。vpt[0]对应virtual address page entry [0], … vpt[N]对应page entry[N]。
这个神奇的映射关系来源于env_setup_vm里的语句e->env_pgdir[PDX(VPT)] = e->env_cr3 | PTE_P | PTE_W;
至于怎么解析…假设访问page entry[0],对应vpt[0]。vpt[0]其实就是VPT的地址0xefc0 0000 –> 1110 1111 1100 0000 0000…
@step1, 取前10bit获得其page table对应的physical address,发现竟然映射回了pgdir。
@step2, 接下来取中间的10bit,此时对应到pgdir[0],也即头一份的page table的物理地址;
@step3, 取最后的12bit(这里最后2bit应该都是0,所以其实是对齐于4字节的),取到page table[0]。就是页表的第一项…mission complete, vpt[0]对应于page table entry[0]得证。
希望分析的对,内存真是黑魔法…
3.2 Interrupt & Exception:
印象比较深的就是page fault对应的处理是在用户态进行的:在内核态时设置好返回用的Trapframe,通过env_run跳转到用户态;在专门的stack上处理该exception;
Copy-on-Write, COW, COW, COW…milk…milk…
4.1 fork
parent与child拥有相同的Trapframe(eip应该是指向系统调用的下一条指令的地址,又即系统调用返回后的第一条指令),以及相同的virtual address。不同的是,child的env属性中eax(作为返回值)以及status(NOT_RUNNABLE)被修改了。所以二者会在同一地址返回,但因为eax不同,进而进入不同的执行分支。
4. 2 IPC
传值(int)与page映射。在内核态进行判断。
5. File System
根目录的相关内容存在SuperBlock中,方便查找。
文件内容映射到内存中,整整3GB的内存空间。读写基本都还是与内存打交道。
6. Shell
duppage, pipe, 等。
补:
pageref的使用貌似就是操作系统的Objc的reference count;
dev与file/pipe的关系,分明就是C的面向对象的实现;
以上。