操作系统lab3

操作系统lab3
shikiLAB3实验报告
思考题
Thingking 1
请结合MOS中的页目录自映射应用解释代码中e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V 的含义。
- 将页目录自身物理地址存储到页目录中虚拟地址为
UVPT
的页目录项中,并将其权限位设置为只读,完成页目录自映射。
1 | o KERNBASE -----> +----------------------------+----|-------0x8002 0000 | |
由此虚拟内存空间结构图可知,UVPT即为用户页表起始位置,将其对应物理地址存入页目录中等比例偏移的位置即可完成页目录的自映射。
Thingking 2
elf_load_seg 以函数指针的形式,接受外部自定义的回调函数 map_page。请你找到与之相关的data这一参数在此处的来源,并思考它的作用。没有这个参数可不可以?为什么?
data
这一参数来源于load_icode
函数中的进程控制块结构体指针e
,作为回调函数map_page
的传入参数,提供了此处回调函数的具体实现函数load_icode_mapper
中所需要的env->env_pgdir
和env->env_asid
两个量。如果没有
data
这个参数将不能提供上述两个量,无法实现所需功能。
Thingking 3
结合 elf_load_seg 的参数和实现,考虑该函数需要处理哪些页面加载的情况。
- 函数部分代码如下
1 | u_long offset = va - ROUNDDOWN(va, PAGE_SIZE); |
由代码可知,需要处理一下几种情况:
段虚拟地址与页虚拟地址的边界不对齐,则需要使用
u_long offset = va - ROUNDDOWN(va, PAGE_SIZE)
计算出其相对于页边界的偏移量处理了段大小小于页大小的情况
如果二进制文件大小超过页大小,则需要将多个页进行映射
如果二进制文件大小小于段大小,则需要继续进行映射,直到达到段的大小为止
Thingking 4
你认为这里的env_tf.cp0_epc存储的是物理地址还是虚拟地址?
- 由前面的学习我们知道CPU只能通过虚拟地址进行访存,因此此处
env_tf.cp0_epc
储存的是虚拟地址
Thingking 5
试找出0、1、2、3号异常处理函数的具体实现位置。8号异常(系统调用)涉及的do_syscall()函数将在Lab4中实现。
handle_int
位于genex.S
中,代码如下:1
2
3
4
5
6
7
8
9
10NESTED(handle_int, TF_SIZE, zero)
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUS_IM7
bnez t1, timer_irq
timer_irq:
li a0, 0
j schedule
END(handle_int)handle_mod
和handle_tlb
位于genex.S
中,代码如下:1
2
3
4
5
6
7
8
9.macro BUILD_HANDLER exception handler
NESTED(handle_\exception, TF_SIZE + 8, zero)
move a0, sp
addiu sp, sp, -8
jal \handler
addiu sp, sp, 8
j ret_from_exception
END(handle_\exception)
.endm此函数可实现根据
expection
调用对应的handler
函数进行处理。继续阅读
genex.S
我们可以发现他实现了如下宏:1
2BUILD_HANDLER tlb do_tlb_refill
BUILD_HANDLER mod do_tlb_mod进一步可知
handle_tlb
会进一步调用do_tlb_refill
,handle_mod
会进一步调用do_tlb_mod
函数进行处理。
Thingking 6
阅读entry.S、genex.S和env_asm.S这几个文件,并尝试说出时钟中断 在哪些时候开启,在哪些时候关闭。
- 阅读
entry.S
,有如下代码:
1 | mfc0 t0, CP0_STATUS |
可知,当开始处理异常时关闭时钟中断。
由env_asm.S
中的如下代码可知,异常处理结束后调用schedule
后再直接调用env_run
后再调用env_pop_tf
函数恢复时钟中断。
1 | LEAF(env_pop_tf) |
难点分析
- 理解回调函数
map_page
的使用:使用回调函数可以使调用的elf_load_seg
函数能够根据回调函数和传入的参数执行不同的操作,增加了elf_load_seg
函数的复用性。 ## 实验体会
使用链表宏能够大幅度降低代码的复杂度,本次实验中需要实现空闲进程链表,只需要将lab2中使用的链表宏的传入参数修改为空闲进程链表即可,十分方便,同时也避免了直接在代码中使用大段的链表创建代码,使代码更简洁易读。
原创说明
参考了往年学长的博客:https://b1fang.github.io/2023/04/11/OS-Lab3/