• OS-lab2


    OS-lab2

    启动之后,我们的操作系统要能运行,需要一个载体,就是内存。内存的访问不是直接的,而是通过MMU完成。在完成MMU之前,我们先看看一些需要用到的宏定义和函数。

    include

    • pmap.h

      定义了内存控制块Page结构体,用于记录页面的分配和使用情况。其中pp_link有两个成员,*le_next用于指向下一个元素,le_prev用于指向前一个元素的**le_next的地址。pp_ref用于记录页面被引用的次数。
      page2pa函数通过给定的Page控制块计算对应的页面的物理地址。
      page2ppn函数通过给定的Page控制块计算这个页面控制块在整个页面控制块数组中的下标。
      pa2page函数通过给定的物理地址计算对应的页面控制块。
      page2kva函数通过给定的Page控制块计算计算这个页面对应的内核虚地址。
      va2pa函数通过给定的页目录和虚拟地址计算对应的物理地址。

      此外还声明了pmap.c中的一些函数。

    • queue.h

      通过宏定义定义了关于链表的一些操作,如初始化、插入删除等。

    • mmu.h

      定义了一系列变量如页面大小BY2PG、标志位PTE_V等。PDX(va)用于获得虚拟地址的高10位,PTX(va)类似。PADDR(kva)用于将内核虚拟地址转化为物理地址,KADDR正好相反。PTE_ADDR用于获得页表项存储的物理地址。

    现在,我们一步一步实现MMU。

    mm

    • pmap.c

      这个文件集合了管理内存的大部分函数。其中*pages是页面控制块数组,freemem是空闲内存的地址。

      mips_detect_memory函数手动给basememmaxpanpage等全局变量进行了赋值。
      *alloc函数手动分配n字节的空闲内存。具体思路即修改freemem的值,然后将alooced_mem清零后返回这个地址。
      *boot_pgdir_walk函数用于获取对应虚拟地址对应的二级页表项。具体流程是通过页目录找到页目录项地址;将页目录项的值转为虚拟地址;检查是否存在,若不存在且create为1,就分配一页,并给对应的页表项赋上标志位;然后再求得对应二级页表项的虚拟地址并返回。
      boot_map_segment函数用于将size大小的虚拟地址区间映射到size大小的物理地址区间。首先将sizeBY2PG取整;然后以页为单位,利用*boot_pgdir_walk获得每一页的页表项,再将物理地址和对应的标志位赋给对应的页表项,完成映射。
      mips_vm_init函数完成初始的建立两级页表的任务。首先是用alloc函数分配一页给页目录;然后分配npagePagepages数组,用于管理页面;再将pages数组这片区域映射到物理内存;类似的,分配空间给envs进程控制块数组,并映射到对应的物理内存区域。

      以上都是在启动过程中完成的操作。核心是mips_vm_init函数。

      page_init函数用于初始化pages数组并设置page_free_list数组。首先用LIST_INIT函数初始化page_free_list;然后通过freememend求得已经分配了多少空闲内存;将已分配的内存即freemem以下的内存以页为单位,通过修改pp_ref为1的方式记录下来;剩下的内存即freemem以上的内存则将pp_ref记为0,并利用LIST_INSERT_HEAD加入到page_free_list中。
      page_alloc函数用于分配一页物理内存。首先需要检查是否存在空闲内存,即利用LIST_EMPTY检查page_free_list是否为空;然后取出第一项并在链表中删掉这一项;最后将这一项对应的内存清零后返回这一页面控制块。
      page_free函数用来释放一页内存。当pp_ref为0时将这一页利用LIST_INSERT_HEAD加入到page_free_list中。
      pgdir_walk函数类似boot_pgdir_walk函数,基本思路一样。区别在于,pgdir_walk函数是在启动之后,所以在需要创建新页表的时候可以使用page_alloc函数,并且分配后将对应的pp_ref增加。boot_pgdir_walk函数由于没有建立页表映射机制,对于pp_ref是无法操作的。
      page_insert函数用于将物理页映射到特定虚拟地址。首先利用pgdir_walk函数取得虚拟地址va的页表项;检查这一页表项是否已经对应到了指定页面上,若页表项不为空且已经映射到了指定页面,则利用tlb_invalidate更新tlb,然后给对应的页表项赋值并返回;若这一页表项不为空且映射的页面不是指定页面,则需要用page_remove将这一虚拟地址对应的页面移除;然后利用tlb_invalidate更新tlb;再一次利用pgdir_walk函数取得页表项,对这一页表项赋值并增加pp_ref
      page_lookup函数用于获得虚拟地址对应的Page和页表项。首先通过pgdir_walk得到虚拟地址对应的页表项;如果页表项为空或页表项有效位为0则返回;然后通过pa2page得到Page
      page_decref函数用于减少pp_ref
      page_remove函数用于移除物理页面到虚拟地址的映射。首先利用page_lookup获得Page和对应的页表项;减少pp_ref,若pp_ref为0则需要用page_free释放掉这一物理页;将页表项清零,并用tlb_invalidate更新tlb。
      tlb_invalidate函数用于使虚拟地址对应的tlb表项失效,而下次访问这个地址就会触发tlb充填,完成对tlb的更新。核心是调用tlb_out函数。

      剩下的三个函数physical_memory_manage_checkpage_checkpageout用于检查以上的内存管理函数功能是否正确。

    • tlb_asm.S

      这个文件用于处理tlb更新,即tlb_out函数。首先将CP0_ENTRYHI寄存器的值取出来,将虚拟地址写入;通过tlbp查找与CP0_ENTRYHI内容匹配的页表项并写入CP0_INDEX,由于tlb内部采用流水线设计,因此这条指令后需要执行nop;若找到则将CP0_ENTRYHICP0_ENTRYLO0清零,这样在未来对这一虚拟地址进行访问就会诱发tlb充填;利用tlbwi根据CP0_INDEX写tlb,然后恢复CP0_ENTRYHI;若没找到则将CP0_ENTRYHI恢复为原来的值并返回。

  • 相关阅读:
    AcWing 1027. 方格取数 dp
    AcWing 1014. 登山 dp
    acwing 482. 合唱队形 dp
    LeetCode 1463. 摘樱桃II dp
    LeetCode 100. 相同的树 树的遍历
    LeetCode 336. 回文对 哈希
    LeetCode 815. 公交路线 最短路 哈希
    算法问题实战策略 DARPA大挑战 二分
    算法问题实战策略 LUNCHBOX 贪心
    AcWing 1100. 抓住那头牛 BFS
  • 原文地址:https://www.cnblogs.com/p-wk/p/13183440.html
Copyright © 2020-2023  润新知