玩具操作系统也有系统调用
综述
首先我们来看看我们的系统调用是怎么工作的。我们的程序要进行一个系统调用,得有东西让他调用吧。所以我们必须有一个 系统调用的封装
。在我们的例子中,就是 get_ticks()
这个函数。系统调用一般都是通过中断来实现的,所以我们要统一一个系统调用的中断号,初始化 idt
,指明该中断的对应处理程序。然后,一个中断肯定不止实现一个功能,所以,我们要同一个 量
来告诉系统我们要的是哪个功能,在我们的实现中,我们是通过对 eax
这个寄存器赋予不同的值来指明对应的功能的。由于是中断,所以当中断发生了之后,我们当然要保存被中断的进程的信息,所以我们要用到之前用到的 save
函数,但是由于函数里面已经对 eax
进行了赋值,所以我们必须将 save
中与 eax
的相关寄存器都换掉。然后,我们前面说过要实现多个功能,所以我们建立了一个数组 sys_call_table
,根据 eax
的值在数组中找到相应的处理程序。所以,简单来说,系统调用就是这样的:
用户调用系统调用的封装函数 -> 封装函数赋值
eax
,执行中断 -> 中断处理程序在sys_call_table
数组中根据eax
找到最终要执行的程序,并且执行之。至此,一个完整的中断结束~
遇到的一些问题
昨天在实现的时候,发现了输出的 ticks
一直都是 0 ,一开始也不知道为什么,还稀里糊涂地在那里 Debug
里半天,直到刚才才找到了错误之处。很简单,我错误地将 sys_get_ticks()
的返回值弄成了 void
。。。
一开始的时候,一启动就会产生 #GP
的错误,之后才发现,我在 init_decriptor()
初始化 sys_call
的地方,习惯性地将 attr
弄成 PRIVILEGE_KERL
,其实应该是 PRIVILEGE_USER
。既然犯错误了,顺便复习一下 DPL
的知识。之所以会产生 #GP
的错误,主要是 DPL
在起作用。对于调用门来说,DPL 规定了当前执行的程序或任务可以访问此调用门的最低特权级,而调用这个中断的 —— 我们的进程 —— 特权级是 1,很明显是低于 0 的,所以才会产生这个错误。
今天在实现的时候,发现有出现了很奇怪的 #GP
错误(这是我用 bochs 的 snapshot 截下来的):
Exception! --> #GP General Protection
ß
EFLAGS:0x11096CS:0x8EIP:0x306F4Error code:0xC
BASEADDRL BASEADDRH LENGTHLOW LENGTHH TYPE
00000000h 00000000h 0009F000h 00000000h 00000001h
0009F000h 00000000h 00001000h 00000000h 00000002h
000E8000h 00000000h 00018000h 00000000h 00000002h
00100000h 00000000h 01EF0000h 00000000h 00000001h
01FF0000h 00000000h 00010000h 00000000h 00000003h
FFFC0000h 00000000h 00040000h 00000000h 00000002h
RAM SIZE : 01FF0000h
-----"cstart" begins-----
-----"cstart" ends-----
~~~~~~~~~~~ kernel_main ~~~~~~~~~~~~
B.
一开始我一直不知道什么怎么解决。然后我就乱弄,然后错误就解决了。虽然我现在还是不知道究竟是什么错误,不过我说一下我的解决方法,用同样的问题可以参考一下。其实没有什么的,就是用 bximage
重新建立一个 a.img
,问题就解决了。
下午在实现的时候,出现了一个很奇怪的 bug ,输出到一半就停止了,又是长时间的 Debug ,总算找到了,又是一个低级的粗心错误。我感觉到,**粗心的程序员注定是短命的,因为他们把大部分时间花在了毫无意义的 Debug **。这个一定要改!!!!
就是把 schedule()
函数写错了:
PUBLIC void schedule()
{
PROCESS *p;
int greatest_ticks = 0;
while (!greatest_ticks) {
for (p = proc_table; p < proc_table + NR_TASKS; p++) {
if (p->ticks > greatest_ticks) {
greatest_ticks = p->ticks;
p_proc_ready = p;
}
}
}
if (!greatest_ticks) {
for (p = proc_table; p < proc_table + NR_TASKS; p++) {
p->ticks = p->priority;
}
}
}
不知道你看出来了没有,就是把 if
这一行弄在了 while
循环之外了。。。
顺便解释一下这个函数的作用吧。其实就是在进程表中找到 ticks 最大的,最为下一个要运行的进程。如果所有的进程的 ticks 都为 0,那么就将所有的进程的 ticks 初始化为 priority 。而上面的错误之所以会发生,就是当所有的进程的 ticks 都为 0 的时候,由于 greatest_ticks 一直为零,所以就死循环了。
好了,第六章到此结束了。错误不少,收获不少。向第七章进军!
EOF
Author: simowce
Permalink: https://blog.simowce.com/system-call/
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。