在上一篇的基础之上,实现加载中断idt,并调用中断:
boot.s用来加载kernel
%define LOAD_KERNEL_TO 0x1000 ;加载到0x1000:0000处执行
%define KERNEL_LEN 20
;内核占据多少个扇区 20*512
org 0x7c00
mov ax,cs
mov ds,ax
mov es,ax
;display"Loading kernel..."
mov ax,msg
mov bp,ax
mov cx,msgLen
mov ax,0x1301
mov bx,0x000c
mov dl,0
int 10h
load:
mov dh,0 ;磁头号
mov dl,0x00 ;驱动器号
mov ch,0 ;磁道号
mov cl,2 ;起始扇区号
mov ax,LOAD_KERNEL_TO
mov es,ax ;es:bx -> read data to
xor bx,bx ;
mov ah,02h ;param
mov al,KERNEL_LEN
;how many blocks to read
int 13h
system:
jmp LOAD_KERNEL_TO:0x00
msg:
db "Loading kernel...."
msgLen equ ($ - msg)
times 510-($-$$) db 0
dw 0xaa55
kernel.s如下:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov ax,msg
mov bp,ax
mov ax,0x1301
mov bx,0x000c
mov cx,msgLen
mov dx,0x0b00
int 10h
jmp start
msg:
db "kernel is started!"
msgLen equ $ - msg
;gdt
;as编译器的写法
; .quad 0x0000000000000000
;gdt_cs: .quad 0x00cf9a000000ffff ;cs
;gdt_ds: .quad 0x00c092000000ffff ;ds
;gdt_gs: .quad 0x00c0920b8000ffff ;gs
gdt: db 0,0,0,0,0,0,0,0
gdt_cs: db 0xff,0xff,0,0,0,0x9a,0xcf,0
gdt_ds: db 0xff,0xff,0,0,0,0x92,0xcf,0
gdt_gs: db 0xff,0xff,0,0x80,0x0b,0x92,0xc0,0
gdtLen equ $-gdt
gdtPtr: dw gdtLen - 1
dd 0
selector_cs equ gdt_cs - gdt
selector_ds equ gdt_ds - gdt
selector_gs equ gdt_gs - gdt
;idt
idt:
;256 selector
%rep 256
dw intHandler - label_cs ;offset
dw selector_cs ;selector
dw 0x8e00 ;property
dw 0 ;offset
%endrep
idtLen equ $ - idt
idtPtr dw idtLen - 1
dd 0
start:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
;initial cs descriptor
;offset
xor eax,eax
mov ax,cs
shl eax,4
add eax,label_cs
mov word [gdt_cs + 2],ax
shr eax,16
mov byte [gdt_cs + 4],al
mov byte [gdt_cs + 7],ah
;起初的时候并没有这段代码
;即,cs段限长为0xfffff
;在bochs中调试的时候,运行到后面访问数据段[0]号内存的时候
;出现“00013868788e[CPU0 ] write_virtual_checks(): no write access to seg Next at t=13868789”
;的错误,但是使用qemu运行好像没有什么问题,加上如下初始化段限长的代码之后,bochs调试没有这样的错误了
;《linux内核完全剖析》一文中,cs段和ds段直接设置相同的起始地址0,段限长为0x07ff
;length
mov eax,label_cs_end - label_cs + 0xff
mov word [gdt_cs],ax
shr eax,16
or al,11110000b
and byte [gdt_cs + 6],al
;initial ds descriptor
xor eax,eax
mov ax,cs
shl eax,4
add eax,label_ds
mov word [gdt_ds + 2],ax
shr eax,16
mov byte [gdt_ds + 4],al
mov byte [gdt_ds + 7],ah
;initial gdtPtr
xor eax,eax
mov ax,cs
shl eax,4
add eax,gdt
mov dword [gdtPtr + 2],eax
;initial idtPtr
xor eax,eax
mov ax,cs
shl eax,4
add eax,idt
mov dword [idtPtr + 2],eax
;set the 0x80 interrupt
mov eax,intHandler - label_cs
mov word [idt+0x80*8],ax
mov word [idt+0x80*8+2],selector_cs
mov word [idt+0x80*8+4],0x8e00
shr eax,16
mov word [idt+0x80*8+6],ax
;load gdtPtr
lgdt [gdtPtr]
;this is very important!!
cli
;load idtPtr
lidt [idtPtr]
;enable A20
in al,92h
or al,00000010b
out 92h,al
;protect mode
mov eax,cr0
or eax,1
mov cr0,eax
jmp dword selector_cs:0
[bits 32]
[section .32]
label_cs:
;initial ds
mov ax,selector_ds
mov ds,ax
;inital ss,sp
mov ax,selector_ds
mov ss,ax
mov esp,stackOff
mov ah,0ch
mov al,'P'
call display_char
mov ah,0ch
mov al,'r'
call display_char
int 0x80
jmp $
display_char:
push gs
push ebx
mov ebx,selector_gs
mov gs,ebx
; mov [gs:((80*cusor_i+cusor_j)*2)],ax
xor ebx,ebx
mov bx,[0] ;cursor_i is 0
shl bx,1
mov [gs:bx],ax
shr bx,1
inc bx
cmp bx,2000
je .2
jmp .1
.2 mov bx,0
.1 mov word [0],bx ;cursor_i is 0
pop ebx
pop gs
ret
intHandler:
mov ah,0ch
mov al,'I'
call display_char
mov ah,0ch
mov al,'n'
call display_char
mov ah,0ch
mov al,'t'
call display_char
iretd ;very important
label_cs_end:
label_ds:
cusor_i dw 0 ;cusor_i [0,2000)
;stack room
times 1024 db 0
stack:
stackOff equ stack - label_ds ;stack offset
times 512*20 - ($-$$) db 0