之前的boot启动镜像文件在需要改变后继文件(kernel.img)时要用partcopy,并且要计算文件的长度,使用起来不方便,现在我们可以引入微软的软盘FAT格式,如果我们使用软盘来作为测试的介质,那么在使用起来会很方便。 ;; 文件:boot.asm ;; 作用:从7c00h处启动,显示载入系统信息"Loading System..." ;; 没有文件系统,1.44M 512bits/80sec 软盘启动, ;; 创建日期:2004/01/30 flyback ;; [email protected] ;; =================================== %define loadpoint 9000h ; 载入点,初始化程序载入到9000h的地方 %define loadoffset 0000h
bits 16 ORG 0x0 ; 启动入口地址 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, 0x7c0 ; mov ds, ax ; 设置数据段 mov es, ax ; mov ax, 0x0000; 设置堆栈段 mov ss, ax mov sp, 0ffffh ; 堆栈入口 sti ; 开中断 mov si, brOEM ; system info call pntchr mov si, CRLF call pntchr 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个扩展名称 mov 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 mov si, CRLF 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 ; destination of image CS mov es, ax mov bx, loadoffset ; destination for image IP 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! ; push WORD loadpoint ;--->pop CS (second) ; push WORD loadoffset ;--->pop IP (first) ; retf mov si, CRLF call pntchr jmp word loadpoint:loadoffset failure: mov si, CRLF call pntchr mov si, loadfail call pntchr hlt jmp $ ;-------------------- 数据区------------------------------- loadmsg db 'Loading System:',0 ; 要显示的字符窜以0结尾 loadfail db 'Load init Failure!',0 ; 载入失败信息 Sector db 0x00 Head db 0x00 Track db 0x00 datasector dw 0x0000 ; 33 数据区起始扇区号 rootaccess equ 0x0200 ; 存放目录数据的偏移地址 cluster dw 0x0000 kernelname db "KERNEL IMG" ; 11 chars kernellen equ $ - kernelname ; 长度 CRLF db 13,10,0 Progress db ".", 0 ; msgFailure db "ERROR!", 0x00 ; loaddir db 'Load Dir:', 0 ;字符串,回车,换行,0 loadfat db 'Load FAT:', 0 ;字符串,回车,换行,0 ;readsec db 'read sec', 13,10,0 ; ----------------子程序区------------------------- ;*********************显示字符串**************
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: ;mov si, readsec ;call pntchr ;mov di, 0x0005 .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 ;int 0x13 ;dec di 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 ; ----------------------------------------------------------------- times 510 - ($ - $$) db 0 ; 保证boot区有512个字节 dw 0AA55h ; boot区标记
上面是改进后的boot.asm编译后用partcopy 放入软盘开始的512字节 这时,我们只要把我们的其它程序编译成独立的镜像文件命名为KERNEL.IMG拷贝到软盘(软盘文件)就可以了 ;------------------------------------------------- ;; 文件:显示初始化信息 ;; KERNEL.ASM ;; 作用:显示初始化信息 ;; [email protected] ;;------------------------------------------------- start: mov ax, cs mov ds, ax mov es, ax lea si, [prompt] ; press a key to clear screen call pntchr ; 等待按下键盘 ;mov ah, 0x10 ;int 0x16 ; cls mov ah, 0x06 mov al, 0x00 mov bh,0x07 mov cx, 0x0 mov dx,0x184f int 0x10 lea si, [start2msg] call pntchr ; 显示图形功能 ; 保存原来的显示方式 mov ah, 0x0f int 0x10 mov [gmode], ax ; 设置图形模式640X480 mov ah,0x0 mov al, 0x12 int 0x10 ; 设置调色板 mov ah, 0x0b mov bh, 0x0 mov bl, 0x11 int 0x10 ; 显示字符串 lea bp, [start2msg] ; es:bp mov ah, 0x13 mov al, 0x1 mov bh, 0 mov bl, 0x71 mov dx, 0x00 mov cx, msgsize int 0x10 ; 划线 mov bx, 0x0 mov cx, 64 mov dx,70 .pix: mov ah,0x0c mov al, bl int 0x10 inc cx cmp cx,576 jne .pix mov cx,64 inc bl inc dx cmp dx, 280 jne .pix ; 等待键盘 mov ah, 0x10 int 0x16 ; 恢复原来的图形 mov ax, [gmode] mov ah, 0x0 int 0x10 mov si, retmode call pntchr jmp $ nop ;----------------显示字符串---------------------- pntchr: lodsb ; 从DS:SI装载一个字符到AL or al,al ; jz endpntchr ; 如果 al = 0, 返回 ; mov ah,0x0E ; mov bx,0x0007 ; int 0x10 ; 调用bios中断显示字符 jmp pntchr ; ; endpntchr: ; ret ; 返回 start2msg db 'Display 640X480 Video mode:',13,10,0 msgsize equ ($-start2msg) prompt db 'Press any key...',13,10,0 prosize equ ($ - prompt) retmode db 'Return to Text Mode.', 13,10,0 gmode dw 0 把上面文件编译成KERNEL.IMG(大写)拷贝到做好的软盘里,然后用它启动。 
|