xv6问题集合
进程表在哪
进程切换的过程
spinlock
为什么spinlock中可以直接使用了push_off和pop_off来关闭/开启中断,而不需要进入内核?
spinlock中使用了push_off和pop_off来关闭/开启中断,这个中断包括外部中断和定时中断吗?
如果一个用户进程acquire陷入死循环,那么中断是否永远关闭?
如果一个用户进程acquire后还没有release,而另一个进程release锁,并且这两个进程的锁不是同一个,那么中断是否开启了?
1 | void |
在中断使能方面,MIE 、SIE 、UIE 分别提供了 machine mode 、supervisor mode 、user mode 的全局中断使能位;
User级中运行用户程序,Supervisor级中运行操作系统内核(和设备驱动),Machine级中运行BootLoader和其它固件。
- machine mode 拥有所有的特权,一般在启动时候用于配置电脑的环境
- supervisor mode 的权限相对低些,可以执行特权指令,例如是否使能中断等
- user mode 的权限级别最低,完成一些特殊功能的时候需要通过系统调用进入 supervisor mode
- 在 RISC-V 中,通过寄存器 sstatus 中保存的 SPP 位来判断是处于内核态 (1) 还是用户态 (0)
中断分为外中断和内中断,外中断包括 I/O 中断、时钟中断等,内中断包括异常、系统调用和中止。
http://rcore-os.cn/rCore-Tutorial-deploy/docs/lab-1/guide/part-2.html
- https://dingfen.github.io/risc-v/2020/08/05/riscv-privileged.html
kalloc
在kinit中freerange中end的地址是多少?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
extern char end[]; // first address after kernel.
// defined by kernel.ld.
void
kinit()
{
initlock(&kmem.lock, "kmem");
freerange(end, (void*)PHYSTOP);
}
void
freerange(void *pa_start, void *pa_end)
{
char *p;
p = (char*)PGROUNDUP((uint64)pa_start);
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
kfree(p);
}
每个CPU都有自己的定时中断吗?
trap是怎么跳转到trampoline中的usertrap()的?
riscv为处理trap提供了sstatuts、scause、stvec、sepc、sscratch等寄存器,这些寄存器都会被中断隐指令所使用到:
(1)stvec寄存器存放着trap wrapper的地址。当trap发生时,stvec的值将被读入到pc中
(2)scause记录这个trap的发生原因。当trap发生时,这个寄存器被设置
(3)sepc保存pc的值。在PC的值被更新为stvec之前,PC值被保存在这个寄存器中
(4)sstatuts的SPP位记录着当前CPU所处的mode。
(5)sscratch记录着这个进程的trapframe地址。保存现场时,需要将寄存器保存在trapframe上。
总而言之,当trap发生时,首先会“执行中断隐指令”,完成关中断和设定trap相关寄存器等操作,而保护现场等操作,是由相应的指令执行的。
在内核初始化的时候,会设置stvec寄存器,因此将中断处理入口设置成了kernelvec。1
2
3
4
5void
trapinithart(void)
{
w_stvec((uint64)kernelvec);
}
在内核态的时候是怎么trap的?
kernelvec、kerneltrap
trampoline是什么
trampoline是跳板代码,包含以下这两段汇编:
1.uservec的作用是保存现在进程的栈帧,恢复kernel的tp、satp,切换到usertrap();usertrap()中通过yield()切换到调度器线程。
2.userret的作用是恢复用户的satp,恢复进程的栈帧,切换到usertrapret()。
为什么调度器是一个线程,而不是一个进程
首先要了解线程切换和进程切换要保存和恢复什么,
对于线程来说只需要保存栈帧(寄存器现场)就行,
对于进程来说要保存PCB(PCB中包含栈帧、打开的文件描述符等)、需要重新映射虚拟地址空间、进出OS内核、寄存器切换,
因此进程切换的代价要高于线性切换的代价。
在xv6中,通过保存和恢复栈帧来切换到调度器,并且调度器没有对应的PCB,所有调度器是一个线程。
在 usertrap函数中 p->trapframe->epc += 4;
epc = epc + 4,epc下一条指令是什么?是不是ecall的下一条指令?
syscall,ecall的下一条指令是ret
trap page是什么?有什么?
为什么fork父进程返回子进程的PID而子进程返回0?
对于父进程来说,fork返回子进程的pid,而子进程没有拷贝a0,而是把a0设成0,所以对于子进程来说返回0.
proc.c里面有exit()(sys_exit调用exit),提供给用户的系统调用接口也是exit,不会冲突吗?
同样的sys_wait调用wait,而提供给用户的系统调用接口也是wait,不会冲突吗?
同样的sys_kill调用kill,而提供给用户的系统调用接口也是kill,不会冲突吗?
文件描述符是不是proc结构体里面ofile(open file array)的下标?
是的,ofile[i]指向file struct,如果file struct的类型是fd_inode,那么file struct中的ip指向inde。
内核中有一个大小为100的ftable数组。
exec执行成功会不会有return?如果没有,那么是什么原因?
sys_exec和exec函数。

