您的位置:首页 > 其它

大家一起写操作系统(3)-时钟中断

2013-01-26 12:36 387 查看
  大家都知道操作系统利用中断来与外设进行交互。80xx86兼容机使用两片级联的8259A可编程中断控制芯片组成一个中断控制器,用于实现与I/O设备的交互。可编程意味着我们可以为不同的外设(时钟,键盘,鼠标等)分配不同的中断号,从而执行不同的中断处理过程。

  BIOS初始化这个中断控制器时将中断号8分配给了时钟控制器,因而下面我们通过将中断向量表中的8号描述符设为我们的中断程序地址,进而实现时钟中断程序。我们在中断程序中打印字符'E',每打2000次后再从头开始打,为了能够看出重复打印的效果,满2000次后更换颜色。

LATCH equ 11930

VIDEO_DS equ 0x18

[SECTION text]

[BITS 32]

startup_32:

mov eax,0x10

mov ds,ax

lss esp,[init_stack] ;mem low->reg,mem high->ss

call setup_idt ;初始化IDT中断向量表

call setup_gdt ;初始化GDT

mov eax,0x10 ;初始化完GDT后重新加载ds,es,fs,gs,ss,sp

mov ds,ax

mov es,ax

mov fs,ax

mov gs,ax

lss esp,[init_stack]

;设置8253定时芯片,把计数器通道0设置成每隔10ms向中断控制器发送一个中断请求

mov al,0x36

mov edx,0x43

out dx,al

mov eax,LATCH

mov edx,0x40

out dx,al

mov al,ah

out dx,al

sti ;开中断

loop:

jmp loop

setup_gdt:

lgdt [lgdt_opcode]

ret

;begin setup_idt fun ;初始化idt,256个描述符全初始化为打印字符函数

setup_idt:

lea edx,[ignore_int] ;中断入口偏移放入edx

mov eax,0x00080000 ;eax高位为内核代码段选择子

mov ax,dx ;eax低位为中断入口偏移低位

mov dx,0x8E00 ;edx低位为中断门定义.DPL=0

lea edi,[idt] ;得到idt表位置,准备初始化

mov ecx,256 ;初始化256 IDT描述符

rp_idt:

mov [edi],eax

mov [edi+4],edx

add edi,8

dec ecx

jne rp_idt

lidt [lidt_opcode]

ret

;end setup_idt fun

ignore_int: ;默认中断处理函数

push ds

push eax

mov eax,0x10

mov ds,ax

mov eax,69

call write_char

mov al,0x20

out 0x20,al

pop eax

pop ds

iret

;BEGIN lidt

;Begin write_char

write_char: ;打印字符函数

push gs

push ebx

mov ebx,VIDEO_DS ;取显存数据段

mov gs,bx

mov bx,[color] ;取显示颜色

cmp bx,0

jg change_color ;当前显示1

mov ah, 0Ch ;黑底红字

jmp dis

change_color:

mov ah, 0Fh ;

dis:

mov bx,[DWORD scr_loc] ;取显存位置

mov [byte gs:ebx],ax ;写入显存

add ebx,2 ;下一个位置

mov [DWORD scr_loc],ebx ;放入内存保存

cmp ebx,2000 ;是否大于2000

jb exit ;小于2000直接退出

mov bx,[color]

cmp bx,0

jz change_color1 ;原来为0,改为1

mov bx,0 ;原来为1,改为0

jmp exit1

change_color1:

mov bx,1

exit1:

mov [color],bx

xor ebx,ebx ;位置置0

mov [DWORD scr_loc],ebx

exit:

pop ebx

pop gs

ret

;End write_char

color: db 0 ;显示颜色

current: dd 0 ;当前执行的任务号

scr_loc: dw 0 ;屏幕位置

align 2

lidt_opcode: ;LIDT寄存器加载的内容

dw 256*8-1 ;长度

dd idt ;线性基址

;END lidt

lgdt_opcode: ;GDT寄存器加载的内容

dw (end_gdt - gdt)-1

dd gdt

align 3 ;GDT内容

gdt:

dd 0x00000000 ;NULL

dd 0x00000000

dd 0x000007ff

dd 0x00c09a00 ;内核代码段0x08

dd 0x000007ff

dd 0x00c09200 ;内核数据段0x10

dd 0x80000002

dd 0x00c0920b ;显存数据段描述符0x18

dw 0x68

dw tss0

dw 0x8900

dw 0x0000 ;内核TSS 0x20

end_gdt:

tss0:

dd 0

dd init_stack,0x10 ;内核esp0,ss0

dd 0,0,0,0,0 ;esp1,ss1,esp2,ss2,cr3

dd 0,0,0,0,0 ;eip,eflags,eax,ecx,edx

dd 0,0,0,0,0 ;ebx,esp,ebp,esi,edi

dd 0,0,0,0,0,0 ;es,cs,ss,ds,fs,gs

dd 0,0x80000000 ;ldt,trace bitmap

idt:

times 512 dd 0 ;初始化中断描述表

kernel_stack:

times 128 dw 0 ;512B内核堆栈

init_stack:

dd init_stack ;堆栈段偏移位置

dw 0x10 ;内核数据段选择符

同样,将编译生成的bin文件复制到前面所说的软盘映像IMG的第2扇区开始处,引导程序就会将其加载到内存0处并执行,然后可以看到屏幕上不停地打印字符'E'.如果对程序中有所疑问,可以查看大家一起写操作系统预备知识.我会将中断的相关知识写到预备知识里。下一章将会介绍如何创建2个任务,并在任务间来回调度。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: