实验目标:自定义一个保护模式下的软中断(int 0x80),使得在使用 int 0x80 中断后在屏幕上打印字符串 “int 0x80”
实现思路
直接开始吧,让我们先找个以前实现过的基础代码:loader.asm
回顾代码的框架
boot.asm 跳转到 loader.asm,并打印 “Welcome to KOS.”
|
CODE16_START ; 实模式,打印 “Loader...”
|
CODE32_START ; 进入保护模式,打印 “Enter protection”
老规矩,先把最终实现代码给你们,再来一步一步讲解过程.最终代码:loader.asm
先准备好 2 个中断服务程序,注意,中断服务程序必须用 iret 返回
DefaultHandler 函数用于默认中断处理函数,仅提供函数地址作用,可以不用实现函数内部功能;Int0x80Handler 函数就是我们本次实验的目标函数,内部实现打印 “int 0x80” 字符串
DefaultHandler:
iret
DefaultHandler_Offset equ DefaultHandler-CODE32_START
Int0x80Handler:
mov ebp, msg_int0x80_offset
mov bl, 0x0F ; 打印属性,黑底白字
; 坐标 (0, 3)
mov dl, 0x00
mov dh, 0x03
call print_str_32
iret
Int0x80Handler_Offset equ Int0x80Handler-CODE32_START
接下来构建一个 IDT 中断描述符表,可以借用 【调用门】代码中门描述符的定义。共 256 个中断描述符
; 中断描述符表定义
; 选择子, 偏移地址, 参数个数,属性
IDT_BASE : Gate CODE32_SELECTOR, DefaultHandler_Offset, 0, DA_INTR_GATE
Gate CODE32_SELECTOR, DefaultHandler_Offset, 0, DA_INTR_GATE
Gate CODE32_SELECTOR, DefaultHandler_Offset, 0, DA_INTR_GATE
...(重复 256 次)
IDT_LEN equ $ - IDT_BASE
我们看到中断描述符表中有大量重复的代码,我们可以使用 rep 指令处理重复操作,rep 使用格式如下:
; 重复 n 次 xxx
%rep n
xxx
%endrep
改动一下
IDT_BASE:
%rep 256
Gate CODE32_SELECTOR, DefaultHandler_Offset, 0, DA_INTR_GATE
%endrep
IDT_LEN equ $ - IDT_BASE
int 0x80 中断在整个中断描述符表中排第 129 位,于是再次改动一下:
; IDT 中断描述符表定义
; 选择子, 偏移地址, 参数个数, 属性
IDT_BASE:
%rep 128
Gate CODE32_SELECTOR, DefaultHandler_Offset, 0, DA_INTR_GATE
%endrep
Gate CODE32_SELECTOR, Int0x80Handler_Offset, 0, DA_INTR_GATE
%rep 127
Gate CODE32_SELECTOR, DefaultHandler_Offset, 0, DA_INTR_GATE
%endrep
IDT_LEN equ $ - IDT_BASE
中段描述符表 IDT 我们已经构建好了,参考全局描述符表加载(lgdt),我们需要告诉 CPU 哪片内存是 IDT,即 lidt 指令,其格式是 lidt [6 个字节的内存数据首地址]
我们只需要先定义这 6 个字节的数据
IDT_PTR :
dw IDT_LEN - 1
dd IDT_BASE
然后再使用 lidt 就可以了,注意:要放在实模式下调用
lidt [IDT_PTR]
准备工作全部完成啦,下面就是在 32 位保护模式下调用 int 0x80 触发中断
运行一下,看看最终效果
实验目标:处理外部时钟中断(接主 8259A IRQ0 引脚),接收到时钟中断后,在屏幕上循环打印 '0'-'9'
先提供实验完整代码:loader.asm
实现思路跟实验一一样,都是套路
由于本实验依赖 8259A,所以先把 8259A驱动编写 中实现的驱动代码复制过来并初始化 8259A
call pic_init
准备中断服务函数,注意程序最后需要调用 write_m_EOI 手动结束中断,如果不手动结束中断,那么该中断只会触发一次
TimerHandler:
cmp al, '9' ; 判断 al 是否为 '9'
je .to_0 ; 如果 al=9,则跳转到 .to_0 处执行
inc al
jmp .display ; 跳转到 .display 处执行
.to_0:
mov al, '0' ; al = '0'
.display: ; 使用现存方式打印,al 为要打印的字符,ah 为打印属性
mov ah, 0x0F ; 打印属性,黑底白字
mov [gs:(80*4+0)*2], ax ; (80 * 4 + 0)*2 ; 坐标 (0, 4)
call write_m_EOI ; 手动结束中断
iret
TimerHandler_Offset equ TimerHandler-CODE32_START
回想一下8259A驱动编写 中,pic_init 将主 8259A IRQ0 引脚(外部时钟)的中断向量号设置为了 0x20,于是我们在中段描述符表 IDT 中添加对应的中断描述符(第 33 个)
...
Gate CODE32_SELECTOR, TimerHandler_Offset, 0, DA_INTR_GATE
...
编译运行一下,理论是应看到实验现象,但是并没有
思考一下,8259A 的 IMR 寄存器起到放行作用,是不是 IMR 寄存器默认不放行呢?
于是,我们把 IMR 寄存器的 bit0 (对应IRQ0,即外部时钟引脚)清零
EnableTimer:
push ax
call read_m_IMR
and al, 0xFE
call write_m_IMR
pop ax
ret
再次编译运行一下,发现还是不行,又是什么原因导致没有出现我们想要的现象呢?
我们又想到, 在讲 8259A 的时候我们就说过,不过 8259A 能屏蔽中断,CPU 也可以屏蔽中断,是不是 CPU 把外部中断屏蔽了呢?
实验一下不就知道了吗,sti 指令就可以开启 CPU 中断(cli:关中断)
果然,加上 sti 指令后,屏幕上果然循环打印出 '0'-'9'。这说明 CPU 默认是屏蔽外部中断的
再改动一下,不执行 EnableTimer 函数,即不手动放行 8259A IRQ 中断
; call EnableTimer
sti
发现依然能循环打印出 '0'-'9',这说明 8259A 的 IMR 寄存器是默认放行的
最后贴上实验截图,虽然无法看到 '0'-'9' 跳动过程,但至少能证明我们的代码是实实在在运行成功的
ndisasm -o 0x900 loader.bin > loader.txt
<bochs:1> b 0x1214
<bochs:2> b 0x125B
<bochs:3> b 0x1273
<bochs:4> c
...
(0) Breakpoint 1, 0x00001214 in ?? ()
Next at t=16768062
(0) [0x00001214] 0008:00000032 (unk. ctxt): sti ; fb
<bochs:5> reg
eax: 0x00000030 48
ecx: 0x00000009 9
edx: 0x00000300 768
ebx: 0x0000000f 15
esp: 0x00000fff 4095
ebp: 0x00000011 17
esi: 0x0000130f 4879
edi: 0x00000923 2339
eip: 0x00000032
eflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf
<bochs:6> s
Next at t=16768063
(0) [0x00001215] 0008:00000033 (unk. ctxt): jmp .-2 (0x00001215) ; ebfe
<bochs:7> reg
eax: 0x00000030 48
ecx: 0x00000009 9
edx: 0x00000300 768
ebx: 0x0000000f 15
esp: 0x00000fff 4095
ebp: 0x00000011 17
esi: 0x0000130f 4879
edi: 0x00000923 2339
eip: 0x00000033
eflags 0x00000246: id vip vif ac vm rf nt IOPL=0 of df IF tf sf ZF af PF cf
<bochs:8> c
(0) Breakpoint 3, 0x00001273 in ?? ()
Next at t=16921763
(0) [0x00001273] 0008:00000091 (unk. ctxt): iretd ; cf
<bochs:9> reg
eax: 0x00000f31 3889
ecx: 0x00000009 9
edx: 0x00000300 768
ebx: 0x0000000f 15
esp: 0x00000ff3 4083
ebp: 0x00000011 17
esi: 0x0000130f 4879
edi: 0x00000923 2339
eip: 0x00000091
eflags 0x00000003: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af pf CF
<bochs:10> s
Next at t=16921764
(0) [0x00001215] 0008:00000033 (unk. ctxt): jmp .-2 (0x00001215) ; ebfe
<bochs:11> reg
eax: 0x00000f31 3889
ecx: 0x00000009 9
edx: 0x00000300 768
ebx: 0x0000000f 15
esp: 0x00000fff 4095
ebp: 0x00000011 17
esi: 0x0000130f 4879
edi: 0x00000923 2339
eip: 0x00000033
eflags 0x00000246: id vip vif ac vm rf nt IOPL=0 of df IF tf sf ZF af PF cf
<bochs:12>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。