操作系统入门(六) - 2 - 加入中断在保护模式试试看

来源:互联网 发布:fm奥克斯福德数据 编辑:程序博客网 时间:2024/05/16 11:56
加入中断试试看
2006-5-20 blog.csdn.net/flyback fly-back@163.com
一直都没有考虑中断,现在在保护模式下把中断加上去看看是怎么回事
现在的文件有:
kernel.asm
fatboot.asm
pnt.asm
readdisk.asm
system.asm
kernel.ld
build.bat
start.txt
start.bat
文件KERNEL.asm
; ==================================
;; 文件:    KERNEL.asm
;; 作用:    系统在进入保护模式之前
;;          要进行的初始化操作包括:
 
;       1.载入32位系统文件system.img
;       2.设置GDT和中断(空的)32位的时候再设置
 
 
;; 创建日期:2006/04/30 flyback
;; 修改日期:2006/05/07 flyback
;;    http://blog.csdn.net/flyback
;;    fly-back@163.com
; ==================================
 
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
 
; ===========
;   al的数按16
;   进制显示出来
;   al = num
; ===========
_Num2Str:
   
    push bx
    push eax
 
    jmp .handle
    .show db ' '
    .dath db 0
    .datl db 0,0
    .tab db '0123456789ABCDEF'
.handle:
    and ax, 0xff
    push ax
    and ax, 0x0f
    lea si, [dword .tab]
    add si, ax
    mov al, byte[si]
 
    lea si, [dword .datl]
    mov [si], al
   
    pop ax
    shr ax, 4
    and ax, 0x0f
 
    lea si, [dword .tab]
    add si, ax
    mov al, byte[si]
    lea si, [dword .dath]
    mov [si], al
    lea si, [dword .show]
    pop eax
    pop bx
   
    ret
 
文件readdisk.asm
; ==================================
;; 文件:    readdisk.asm
;; 作用:    需要调用的读读磁盘文件子程序
 
;; 创建日期:2006/04/30 flyback
;; 修改日期:2006/05/07 flyback
;;    http://blog.csdn.net/flyback
;; fly-back@163.com
; ==================================
[bits 16]
[extern _pntchr]
[extern _cls]
[extern _NextLine]
[extern _Num2Str]
[extern _ShowAddress]
[global _readsystem]
 
segment .data
align 4
progress           db '.', 0
Load                db ' Loading system file now, please wait', 0
ErrorMsg            db ' An error occur!',0
SystemFileName   db 'SYSTEM IMG'
SystemFileNameLen    equ $ - SystemFileName
protectmode     db ' Goto protected mode',0
LoadRootMsg     db ' Loading root',0
LoadFileDescriptor   db ' Loading file descriptor',0
LoadSystemImage db ' Loading system file image',0
NotFound            db ' File not found!', 0
 
bpsadd          equ 0xb     ;brBPS     DW 0x200        ; 000Bh - 每扇区的字节数 512
spcadd          equ 0xd     ;brSPC     DB 0x01            ; 000Dh - 每簇扇区数
rescountadd         equ 0xe     ;brResCount DW    0x0001     ; 000Eh - 保留扇区数
fatsadd         equ 0x10        ;brFATs     DB 0x02            ; 0010h - FAT 备份数
rootentriesadd   equ 0x11        ;brRootEntries   DW    0x00e0     ; 0011h - 根目录入口数
sectorscountadd equ 0x13        ;brSectorCount DW    2880        ; 0013h - 磁盘容量扇区数< 32MB
mediaadd            equ 0x15        ;brMedia        DB    240         ; 0015h - 媒体描述符
spfadd          equ 0x16        ;brSPF     DW 9           ; 0016h - FAT扇区数
sphadd          equ 0x18        ;brSPH     DW 18         ; 0018h - 每磁道扇区数
hpcadd          equ 0x1a        ;brHPC     DW 2           ; 001Ah - 盘面数
hideadd         equ 0x1c        ;brHidden        DD 0            ; 001Ch - 隐藏扇区数
sectors         equ 0x20        ;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 - 系统保留
 
SYSSEG     equ 0x9000
SYSOFF     equ 0x1000
 
Sector     db 0x00
Head        db 0x00
Track       db 0x00
datasector    dw 0x0000                    ; 33 数据区起始扇区号
cluster     dw 0x0000
 
segment .text
;*************************************************************************
; 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        ; 一个扇区
 
    lea     si, [dword Track] 
    mov     ch, [si]    ; track
 
    lea     si, [dword Sector]
    mov     cl, [si]    ; sector
 
    lea     si, [dword Head]
    mov     dh, [si]    ; head
 
    mov     dl, 0           ; 因为是a:所以为0
    int     0x13            ; 调用中断
 
    jnc     .SUCCESS        ; test for read error
 
    xor     ax, ax
   
    pop     cx
    pop     bx
    pop     ax
   
    jnz     near    .secloop
 
    jmp     failure         ; 错误则显示出错信息并停止
   
