zhuzilin's Blog

about

6.828 笔记6

date: 2019-02-22
tags: OS  6.828  

这里会记录阅读6.828课程lecture note的我的个人笔记。可能会中英混杂,不是很适合外人阅读,也请见谅。

Lecture 7: Using Virtual Memory

  • 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。但是他们都是一样的。所以实际上可以统一一下。修改方式是改kvmallocfreevm(不知道该怎么改,主要是现在的版本只有在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数据

    • 使用PTE来检测什么时候需要disk access
    • 用page table来找到least recent used disk block 并把其写回硬盘(LRU)

    当同时使用的内存小于RAM的时候,非常work。

  • Feature: memory-mapped files

    通过load, store而不是read, write, lseek来access files以轻松访问文件的某一部分

    • 会使用mmap system call
    • 用memory offset而不是seeking
  • Feature: distributed shared memory

    用虚拟内存来假装物理内存 is shared between several machines on the network

    注意只有read only page可以复制,而能够写入的不能。

JOS and virtual memory

    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 ------------>  +------------------------------+                 --+
  • segment仅仅用来切换隐私权限。
  • 用paging来处理进程的地址空间。
  • 用pagine来管理地址空间的访问权限。

The UVPD

不是很明白这个的全称是啥?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),然后如下图:

PD指向自己

这样如果PDX和PTX都是V,两次之后还是会指向PD,如果PDX=V但是PTX!=V,那么运行之后就会指向某一个page table。通过以上的方式,我们就把虚拟地址映射到了PD和PT了。