目录
参考:
物理内存管理带来的问题
- 比如4GB的flash, 如果应用程序可直接访问物理内存,那么可能一个非法的操作会导致程序无法正常工作,常见于跑裸机的单片机程序。
- 而操作系统为了保护程序可正常运行,引入了虚拟内存的概念,换句话说:对应用程序来讲:操作的内存是虚拟内存。
- 而操作系统做的事情就是把虚拟内存映射到物理内存。那么如何映射就是需要设计的关键。即物理地址 = func_map(虚拟内存); 这个func_map就叫页表,以下有常见的现有的设计实现
直接映射
- 页表方案:比如一个4GB的flash,那么需要2^32个地址去访问,而地址从0-2^32,这么大的数需要4字节的数据去存,也就是需要 uint64 flash[2^32];
- 内存开销:这样的数组去访问每个物理地址。这样的数组有多大呢? 4*4GB = 16GB, 就是说访问4GB的flash需要16GB的内存,这肯定是不可以的。
这一样的实现是 physical_addr = flash[virtual_addr];
一级页表
- 页表方案:
- 为了减少内存开销,有了分页机制:把4GB的flash,分为一页4K。
- 如果需要访问flash的物理地址,需要页数+页内偏移。
- 一页大小为4K,需要访问所有内存,即0-2^12,即至少12位来得到偏移量
- 而访问所有的页数:4GB/4K = 2^32/ 2^12 = 2^20页,故需要20位来访问所有的页
- 综上:可设计虚拟地址的31-12位得到页表数,11-0得到页内的偏移。
这样的实现通过虚拟地址访问物理地址的伪代码如下:
#define PAGE_SIZE 2^12 // 4K大小的页 //通过传入的virtual_addr访问物理地址 uint32 Func_map(uint32 virtual_addr) { // 得到高20位 uint32 page_Number = virtual_addr & 0xfffff000; // 得到低12位 uint32 ofst= virtual_addr & 0x00000fff; // 得到页表位置 uint32 phy_page = page_Number * PAGE_SIZE; // 返回页表内存+偏移得到具体的物理位置 return phy_page + ofst; }
- 页表的开销:一个虚拟地址为4字节,共需要4GB/4K = 2^32/ 2^12 = 2^20个虚拟地址,一共占4*2^20字节== 4M,即维护一级页表:可访问4G的物理内存,开销为4M
二级页表
前人又设计了二级页表实现:
- 将虚拟地址分割为三分部,高10位作为页目录中元素的下标,中间10位作为页表中元素的下标,最后12位作为页内偏移
- 其中通过页表下标和页内偏移得到物理内存地址和一级页表的方法是一样的。
- 一级页表可知:4M的页表开销,并不需要完全使用(物理内存用不到4G)。而二级页表就是通过页目录来管理。需要使用物理内存,则通过页目录记录下页表,通过页表访问一段内存。
- 页表需要4M来感知4G的物理内存,而页目录需4K+ 页目录4M--》可访问4K个页表。
- 一个页目录下标可访问一组页表(页表下标是10位,共2^10个),即可访问2^10个页表,而每个页表配合页内偏移12位( 2^12的地址,即4M的内存),所以一个页目录可访问2^12 * 2^10=4M的内存。
- 而一共可以有2^10个页目录,而一个页目录可用2^10个页表,而一个页表占4K,故共可访问2^10 * 2^10 * 4K = 4GB 的物理内存。
- 伪代码如下:
uint32 g_pageDir[2^12]; //4K的页目录 //传入虚拟地址,得到物理地址 uint32 func_map(uint32 virtual_addr) { // 得到高10位 uint32 page_dir= virtual_addr & 0xffC00000; // 得到中10位 uint32 page_tbl= virtual_addr & 0x002ff000; // 得到低12位 uint32 ofst= virtual_addr & 0x00000fff; uint32_t* pageTable = g_pageDir[page_dir];//指向页表块 uint32 phy_addr = pageTable [page_tbl]; //指向物理块 return (phy_addr + ofst); //得到物理内存的具体位置 }
综上:可通过32位的虚拟地址 + 二级页表访问4GB的物理内存,
- 为什么需要额外的4K的页目录来操作物理内存呢?因为实际使用中,我们并不需要用完4GB的flash, 所以并不需要4M的开销。用多少页表生成多少,而需要的额外开销就是找到页表index的页目录,远小于4M+4K,更加灵活。