坑爹的一周终于过去了,今天去考了所谓的java证书,一天学习的东西还能应付应付。但是那考卷质量不行,估计这结果也是可以是水水过的。所以一有时间,我就开始第六天。毕竟我的目标是学习linux,要抓紧时间,先实现一个自己的。今天也把GDT大概搞清楚了。而且今天学了键盘的中断,感觉还是蛮好的。虽然掉进一个坑。
分割文件:
kernel.c文件太大了,必须分开处理。现在的分割为4个,如下:
- graphic.c: 处理图像绘制,界面等
- init.c: kernel入口
- dsctbl.c: GDT和IDT初始化
- int.c: 中断设置
Makefile用通配符,可以同时编译依赖关系,免得写上一大坨。还学到了ld -r选项,relocatable,就可以把这些.o文件都重新整合起来。所以代码还是见github。
GDT理解:
感觉今天最大的收获,是搞明白了GDT。原本以为GDT会影响代码的跳转,后来看看资料,发现GDT的作用就是分割内存,保护系统和机器。CS,SS等寄存器不影响代码的执行和跳转。我现在实现的还只是Flat Setup,就是系统代码段使用32bits地址空间,系统数据段也是使用全部内存。这当然不能实现数据隔离,但是目前我还没有真正区别开数据和代码,所以先这样不管。能运行就好。GDT的意义如下:
要注意的是,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启动了保护机制。
1 2 3 | set_gatedesc(idt + 0x21, (int) _asm_inthandler21, 1 * 8, AR_INTGATE32); set_gatedesc(idt + 0x27, (int) _asm_inthandler27, 1 * 8, AR_INTGATE32); set_gatedesc(idt + 0x2c, (int) _asm_inthandler2c, 1 * 8, AR_INTGATE32); |
说是使用_asm_inthandler处理,其实是在中间CALL了C写的函数。比如INT 0x21的真正出来函数为:
1 2 3 4 5 6 | void inthandler21(int *esp) { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15); putfont8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 21 (IRQ-1) : PS/2 keyboard"); } |
最后的键盘中断,鼠标还没有完成,要到下一天。
链接: