date: 2019-02-22
tags: OS 6.828
这里会记录阅读6.828课程lecture note的我的个人笔记。可能会中英混杂,不是很适合外人阅读,也请见谅。
step back: 从整个课程的角度
没有设计OS的最好方式
很多OS都使用虚拟内存,但是这不一定。
xv6和JOS都是OS设计的例子,但是他们和真正的OS相比还是有很大差距的。
guard page to protect against stack overflow
在user stack后面放一个没有被map的page,这样如果stack overflow了,会得到page fault
当application跑到guard page上来的时候分配more stack。
优化:one zero-filled page
观察到很多时候一些memory从来不会被写入,而因为所有的内存都会用0进行初始化,所以可以使用一个zeroed page for all zero mappings。
当需要zero-filled page的时候,就map到这个zeroed page
在写入的时候,make copy of page and map it read/write in app address space
case T_PGFLT:
{
int write = (tf->err & FEC_WR) > 0;
uint va = PGROUNDDOWN(rcr2());
if (va < proc->sz){
if (write){
char *mem = kalloc();
if(mem == 0){
cprintf("out of memory\n");
exit();
return;
}
memset(mem, 0, PGSIZE);
cprintf("kernel faulting in read/write page at %x\n", va);
mappages(proc->pgdir, (char*)va, PGSIZE, v2p(mem), PTE_W|PTE_U);
}else{
cprintf("kernel faulting in read-only zero page at %x\n", va);
mappages(proc->pgdir, (char*)va, PGSIZE, v2p(zero_page), PTE_U);
}
return;
}
}
这里我并没有在xv6黎曼进行修改,因为不知道这个zero_page
是应该在什么时候实现。
优化:share kernel page mapping
注意到kvmalloc
会对所有的process都分配kernel page table。但是他们都是一样的。所以实际上可以统一一下。修改方式是改kvmalloc
和freevm
(不知道该怎么改,主要是现在的版本只有在main里面会调用一次kvmalloc
,而不是每次执行新的process都会,所以就不知道该怎么弄了)
优化:copy-on-write fork
很多时候都是fork之后马上exec,如果赋值了会很浪费,所以把parent和child的内存先共享着,并且把child的内存设置为copy on write,也就是有写入的时候再复制。
稍微具体一点就是修改fork
来map pages copy-on-write (use extra available system bits in PTEs and PDEs)
on page fault, make copy of page and map it read/write
优化:demanding paging
现在的exec可能会把整个文件都加载到内存中,这样会很慢,并且有可能没必要。可以先分配page,并标记为on demand,on default从file中读取对应的page。会遇到的挑战就是如果文件比物理内存还大怎么办?下一条会给出解决方案。
Feature: 用比物理内存更大的虚拟内存
有的时候可能需要比物理内存还大的内存。解决方法就是把内存中不常用的部分存在硬盘上。
在硬盘和内存之间"page in" and out数据
当同时使用的内存小于RAM的时候,非常work。
Feature: memory-mapped files
通过load, store而不是read, write, lseek来access files以轻松访问文件的某一部分
mmap
system callFeature: distributed shared memory
用虚拟内存来假装物理内存 is shared between several machines on the network
注意只有read only page可以复制,而能够写入的不能。
4 Gig --------> +------------------------------+
| | RW/--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: . :
: . :
: . :
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
| | RW/--
| Remapped Physical Memory | RW/--
| | RW/--
KERNBASE, ----> +------------------------------+ 0xf0000000 --+
KSTACKTOP | CPU0's Kernel Stack | RW/-- KSTKSIZE |
| - - - - - - - - - - - - - - -| |
| Invalid Memory (*) | --/-- KSTKGAP |
+------------------------------+ |
| CPU1's Kernel Stack | RW/-- KSTKSIZE |
| - - - - - - - - - - - - - - -| PTSIZE
| Invalid Memory (*) | --/-- KSTKGAP |
+------------------------------+ |
: . : |
: . : |
MMIOLIM ------> +------------------------------+ 0xefc00000 --+
| Memory-mapped I/O | RW/-- PTSIZE
ULIM, MMIOBASE --> +------------------------------+ 0xef800000
| Cur. Page Table (User R-) | R-/R- PTSIZE
UVPT ----> +------------------------------+ 0xef400000
| RO PAGES | R-/R- PTSIZE
UPAGES ----> +------------------------------+ 0xef000000
| RO ENVS | R-/R- PTSIZE
UTOP,UENVS ------> +------------------------------+ 0xeec00000
UXSTACKTOP -/ | User Exception Stack | RW/RW PGSIZE
+------------------------------+ 0xeebff000
| Empty Memory (*) | --/-- PGSIZE
USTACKTOP ---> +------------------------------+ 0xeebfe000
| Normal User Stack | RW/RW PGSIZE
+------------------------------+ 0xeebfd000
| |
| |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
. .
. .
. .
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| Program Data & Heap |
UTEXT --------> +------------------------------+ 0x00800000
PFTEMP -------> | Empty Memory (*) | PTSIZE
| |
UTEMP --------> +------------------------------+ 0x00400000 --+
| Empty Memory (*) | |
| - - - - - - - - - - - - - - -| |
| User STAB Data (optional) | PTSIZE
USTABDATA ----> +------------------------------+ 0x00200000 |
| Empty Memory (*) | |
0 ------------> +------------------------------+ --+
不是很明白这个的全称是啥?User Virtual Page Directory?
下图和下面的代码很好的演示了如何能够找到一个虚拟地址。
pd = lcr3();
pt = *(pd + 4*PDX);
page = *(pt + 4*PTX);
但是这种方式我们该如何用VA来访问PD或者某一个page table呢?或者说PD和PT也应该有自己的映射才对。采用的方法是通过让PD自己指向自己,也就是两步都是指向自己的开头,在JOS中V是0x3BD
。UVPD(应该就是page directory)是 (0x3BD<<22)|(0x3BD<<12),然后如下图:
这样如果PDX和PTX都是V,两次之后还是会指向PD,如果PDX=V但是PTX!=V,那么运行之后就会指向某一个page table。通过以上的方式,我们就把虚拟地址映射到了PD和PT了。