30天自制操作系统-第06天-分割编译与中断处理

1.分割源文件(06_day/harib03a)

    bookpack.c  拆分为以下三个文件:

         graphic.c:绘画处理

         dsctbl.c : GDT,IDT等的处理

         bootpack.c 其他处理 

2.整理 makefile(06_day/harib03b)

      前一节c 语言文件变多,原有文件增加多个单个文件的处理脚本,以后每增加新的C文件,都要去修改 MaleFile,不利于维护,现在将两种类型单个文件的处理抽象成两个一般规则:

      %.gas : %.c MakeFile

           $(cc1) -o $*.gas $*.c

      %.nas : %.gas MakeFile

          $(GAS2NASK) $*.gas  $*.nas

       Make.exe  首先寻找普通规则,再去找一般规则

3.整理头文件

  将前述三个C文件中重复声明的函数和变量抽出来,生成一个bookpack.h文件,然后,各个c文件加上#include "bootpack.h"

4.naskfunc.nas里的_load_gdtr函数:

   _load_gdtr:                                 ;void load_gdtr(int limit,int addr)

               MOV   AX,[ESP + 4]         ;limit

               MOV   [ESP+6],AX          ;作者使用了技巧,[ESP + 8]存放的是地址

               LGDT  [ESP+6]                ;给GDTR赋值,从指定地址(此处[ESP+6])读取六字节

               RET

GDTR寄存器:48b(6字节),低16b是段上限‘

5.GDT结构和初始化代码的再次说明:

1) struct SEGMENT_DESCRIPTOR {

//只定义了与本书内容相关部分
short limit_low, //段上限低16b

short base_low; //段基址的低16b
char base_mid,//段基址的中8b,与前面低16b的组成段基址的低24b;

char access_right;  //高4b称为扩展访问权
char limit_high, //段上限高8b

char base_high; //段基址的高8b
}; //GDT 8字节内容

2) void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
if (limit > 0xfffff) {
ar |= 0x8000; /* G_bit = 1  如果为1,则limit的单位是页,一页4kb*/ 
limit /= 0x1000;
}
sd->limit_low = limit & 0xffff; //低16b存入limit_low
sd->base_low = base & 0xffff;  //低16b存入base_low
sd->base_mid = (base >> 16) & 0xff; //段基址的中8b,与前面低16b的组成段基址的低24b
sd->access_right = ar & 0xff; //取ar的低字节存入access_right
sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); //其中高4位存储ar的段属性高4位,对应((ar >> 8) & 0xf0),低4位存储limit段大小的高4位,对应((limit >> 16) & 0x0f)

sd->base_high = (base >> 24) & 0xff;
return;
}

3)ar的解释:

高4b:称为扩展访问权,"GD00",G指的是G bit,为1的话,段大小的单位不是字节,是页,一页4kb;D指段模式,1指32b,0代表16b

低8b:

       0x00:未使用

       0x92:系统专用,可读写,不可执行

       0x9a:系统专用,可执行,可读不可写

       0xf2:程序用,可读写,不可执行

       0xfa:程序用,可执行,可读不可写

6.初始化PIC(06_day/harib03d)

  PIC:可编程中断器

  要移动鼠标,必须使用中断,欲用中断,先必须初始化GDT和IDT

  CPU -->主 PIC(IRQ2) -->从PIC

PIC的寄存器都是8位寄存器,其中IMR称为中断屏蔽寄存器,对应8路IRQ信号,当该位为1时,说明对应的IRQ信号被屏蔽,PIC就忽略该路信号。ICW为初始化控制数据的寄存器,ICW一共有4个,ICW1,ICW4与PIC主板配线方式,中断信号的电气特性等有关,ICW3是用有关主从连接的设定,ICW2是决定IRQ哪一号中断通知CPU。

当应用程序对操作系统破坏时,CPU内部会自动产生中断信号0x00~0x1f,以此来保护系统。所以IPQ的中断号码只能从0x20开始,到0x2f。

  1)初始化中断(int.c)

void init_pic(void)//PIC的初始化程序

 

 


{
io_out8(PIC0_IMR, 0xff );//禁止所有中断
io_out8(PIC1_IMR, 0xff ); //禁止所有中断
//主PIC的相关设定
io_out8(PIC0_ICW1, 0x11 ); //边沿触发模式
io_out8(PIC0_ICW2, 0x20 ); //IRQ0-7由INT20-27接收
io_out8(PIC0_ICW3, 1 << 2); //PIC1由IRQ2连接,对应的ICW3为0000 0100,所以是1<<2
io_out8(PIC0_ICW4, 0x01 ); //无缓冲区模式
//从PIC的相关设定
io_out8(PIC1_ICW1, 0x11 ); //边沿触发模式
io_out8(PIC1_ICW2, 0x28 ); IRQ8-15由INT28-2f接收
io_out8(PIC1_ICW3, 2 ); PIC1由IRQ2连接,2为标识号,表示IRQ2
io_out8(PIC1_ICW4, 0x01 ); 无缓冲区模式
io_out8(PIC0_IMR, 0xfb );//11111011 PIC1以外全部禁止
io_out8(PIC1_IMR, 0xff );//11111111 禁止所有中断
return;
}
这部分代码是PIC的初始化程序。对PIC中的众多寄存器进行初始化,使用端口号码对其区分。PIC和CPU的通信是通过函数in_out8实现,CPU将要设置的值使用OUT指令传给相应的端口。

7.中断处理程序的制作(06_day/harib03e):

 鼠标 中断是IRQ12,键盘中断是IRQ1,INT 0x21键盘中断,INT0x2c 鼠标中断

 1) 键盘中断(int.c)

void inthandler21(int *esp)
{

//esp暂时未用
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;//定义一个结构体变量
boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15);//绘制背景
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 21 (IRQ-1) : PS/2 keyboard");//打印字符
for (;;) {
io_hlt();
}
}

注意有些机型上要处理IRQ7

io_sti(),这个函数表示中断许可标志变为1,允许CPU接受来自外部设备的中断。

2)naskfunc.nas

_asm_inthandler21:
PUSH ES
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS
MOV DS,AX
MOV ES,AX
CALL _inthandler21    ;调用c语言的中断处理函数
POP EAX
POPAD
POP DS
POP ES
IRETD      ;中断返回

这部分代码的作用是在执行中断处理程序之前保存寄存器的值,在执行后恢复寄存器的值,以便可以正常返回到CPU原来被打断处理的任务。

3)IDT 初始化(是naskfunc.nas里的中断函数)

set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
// 2* 8 指段号是2,低三位有别的用途,所以乘以8

8.make run

9.问题:

   #define ADR_BOTPAK 0x00280000

   0x280000以及远远超过 软盘容量数字

    

   

   

posted @   煮酒熬码  阅读(99)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示