【BUAA S4 OS】Lab2 内存管理

4 篇文章 0 订阅

指导书梳理

在这里插入图片描述

内核程序启动

  • mips_init(u_int argc, char **argv, char **penv, u_int ram_low_size)
    • 参数是由 bootloader 传递给内核的,其中的 ram_low_size 参数指定了硬件可用内存大小

物理内存管理

链表宏

  • LIST_ENTRY(type),作为一个特殊的类型出现,例如可以进行如下的定义:

    LIST_ENTRY(Page) a;
    

    它的本质是一个链表项,包括指向下一个元素的指针 le_next,以及指向前一个元素链表项 le_next 的指针 le_prev。le_prev 是一个指针的指针,它的作用是当删除一个元素时,更改前一个元素链表项的 le_next

    在这里插入图片描述

    • 黑框框起来的是一个元素(结构体)
    • 蓝&橙部分是一个LIST_ENTRY(type)类型的链表项,是元素(结构体)的一个字段
  • C 语言并没有泛型的语法,因此需要通过宏另辟蹊径来实现泛型

虚拟内存管理

两级页表结构

  • 对于一个 32 位的虚存地址,从低到高从 0 开始编号,其 31-22 位表示的是一级页表项的偏移量21-12 位表示的是二级页表项的偏移量,11-0 位表示的是页内偏移量

  • 页表项组成

    在 MOS 中,每个页表均由 1024 个页表项组成,每个页表项由 32 位组成,包括 20位物理页号以及 12 位标志位。
    高 6 位硬件标志位用于存入 EntryLo 寄存器中,供硬件使用,低 6 位软件标志位不会被存入 TLB 中,仅供软件使用。当页表项需要借助 EntryLo 寄存器填入 TLB 时,页表项会被右移 6 位,仅将高 20 位物理页号以及 6 位硬件标志位填入 TLB 使用

访问内存与 TLB 重填

  • TLB组成:每个 TLB 表项都有两个组成部分,包括一组 Key 和两组 Data
  • TLB 事实上构建了一个映射 < VPN, ASID > ⟶ T L B \stackrel{TLB}{\longrightarrow} TLB< PFN, N, D, V, G >。

EntryHi、EntryLo0、EntryLo1

在这里插入图片描述

都是 CP0 中的寄存器,只是分别对应到 TLB 的 Key与两组 Data,并不是 TLB 本身。

  • EntryLo0、EntryLo1 拥有完全相同的位结构, 分别存储 Key 对应的偶页与奇页
    • 4Kc 中的 TLB 采用奇偶页的设计,使用 VPN 中的高 19 位与 ASID 作为
      Key,一次查找到两个 Data(一对相邻页面的两个页表项),并用 VPN 中的最低 1 位在两个 Data 中选择命中的结果。因此在对 TLB 进行维护(无效化、重填)时,除了维护目标页面,同时还需要维护目标页面的邻居页面
  • Key——EntryHi
    • VPN(Virtual Page Number)
      • 当 TLB 缺失(CPU 发出虚拟地址,TLB 查找对应物理地址但未查到)时,EntryHi 中的 VPN **自动(由硬件)**填充为对应虚拟地址的虚页号
      • 当需要填充或检索 TLB 表项时,软件需要将 VPN 段填充为对应的虚拟地址
  • Data——EntryLo
    • PFN:Physical Frame Number

      • 软件通过填写 PFN,接着使用 TLB 写指令,才可以将此时 EntryHi 中的 Key与 EntryLo 中的 Data 写入 TLB
    • D:Dirty

      事实上是可写位。当该位为 1 时,对应的页可写;否则对相应页的任何写操作都将引发 TLB 异常。

    • G:Global

      如果该位为 1,则 CPU 发出的虚拟地址只需要与该表项的 VPN 匹配,即可与此 TLB 项匹配成功(不需要检查 ASID 是否匹配)

TLB 相关指令

  • tlbr:以 Index 寄存器中的值为索引,出 TLB 中对应的表项到 EntryHi 与 EntryLo0、EntryLo1
  • tlbwi:以 Index 寄存器中的值为索引,将此时 EntryHi 与 EntryLo0、EntryLo1 的值索引指定的 TLB 表项中
  • tlbwr:将 EntryHi 与 EntryLo0、EntryLo1 的数据随机写到一个 TLB 表项中(使用 Random 寄存器来“随机”指定表项)
  • tlbp:根据 EntryHi 中的 Key(包含 VPN 与 ASID),查找 TLB 中与之对应的表项,并将表项的索引存入 Index 寄存器(若未找到匹配项,则 Index 最高位被置 1),前后都应各插入一个 nop 以解决数据冒险

TLB的维护

具体来说,维护 TLB 的流程如下:

  1. 更新页表中虚拟地址对应的页表项的同时,将 TLB 中对应的旧表项无效化
  2. 在下一次访问该虚拟地址时,硬件会触发 TLB 重填异常,此时操作系统对 TLB 进行重填

