自制操作系统日志——第六天

30天自制操作系统——第六天

今天我们继续加把劲,争取把GDT和IDT这两个搞定。



一、整理文件

如果把所有代码都写在一个c文件里,可能会显得比较臃肿,且不利于我们后续对代码的修改,因此我们进行以下分割:
在这里插入图片描述
因此,我们还需要对makefile进行修改,利用makefile的特殊规则进行处理,如下:

OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \
		int.obj

TOOLPATH = ../z_tools/
INCPATH  = ../z_tools/haribote/

MAKE     = $(TOOLPATH)make.exe -r
NASK     = $(TOOLPATH)nask.exe
CC1      = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet
GAS2NASK = $(TOOLPATH)gas2nask.exe -a
OBJ2BIM  = $(TOOLPATH)obj2bim.exe
MAKEFONT = $(TOOLPATH)makefont.exe
BIN2OBJ  = $(TOOLPATH)bin2obj.exe
BIM2HRB  = $(TOOLPATH)bim2hrb.exe
RULEFILE = $(TOOLPATH)haribote/haribote.rul
EDIMG    = $(TOOLPATH)edimg.exe
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = copy
DEL      = del

#默认

default :
	$(MAKE) img

#操作

ipl10.bin : ipl10.nas Makefile
	$(NASK) ipl10.nas ipl10.bin ipl10.lst

asmhead.bin : asmhead.nas Makefile
	$(NASK) asmhead.nas asmhead.bin asmhead.lst

hankaku.bin : hankaku.txt Makefile
	$(MAKEFONT) hankaku.txt hankaku.bin

hankaku.obj : hankaku.bin Makefile
	$(BIN2OBJ) hankaku.bin hankaku.obj _hankaku

bootpack.bim : $(OBJS_BOOTPACK) Makefile
	$(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \
		$(OBJS_BOOTPACK)
# 3MB+64KB=3136KB

bootpack.hrb : bootpack.bim Makefile
	$(BIM2HRB) bootpack.bim bootpack.hrb 0

haribote.sys : asmhead.bin bootpack.hrb Makefile
	copy /B asmhead.bin+bootpack.hrb haribote.sys

haribote.img : ipl10.bin haribote.sys Makefile
	$(EDIMG)   imgin:../z_tools/fdimg0at.tek \
		wbinimg src:ipl10.bin len:512 from:0 to:0 \
		copy from:haribote.sys to:@: \
		imgout:haribote.img

# 其他指令
#%为Makefile规则通配符,一般用于规则描述,表示所有的目标文件及其依赖文件
#$* 表示取得 %及其之前的所有字符!!!

%.gas : %.c Makefile
	$(CC1) -o $*.gas $*.c

%.nas : %.gas Makefile
	$(GAS2NASK) $*.gas $*.nas

%.obj : %.nas Makefile
	$(NASK) $*.nas $*.obj $*.lst


# 运行程序

img :
	$(MAKE) haribote.img

run :
	$(MAKE) img
	$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
	$(MAKE) -C ../z_tools/qemu

install :
	$(MAKE) img
	$(IMGTOL) w a: haribote.img

clean :
	-$(DEL) *.bin
	-$(DEL) *.lst
	-$(DEL) *.gas
	-$(DEL) *.obj
	-$(DEL) bootpack.nas
	-$(DEL) bootpack.map
	-$(DEL) bootpack.bim
	-$(DEL) bootpack.hrb
	-$(DEL) haribote.sys

src :
	$(MAKE) clean
	-$(DEL) haribote.img

然后,我们还需将之前的声明还有结构体等等,都放在头文件当中:
在这里插入图片描述

在这里插入图片描述

二、制作中断程序

PIC初始化

**PIC:**可编程中断控制器,由于一般来说cpu只能处理一个中断。因此,为方便能够同时处理多个处理中断程序,设计了PIC将8个中断信号集合成一个中断信号的装置。
PIC会同时监管这8个处理器管脚,一旦有要处理的,就会将会唯一的输出管脚设置成on进行中断。

除此之外,还设计了主从PIC模式,将中断信号拓展至16个,其中利用IRQ2连接从PIC。从PIC的中断需要经过主PIC同意后,cpu才会执行。
在这里插入图片描述
以下,将给出代码,代码中有详细的注释,可参考一下(仅代表个人理解),int.c:

#include "bootpack.h"

/*PIC0 ==> 主PIC  PIC1 ==> 从PIC
  IMR  ==> 中断屏蔽寄存器,8位分别对应着8路IRQ信号,置为1则该路的中断会被屏蔽;
  ICW  ==> ICW1与ICW4 是与PIC主板配线,电气特性有关;
           ICW3与主从有关;
           ICW2可用于设定中断号,即将PIC0-15与int 20-2f对应起来,进行统一管理。  
*/
void init_pic(void)
{
	io_out8(PIC0_IMR, 0xff); //禁止所有中断
	io_out8(PIC1_IMR, 0xff); //禁止所有中断

	io_out8(PIC0_ICW1, 0x11); //边沿触发模式
	io_out8(PIC0_ICW2, 0x20); //IRQ0-7由int20-27接收;
	io_out8(PIC0_ICW3, 1 << 2); //PIC1由IRQ2连接;由于硬件已经规定了主的2号连接从,因此这里要写入00000100
	io_out8(PIC0_ICW4, 0x01); //无缓冲区模式

	io_out8(PIC1_ICW1, 0x11); //边沿触发模式
	io_out8(PIC1_ICW2, 0x28); //IRQ8-15由int28-2f接收
	io_out8(PIC1_ICW3,  2  ); //PIC1由IRQ2连接
	io_out8(PIC1_ICW4, 0x01); //无缓冲区模式

	io_out8(PIC0_IMR, 0xfb); //11111011 PIC1外全禁止
	io_out8(PIC1_IMR, 0xff); //11111111 禁止所有中断

	return;
}

//鼠标中断利用IRQ12(int 2c) 键盘中断利用IRQ1(int 21)
void inthandler21(int *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();
	}
}

