BUAA_OS lab2 难点梳理
BUAA_OS lab2 难点梳理
实验重点
所列出的实验重点为笔者在进行lab2过程中认为需要深刻理解的部分。
进行内存访问的流程
熟悉mips内存映射布局,即理解mmu.h内图
二级页表的理解和实现
以下将参考指导书逻辑,对于重难点进行梳理。
内存访问
首先,简易梳理内存访问流程。
TLB根据虚拟地址查找
若存在,在cache中查找;若不存在,按照页表查询,再查cache,更新tlb
若cache命中则ok;若未命中,进行页面替换
内存布局及初始化步骤的理解
lab2主要涉及的内存布局图如下:
kuseg:用户态可用地址,需要mmu进行地址转换
kseg0:内核地址,转换不需要mmu,只需要将最高位清0
与内存布局密切相关的,就是初始化部分的各个函数,包括创建二级页表的部分。
我们以mips_vm_init()展开理解初始化的各个步骤。
1 void mips_vm_init()
2 {
3 extern char end[];
4 extern int mCONTEXT;
5 extern struct Env *envs;
6
7 Pde *pgdir;
8 u_int n;
9
10 /* Step 1: Allocate a page for page directory(first level page table). */
11 pgdir = alloc(BY2PG, BY2PG, 1);
12 printf("to memory %x for struct page directory.\n", freemem);
13 mCONTEXT = (int)pgdir;
14
15 boot_pgdir = pgdir;
16
17 /* Step 2: Allocate proper size of physical memory for global array `pages`,
18 * for physical memory management. Then, map virtual address `UPAGES` to
19 * physical address `pages` allocated before. For consideration of alignment,
20 * you should round up the memory size before map. */
21 pages = (struct Page *)alloc(npage * sizeof(struct Page), BY2PG, 1);
22 printf("to memory %x for struct Pages.\n", freemem);
23 n = ROUND(npage * sizeof(struct Page), BY2PG);
24 boot_map_segment(pgdir, UPAGES, n, PADDR(pages), PTE_R);;
25 /* Step 3, Allocate proper size of physical memory for global array `envs`,
26 * for process management. Then map the physical address to `UENVS`. */
27 envs = (struct Env *)alloc(NENV * sizeof(struct Env), BY2PG, 1);
28 n = ROUND(NENV * sizeof(struct Env), BY2PG);
29 boot_map_segment(pgdir, UENVS, n, PADDR(envs), PTE_R);
30
31 printf("pmap.c:\t mips vm init success\n");
32 }
mips_vm_init
首先,调用alloc函数为pgdir开出一块空间。在此需要理解,alloc函数的本质就是将freemem上移,以表示预留空间。在执行完这一条alloc后,freemem的值由end[](0x80400000)增加为0x80401000
然后,调用alloc函数为pages开出一块空间。需要注意的是,pages是用来记录各物理页信息的Page结构体数组,可以根据某Page在pages中的偏移量,间接求出对应的物理页地址。此时,freemem再次增加。与pgdir不同的是,紧接着又调用了boot_map_segment()函数。其作用下文中再叙述。
最后,与第二步相似,为envs先alloc再map。
接下来,我们看一下boot_map_segment()是用来干啥的。
1 void boot_map_segment(Pde *pgdir, u_long va, u_long size, u_long pa, int perm)
2 {
3 int i, va_temp;
4 Pte *pgtable_entry;
5
6 /* Step 1: Check if `size` is a multiple of BY2PG. */
7
8 if(size%BY2PG!=0){
9 return;
10 }
11
12 /* Step 2: Map virtual address space to physical address. */
13 /* Hint: Use `boot_pgdir_walk` to get the page table entry of virtual address `va`. */
14
15 for(i=0;i<size;i+=BY2PG){
16 pgtable_entry=boot_pgdir_walk(pgdir,va+i,1);
17 *pgtable_entry=(pa+i)|perm|PTE_V;
18 }
19 return;
20 }
boot_map_segment
可以看出,boot_map_segment()的作用就是将[va, va+size)的虚拟地址和[pa, pa+size)的物理地址建立映射关系。通俗来讲,就是将虚拟地址va对应的页表项写入需要对应的pa的值,并设置标志位。
具体实现为,通过boot_pgdir_walk()获取地址为va+i对应的页表项,然后修改它的值。
那么自然而然,我们再来看一下boot_pgdir_walk()是怎么找到va+i对应的页表项地址的。
1 static Pte *boot_pgdir_walk(Pde *pgdir, u_long va, int create)
2 {
3
4 Pde *pgdir_entryp;
5 Pte *pgtable, *pgtable_entry;
6
7 /* Step 1: Get the corresponding page directory entry and page table. */
8 /* Hint: Use KADDR and PTE_ADDR to get the page table from page directory
9 * entry value. */
10 pgdir_entryp = pgdir+PDX(va); //获取一级页表项的虚拟地址
11 pgtable=KADDR(PTE_ADDR(*pgdir_entryp)); //获取二级页表入口的虚拟地址
12 /* Step 2: If the corresponding page table is not exist and parameter `create`
13 * is set, create one. And set the correct permission bits for this new page
14 * table. */
15 if((*pgdir_entryp & PTE_V)==0 && create){ //如果没有二级页表,且需要创建
16 pgtable = alloc(BY2PG,BY2PG,1); //创建二级页表
17 *pgdir_entryp = PADDR(pgtable)|PTE_V; //将指向该二级页表的一级页表项的值设置为其物理地址
18 }
19 /* Step 3: Get the page table entry for `va`, and return it. */
20 pgtable_entry=pgtable+PTX(va); //返回指向对应二级页表项地址的指针
21 return pgtable_entry;
22
23 }
boot_pgdir_walk
该函数的具体行为已体现在注释中了,不再赘述。
看到这个boot_pgdir_walk()函数在寻找二级页表项的时候,可能会感觉被虚拟和物理地址的转换绕晕了,那么就来捋一下它究竟是根据什么地址找到的页表项吧。
首先需要明确,在想要访问页表的时候,无论是一级还是二级,都用的虚拟地址;而一级页表中存的二级页表地址和二级页表中存的页地址,都是物理地址。
明确这一点之后,以下这句就不难理解了。pgdir中存的是物理地址,但需要转化成虚拟地址访问。其他类似。
pgtable=KADDR(PTE_ADDR(*pgdir_entryp));
另外,我们会发现,在需要访问的二级页表不存在时,同样调用了alloc,上移freemem,为新页开出空间。这是因为,我们采用的二级页表是动态的,需要哪个就装入哪个,而不是将所有二级页表都放入内存,因为这样太占空间了。
到此位置,初始化部分就完成一大半了,这时候只需要再调用page_init()函数,将此时freemem以下的部分都设置p->pp_ref=1,即该物理页被使用了。因此,根据freemem上移的顺序,物理内存的最底端为pgdir,其次为pages,envs,后来alloc的页等等。
页面置换
在完成初始化之后,进行之后的页面插入、删除、分配、置换就变得容易多了。接下来,就以page_insert()函数来梳理一下后期相关的页面操作。
1 int
2 page_insert(Pde *pgdir, struct Page *pp, u_long va, u_int perm)
3 {
4 u_int PERM;
5 Pte *pgtable_entry;
6 PERM = perm | PTE_V;
7 /* Step 1: Get corresponding page table entry. */
8 pgdir_walk(pgdir, va, 0, &pgtable_entry);
9
10 if (pgtable_entry!=0 &&(*pgtable_entry&PTE_V)!= 0) {
11 if (pa2page(*pgtable_entry) != pp) {
12 page_remove(pgdir, va);
13 } else {
14 tlb_invalidate(pgdir, va);
15 *pgtable_entry = (page2pa(pp) | PERM);
16 return 0;
17 }
18 }
19
20 /* Step 2: Update TLB. */
21
22 /* hint: use tlb_invalidate function */
23 tlb_invalidate(pgdir,va);
24
25 /* Step 3: Do check, re-get page table entry to validate the insertion. */
26
27 int x = pgdir_walk(pgdir, va, 1, &pgtable_entry);
28 /* Step 3.1 Check if the page can be insert, if can鈥檛 return -E_NO_MEM */
29 if(x==-E_NO_MEM){
30 return -E_NO_MEM;
31 }
32 // printf("0x%x\n",PTE_ADDR(pgdir[0]));
33 /* Step 3.2 Insert page and increment the pp_ref */
34 *pgtable_entry=(page2pa(pp)|PERM);
35 pp->pp_ref+=1;
36 return 0;
37 }
page_insert
第一步是使用pgdir_walk()函数,获取va所对应的二级页表项。由此看来,pgdir_walk()与之前初始化部分提到的boot_pgdir_walk()作用基本相同呢。然不同之处在于,在调用page_insert()时,内存初始化部分已经完成,空闲页表已经使用page_free_list串起来了,因此再分配新页面的时候,直接取出空页即可。
之后的步骤,就是对内存访问的具体步骤的实现了。
1 . . 感言
至此,lab2的部分基本就结束了。回想完成lab2的时候,脑子还是一团浆糊,对于许多操作都很不理解。如今回头写总结,才发现主要就是对于初始化部分的具体行为理解不清。
另外,lab2对queue.h部分的操作不涉及理解难度,就是指针复(chong)习(xue),注意指针别飞了,就没有大问题。
(代码仓库位于右上角Github)
BUAA_OS lab2 难点梳理的更多相关文章
- BUAA_OS lab3 难点梳理
BUAA_OS lab3 难点梳理 实验难点 进程创建 对于初始化部分,首先需要在pmap.c中修改mips_vm_init()函数,为envs开空间,并map到UENVS空间. 其次,模仿page_ ...
- BUAA_OS lab4 难点梳理
BUAA_OS lab4 难点梳理 lab4体会到了OS难度的飞升.实验需要掌握的重点有以下: 系统调用流程 进程通信机制 fork 本lab理解难度较高,接下来将以以上三部分分别梳理. 系统调用 概 ...
- Collection集合重难点梳理,增强for注意事项和三种遍历的应用场景,栈和队列特点,数组和链表特点,ArrayList源码解析, LinkedList-源码解析
重难点梳理 使用到的新单词: 1.collection[kəˈlekʃn] 聚集 2.empty[ˈempti] 空的 3.clear[klɪə(r)] 清除 4.iterator 迭代器 学习目标: ...
- HRMS(人力资源管理系统)-从单机应用到SaaS应用-系统介绍
上周发布的<2018,全新出发(全力推动实现住有所居)>文章,其中记录了个人在这5年过程中的成长和收获,有幸认识了不少博客园的朋友,大家一起学习交流,在这个过程当中好多朋友提出SaaS系统 ...
- 《BAT前端进阶[师徒班]》学习总结
这是一个培训课 是的,这是一个面向中级前端的培训班,但明显跟传统的填鸭式培训班不太一样.这边的老师都是大牛这是毫无疑问的,而且都是一线开发人员.而且课程一开始就说明了面向了是有1-3年有工作经验的前端 ...
- 什么是泛型?,Set集合,TreeSet集合自然排序和比较器排序,数据结构-二叉树,数据结构-平衡二叉树
==知识点== 1.泛型 2.Set集合 3.TreeSet 4.数据结构-二叉树 5.数据结构-平衡二叉树 ==用到的单词== 1.element[ˈelɪmənt] 要素 元素(软) 2.key[ ...
- 什么是可变参数?如何创建不可变集合?Steam三类方法是什么?获取流方法特点?流中间方法特点?终结流方法特点?
==知识梳理== ==重难点梳理== ==今日目标== 1.能够了解什么是可变参数 2.能够了解如何去创建不可变集合 3.能够掌握Stream流的使用 ==知识点== 1.可变参数 2.Stream流 ...
- 多线程,线程类三种方式,线程调度,线程同步,死锁,线程间的通信,阻塞队列,wait和sleep区别?
重难点梳理 知识点梳理 学习目标 1.能够知道什么是进程什么是线程(进程和线程的概述,多进程和多线程的意义) 2.能够掌握线程常见API的使用 3.能够理解什么是线程安全问题 4.能够知道什么是锁 5 ...
- JDBC基础:JDBC快速入门,JDBC工具类,SQL注入攻击,JDBC管理事务
JDBC基础 重难点梳理 一.JDBC快速入门 1.jdbc的概念 JDBC(Java DataBase Connectivity:java数据库连接)是一种用于执行SQL语句的Java API,可以 ...
随机推荐
- FileReader, readAsText
readastext filereader FileReader.readAsText() https://developer.mozilla.org/zh-CN/docs/Web/API/FileR ...
- Flutter: provider 使用小部件的小部件构建的依赖注入系统
文档 dependencies: provider: import 'package:dart_printf/dart_printf.dart'; import 'package:flutter/ma ...
- linux驱动系列之程序反汇编
摘抄网页:http://www.169it.com/article/330129798173630299.html 参考网页:http://www.cppblog.com/liu1061/articl ...
- 生成UUID的代码
代码: String reqId = UUID.randomUUID().toString().replace("-", "");
- dpi dp px 换算关系
getResources().getDisplayMetrics().densityDpi 就是屏幕密度.getResources().getDisplayMetrics().density 也可以理 ...
- STL栈
stack的基本操作有: 1.入栈:如s.push(x); 2.出栈:如s.pop(). 注意:出栈操作只是删除栈顶的元素,并不返回该元素. 3.访问栈顶:如s.top(); 4.判断栈空:如s.em ...
- Power BI成功的背后
Power BI成功的背后 魔力象限 又是一年Gartner数据分析与BI魔力象限报告的发布,Power BI毫无悬念的第一,并且拉开与其他产品的差距越来越大.在Power BI dataflows( ...
- Linux操作php.ini文件
有时你使用的是别人搭建好的环境,不知道php.ini在哪里,或者好久没有修改配置了,已经忘记了路径在哪,所以在操作文件之前,得先要找到.ini路径. 找php.ini 方式一 $ php -i | g ...
- POJ-2195(最小费用最大流+MCMF算法)
Going Home POJ-2195 这题使用的是最小费用流的模板. 建模的时候我的方法出现错误,导致出现WA,根据网上的建图方法没错. 这里的建图方法是每次到相邻点的最大容量为INF,而花费为1, ...
- 少走弯路之marshalsec的编译(RMI必备工具)
0x00 实验环境 实验机:Ubuntu18(公网Linux系统) 0x01 安装包 私聊我博客将会第一时间提供安装包环境: 0x02 避坑指南 由上篇文章:https://www.cnblo ...