时纪

  • 注意检查空间是否超出了最大物理地址
  • E2_3
    • LIST相关宏操作的(参数)一般都是指针啊啊啊啊!!在使用的是后如果传入的不是指针记得取地址!!

    • 从物理地址 0x400000 开始分配物理内存,用于建立管理内存的数据结构,获取方式为

      extern char end[];
      startAdd = (u_long)end;
      
    • 循环又没写i++

  • E2_4
    • 异常返回值是-E_NO_MEM题目没给出去相关板块找!!(找调用了这个函数的模块,看条件判断部分,就能得知异常返回值)

使用 tlb_invalidate 函数可以实现删除特定虚拟地址的映射,每当页表被修改,就需要调用该函数以保证下次访问相应虚拟地址时一定触发 TLB 重填,进而保证访存的正确性。
然而在 MOS 中,一旦物理页全部被分配,进行新的物理页分配时并不会进行任何的页面置换,而是直接返回错误,即在对应 page_alloc 函数中返回 -E_NO_MEM。

  • E2_6
    • 虚拟内存管理中的很多地址相关宏传入参数是u_long而不是指针,使用宏时注意看宏具体的实现
    • PTE_V 等并不是有效位的值1/0,而是已经把1/0填在相应位的与地址位数对齐的值(其他位为零),所以可以用 | 实现地址的生成
    • 移位运算的优先级比加法运算低
  • E2_7
    • 只要修改了页表(不管是改页面映射关系还是改权限),就需要调用 tlb_invalidate 函数删除特定虚拟地址的映射,不然TLB和页表信息会不同步
    • va 是二级页表页面的虚拟地址!不是数据页
  • 调试出错,发现makefile错了,追根溯源,发现应该是添加注释的时候输了中文空格,造成文件出错了……

exam前准备

提醒

  • 注意有效位 PTE_V 的检验

参数、宏、函数

缩写对照

  • Pde 一级页表项类型
  • Pte 二级页表项类型

在这里插入图片描述

地址相互转换相关

  • kseg0 处虚地址物理地址 的转换用的是宏(PADDR、KADDR),其他基本上都是函数(pa2page等)

从地址中获取信息

都是宏、在mmu.h

函数作用

  • pgdir_walk VS page_lookup

    都在相应的页表中找到对应的页表项,将其地址赋给*ppte

    • pgdir_walk 还可以创建新的页表项
    • page_lookup 重点在返回虚拟地址映射到的页控制块

Exam翻车分析

题目理解出现偏差——理解错题意&以为实现了自映射机制

  • 理解错题意 :*pte是页表项本身的虚拟地址,而题目里的va指的是给定的虚拟地址,要根据这个va范围内的虚拟地址到页表中去找相应的物理页框们,这个范围不是对页表项本身虚拟地址范围的限制

  • 以为实现了自映射lab2中的内核页表并没有实现自映射机制,所以va连续且递增并不代表它们对应的pte也是连续且递增的,因此不能把va转换成pte后比较

  • 正确的几个pte

    在这里插入图片描述

  • 把va的上下界转换成pte,然后用来限制遍历的pte:因为没实现自映射,pte不像va一样连续且递增,所以pte上下界并不与va的上下界对应,导致有些正确pte会被判为不在范围内

    在这里插入图片描述

【疑问】页表在虚拟内存中不应该是连续的吗,这样怎么保证其连续性?

展开*ppte表达式

*ppte = (Pte*)(KADDR( PTE_ADDR(*pgdir_entryp) + (PTX(va)<<2) ))
			= (Pte*)( page2pa(pp) + PTX(va)<<2 + 0x80000000 )

然而,根据映射机制【3】

*ppte = (Pte*)PTbase + VPN(va)
			= (Pte*)(PTbase + (VPN(va)<<2))
			= (Pte*)(PTbase + ( (PDX(va)<<10 + PTX(va)) <<2))
			= (Pte*)( PTbase + PDX(va)<<12 + PTX(va)<<2 )

两者应该相等,那怎么保证下式成立呢?pp是alloc随便分配的页面啊?

page2pa(pp) + 0x80000000 = PTbase + PDX(va)<<12 

Lab2、内核页表没有实现页表自映射,因此【3】不成立

【延伸】页表到底存储在哪?

页目录和页表都存储在kseg0。因为页表是内核数据结构,需要存储在内核这部分的区域中。内核在读写页表时,就是通过虚拟地址中的kseg0段进行的。

在lab3中,会为每个进程创建一个页表并利用kuseg实现自映射,在完成自映射后,用户进程就可以通过kuseg访问内存中自己的页表,而内核通过kseg0管理所有进程的页表

  • 在某些操作系统中,会分进程页表和内核页表,可以理解为内核页表用于内存的实际管理,而进程页表是一种方便用户查阅的机制。

    MOS的设计中,内核自身没有页表

代码编写(指针使用)不够规范

  • 指针解引用前必须先验证其非NULL,野指针会导致卡死
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值