.SUCCESS
    lea     si,[dword progress]
    call        _pntchr
 
    pop     cx
    pop     bx
    pop     ax
 
    add     bx, [fs:bpsadd] ; 读取下一个扇区的内容
 
    inc ax                
    loop    .gotomain            ; cx -= 1, if cx != 0, jmp .main
    ret
 
    ;    .Main已经不能用普通跳转了
    ;   因为loop只能是short jmp
 
.gotomain:
    jmp near .Main
 
;*************************************************************************
; PROCEDURE LBACHS
; 转换逻辑块访问为读取磁盘所使用的磁道,盘面,扇区
; 相对扇区 = (逻辑扇区 / 每磁道扇区数) + 1
; 相对盘面   = (逻辑扇区 / 每磁道扇区数) MOD 盘面数
; 相对磁道 = 逻辑扇区 / (每磁道扇区数 * 盘面数)
;*************************************************************************
LBACHS:
    xor     dx, dx             ; dx = 0
    div     WORD [fs:sphadd]     ; div m16: ax/18 -> :ax 余数:dx
    inc     dl                  ;
    lea     si,[dword Sector]
    mov     [si], dl                ; sector No relative to the Track
 
    xor     dx, dx             ; dx = 0
    div     word [fs:hpcadd]     ; ax/2 -> :ax 余数:dx
 
    lea     si, [dword Head]
    mov     [si], dl        ;
 
    lea     si, [dword Track]
    mov     [si], al        ;
 
    ret
 
;*************************************************************************
; PROCEDURE ClusterLBA
; 转换单元访问到直接扇区访问
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
    sub     ax, 0x0002                          ; zero base cluster number
    xor     cx, cx
    mov     cl, BYTE [fs:spcadd]        ; convert byte to word
    mul     cx
 
    lea     si, [dword datasector]
    add     ax, [si]               ; base data sector
 
    ret
 
 
_readsystem:   
    lea     si, [dword Load]
    call        _pntchr
 
    mov     ax, 0x7c0
    mov     fs, ax 
    mov     es, ax
 
loadroot:
    call        _NextLine
    lea     si, [dword LoadRootMsg]
    call        _pntchr
 
    mov     cx, 0
    mov     dx, 0  
 
    mov     ax, 0x0020            ; 32个字节/文件
 
    ; mul       WORD [brRootEntries] ; 32*224(文件数) = 7168 (最多所有文件所占的字节数)
    mul     word [fs:rootentriesadd]
 
    ; div       WORD [brBPS]         ; 7168/512 = 14 (Root dir) 文件的目录描述字节占用的扇区数14
    div     word [fs:bpsadd]
 
    xchg        ax, cx             ; CX = 14
 
    ; mov       al, [brFATs]            ; 2
    mov     al, [fs:fatsadd]
   
    ; mul       word [brSPF]         ; 9 * 2 = 18
    mul     word [fs:spfadd]
   
    ; add       ax, word [brResCount]    ; 18 + 1 now AX = 19
    add     ax, word [fs:rescountadd]
   
    ; mov       WORD[datasector], ax     ; 目录起始的扇区 19
    lea     si, [dword datasector]
    mov     [si], ax
   
    ; add       WORD[datasector], cx     ; 数据区起始扇区 33
    lea     si, [dword datasector]
    add     [si], cx
   
    ; 目录放入0x0200内存
   
    mov     bx, 0x0200
    call        ReadSec
 
    ; 比较目录中是否有SYS.img文件存在
 
    ; mov     cx, WORD [brRootEntries] ; CX:224 在目录的所有文件中寻找
    mov     cx, [fs:rootentriesadd]
   
    mov     ax, fs
    mov     es, ax
   
    mov     di, 0x0200            ; 从目录入口处开始 0x200
.LOOP:
    push        cx                      ; 保护 CX = 224
   
    mov     cx, SystemFileNameLen            ; 8个文件名称和3个扩展名称
    lea     si, [dword SystemFileName]          ;
    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 自动减
 
    call        _NextLine
    lea     si, [dword NotFound]
    call        _pntchr
    jmp     failure
 
    ; 载入文件描述子节
