上篇原本打算先实现个在任务状态运行的例子,可是代码有问题(编译错代码了),任务那部分确实还不是很熟悉; html
本篇的目的:1.实现实例化中断的描述符 架构
2.实现时钟中断 oop
对于中断分类暂且还没搞太清楚,这里先无论,直接看怎么安装的。 测试
中断在实模式下是直接用的,例如:int 10h spa
可是保护模式下是的实现,跟装载GDT很相似。 .net
只是描述符要用到GDT的选择子+偏移量构成,也就是经过中断调用的实际是一个处理的方法。 code
lidt的描述符结构 htm
此次代码是好的 blog
;目的是中断门 [org 0x7c00] [bits 16] ;定义全局描述符的常量又不占用内存空间 gdt_basic equ 0x00007e00 ;#1 数据段 4G data_basic equ 0x0000000 ;#2 当前的程序代码段 512 code_basic equ 0x00007c00 ;#3 全局堆栈基地址 4kb stack_basic equ 0x00007c00 ;#4 显示描述基地址 show_basic equ 0x000B8000 ;$1 中断向量表安装的位置 interrupt_basic equ 0x00008000 ;这样高四位0好算 256*8=2^11+ mov ax,cs mov ds,ax call show_style ;设置显示模式 主要是清屏 ;计算GDT所在的逻辑段地址 mov eax,gdt_basic ;获得描述符的基地址 xor edx,edx mov ebx,16 div ebx mov ds,eax ;令DS指向该段以进行操做 mov ebx,edx ;段内起始偏移地址 ;建立0#描述符,它是空描述符,这是处理器的要求 ;#1建立1#描述符,这是一个数据段,对应0~4GB的线性地址空间 mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 ;#2建立保护模式下初始代码段描述符 mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,界限0x1FF mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 ;#3创建保护模式下的堆栈段描述符 ;基地址为0x00007C00,界限0xFFFFE mov dword [ebx+0x18],0x7c00fffe ;粒度为4KB mov dword [ebx+0x1c],0x00cf9600 ;#4创建保护模式下的显示缓冲区描述符 mov dword [ebx+0x20],0x80007fff ;基地址为0x000B8000,界限0x07FFF mov dword [ebx+0x24],0x0040920b ;粒度为字节 ;=============================================================== ;初始化描述符表寄存器GDTR ;由于上面吧数据段地址改了因此这利用代码段 mov word [cs:pgdt], 39 ;描述符表的界限(总字节数减一) n*8-1; lgdt [cs:pgdt] in al,0x92 ;南桥芯片内的端口 or al,0000_0010B out 0x92,al ;打开A20 cli ;保护模式下中断机制还没有创建,应 ;禁止中断 mov eax,cr0 or eax,1 mov cr0,eax ;设置PE位 ;如下进入保护模式... ... jmp dword 0x0010:protect_loader-0x7C00;16位的描述符选择子:32位偏移 ;hlt ;程序终止 ;===================showStyle============================= show_style: ;设置显示方式 mov ah,0x00 mov al,0x03 int 10h ret ;========================================================= [bits 32] interrupt_show: pushad xor eax,eax mov eax,0x0020 ;#4显示段的选择子 mov es,eax mov eax,0x0008 ;#1数据段选择子 mov ds,eax xor ebx,ebx mov word bx,[ds:show_position] mov byte [es:ebx],'^' add bx,2 cmp bx,80*2*25 jle .init1 sub bx,80*2*25 .init1: mov word [ds:show_position],bx popad iretd protect_loader: mov eax,0x0018 mov ss,eax xor esp,esp cli ;$1硬件中断 依据代码段#2 mov eax,0x0008 mov ds,eax ;4G mov eax,0x0010 ;代码段描述子 shl eax,16 mov ebx,interrupt_show ;中断实现的偏移量 sub ebx,0x7c00 ;由于知道高16位确定为0 and ebx,0x0000FFFF or eax,ebx mov ebx,interrupt_basic ;中断描述符的地方 mov ecx,256 loop_idt: mov dword [ebx+0x00],eax mov dword [ebx+0x04],0x00008E00 ; add ebx,8 loop loop_idt ;从新初始化键盘中断0x09 lidt [ds:interrupt_des] int 080h ;测试下效果 sti int 009h loop1: jmp loop1; ;--------------数据段-------------------------------------------- show_position dw 0 ;80*25=2000 2^16= pgdt dw 0 dd gdt_basic ;GDT的物理地? interrupt_des dw 256*8-1 ;idt dd interrupt_basic times 510-($-$$) db 0 db 0x55 ;引导识别标示 db 0xaa
这里主要是对8259a控制器的编写控制 索引
参考: http://blog.csdn.net/jltxgcy/article/details/8661959
http://wenku.baidu.com/view/dcbef6140b4e767f5acfcef3.html
对于主从控制器的编写主要是从端口
0x20/0xa0 ICW1 主要设置从片是否链接
0x21/0xa1 ICW2 主要负责设置IRO,IR8对应的中断
0x21/0xa1 ICW3 若是有从片 主片1对应的从片的连接,从片同样
0x21/0xa1 ICW4 处理器架构的标志,还有就是个结束的标志
上面的必须按照顺序来设定,下面的好像没要求
0x21/0xa1 OCW1 中断屏蔽 置1屏蔽 0开启
0x20/0xa0 OCW2 优先权控制以及结束
实现响应中断是根据:8259a的从片 IR80中断号的重定向与开启(这里必需要注意:主片与从片的连接也必须开启)
经过RTC来实现响应中断的
下面是代码: 比上面多添加了8259a的初始化,和RTC的操做
;目的是中断门 [org 0x7c00] [bits 16] ;定义全局描述符的常量又不占用内存空间 gdt_basic equ 0x00007e00 ;#1 数据段 4G data_basic equ 0x0000000 ;#2 当前的程序代码段 512 code_basic equ 0x00007c00 ;#3 全局堆栈基地址 4kb stack_basic equ 0x00007c00 ;#4 显示描述基地址 show_basic equ 0x000B8000 ;$1 中断向量表安装的位置 interrupt_basic equ 0x00008000 ;这样高四位0好算 256*8=2^11+00009000 mov ax,cs mov ds,ax call show_style ;设置显示模式 主要是清屏 ;计算GDT所在的逻辑段地址 mov eax,gdt_basic ;获得描述符的基地址 xor edx,edx mov ebx,16 div ebx mov ds,eax ;令DS指向该段以进行操做 mov ebx,edx ;段内起始偏移地址 ;建立0#描述符,它是空描述符,这是处理器的要求 ;#1建立1#描述符,这是一个数据段,对应0~4GB的线性地址空间 mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 ;#2建立保护模式下初始代码段描述符 mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,界限0x1FF mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 ;#3创建保护模式下的堆栈段描述符 ;基地址为0x00007C00,界限0xFFFFE mov dword [ebx+0x18],0x7c00fffe ;粒度为4KB mov dword [ebx+0x1c],0x00cf9600 ;#4创建保护模式下的显示缓冲区描述符 mov dword [ebx+0x20],0x80007fff ;基地址为0x000B8000,界限0x07FFF mov dword [ebx+0x24],0x0040920b ;粒度为字节 ;=============================================================== ;初始化描述符表寄存器GDTR ;由于上面吧数据段地址改了因此这利用代码段 mov word [cs:pgdt], 39 ;描述符表的界限(总字节数减一) n*8-1; lgdt [cs:pgdt] in al,0x92 ;南桥芯片内的端口 or al,0000_0010B out 0x92,al ;打开A20 cli ;保护模式下中断机制还没有创建,应 ;禁止中断 mov eax,cr0 or eax,1 mov cr0,eax ;设置PE位 ;如下进入保护模式... ... jmp dword 0x0010:protect_loader-0x7C00;16位的描述符选择子:32位偏移 ;hlt ;程序终止 ;===================showStyle============================= show_style: ;设置显示方式 mov ah,0x00 mov al,0x03 int 10h ret ;========================================================= [bits 32] protect_loader: mov eax,0x0018 mov ss,eax xor esp,esp ;cli ;$1硬件中断 依据代码段#2 mov eax,0x0008 mov ds,eax ;4G mov eax,0x0010 ;代码段描述子 shl eax,16 mov ebx,interrupt_show ;中断实现的偏移量 sub ebx,0x7c00 ;由于知道高16位确定为0 and ebx,0x0000FFFF or eax,ebx mov ebx,interrupt_basic ;中断描述符的地方 xor esi,esi mov ecx,256 .loop_idt: mov dword [ebx+esi+0x00],eax mov dword [ebx+esi+0x04],0x00008E00 ; add esi,8 loop .loop_idt ;从新初始化时钟中断0x70 mov eax,0x0010 ;代码段描述子 shl eax,16 mov ebx,time_interrupt ;中断实现的偏移量 sub ebx,0x7c00 and ebx,0x0000FFFF or eax,ebx mov ebx,interrupt_basic mov dword[ebx+0x28*8],eax mov dword[ebx+0x28*8+4],0x00008E00 lidt [ds:interrupt_des] ;call Init8259A xor eax,eax ;设置8259A中断控制器 mov al, 011h out 020h, al ; 主8259, ICW1. call io_delay out 0A0h, al ; 从8259, ICW1. call io_delay mov al, 020h ; IRQ0 对应中断向量 0x20 out 021h, al ; 主8259, ICW2. call io_delay mov al, 028h ; IRQ8 对应中断向量 0x28 out 0A1h, al ; 从8259, ICW2. call io_delay mov al, 004h ; IR2 对应从8259 out 021h, al ; 主8259, ICW3. call io_delay mov al, 002h ; 对应主8259的 IR2 out 0A1h, al ; 从8259, ICW3. call io_delay mov al, 001h out 021h, al ; 主8259, ICW4. call io_delay out 0A1h, al ; 从8259, ICW4. call io_delay mov al, 11111111b ; 仅仅开启定时器中断 ;mov al, 11111111b ; 屏蔽主8259全部中断 out 021h, al ; 主8259, OCW1. call io_delay mov al, 11111110b ; 屏蔽从8259全部中断 out 0A1h, al ; 从8259, OCW1. call io_delay ;设置和时钟中断相关的硬件 mov al,0x0b ;RTC寄存器B 0000_1011 or al,0x80 ;阻断NMI 1000_0000 out 0x70,al mov al,0x12 ;设置寄存器B,禁止周期性中断,开放更 out 0x71,al ;新结束后中断,BCD码,24小时制 mov al,0x0c out 0x70,al in al,0x71 ;读RTC寄存器C,复位未决的中断状态 sti ;int 70h .loop: jmp .loop; ;---------------------------------------------------------------- interrupt_show: pushad xor eax,eax mov eax,0x0020 ;#4显示段的选择子 mov es,eax mov eax,0x0008 ;#1数据段选择子 mov ds,eax xor ebx,ebx mov word bx,[ds:show_position] mov byte [es:ebx],'^' add bx,2 call show_index mov word [ds:show_position],bx popad iretd ;------------------------------------------------------------------ show_index: cmp bx,80*2*25 jle .init1 sub bx,80*2*25 .init1: ret ; IR0中断-----------0x70----------------------------------------------------------- time_interrupt: pushad int 10h mov al,0x20 ;中断结束命令EOI out 0xa0,al ;向8259A从片发送 out 0x20,al ;向8259A主片发送 mov al,0x0c ;寄存器C的索引。且开放NMI out 0x70,al in al,0x71 ;读一下RTC的寄存器C,不然只发生一次中断 ;暂且随便调用一个中断 popad iretd ; Init8259A --------------------------------------------------------------------------------------------- Init8259A: pushad popad ret ; --------------------------------------------------------- io_delay: nop nop nop nop ret ;--------------数据段-------------------------------------------- show_position dw 0 ;80*25=2000 2^16= pgdt dw 0 dd gdt_basic ;GDT的物理地? interrupt_des dw 256*8-1 ;idt dd interrupt_basic times 510-($-$$) db 0 db 0x55 ;引导识别标示 db 0xaa
效果图可能不是太明显确实是响应定时中断产生的输出: