JOS处理器的32位线性地址空间分为两部分,内核控制ULIM分割线以上的部分,为内核保留大约256MB
(0xf000000-0xffffffff)的虚拟地址空间,用户环境控制下方部分,约3.72G
(0x0-0xef800000)。
用户环境将没有对以上ULIM内存的任何权限,只有内核能够读写这个内存;
[UTOP,ULIM],内核和用户环境都可以读取但不能写入这个地址范围,此地址范围用于向用户环境公开某些只读内核数据结构;
UTOP下的地址空间供用户环境使用;用户环境将设置访问此内存的权限。
补全mem_init
主要映射了三个区域:
第一个是[UPAGES, UPAGES+PTSIZE)
映射到页表存储的物理地址[pages, pages+4M)
。
第二个是[KSTACKTOP-KSTKSIZE, KSTACKTOP)
映射到[bootstack,bootstack+32KB)
处。
第三个则是映射整个内核的虚拟空间[KERNBASE, 2*32-KERNBASE)
到 物理地址[0,256M)
。
谢谢__七把刀__
// check pages array
n = ROUNDUP(npages*sizeof(struct PageInfo), PGSIZE);
for (i = 0; i < n; i += PGSIZE)
assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);
// check phys mem
for (i = 0; i < npages * PGSIZE; i += PGSIZE)
assert(check_va2pa(pgdir, KERNBASE + i) == i);
// check kernel stack
for (i = 0; i < KSTKSIZE; i += PGSIZE)
assert(check_va2pa(pgdir, KSTACKTOP - KSTKSIZE + i) == PADDR(bootstack) + i);
assert(check_va2pa(pgdir, KSTACKTOP - PTSIZE) == ~0);
补全如下:
boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U|PTE_P);
//[KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory
//[KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed
boot_map_region(kern_pgdir, KSTACKTOP-KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W|PTE_P);
// firstly, I set the size parameter to npages*PGSIZE, but it is not 2^32-KERNBASE
boot_map_region(kern_pgdir, KERNBASE, 0x100000000-KERNBASE, 0, PTE_W|PTE_P);
经过不断调试修改,终于:
问答
答:之前就提到过,所有地址引用都会被当作虚拟地址,并被MMU所解释,所有c指针都是虚拟地址,所以这里的x是uintptr_t。
2.尽量多的填好下面表格
entries (rows) in the page directory,其中Base Virtual Address不知道什么意思。。。
Entry=PDT(va); Points to (logically)可以在memlayout.h中查到。
Entry(PDENo.) | Base Virtual Address | Points to (logically): |
---|---|---|
1023 | 0xfff00000 | Page table for top 4MB of phys memory |
… | … | Page table for top 4MB of phys memory |
960 | 0xf0000000 | Page table for top 4MB of phys memory |
959 | 0xefff8000 | Kernel Stack & Invalid Memory |
958 | 0 | NULL |
957 | 0xef400000 | User read-only virtual page table |
956 | 0xef000000 | Read-only copies of the Page structures |
955 | NULL | NULL |
… | NULL | NULL |
0 | 0x00000000 | 0 |
3.我们将内核和用户环境放在相同的地址空间中。为什么用户程序不能读取或写入内核内存?什么特定的机制保护内核内存?
Since kernel and user memory are both present in each environment’s address space, we will have to use
permission bits
in our x86 page tables to allow user code access only to the user part of the address space.
4.这个操作系统能支持的最大物理内存是多少?为什么?
npages = totalmem / (PGSIZE / 1024);
npages_basemem = basemem / (PGSIZE / 1024);
cprintf("Physical memory: %uK available, base = %uK, extended = %uK\n",
totalmem, basemem, totalmem - basemem);
由此可知物理页数量npages=131072k/(4k/1024)=32768k;每页4KB,故能支持的最大物理内存是32768 * 4KB=128M。。。错了,why?
换一种算法,从memlayout.h中可以直到,分配了[UPAGES, UVPT)一共PTSIZE(4M)
的空间给pages
,每个PageInfo结构体大小是8byte,故一共有4MB/8B=0.5M个结构体,即0.5M个物理页,每页4KB,故物理内存是0.5M * 4KB=2GB
那么为什么虚拟地址空间却有4G呢?
PDE有1K,PTE有1K,每页4KB ,一共4GB?之所以能以2GB的物理内存实现4GB的地址空间,是不是也是分页机制的一个优点呢。当需要用的时候才分配物理页并建立映射,没建立任何映射的物理页就释放掉。
5.如果我们有最大的物理内存,那么管理内存需要多少空间开销?这个开销是如何分解的?
寻址是从(uint32_t)pgdir-->(uint32_t)pgtable-->(struct PageInfo)pages
如果物理内存为2GB的话,npages=2GB/4KB=0.5M个,每个PageInfo是8byte,故pages有4MB
0.5M个npages就会有0.5M个页表项PTE,页表项是uint32_t的,大小4byte,故pgtable为2M
(每个页表1024个页表项,一共512个页表)
pgdir我不太懂,按道理只有512个页表,就应该只有512个页目录表项PDE,每个4byte,那pgdir大小有2KB就够了,但是代码里可以发现分配给pgdir是4KB
,是因为物理页是4KB,所以分配也是4K对齐的吗
因此管理内存需要的空间开销是4K+2M+4M
QUESTION 6
重新访问kern/entry.S和kern / entrypgdir.c的页表设置。在打开分页之后,EIP(寄存器)什么时候从很小的数字(略大于1MB)过渡到在KERNBASE之上运行?在启用分页和开始在KERNBASE之上的EIP上运行之间,是什么使我们能够在较低的EIP上继续执行?为什么这种转变是必要的?
不太懂。。。
mov $relocated, %eax;jmp *%eax
从这之后就跳转到高地址运行了。
it maps virtual addresses
[KERNBASE, KERNBASE+4MB)
to physical addresses[0, 4MB)
. We choose 4MB because that’s how much we can map with one page table and it’s enough to get us through early boot. We also map virtual addresses[0, 4MB)
to physical addresses[0, 4MB)
;
在entry.S中我们的cr3
加载的是entry_pgdir
,它将虚拟地址 [0, 4M)和[KERNBASE, KERNBASE+4M)都映射到了物理地址 [0, 4M),所以能保证正常运行。
谢谢仁兄
到后面cr3
中加载的是kern_pgdir
,没有把地位虚拟地址 [0, 4M)映射到物理地址 [0, 4M),故需要转变。