您的位置:首页 > 运维架构 > Linux

操作系统实现----中断调用

2013-12-10 00:05 1011 查看
在上一篇的基础之上,实现加载中断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

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