加入中断试试看
一直都没有考虑中断,现在在保护模式下把中断加上去看看是怎么回事
现在的文件有:
文件KERNEL.asm
; ==================================
;; 文件: KERNEL.asm
;; 作用: 系统在进入保护模式之前
;; 要进行的初始化操作包括:
; 1.载入32位系统文件system.img
; 2.设置GDT和中断(空的)在32位的时候再设置
;; 创建日期:2006/04/30 flyback
;; 修改日期:2006/05/07 flyback
;; http://blog.csdn.net/flyback
; ==================================
global start
extern _pntchr
extern _cls
extern _NextLine
extern _readsystem
[section .text]
[bits 16]
start:
mov ax, cs
mov ds, ax
mov ss, ax
mov sp, 0xfff0
sti
call _cls
lea si, [dword KernelLoad]
call _pntchr
call _NextLine
lea si, [dword welcomemsg]
call _pntchr
call _NextLine
call _readsystem
; 打开A20
in al, 92h
or al, 00000010b
out 92h, al
; end 打开A20
; 设置GDT
cli
lea si, [dword gdtr]
lgdt [si]
; end 设置GDT
; 设置idt
lea si, [dword idtr]
lidt [si]
; end 设置idt
mov eax, cr0
or eax,1
mov cr0, eax
jmp dword codesel:SYSSEG * 0x10 + SYSOFF
[bits 32]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 设置中断0
; 显示20在屏幕上
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
int0x0:
pusha
mov ax,datasel
mov gs,ax
mov byte[gs:dword 0xB8000],'2'
mov byte [gs:dword 0xB8002],'0'
popa
iret
int0x1:
; =======
; 清屏幕
; =======
pusha
mov ax, datasel
mov ds, ax
mov es, ax
mov eax, dword 0xb8000
mov edi, eax
mov ecx, 25 * 80
mov ah, 0x7
mov al, ' '
rep stosw
popa
iret
[bits 16]
gdtr :
dw gdtend - gdt - 1 ; gdt的长度
dd gdt ; gdt的物理地址
gdt:
gdt0:
dw 0,0,0,0 ; 据说是一定要为0否则会有错
codesel_gdt:
dw 0xffff ; 界限Limit值 = 0x100000 * 0x1000 = 4GB
dw 0 ; 基地址 = 0
dw 0x9A00 ; 表示代码段可读可执行
dw 0x00CF ; 粒度(不知道是什么意思)
datasel_gdt:
dw 0xffff ; 4GB
dw 0x0 ; 基地址
dw 0x9200 ; 数据段可读可写
dw 0x00CF ; 粒度
gdtend:
codesel equ codesel_gdt - gdt
datasel equ datasel_gdt - gdt
align 4
idtr: dw idt_end - idt - 1 ; IDT limit
dd idt ; linear, physical address of IDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; interrupt descriptor table (IDT)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
idt:
dw int0x0 - $$ ; 这里是offset
dw codesel
db 0
db 0x8E
dw SYSSEG / 0x1000 ; 这里为0x9000 / 0x1000 = 0x9如果程序用到int 0x0的时候则跳转到8:0x9:int0x0
dw int0x1 - $$
dw codesel
db 0
db 0x8E
dw SYSSEG / 0x1000
idt_end:
segment .data
welcomemsg db 'Welcome to DIY OS!'
CopyRight db ' Create by http://blog.csdn.net/flyback.',0
KernelLoad db 'KERNEL.img was loaded!',0
SYSSEG equ 0x9000
SYSOFF equ 0x1000
文件fatboot.asm
;; 文件:fatboot.asm
;; 作用: 从7c00h处启动
;; 把kernel.img载入到0x90000的地方
;; 用32位方式执行
;; 有文件系统,1.44M 512bits/80sec 软盘启动,
;; 创建日期:2004/01/30 flyback
;; 修改日期:2006/04/24 flyback
;; http://blog.csdn.net/flyback
;; mailto:fly-back@163.com
;; ===================================
%define loadpoint 0x9000 ; 载入点,初始化程序载入到9000h的地方
%define loadoffset 0x0
bits 16
ORG 0x7c00 ; 启动入口地址
main:
jmp short start ; 跳转到开始程序入口
nop ;
; 引导区文件系统数据
;----------------------------------------------------------------------------
brOEM DB ' -My-0S.' ; 0003h - 引导程序的名字
brBPS DW 0x200 ; 000Bh - 每扇区的字节数 512
brSPC DB 0x01 ; 000Dh - 每簇扇区数
brResCount DW 0x0001 ; 000Eh - 保留扇区数
brFATs DB 0x02 ; 0010h - FAT 备份数
brRootEntries DW 0x00e0 ; 0011h - 根目录入口数
brSectorCount
DW 2880 ; 0013h - 磁盘容量扇区数< 32MB
brMedia DB 240 ; 0015h - 媒体描述符
brSPF DW 9 ; 0016h - 每FAT扇区数
brSPH DW 18 ; 0018h - 每磁道扇区数
brHPC DW 2 ; 001Ah - 盘面数
brHidden DD 0 ; 001Ch - 隐藏扇区数
brSectors DD 0 ; 0020h - 如果大于32m的扇区总数
DB 0 ; 0024h - 物理驱动器号
DB 0 ; 0025h - 系统保留
DB 29H ; 0026h - 扩展扇区标记(包含29h)
brSerialNum DD 00000006H ; 0027h - 卷ID
brLabel DB 'teachosdisk' ; 002Bh - 卷标
brFSID DB 'FAT12 ' ; 0036h - 系统保留
;------------------------------------------------------------------------
start:
cli ; 关中断,防止意外中断打断程序执行
mov ax, cs ;
mov ds, ax ; 设置数据段
mov es, ax ;
mov ax, 0x0000; 设置堆栈段
mov ss, ax
mov sp, 0ffffh ; 堆栈入口
sti ; 开中断
mov si, loadmsg ; 调用显示载入信息
call pntchr
; 把磁盘目录信息载入到7c00:0200的地方
loadroot:
mov cx, 0
mov dx, 0
mov ax, 0x0020 ; 32个字节/文件
mul WORD [brRootEntries] ; 32*224(文件数) = 7168 (最多所有文件所占的字节数)
div WORD [brBPS] ; 7168/512 = 14 (Root dir) 文件的目录描述字节占用的扇区数14
xchg ax, cx ; CX = 14
mov al, [brFATs] ; 2
mul word [brSPF] ; 9 * 2 = 18
add ax, word [brResCount] ; 18 + 1 now AX = 19
mov WORD[datasector], ax ; 目录起始的扇区 19
add WORD[datasector], cx ; 数据区起始扇区 33
; 目录放入0x0200内存
mov bx, 0x0200
call ReadSec
; 比较目录中是否有init.img文件存在
mov cx, WORD [brRootEntries] ; CX:224 在目录的所有文件中寻找
mov di, 0x0200 ; 从目录入口处开始 0x200
.LOOP:
push cx ; 保护 CX = 224
mov cx, kernellen ; 8个文件名称和3个扩展名称
lea si, [kernelname] ;
push di
repe cmpsb ; stop compare if cx >0 or the
; first unequal is met(zf=1)!
pop di
je loadfiledec ;if zf = 1, jmp LOAD_FAT!(Seek OK!)
pop cx
add di, 0x0020 ; 跳到下一个目录入口
loop .LOOP ; cx 自动减
jmp failure
; 载入文件描述子节
loadfiledec:
; 把启动的镜像文件*.img文件的起始单元保存起来
mov si, CRLF
call pntchr
mov si, loadfat
call pntchr
lea si, [kernelname]
call pntchr
mov dx, WORD [di + 0x001A] ;the file's first cluster
mov WORD [cluster], dx ; store the first cluster
; 计算fat的大小并保存到07c00:0x0200(ds:bx)
xor ax, ax
mov al, BYTE [brFATs] ; al:2
mul WORD [brSPF] ; AH:18 = 9*2
mov cx, ax ; CX:18
; 读取数据放入到0x7c00:0x0200 ds:bx
mov ax, WORD [brResCount] ; AX:1
mov bx, 0x0200 ;
call ReadSec ; AX:1 CX:18 BX:0200
; 读取img 放入 9000:0x0000处
mov ax, loadpoint
mov es, ax
mov bx, loadoffset
push bx
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
; AX:[cluster] ES:BX[9000:0000](dest)
xor cx, cx
mov cl, BYTE [brSPC] ; CL:1
call ReadSec ; AX:LBA CX:1 BX:0000 ES:0100
push bx
; 计算下一个单元
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file,>=0x0FF0: end or bad!
jb LOAD_IMAGE ; if dx<0x0ff0 (CF=1), jmp Load_image
DONE: ; this Label is not used!
jmp gotopm
failure:
mov si, CRLF
call pntchr
mov si, loadfail
call pntchr
hlt
; ----------------子程序区-------------------------
;*********************显示字符串********************************************
;
;
;
;***************************************************************************
pntchr:
pusha
.pnt:
lodsb ; 从DS:SI装载一个字符到AL
or al,al ;
jz endpntchr ; 如果 al = 0, 返回
;
mov ah,0x0E ;
mov bx,0x004a ;
int 0x10 ; 调用bios中断显示字符
jmp .pnt ;
;
endpntchr: ;
popa
ret ; 返回
;*************************************************************************
; PROCEDURE ReadSec
; 从ax+1的地方把cx个扇区载入到es:bx的内存
; 注意扇区是从2开始,1扇区已经读入了
;*************************************************************************
ReadSec:
.Main:
.secloop:
push ax
push bx
push cx ;protect ax, bx, cx
call LBACHS ; 调用转换
mov ah, 0x02 ; BIOS 读取扇区命令
mov al, 0x01 ; 一个扇区
mov ch, BYTE [Track] ; track
mov cl, BYTE [Sector] ; sector
mov dh, BYTE [Head] ; head
mov dl, 0 ; 因为是a:所以为0
int 0x13 ; 调用中断
jnc .SUCCESS ; test for read error
xor ax, ax
pop cx
pop bx
pop ax
jnz .secloop
jmp failure ; 错误则显示出错信息并停止
hlt
.SUCCESS
mov si, Progress
call pntchr
pop cx
pop bx
pop ax
add bx, WORD [brBPS] ; 读取下一个扇区的内容
inc ax
loop .Main ; cx -= 1, if cx != 0, jmp .main
ret
;*************************************************************************
; PROCEDURE LBACHS
; 转换逻辑块访问为读取磁盘所使用的磁道,盘面,扇区
; 相对扇区 = (逻辑扇区 / 每磁道扇区数) + 1
; 相对盘面 = (逻辑扇区 / 每磁道扇区数) MOD 盘面数
; 相对磁道 = 逻辑扇区 / (每磁道扇区数 * 盘面数)
;*************************************************************************
LBACHS:
xor dx, dx ; dx = 0
div WORD [brSPH] ; div m16: ax/18 -> 商:ax 余数:dx
inc dl ;
mov BYTE [Sector], dl ;sector No relative to the Track
xor dx, dx ; dx = 0
div WORD [brHPC] ; ax/2 -> 商:ax 余数:dx
mov BYTE [Head], dl ;
mov BYTE [Track], al ;
ret
;*************************************************************************
; PROCEDURE ClusterLBA
; 转换单元访问到直接扇区访问
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [brSPC] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;-------------------- 数据区-------------------------------
loadmsg db 'Boot',0 ; 要显示的字符窜以0结尾
loadfail db 'Load Fail',0 ; 载入失败信息
Sector db 0x00
Head db 0x00
Track db 0x00
datasector dw 0x0000 ; 33 数据区起始扇区号
rootaccess equ 0x0200 ; 存放目录数据的偏移地址
cluster dw 0x0000
CRLF db 13,10,0
Progress db ".", 0
loadfat db 'Load', 0 ;字符串,回车,换行,0
kernelname db "KERNEL IMG" ; 11 chars
kernellen equ $ - kernelname ; 长度
gdtr :
dw gdtend - gdt - 1 ; gdt的长度
dd gdt ; gdt的物理地址
gdt:
gdt0:
dw 0,0,0,0 ; 据说是一定要为0否则会有错
codesel_gdt:
dw 0xffff ; 界限Limit值 = 0x100000 * 0x1000 = 4GB
dw 0 ; 基地址 = 0
dw 0x9A00 ; 表示代码段可读可执行
dw 0x00CF ; 粒度(不知道是什么意思)
datasel_gdt:
dw 0xffff ; 4GB
dw 0x0 ; 基地址
dw 0x9200 ; 数据段可读可写
dw 0x00CF ; 粒度
gdtend:
codesel equ codesel_gdt - gdt
datasel equ datasel_gdt - gdt
; 从这里启动KERNEL,原来要作为保护模式的跳转
gotopm:
jmp dword loadpoint:loadoffset
; -----------------------------------------------------------------
times 510 - ($ - $$) db 0 ; 保证boot区有512个字节
dw 0AA55h ; boot区标记
times 1474560 - ( $ - $$) db 0 ; 大小为1.44M
文件 pnt.asm
; ==================================
;; 文件: pnt.asm
;; 作用: 需要调用的显示部分子程序
;; 创建日期:2006/04/30 flyback
;; 修改日期:2006/05/07 flyback
;; http://blog.csdn.net/flyback
;; fly-back@163.com
; ==================================
[bits 16]
[global _pntchr]
[global _cls]
[global _NextLine]
[global _Num2Str]
[global _ShowAddress]
[global _NextCursor]
segment .data
_row dw 0
_col dw 0
[section .text]
_pntchr:
push ebx
push eax
push si
push di
push cx
push es
mov ax, 0xb800
mov es, ax
push si
lea si, [dword _row]
mov ax, [si]
mov bx, 80 * 2
mul bx
lea si, [dword _col]
add ax, [si]
mov di, ax
pop si
.pnt:
mov al, byte[ds:si]
test al, 0xff
jz .endpntchr
mov byte[es:di], al
inc di
mov byte[es:di], 0x7
inc di
inc si
call _NextCursor
jmp .pnt ;
.endpntchr: ;
pop es
pop cx
pop di
pop si
pop eax
pop ebx
ret ; 返回
; =======
; 清屏幕
; =======
_cls:
push ax
push es
push di
push ecx
push si
; push fs
mov ax, 0xb800
mov es, ax
mov ax, 0
mov di, ax
mov ecx, 25 * 80
mov ah, 0x7
mov al, ' '
rep stosw
mov ax, 0
mov es, ax
lea si, [dword _row]
mov [si], ax
lea si, [dword _col]
mov [si], ax
; pop fs
pop si
pop ecx
pop di
pop es
pop ax
ret
; =============
; 跳到下一行
; =============
_NextLine:
push si
lea si, [dword _row]
inc word[si]
lea si, [dword _col]
mov word [si], 0
pop si
ret
; =================
; 设置光标的下一个位置
; =================
_NextCursor:
push si
lea si, [dword _col]
inc word[si]
inc word[si]
cmp word [si], 80 * 2
jne .addcol
mov word [si], 0
lea si, [dword _row]
inc word[si]
.addcol:
pop si
ret
; ===================
; 显示指定位置的地址内容
; 入口参数:
; si = 有效地址
; cx = 内容个数
; ===================
_ShowAddress:
push eax
.lod
lodsb
or cx,cx
jz .end
push si
call _Num2Str
call _pntchr
; call _NextLine
pop si
loop .lod
.end
pop eax
ret