[第6天] 中断

       坑爹的一周终于过去了,今天去考了所谓的java证书,一天学习的东西还能应付应付。但是那考卷质量不行,估计这结果也是可以是水水过的。所以一有时间,我就开始第六天。毕竟我的目标是学习linux,要抓紧时间,先实现一个自己的。今天也把GDT大概搞清楚了。而且今天学了键盘的中断,感觉还是蛮好的。虽然掉进一个坑。

分割文件:

        kernel.c文件太大了,必须分开处理。现在的分割为4个,如下:

  1. graphic.c: 处理图像绘制,界面等
  2. init.c: kernel入口
  3. dsctbl.c: GDT和IDT初始化
  4. int.c: 中断设置

      Makefile用通配符,可以同时编译依赖关系,免得写上一大坨。还学到了ld -r选项,relocatable,就可以把这些.o文件都重新整合起来。所以代码还是见github

GDT理解:

        感觉今天最大的收获,是搞明白了GDT。原本以为GDT会影响代码的跳转,后来看看资料,发现GDT的作用就是分割内存,保护系统和机器。CS,SS等寄存器不影响代码的执行和跳转。我现在实现的还只是Flat Setup,就是系统代码段使用32bits地址空间,系统数据段也是使用全部内存。这当然不能实现数据隔离,但是目前我还没有真正区别开数据和代码,所以先这样不管。能运行就好。GDT的意义如下:

580px-SegmentDescriptor.svg

       要注意的是,Base是分成3块的。还有G,DB,A各种意义,可以直接网上找。要注意这只是一条GDT。可以设置很多记录。当然进入保护模式,必不可少的有3个记录。Null Segment,Code Segment,Data Segment。Null是保留的,无意义,起始位置是0x00,Code Segment为0x08,Data Segment为0x10,因为每个有8 bytes。以此类推下去。当要跳转时, jmp CODE_SEG:init_pm ,CODE_SEG就是0x8。CPU就会自动将该地址描述的GDT内容读入。大概是这样,估计还有点理解错误。还有IDT,没去搞。

中断处理:

        中断处理,先要初始化PIC,我就直接抄代码,跳过了。直接IRQ,IRQ是指Interrupt Request。用INT 0x20-INT 0x2f,接收IRQ0~15, (因为INT 0x1f之前是CPU自己用的)。鼠标对应的中断是IRQ12,键盘是IRQ1,因此要处理INT 0x2c和INT 0x21。先要注册中断处理程序。其中_asm_inthandler是用汇编写的处理程序。1*8 指第一块GDT,我就傻逼了。作者用的是2*8,因为作者把第二块当作代码段,不按常理出牌啊!害我搞了半天。中断发生后总是会自动重启。因为这用的是数据段,不能执行。所以CPU启动了保护机制。

         说是使用_asm_inthandler处理,其实是在中间CALL了C写的函数。比如INT 0x21的真正出来函数为:

 最后的键盘中断,鼠标还没有完成,要到下一天。

SlefMouse

链接:

  1. Makeflie ld
  2. GDT and IDT

[第5天] 字体和鼠标

       今天比较轻松愉快,作者介绍了如何显示字体和做了一个鼠标模型。当然是用显示的点阵原理做的。我觉得这个显示字体的原理应该跟真正操作系统差不多。为了规范,我没有像以前那样把内核直接拼接到第二扇区,我把他当作文件一样放进去。从img文件可以看出,这个文件的起始位置在0x4400,所以要读很多扇区,干脆就读了10个柱面。相应的内存位置也改了,从0x1000改到0xc400了。

数据读取:

       这本来是好几天前的事情,但是我现在才真正理解这个读取。作者采用的方法是1个扇区1个扇区的读,而int 13h这个中断,明明可以连续读好几个扇区,效率高啊。但是因为这个原因,我debug好久,才发现不能这么做,这样做会引起DMA boundary error,这个太坑了ES:BX越了64K的界就会悲剧,怪不得我不能连续读4个扇区。我没有找解决方法,直接按作者的来。代码类似就不放了,关键教训就是 DMA Boundary Error。。

显示字符:

        字符就是点阵啊。比如A可以表示成8*16,如下图所示。用二进制表示就是下面的代码。有了这些二进制之后,就可以在对应的1位把颜色改成白色,0位改成背景色。代码见github

 A

制作字体:

       256个ascii,一个个做过来很蛋碎,还好作者提供了友人的制作的字体。但那字体都是.*表示,要经过转换。python就上了,直接脚本处理,然后tr命令去掉引号就万事ok了。然后当作头文件引入即可。作者使用链接的方式,我感觉没必要。总之所以字符都能显示了。还遇到一个事,就是sprintf不能用,因为我是64位系统,先不管这事,自己写个转换函数就能输出数字了。以后再想如何优雅的处理32位的事情。

制作鼠标:

      原理与制作字体一致,这鼠标还不能动。作者由此挖了个大坑,这次我没有跳进去。后面几天讲中断处理,感觉很麻烦。下面是目前系统的样子。总体代码见github

SlefMouse

GDT和IDT:

        GDTIDT这东西我还是没有完全搞懂。反正跟32位保护模式密切相关,什么代码段数据段的。一不小心代码就执行不了。本来我也把代码复制到0x280000去了,但是有可能入口地址啊,段寄存器啊什么的原因,导致不能运行代码。我就先放着不管了。

真机操作:

        做了操作系统不能在真机上跑,怎么行。但这事折腾了我1个晚上。刚开始我以为内存位置不对搞了半天。后来靠我天才的测试方法发现,原来disk read之前就跪了。对比时候发现是sp寄存器的问题。谁说sp寄存器一定要初始化为0x7c00啊,我参考的那个告诉我0x9000,太坑。。反正寄存器初始化正确后,我就能在同学的机子上跑了。我自己的笔记本是disk read error。我原本以为是显示用的LVDS而不是VGA的关系,然后我陷入了沉思,其他grub是怎么做到的? 后来我发现那个A20 没有打开。这个A20是允许使用超过1M的内存空间,一般都是打开的啊。我这么做之后,发现行了!!

        后来我突然就发现一个严重的问题,TMD,这个A20是读了磁盘之后才启用的啊,根本没有关系啊!!我无语了,我用特殊的调试技巧,发现真没关系。我把那段代码改掉,随便放点其他的代码,一样可以!!妹的,难道是跟引导长度有关,还是我BIOS的BUG? 还是更深层的原因,我还不知道。。反正成功了!上图!(事实证明是我电脑问题,BIOS Bug的可能性大,别的电脑都行)

Real Laptop

链接:

  1. Understanding the PC Boot Proces and Writing a Bootloader