Skip to content

pa3-3

题目

1.Kernel的虚拟页和物理页的映射关系是什么?请画图说明;
  • 首先init_page()函数中进行对两级页表的创建与初始化,先对函数进行分析。

  • 核心代码

    • c for (pdir_idx = 0; pdir_idx < PHY_MEM / PT_SIZE; pdir_idx++) { pdir[pdir_idx].val = make_pde(ptable); pdir[pdir_idx + KOFFSET / PT_SIZE].val = make_pde(ptable); for (ptable_idx = 0; ptable_idx < NR_PTE; ptable_idx++) { ptable->val = make_pte(pframe_idx << 12); pframe_idx++; ptable++; } }
  • 外层循环枚举pde表(一级页表中的项的编号),对pde表项进行初始化(指向对应的二级页表的首地址)

  • 内层循环再枚举页表中每一项的序号,并将页映射到pframe_idx<<12对应的物理地址

  • 此外每创建一个pde表,都会在用户区和系统内核区创建两个备份,即会共享同一个页表

  • 即pde的每一个表项都会对应一个大小为4kb的二级页表(共1024个),每个二级页表内又有1024个pte表项

    • Snipaste_2023-05-17_10-43-56
  • 具体的物理页与虚拟页的映射是在加载程序(elf)时通过paddr=mm_malloc(ph->p_vaddr,ph->p_memsz);分配并完成的,将处于虚拟地址空间的数据以页为单位读取到主存中的物理页并进行映射。

2.以某一个测试用例为例,画图说明用户进程的虚拟页和物理页间映射关系又是怎样的?Kernel映射为哪一段?你可以在loader()中通过Log()输出mm_malloc的结果来查看映射关系,并结合init_mm()中的代码绘出内核映射关系。
  • 用户进程的映射关系

  • 在loader中对转化前后的数据进行打印

  • image-20230517113215751

  • 地址 内容 地址
    0x804c000-0x804d000 用户进程数据段 0x1030000-0x104000
    0x804a000-0x804b000 用户进程代码段 0x1020000-0x103000
    0x8049000-0x804a000 用户进程代码段 0x1010000-0x102000
    0x0000000-0x0001000 空页 0x1000000-0x101000
  • kernel映射

  • 地址 内容 地址
    0xc0031000-0xc0030000 Kernel 代码区 0x31000-0x30000
3.“在Kernel完成页表初始化前,程序无法访问全局变量”这一表述是否正确?在init_page()里面我们对全局变量进行了怎样的处理?
  • 正确,对于普通的全局变量,由于其地址都是在虚拟空间中的,需要转化为物理地址才能使同,而无法预先知道全局变量的物理空间究竟会是多少因此无法直接进行访问。
  • 但是对于init_page()中的全局变量,由于程序为系统指定了固定的物理空间与虚拟空间的对应关系,因此可以通过使用偏移量的方式映射,从而实现对去全局变量的访问
  • 使用宏#define va_to_pa(addr) ((void *)(((uint32_t)(addr)) - KOFFSET))

总结

  • 本阶段完成过程比较曲折,pa3已经进入尾声,完成了很多内容,在出现程序崩溃时定位错误有些难度,因为之前完成的部分都有可能是存在问题的。
  • 比如就发现了pa3-1的cache完全写错了(大小端理解错误)
  • 还犯了一个非常弱智的错误,发现会遇到没有加载到主存的页,而这显然是出现了问题。经gdb调试发现,从0x8049000即程序代码段开始所有内容都是0,这就导致程序一直向前错误执行,直到到达下一个没有加载到主存的本不应该到达的页。
  • 检查了很久才发现是在loading中只为程序分配了空间却没有使用cpy进行复制。。。
  • 总的来说pa3中大致体验了下层次存储结构实际的实现(虽然大部分代码都是框架写好的),对存储系统以及硬件与操作系统的关系与区别有了更深刻的理解和体会。