说明:icw2设置8259的irq0(timer)为0x20,则0x21(irq1)为keyboard.
nasm编译.
[section .text]
[org 0x100]
[bits 16]
start:
xor eax,eax
mov ax,cs
shl eax,4
mov ebx,eax
mov [gdt1+2],ax
mov [gdt2+2],ax
shr eax,16
mov [gdt1+4],al
mov [gdt2+4],al
mov [gdt1+7],ah
mov [gdt2+7],ah
lea eax,[ebx+gdt]
mov [gdtr+2],eax
lea eax,[ebx+idt]
mov [idtr+2],eax
cli
lgdt [gdtr]
lidt [idtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp SYS_CODE_SEL:do_pm
[bits 32]
do_pm:
mov ax,VIDEO_SEL
mov gs,ax
mov ax,SYS_DATA_SEL
mov ds,ax
mov byte [gs:(8 * 80 + 10) * 2],'P'
mov byte [gs:(10 * 80 + 10) * 2],'A'
;等输出缓冲区
kbWrite:
WaitLoop: in al, 0x64 ; Read Status byte
and al, 0x01 ; Test OBF flag (Status<0>)
jnz WaitLoop ; Wait for OBF = 0
;out 60h, cl ; Write data to output buffer
mov byte [gs:(10 * 80 + 60) * 2],'O'
mov byte [gs:(10 * 80 + 61) * 2],'K'
;向键盘发送command byte,使其可以产生中断
; mov al,0x60
; out 0x64,al
; mov al,0xf6
; out 0x60,al
; mov al,0x60
; out 0x64,al
; mov al,0xf4
; out 0x60,al
mov al,0x60
out 0x64,al
mov al,0x41
out 0x60,al
mov byte [gs:(20 * 80 + 50 ) * 2],'A'
mov byte [gs:(20 * 80 + 60 ) * 2],'A'
mov byte [gs:(10 * 80 + 65) * 2],'o'
mov byte [gs:(10 * 80 + 66) * 2],'k'
call init8259A
int 0x80 ; display 'S'
sti ; 打开中断,以产生时钟中断
jmp $
init8259A: ; 先写0x20端口,然后是0xA0,再然后是三个0x21,0xA1
mov al,0x11 ; need icw4,级联,8字节中断向量,边缘触发,
out 0x20,al
call io_delay
out 0xA0,al ;
call io_delay
mov al,0x20 ; icw2,低3位全0:80x86, 3-7位中断向量 ,icw2设置主,从8259A的第一个中断对应的向量号,irq0对应0x20
out 0x21,al ; 高5位称为中断类型码,是中断向量的高5位,低3位由引脚决定
call io_delay
mov al,0x28 ; 0x28 = 0010 1000 , irq8(从片第一个) 对应0x28,
out 0xA1,al
call io_delay
mov al,0x04 ; 主片icw3, 第2位为1,表示第2(从0开始)个引脚挂从片
out 0x21,al
call io_delay
mov al,0x02 ; 从片icw3, 低3位表示连的是主片的哪个引脚
out 0xA1,al
call io_delay
mov al,0x01 ; icw4, 第0位表示80x86
out 0x21,al
call io_delay
out 0xA1,al
call io_delay
mov al,0xFD ; 打开时钟,键盘,其余屏掉
out 0x21,al
call io_delay
mov al,0xFF ; 从片屏掉
out 0xA1,al
call io_delay
ret
io_delay:
nop
nop
nop
nop
ret
unhand:
push ax
push gs
mov ax,VIDEO_SEL
mov gs,ax
mov byte [gs:(6 * 80 + 10) * 2],'H'
pop gs
pop ax
iret
clock_timer: ; display green A - Z
pusha
push gs
mov ax,VIDEO_SEL
mov gs,ax
mov byte [gs:((10 * 80 + 10) * 2 + 1)],0x1e ; color
inc byte [gs:(10 * 80 + 10) * 2]
mov al,[gs:(10 * 80 + 10) * 2]
cmp al,0x5C ; 'Z'+1
jne .1
mov byte [gs:(10 * 80 + 10) * 2],0x41
.1
; mov ecx,0x0fffffff ;only for delay
;.2 mov dx,0xffff
; mov ax,0x17
; mul ax
; mov dx,0xffff
; mov ax,0x17
; mul ax
; dec ecx
; cmp ecx,0
; ja .2
call io_delay
mov al,0x20
out 0x20,al
pop gs
popa
iretd ; iret too
keyboard_interrupt:
push eax
push ebx
push gs
mov ax,VIDEO_SEL
mov gs,ax
inc byte [gs:(20 * 80 + 50 ) * 2]
in al,0x60
mov bl,al ;; temp store
and al,0x80
jz break_code
mov al, bl
and al,0x7f
mov si, ax
;cmp al,0xd
;jnz break_code
mov al, byte [ds:(key_map+si)]
mov byte [gs:(20 * 80 + 30 ) * 2],al
break_code:
mov al,0x20
out 0x20,al
pop gs
pop ebx
pop eax
iretd
user_handler:
push ax
push gs
mov ax,VIDEO_SEL
mov gs,ax
mov byte [gs:(12 * 80 + 10) * 2],'S'
pop gs
pop ax
iret ; iretd too
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[section .data]
align 32
data_seg:
char: db 0x41,0xC
pos: dd 0
gdtr: dw gdt_end - gdt - 1
dd 0
idtr: dw idt_end - idt - 1
dd 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;; GDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 32
gdt:
dw 0
dw 0
dw 0
dw 0
SYS_CODE_SEL equ $ - gdt
gdt1: dw 0xFFFF
dw 0
db 0
db 0x9A
db 0xCF
db 0
SYS_DATA_SEL equ $ - gdt
gdt2: dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
VIDEO_SEL equ $ - gdt
dw 0xFFFF
dw 0x8000
db 0x0b
db 0x92
db 0xCF
db 0
gdt_end:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; IDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
idt:
%rep 32 ; 0 - 31
dw unhand
dw SYS_CODE_SEL
db 0
db 0x8E
dw 0
%endrep
.020h: dw clock_timer ; 32
dw SYS_CODE_SEL ; SYS_CODE_SEL指向GDT中的代码段描述符,描述符没有offset。 GDT表项的base+IDT的offset才是最终的目标的地址.
db 0
db 0x8E
dw 0
.021h: dw keyboard_interrupt ; 33
dw SYS_CODE_SEL
db 0
db 0x8E
dw 0
%rep 94 ; 34 - 127
dw unhand
dw SYS_CODE_SEL
db 0
db 0x8E
dw 0
%endrep
.080h: ; 128
dw user_handler
dw SYS_CODE_SEL
db 0
db 0x8E
dw 0
idt_end:
; 中断0-19系统定义 20-31 intel保留,32-255自定义,本程序将主片irq0设为0x20, 从片irq0(irq8)设为0x28
; 并且只打开主片的irq0(时钟中断)
; 中断门寻址: 8259A产生中断irqx,根据icw2找到irqx在idt中的索引号,
; 从IDT中按索引号取出此中断门描述符里的selector,再根据这个selector找到gdt中的代码段描述符,
; 从gdt里取出的代码段描述符里,再取代码段的基地址,加上中断门描述符里的偏移,就是最终的代码入口。
align 2
key_buffer: db 0,0,0,0
key_map:
db 0
db 0
db '1' ;0x2
db '2'
db '3'
db '4'
db '5'
db '6'
db '7'
db '8'
db '9'
db '0'
db '-'
db '=' ;0xd
阅读(1252) | 评论(0) | 转发(0) |