Part 3: Kernel Address Space

JOS 把处理器的32位地址空间划分为两部分。User Environment管理低地址的部分,Kernel则对高地址的部分保持控制。这种划分比较的任意,大致是以inc/memlayout,h中的ULIM为划分。
因为kernel和user memory在彼此的地址空间中存在,我们需要使用权限位来让用户代码只能访问用户的地址空间。不然可能会导致写入了内核代码而产生问题。
用户态应当没有权限来访问在ULIM上的内存,kernel则应当拥有读写权限。用户态代码和内核都对[UTOP, ULIM)的内存只拥有读权限,因为这部分是为了向用户态暴露一部分内核只读数据结构。UTOP下面的地址空间则是留给用户态使用的。

初始化内核地址空间

Exercise 5要求设置UTOP以上的地址空间,补充完成mem_init()中剩下内容。

 //// Map 'pages' read-only by the user at linear address UPAGES// Permissions://    - the new image at UPAGES -- kernel R, user R//      (ie. perm = PTE_U | PTE_P)//    - pages itself -- kernel RW, user NONE// Your code goes here:boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U);//// Use the physical memory that 'bootstack' refers to as the kernel// stack.  The kernel stack grows down from virtual address KSTACKTOP.// We consider the entire range from [KSTACKTOP-PTSIZE, KSTACKTOP)// to be the kernel stack, but break this into two pieces://     * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory//     * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed; so if//       the kernel overflows its stack, it will fault rather than//       overwrite memory.  Known as a "guard page".//     Permissions: kernel RW, user NONE// Your code goes here:boot_map_region(kern_pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W);//// Map all of physical memory at KERNBASE.// Ie.  the VA range [KERNBASE, 2^32) should map to//      the PA range [0, 2^32 - KERNBASE)// We might not have 2^32 - KERNBASE bytes of physical memory, but// we just set up the mapping anyway.// Permissions: kernel RW, user NONE// Your code goes here:boot_map_region(kern_pgdir, KERNBASE, 0x10000000, 0, PTE_W);

然后make qemu看看结果:

Physical memory: 131072K available, base = 640K, extended = 130432K
check_page_free_list() succeeded!
Fail to allocate a new page! Out of Free Physical Memory!
Fail to allocate a new page! Out of Free Physical Memory!
check_page_alloc() succeeded!
Fail to allocate a new page! Out of Free Physical Memory!
Fail to allocate a new page! Out of Free Physical Memory!
Fail to allocate a new page! Out of Free Physical Memory!
Fail to allocate a new page! Out of Free Physical Memory!
Fail to allocate a new page! Out of Free Physical Memory!
Fail to allocate a new page! Out of Free Physical Memory!
check_page() succeeded!
check_kern_pgdir() succeeded!
check_page_free_list() succeeded!
check_page_installed_pgdir() succeeded!

通过了所有测试。
在回答后面的问题之前,我们重新回过头梳理一下这个lab究竟做了什么事情,完成了怎样的映射。

Review:

先来回顾一下各个函数究竟在干什么,特别关注操作对象及其地址情况。
boot_alloc:
给定n,在.bss end (0xf011A0000)之上划分一块n大小,按页对齐的虚拟地址空间。
page_init:
对虚拟地址[0xf011B000, 0xf015B000)pages数组根据物理内存的使用情况进行初始化,产生一个PageInfo的空闲物理内存页的链表。
page_alloc:
给定alloc_flags(决定分配的页是否要清零),从PageInfo的空闲物理内存页的链表中找到代表空闲物理页的PageInfo结构体,并将这个结构体对应的虚拟内存页根据alloc_flag清零或不清零,返回指向这个结构体的指针。
page_free:
将给定的PageInfo结构体加入空闲链表中。这里即不对物理内存做操作,也不对虚拟内存做操作,也不调整页表项。
pgdir_walk:
给定指向页目录的指针和虚拟地址,返回对应虚拟地址的页表项的指针。这里特别需要注意虚拟地址和物理地址的区分。拿到的页目录的指针是虚拟地址,得到的页目录项中包括了页表的物理地址。需要先转换成页表的虚拟地址,然后访问拿到对应的页表项,再取出页表项的虚拟地址,返回。
page_lookup:
给定指向页目录的指针,一个虚拟地址,和一个指向页表项指针的指针。首先查找该虚拟地址对应的页表项,如果不存在指向该页表项的指针,或者该页表项不是Present返回NULL,否则传入的双重指针指向该页表项的指针,返回指向对应该页表项对应物理地址的PageInfo结构体的指针,并且使虚拟地址对应的TLB无效。
page_remove:
给定指向页表项的指针,一个虚拟地址。先查找并拿到虚拟地址对应的PageInfo结构体和指向该虚拟地址对应页表项的指针。减少对该物理页的引用并清空该页表项,相当于取消虚拟地址和其对应物理地址的映射。
page_insert:
给定指向页目录的指针,一个代表物理页的指向PageInfo结构体的指针,和一个虚拟地址。先找到该虚拟地址对应的页表项的指针,如果该指针存在且页表项Present,那么我们先增加对给定物理页的引用,使用page_remove移除原有的映射(顺序是针对corner case的考虑),拿到给定结构体代表的物理页的物理地址,写到给定虚拟地址对应的页表项里,并使该虚拟地址对应的TLB无效。
boot_map_region:
给定指向页目录的指针,一个起始虚拟地址,一个起始物理地址,和地址空间大小以及权限。取出虚拟地址对应的页表项,把对应的物理地址和权限写进去。注意在注释中说不需要增加相应物理页的引用。(感谢GZZ同学解惑,我之前这里还不是特别清楚为什么不用引用计数增加,因为这里并不是真正地分配了page,而仅仅是通过写页表完成了映射)
这里看的时候还需要特别注意,KADDRpage2kva的区别,以及PADDRpage2pa的区别。前者是直接返回某个虚拟地址的物理地址或者是某个物理地址的虚拟地址,即加减KERNBASE,而后者则是返回PageInfo结构体对应的物理地址和虚拟地址。
还需要注意的一点是,分配空闲页是分配空闲页,映射虚拟地址和物理地址只是映射,二者函数功能分离。
我们再回去看mem_init(),映射完成之后就是这么个情况:
然后我们来回答一下剩下的问题:
2. 要看页目录的填充情况,只需要看mem_init函数中的映射行为就可以了。
每个entry对应的基虚拟地址也就是entry乘上0x400000, 因此就不重复说了。

kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P;

手动把UVPT对应的页目录项映射到页目录对应的物理地址,UVPT对应entry 957,内容是页目录的物理地址。

boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U);

UPAGESpages数组占据的物理地址空间建立映射,UPAGES对应entry 956,指向UPAGES对应的页表,页表指向pages数组的物理地址空间。

boot_map_region(kern_pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W);

KSTACKTOP-KSTSIZE(即cpu0的kernelstack)和bootstack占据的物理地址空间建立映射,对应entry 959,指向包含多个kernstack到对应bootstack映射的页表。注意在这里我们只映射了cpu0的kernelstackbootstack,而由于剩下的kernelstack页目录项是一样的,所以页目录项非空,且相应的页表非空,但是页表中除了cpu0 kernelstack之外其它的页表项是空的。

boot_map_region(kern_pgdir, KERNBASE, 0x10000000, 0, PTE_W);

kernel映射到物理地址0开始的256MB物理地址空间,kernel地址从0xf00000000xffffffff, 因此对应的页目录项的enrty从960到1023,指向负责映射kernel的页表,页表指向从0开始的256MB物理地址空间。
3. 因为使用了权限位,因为内核代码的权限位标志为supervisor level且Read-only access
4. 最多支持2G,因为RO PAGES 4096*1024 Byte 一个PageInfo结构为8 Byte,一个物理页4096 Byte,因此最多访问4096 * 1024 / 8 * 4096 = 2GB 这个地方之前没有注意到KADDR的映射是加上kernbase,我以为是映射到全部的4G虚拟地址空间,因此为了不溢出,只能支持256MB。
5. 最多可以放4MB的PageInfo数组,加上4KB的页目录,再加上4MB的页表,一共8MB+4KB 如果只能支持256MB的大小,那么PageInfo数组最多512KB,加上4KB的页目录,但是可以把所有的虚拟地址映射到256MB的物理内存上去,因此页表最多使用4MB大小,这样总共是4612KB.
6. 在jmp *%eax之后。 因为我们之前在entrypgdir.c里面把[0x00000000, 0x00400000)的虚拟地址映射到了[0x00000000, 0x00400000)的物理地址。因为后面kern_pgdir会被加载进来,低虚拟地址就不再使用了。

Challenge

(补坑)

JOS Lab2 Memory Management Part 3 challenge相关推荐

  1. 《MIT JOS Lab2: Memory Management》实验报告

    目录 0  准备文件 1  物理页管理 1.1 boot_alloc( )函数 1.2 mem_init ( )函数 1.2.1 函数中用到的 PageInfo 结构 1.2.2 初始化分配首页 1. ...

  2. MIT 6.828 (二) Lab 2: Memory management

    Lab 2: Memory management 做这个实验之前首先需要知道什么是分页.分段在这个实验里面没用到过. 前面是一大堆教你怎么获取lab2资源的,我不知道怎么弄,后来乱搞了一下,就把lab ...

  3. Item 36. Class-Specific Memory Management

    Item 36. Class-Specific Memory Management 在类中声明operator new 和 operator delete 成员就可以实现类自己的内存分配与管理. cl ...

  4. [翻译] - Inside SQL Server 2000's Memory Management Facilities

    原文地址:Inside SQL Server 2000's Memory Management Facilities     翻译:RicCC Ken Henderson     Microsoft ...

  5. Operating System Concepts--chap9 Memory Management;

    为什么80%的码农都做不了架构师?>>>    这一章节的memory management内容覆盖从bare-machine approach到paging和segmentatio ...

  6. Java (JVM) Memory Model – Memory Management in Java

    原文地址:http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java Understanding JV ...

  7. Objective -C Memory Management 内存管理 第一部分

    Objective -C Memory Management  内存管理  第一部分 Memory management is part of a more general problem in pr ...

  8. Three Memory Management Models

    摘自<Intel® 64 and IA-32 Architectures Software Developer's Manual Combined Volumes1, 2A, 2B, 2C, 2 ...

  9. 异构内存管理 Heterogeneous Memory Management (HMM)

    https://www.kernel.org/doc/html/latest/vm/hmm.html 目录 异构内存管理 (HMM) 使用特定于设备的内存分配器的问题 I/O 总线.设备内存特性 共享 ...

最新文章

  1. 干货丨三大特征选择策略,有效提升你的机器学习水准
  2. Shell脚本的调试技术
  3. 一般计算机系统中的文件系统采用,南昌大学2001年考研专业课试卷操作系统A
  4. libco协程库源码解读
  5. [转]sql,N/$/#/@的含义和作用
  6. caffe运行不停止_caffe(gpu)安装过程及问题解决
  7. log4j mysql 异步_spring boot:配置druid数据库连接池(开启sql防火墙/使用log4j2做异步日志/spring boot 2.3.2)...
  8. html5 上海,【上海校区】HTML5新特性
  9. python精度_通过Python可以达到的最高时间精度范围是多少?
  10. Win10打开或关闭任务栏系统图标
  11. dmx512 java_DMX512控制协议及其实现
  12. wechat 微信ipad协议GO版本 最新不封号 长链接 完整版
  13. js日期格式化的两种方法
  14. 暨南大学计算机系录取分数线,暨南大学2017年在广东省各专业录取分数线
  15. 荒野行动pc版显示连接不到服务器,荒野行动PC版连接不上服务器怎么办 进不去游戏...
  16. Docker 学习笔记(八)-- Dockerfile 构建CentOS 实战测试
  17. Incorrect string value '\xF0\xA0\x9D\xB9\xE5\x82...' for column 'CONTENT' at row 1
  18. 芝加哥面孔数据库(CFD)的人脸模板
  19. 什么是快速连接器?如何选择合适的快速密封接头?
  20. 【CheatEngine】关于BCR的内存分析

热门文章

  1. 央视网上线独立搜索页面索引站内信息:Search.cctv.com
  2. c#12星座速配代码_十二星座运势接口代码示例分享
  3. 山东大学软件学院数据可视化知识点整理
  4. 爱国者一体机电脑蓝屏怎么U盘重装系统教学?
  5. 有关HC-05蓝牙模块的学习记录
  6. 情感分析(Sentiment Analyze)
  7. 最被低估的NFT类型
  8. 众筹模式融资报告发布
  9. 向日葵远程控制Ubuntu无法显示图形化界面
  10. 《达·芬奇密码》解读解密 1