loadfiledec:
    pop     cx ; 有一个cx的值没有弹出来
 
    ; 把启动的镜像文件system.img文件的起始单元保存起来 
    call        _NextLine
    lea     si, [dword LoadFileDescriptor]
    call        _pntchr
    ; call     _NextLine
 
    mov     dx, [fs:di + 0x001A]               ;the file's first cluster
    lea     si, [dword cluster]
 
    mov     [si], dx                  ; store the first cluster
   
    ; 计算fat的大小并保存到07c00:0x0200(ds:bx)
    xor     ax, ax
    mov     al, BYTE [fs:fatsadd]                ; al:2
    mul     WORD [fs:spfadd]                ; AH:18 = 9*2
    mov     cx, ax                             ; CX:18
 
    ; 读取数据放入到0x7c00:0x0200 ds:bx
   
    ; mov     ax, WORD [brResCount]          ; AX:1
    mov     ax, WORD [fs:rescountadd]          ; AX:1
 
    mov     bx, 0x0200                          ;
    call        ReadSec                         ; AX:1 CX:18 BX:0200
 
    ; 读取img 放入 9000:0x1000
    mov     ax, SYSSEG
    mov     es, ax
    mov     bx, SYSOFF
    push        bx
 
LOAD_IMAGE:
    call        _NextLine
    lea     si, [dword LoadSystemImage]
    call        _pntchr
   
 
    ; mov     ax, WORD [cluster]       ; cluster to read
    lea     si, [dword cluster]
    mov     ax, [si]                ; 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 [fs:spcadd] ; CL:1
    call        ReadSec             ; AX:LBA CX:1 BX:0000 ES:0100
    push        bx
   
    ; 计算下一个单元
    lea     si, [dword cluster]
 
    ;mov        ax, WORD [cluster]   ; identify current cluster
    mov     ax, [si]                ; 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, [fs: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
    lea     si ,[dword cluster]
    mov     [si], 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:   
    pop     bx                  ; 有一个多出来的bxstack里面                       
    ret                        
 
    ; 回到主程序,这时system.img
    ; 已经被装在0x9000:0x1000的地方
    ; 只要设置好保护模式的条件就可以跳转了
   
failure:
    call        _NextLine
    lea     si,[dword ErrorMsg]
    call        _pntchr
    call        _NextLine
    hlt
 
文件 system.asm
; ==================================
;; 文件:    system.asm
;; 作用:    调用中断
;;    http://blog.csdn.net/flyback
;; fly-back@163.com
; ==================================
bits 32
org 0x91000
start:
    mov ax, 0x10   
    mov ds, ax   
    mov ss, ax
    mov esp, 0xfff0
 
    int 0x1
    int 0x0
    hlt
 
连接文件kernel.ld文件
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
 .text 0x90000 : {
    *(.text)
 }
 .data 0x90500 : {
    *(.data)
 }
 .bss : {
 *(.bss)
 }
 
}
编译的build.bat文件
nasm -f aout ../asm/kernel.asm -o ../obj/m.o > error.txt
nasm -f aout ../asm/pnt.asm -o ../obj/pnt.o
nasm -f aout ../asm/readdisk.asm -o ../obj/readdisk.o
nasm -fbin -i../inc -o ../img/SYSTEM.img SYSTEM.ASM
ld -T kernel.ld -s -e start ../obj/m.o ../obj/pnt.o ../obj/readdisk.o -o KERNEL.img
 
编译完成后生成了:
fatboot.img
KERNEL.IMG
SYSTEM.IMG
然后打开用winimage打开fatboot.img,KERNEL.IMG system.img放入fatboot.img里面
 
制作bochs的配置文件start.txt
# configuration file generated by Bochs
config_interface: textconfig
display_library: win32
megs: 32
romimage: file=E:/操作系统/Bochs-2.1.1/Bochs-2.1.1/BIOS-bochs-latest, address=0xf0000
vgaromimage: E:/操作系统/Bochs-2.1.1/Bochs-2.1.1/VGABIOS-elpin-2.40
boot: floppy
floppya: 1_44="fatboot.img", status=inserted
floppyb: 1_44="none", status=inserted
ata0: enabled=0
ata1: enabled=0
ata2: enabled=0
ata3: enabled=0
parport1: enabled=1, file="parport.out"
com1: enabled=1, dev=""
usb1: enabled=1, ioaddr=0xff80, irq=10
# no sb16
floppy_bootsig_check: disabled=0
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
floppy_command_delay: 500
ips: 1000000
text_snapshot_check: 0
mouse: enabled=0
private_colormap: enabled=0
i440fxsupport: enabled=0
clock: sync=none, time0=local
# no ne2k
newharddrivesupport: enabled=1
# no loader
log: log.txt
logprefix: %t%e%d
debugger_log: debug.txt
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
pass: action=fatal
keyboard_mapping: enabled=0, map=
keyboard_type: mf
user_shortcut: keys=none
# no cmosimage
 
E:/操作系统/Bochs-2.1.1/Bochs-2.1.1是你安装bochs的目录
fatboot.img 是刚才生成的那个文件
和启动文件start.bat
bochsdbg -f start.txt –q
然后双击Start.bat启动bochs
原创粉丝点击