一个操作系统的实现 -- 单进程

一个操作系统的实现

经过了一天的努力,在刚才,总算出现了上面激动人心的画面了:

真的很高兴,趁着还热乎,赶快记下来:

综述

第六章是 进程 。不过现在这一章的 进程 其实是有点取巧的,它是事先将一个进程需要的寄存器,栈,LDT,代码等准备好,弄成一个进程表,一切都准备完了之后,将 esp 指向进程表的顶部,然后一个一个地 pop ,然后一个跳转,我们的第一个进程就开始运行了。

由于涉及到特权级的转换,所以需要 tss 来记录每个特权级的 ssesp,以便当低特权级到高特权级的切换时,堆栈也能够切换。

由于现在我还没有实现中断,所以,这个进程是一直都在运行的,没有被打断的。不过这种情况将会改变,不过得明天吧。

代码解读

一开始的这些代码没有什么难的,主要提一点:

/kernel/main.c 的 line 27 和 line 29 这两行代码中,有一个我之前一直无法理解的,就是 >> 3 。现解释如下:

每个描述符的大小是 8 字节,>> 3 就相当于 除以8 ,这样就能够得到相应的描述符在 gdt数组 的具体位置了。

犯过的错误以及总结

  1. typedef 之后忘记了一个最重要的 ; . 导致出现了很多匪夷所思的错误,例如提示说 #define EXTERN extern 这一句有错等等。

  2. 每增加一个新的函数就要在 inlcude/proto.h 里面添加相应的声明。

  3. 有关字符串的函数声明在 include/string.h 里面

  4. 用汇编实现的函数如果要被其他文件调用,**千万记得要用 global **。不然肯定是会报 undefined reference to xxx 的!

  5. 一开始出现了 #GP 的错误,提示说在 cs:0x8 eip:0x3059E 这里出现了错误,反汇编了一下,发现这个位置对应的代码是:

         lldt     [esp + P_LDT_SEL]
    

    根据 p_proc->regs.eflags = 0x1202 ,找到了 restart() 的位置:0x30598 .

    不过后来发现了,又是一个粗心导致的错误,我忘记填充 GDT 中的 LDT 的描述符了。不过,发生 #GP 的结果跟我查文档的结果是一样的。

收获

又是花了很多时间在 Debugging 上,不过这一次总算有所收获。

  1. bochssreg 指令能够查看 LDTR
  2. print-stack 后面加个数字能够控制输出的栈的长度

最后,如果你们也想要体验一下 Debug 的话,我把我的 Debug 的过程公开出来:

b 0x7d12 (找到 loader 之后的跳转)
c
b 0x9027e (跳入保护模式)
c
b 0x9039b (跳入内核)
c
b 0x310c9 (restart())

声明,上面的地址只对于我的代码有效,你自己实现的代码与我的可能有出入

下面是原书代码的 Debug 过程:

b 0x7d0a (找到 loader 之后的跳转)
c
b 0x9027f (跳入保护模式)
c
b 0x90393 (跳入内核)
c
b 0x3071c (这一句是根据 kernel/main.c 中很明显的 0x1202 找到的,下面几行就是 restart() 了)

大概就是这些了。明天继续~

EOF

Author: simowce

Permalink: https://blog.simowce.com/chapter-6-single-process/

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。