void inthandler2c(int *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 2C (IRQ-12) : PS/2 mouse");
	for (;;) {
		io_hlt();
	}
}

void inthandler27(int *esp)
/* PIC0中断的不完整策略 */
/* 这个中断在Athlon64X2上通过芯片组提供的便利,只需执行一次 */
/* 这个中断只是接收,不执行任何操作 */
/* 为什么不处理?
	→  因为这个中断可能是电气噪声引发的、只是处理一些重要的情况。*/
{
	io_out8(PIC0_OCW2, 0x67); /* 通知PIC的IRQ-07(参考7-1) */
	return;
}

除此之外,我们还要修改naskdunc,nas ,因为我们完成中断后还要返回的(要用IRET)因此,需要利用汇编进行修改:

	 GLOBAL	        _asm_inthandler21, _asm_inthandler27, _asm_inthandler2c
	 EXTERN	        _inthandler21, _inthandler27, _inthandler2c

_asm_inthandler21:
	PUSH	ES
	PUSH	DS
	PUSHAD
	MOV	EAX,ESP
	PUSH	EAX
	MOV	AX,SS;以下三步是c规定的,必须相同 ss es ds
	MOV	DS,AX
	MOV	ES,AX
	CALL	_inthandler21
	POP	EAX
	POPAD
	POP	DS
	POP	ES
	IRETD

_asm_inthandler27:
	PUSH	ES
	PUSH	DS
	PUSHAD
	MOV	EAX,ESP
	PUSH	EAX
	MOV	AX,SS
	MOV	DS,AX
	MOV	ES,AX
	CALL	_inthandler27
	POP	EAX
	POPAD
	POP	DS
	POP	ES
	IRETD

_asm_inthandler2c:
	PUSH	ES
	PUSH	DS
	PUSHAD
	MOV	EAX,ESP
	PUSH	EAX
	MOV	AX,SS
	MOV	DS,AX
	MOV	ES,AX
	CALL	_inthandler2c
	POP	EAX
	POPAD
	POP	DS
	POP	ES
	IRETD

然后,我们还需要在dsctbl.c中的init_gdtidt中加入如下语句:

/* idt + 0x21 ==> asm_inthandler21注册在idt表的0x21号;
   (int) asm_inthandler21 ==> cpu会自动调用21号中断;
   2 << 3 ==> asm_inthandler21号程序具体在哪一个段地址空间中,上面已经设定了bootpac.hrb在2号段地址中;最低3位不可用
   AR_INTGATE32 ==> 设定位0x008e 代表中断处理的有效设定。
*/
    set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 << 3, AR_INTGATE32);
    set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 << 3, AR_INTGATE32);
    set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 << 3, AR_INTGATE32);

最后一小部分,我们需要在主程序中进行一些设置:
首先。需要使用io_sti()来将IF设置为1,方便我们能够使用外部中断,然后进行初始化,最后在出程序的末尾,开发PIC的IMR权限,以便调用。。。

void HariMain(void)
{
	struct BOOTINFO *binfo = ( struct BOOTINFO *) ADR_BOOTINFO;
	char s[40], mcursor[256];
	int mx,my;

	init_gdtidt();//初始化gdt、idt表
	init_pic();  //初始化pic控制器
	io_sti();

	init_palette();
    init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);
    /* 显示鼠标 */
	mx = (binfo->scrnx - 16) / 2; /* 计算画面的中心坐标*/
	my = (binfo->scrny - 28 - 16) / 2;
	init_mouse_cursor8(mcursor, COL8_008484);
	putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);
	sprintf(s, "(%d, %d)", mx, my);
	putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);
  
    io_out8(PIC0_IMR, 0xf9); /* 开放PIC1和键盘中断(11111001),键盘是IRQ1 */
	io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) ,鼠标是IRQ12*/

	for(;;)   
	{
	     io_hlt();
	    //自建的hlt函数,源目标程序在naskfunc.nas中,c语言本身没有hlt这个命
	}
}

make run:
在这里插入图片描述


总结

总算大致搞完这些中断和段的初始化。而且现在我们还能够使用键盘中断了,可喜可贺。但是鼠标还是不能移动。。。。。那就明天加油吧!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值