Lab2实验报告

Lab2实验报告

思考题

Q1

CPU只能发虚拟地址。因此MIPS汇编程序中的lwsw指令发送的同样都是虚拟地址。


Q2

  1. 因为部分链表结构要经常性地重复使用,使用宏的话能够大大节省代码的编写长度,并且能够更加方便的进行调试。

  2. 通过查看文件中的:单向链表singly-linked list,循环链表 Circular queue functions部分,与双向链表相比较,有如下结论:

    (1) 单向链表:在某一项后插入是,能够直接进行,因为有sle_next;而在元素前面插入的时候,则需要遍历链表来获取相应位置。在删除的时候,也要先遍历找到位置才能进行删除。比如代码中的 while(curelm->field.sle_next != (elm))curelm = curelm->field.sle_next;部分。

    (2) 循环链表:删除插入操作与单向链表类似。但因为其首尾元素相连,因此可以直接进行尾插。你能够观察到循环链表与单向链表都有一个负责遍历的部分CIRCLEQ_FOREACH()

    (3) 双向链表:除去对尾部元素的处理,其它部分的插入删除都十分方便,因为他记录了前后两个节点的信息,这也就代表了可以在O(1)复杂度内完成。而对队尾元素的处理需要循环遍历找到,再进行操作。


Q3

1
2
3
4
5
6
7
8
9
10
C:
struct Page_list {
struct {
struct {
struct Page *le_next;
struct Page **le_prec;
} pp_link;
u_short pp_ref;
}* lh_first;
}

Q4

三级页表页目录基地址:
$$
PT_{base} + PT_{base}<<9+PT_{base}<<18
$$
映射到页目录自身的页目录项:
$$
PT_{base} + PT_{base}<<9+PT_{base}<<18+PT_{base}<<27
$$


Q5

  1. 指导书中提到:同一虚拟地址在不同的地址空间中通常映射到不同的物理地址。因此若没有ASID,则当不同进程提供的TLB不同时,会导致虚拟地址映射到错误的物理地址。
  2. ASID段占6位,可以被设置为$2^6=64$个不同的值,因此R3000 中可最多容纳64个不同的地址空间。

Q6

  1. tlb_invalidate()中调用tlb_out()

    1
    2
    3
    void tlb_invalidate(u_int asid, u_long va) {
    tlb_out(PTE_ADDR(va) | (asid << 6));
    }
  2. 清空映射在TLB中的缓存。

  3. 位于kern/tlb_asm.S

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    LEAF(tlb_out)
    .set noreorder
    mfc0 t0, CP0_ENTRYHI # 将CP0的ENTRYHI寄存器的值赋予t0
    mtc0 a0, CP0_ENTRYHI # 将a0寄存器的值赋予CP0的ENTRYHI
    nop
    tlbp # 根据EntryHi中的Key,查找 TLB 中与之对应的 表项,并将表项的索引存入Index寄存器(若未找 到匹配项,则 Index 最高位被置 1)
    nop
    mfc0 t1, CP0_INDEX # 将CP0的INDEX寄存器的值赋予t1
    .set reorder
    bltz t1, NO_SUCH_ENTRY # 如果t1小于零,即没有在TLB中找到EntryHi对 应的表项(最高位是1),则跳转到 NO_SUCH_ENTRY标签处
    .set noreorder
    mtc0 zero, CP0_ENTRYHI # 将CP0的ENTRYHI寄存器的值置为0
    mtc0 zero, CP0_ENTRYLO0 # 将CP0的ENTRYLO0寄存器的值置为0
    nop
    tlbwi # 以 Index 寄存器中的值为索引,将此时 EntryHi与EntryLo的值写到索引指定
    的 TLB 表项中
    .set reorder

    NO_SUCH_ENTRY:
    mtc0 t0, CP0_ENTRYHI # 将CP0的ENTRYHI寄存器的值复原
    j ra # 函数跳回
    END(tlb_out)

Q7

X86体系结构中的内存管理机制是通过分页和分段结合的方式实现的,且X86支持物理地址的扩展,从32位扩展到36位或更高位,以支持更大的物理内存容量。相比之下,MIPS中的内存管理主要依靠分页机制,不同于X86中的多级页表结构,MIPS采用的是单级页表结构。MIPS的页表包含固定数量的页表项,每个页表项存储虚拟地址和物理地址的映射关系。MIPS体系结构没有像X86那样的分段机制,只有全局和局部两种地址空间。此外,MIPS中的物理地址空间较小,通常为32位,限制了可寻址的物理内存容量。



难点分析

  1. 双向队列插入时候指针的编写顺序排列——为了保证在更改指针指向后,不会再用到原本指向的位置。

    (1) 后插:

    (2) 尾插:

  2. page_alloc()中,进行memset时候要对虚拟地址进行初始化memset(page2kva(pp), 0, BY2PG);

  3. page_walk()中,最终要转化成虚拟地址后才能进行偏移操作,最终赋值。

    *ppte = (Pte *)KADDR(PTE_ADDR(*pgdir_entryp)) + PTX(va);

  4. 二级页表的整体关系以及地址计算。

    • 31~22位是页目录中的表项号,可以根据该表项号从页目录(一级页表)中取出对应的页表项,该页表项中为二级页表首地址。
    • 21~12位是二级页表中的表项号,从二级页表中取出对应的页表项,该页表项中储存的是虚拟地址所对应的物理页框的首地址。
    • 12~0位是页内偏移,通过将上面得到的物理页框的首地址和页内偏移相加,最终就可以得到虚拟地址对应的物理地址。


实验体会

这次实验最大的感受就是对C语言指针的理解会很深的影响到这次实验的效率。

在双向链表的过程中,与我曾认识的“一个指向下一个元素,一个指向上一个元素”不同,此处的双向是“一个是指向下一个元素的指针,一个是指向上一个元素的next指针的指针”,因此在编写的时候就要十分注意指针的赋值关系。此外,在插入过程中,如何按顺序更改指针的对象,是很重要的。

通过对整个Lab2的编写,除了扎实了我的C语言基础,也让我对页表有了一定的了解,知道了如何一级一级的进行物理地址的寻找。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
Runtime Display
  • Copyrights © 2023-2024 Lucas
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信