Tutor

tutor真是不好读

published on

之前参加了一次Topcoder的SRM,把500pt的题目给做了。期间小心翼翼地绕开了无数trick,最后还是挂了。不过在那一次之后,我就学到了一个教训,对a除以b取下整的时候要注意负数的情况。当然这个教训不是本文的重点,我写这个事是因为比赛后我决定把这个教训记下来,但是一直没有写,直到这两天有了新的教训。想想再拖下去不像样,于是就这么写了。这个故事告诉大家,如果没有截止日期,那么什么事都很难做下去。

那么新的教训是来自哪呢?在于我最近开始研究os也就是操作系统要怎么写了。这件事得追溯到我上学的时候,在学校的二手书店里买了一本《自己动手写操作系统》,当然那个时候我兴趣广泛,这本书看了几章弄不明白就放到一边去了。我说兴趣广泛不是为了能力不足而辩解,这只是一个伏笔。我前几天在亚马逊上闲逛,看到一个日本人写的《30天自制操作系统》kindle版,立马对其产生了兴趣,于是买了下来,顺便把学校买的书从箱子中找了出来,兴致勃勃的准备开始折腾一下。

为不了解的人介绍一下,这两本书都是指南类型的书,就是有经验的人写过你说如果你要做一件事,可以先做什么,接着做什么,然后怎么样,你按照这样的步骤就可以完成这样复杂的工程了。

开始真是顺风顺水,照着书上的思路顺利的把bootloader给搞定了,但是从保护模式开始,就令人吐血了。我又懒得参考人家的代码,两本书开始讲gtd的时候,我实在是把握不住了。于是我开始了在互联网上的探索,发现了一系列优质的指南资源,比如osdev.org。通过长时间的研究,我大致把握住了下面几点:

  • cr0寄存器有一位表示是否进入保护模式
  • 保护模式下端寄存器存放的是selector,是通过gtdr这个寄存器指向的table里面的信息来将虚拟地址映射到物理内存地址的,然后gtd中间每一项有base limit flag等字段来描述这个段的信息

当然这些内容对于本文来说是无关紧要的,有意思的地方在于所有这些文章全部简单的描述了一个gtdr之后就给出了类似下面这么一个代码:

   LGDT  [gdtr]
reloadSegments:
   ; Reload CS register containing code selector:
   JMP   0x08:reload_CS ; 0x08 points at the new code selector
.reload_CS:
   ; Reload data segment registers:
   MOV   AX, 0x10 ; 0x10 points at the new data selector
   MOV   DS, AX
   MOV   ES, AX
   MOV   FS, AX
   MOV   GS, AX
   MOV   SS, AX

总之这之后一切就设定好了。我就特别悲伤的对着这段代码研究了很久,先是好不容易理解了这一坨代码其实是设置段寄存器:把cs改成0x08,把其余的改成0x10。这些描述给我留下了无尽的谜团,比如到底是如何通过gtd寻址的,在没有修改cs之前的代码怎么执行的,如果在这些指令执行到一半,我在中间干点别的事情,那么是处于什么情况。这些疑惑一直困扰着我,简直就不能接着干下去。当然这些疑点最终还是被我搞明白了。

导致我写这篇文章的是搞清楚gtd地址翻译的方法。一开始我看到描述符里有一个base字段,我就非常努力的想理解其含义。首先我是这样想的:如果我的链接器认为,程序将会加载到0x40000000这个地址,那么它里面的指令就都是根据这个地址来的,比如一个全局变量,可能就在0x41000000,而实际在物理内存中可能就是在0x010000000那么假如我的base写的是0x40000000,对应到物理地址就应该减去base了。但我又有些犹豫,觉得按照各种指南中模糊的描述来看,也有可能是加上base。这个疑问很麻烦,除非写一个内核代码来测试,但在那之前,我有幸找到了答案。便是通过Intel® 64 and IA-32 Architectures Software Developer Manuals,终极文档。里面写的清清楚楚:

The base address plus the offset thus forms a linear addressin the processor’s linear address space.

还附带了若干图例,把整个一套相关的内容都解释了,堪称完美,让我瞬间为自己到处找tutor和看别人笔记浪费的无数时间感到可惜。这样细想一下,原来不是通过减去0x40000000,而是加上0xC0000000来实现的。于是我得到了一个教训:有问题记得看手册

我必须要说一件事,写指南是一件很麻烦的事情。尤其是为初学者所写的指南,我已经在计算机别的领域有怎么也还算丰富的经验,然而初次涉及内核的开发,依然面对了重重的困难。作为一个有经验的作者,往往不容易回忆起自己刚开始摸索一件事物的时候面对的重重困难。可以回想你开始学习编程的时候,各种各样眼花缭乱的交错的概念理解起来多么困难。

而如果是一个像我这样希望对每一步的细节都非常清楚的读者,恐怕只能寄希望于作者多多花费心血讲解细节,亦或是及时指出可靠的参考材料。一个指南假如仅能通过复制粘贴然后改改其中参数的方法来使用,那么其学习价值恐怕很难得到保证。

所以我希望有志于编写指南传播经验的同学可以谨慎地进行自己的工作,让阅读的人能更好的理解。我如果有机会写点什么指南的话,必将朝着让大家理解的方向多努力。

Read More...