📄 bootsec.asm
字号:
; bootsec.asm :; 启动扇区引导代码, 采用nasm编译生成bootsec.bin, 使用WinImage等工具写入软盘; 镜像文件的起始512字节.; ; Copyright(C) 2007, Alex P.Wonder; phoenixwonder@gmail.com;%include "bootsec.inc" org 07c00h jmp short _start nop;==========================================; FAT12引导扇信息(BS+BPB表);========================================== DECLARE_BOOTSEC_INFO;==========================================; 全局变量;==========================================LoaderFileName db 'LOADER BIN' ; windows98格式化, xxxxxxxxyyy, x中字符不够用空格0x20补齐loadingmsg db 10,'Loading...'errmsg db 14,'Loaded failed!'wSectorNo dw 0wRootDirSizeForLoop dw 0bOdd db 0;==========================================; 引导代码;==========================================_start: ;初始化段寄存器 mov ax, cs mov ds, ax mov ss, ax mov es, ax mov sp, BaseOfBoStack mov ax, 0xb800 mov gs, ax ;软驱复位 xor ah, ah xor dl, dl int 13h ; --在软盘根目录中查找系统引导程序文件'loader.bin'-- mov word [wSectorNo], SectorNoOfRootDir mov ax, [BPB_RootEntCnt] ; 根目录总数 -> wRootDirSizeForLoop(查找总次数赋初值) mov word [wRootDirSizeForLoop], ax L_SEARCH_ROOT_DIR_HERE: mov ax, BaseOfLoader mov es, ax ; (es) <- BaseOfLoader mov bx, 0 ; es:bx -> BaseOfLoader: 0 mov ax, [wSectorNo] ; 读一个扇区FAT表内容到内存es:bx mov cl, 1 call ReadSector push es mov ax, ds mov es, ax push bp mov bp, loadingmsg mov dx, 0x0000 call ShowBootMsg pop bp pop es mov si, LoaderFileName ; ds:si -> 'LOADER.BIN' mov di, 0 cld mov dx, 10h ; 512 / 32(一个FAT项占用的字节数) = 16(一个扇区存有16个FAT项)L_SEARCH_FOR_LOADERBIN: cmp dx, 0 jz L_GOTO_NEXT_SECTOR ; 如果当前扇区中没找到,则查找下一个FAT扇区 dec dx mov cx, 11 ;8.3 fat12 filename formatL_CMP_FILENAME: ; cmp cx, 0 ; jz L_FILENAME_FOUND ; dec cx ; lodsb ; ds:si -> al, si++ cmp al, byte [es:di] ; jz L_GO_ON ; 当前字符相同则继续比较文件名的下一个字符; jmp L_DIFFERENT ; 否则,取下一个FAT目录项比较L_GO_ON: ; inc di ; jmp L_CMP_FILENAME ;L_DIFFERENT: and di, 0ffe0h ; di & 0xffe0 = 当前比较目录项的首字节地址 add di, 20h ; 跳过32字节,即取下一个目录项的首字节地址 mov si, LoaderFileName ; LoaderFileName首字节地址 -> (si) dec word [wRootDirSizeForLoop] ;wRootDirSizeForLoop--, 总比较次数-1 cmp word [wRootDirSizeForLoop], 0 jz L_NO_LOADERBIN ;总次数为0时还没有找到,放弃查找 jmp L_SEARCH_FOR_LOADERBINL_GOTO_NEXT_SECTOR: inc word [wSectorNo] ; wSectorNo++, 下一个FAT扇区 jmp L_SEARCH_ROOT_DIR_HEREL_NO_LOADERBIN: call KillMotor ;关闭驱动器马达 ;显示启动错误信息 mov bp, errmsg mov dx, 0x0200 call ShowBootMsg hlt ; 系统启动失败了 :(L_FILENAME_FOUND: ;找到了LOADER.BIN mov ax, RootDirSectors and di, 0xffe0 ;这时候的di还是指向根目录区中对应的目录项(LOADER.BIN) add di, 01ah ;找到首Sector, 01ah偏移位置存放了该文件在数据区中的首簇号 mov cx, word [es:di] push cx ; 保存首簇号, 1) add cx, ax ; (cx) <= RootDirSectors + 首簇号 add cx, DeltaSectorNo ; 数据区的第一个簇号是2,不是0或1, 所以DeltaSectorNo=1 + 9*2 - 2=17 ; 执行此指令后, (cx) = loader.bin的第一个逻辑扇区号 mov ax, BaseOfLoader mov es, ax mov bx, 0 mov ax, cx ;逻辑扇区号=>(ax)L_GOON_LOADING_FILE: mov cl, 1 ;读一个扇区到 es:bx call ReadSector pop ax ; 当前簇号 => (ax) call GetFATEntry ;获得下一个簇号,并保存在ax中 cmp ax, 0ff8h jae L_FILE_LOADED ;文件读取结束 push ax ;保存当前簇号 ; 下面几行代码获得当前簇号对应的逻辑扇区号 mov dx, RootDirSectors add ax, dx add ax, DeltaSectorNo add bx, [BPB_BytsPerSec] ;指向下一个存放文件内容的内存地址 jmp L_GOON_LOADING_FILEL_FILE_LOADED: ;loader加载完毕, 执行loader jmp BaseOfLoader:0;================================================; 定义一些函数;================================================;读取一个扇区; ax - 起始逻辑扇区号; cl - 扇区数; es:bx - 返回地址ReadSector: push bp mov bp, sp sub sp, 2 ;开辟两个字节存放需要读取的扇区数 mov byte [bp - 2], cl push bx mov bl, [BPB_SecsPerTrk] div bl ; y在al中(商), z在ah中(余数) inc ah ; z++(扇区号) mov cl, ah ; cl <- 起始扇区号 mov dh, al ; dh <- y shr al, 1 ; 柱面号 mov ch, al and dh, 1 ; 磁头号 pop bx mov dl, 0;[BS_DrvNum].CoOnReading: mov ah, 2 mov al, byte [bp - 2] int 13h jc .CoOnReading ; 如果读取错误,CF=1, 这里就不停地读,直到正确为止 mov ax, 0xb800 mov gs, ax inc byte [gs:(80*6 + 0)*2] add sp, 2 pop bp ret; 功 能:; 根据文件的簇号获得对应FAT表项内容(文件下一个簇号).; 输 入:; ax - 文件的当前簇号; 输 出:; ax - 下一个簇号; 返回值:GetFATEntry: push es push bx push ax mov ax, BaseOfLoader sub ax, 0100h mov es, ax ;BaseOfLoader地址前空出4k给es段(用来临时保存读取的FAT扇区) pop ax mov byte [bOdd], 0 mov bx, 3 mul bx ; ax*3 => (dx:ax) mov bx, 2 div bx ; (dx:ax) / 2 => (ax):商, (dx):余数 cmp dx, 0 jz L_EVEN mov byte [bOdd], 1L_EVEN: xor dx, dx mov bx, [BPB_BytsPerSec] div bx ; 求逻辑扇区号对应的FAT项在第几个FAT内容扇区中, (ax)/BPB_BytsPerSec => ax(扇区号) push dx ; dx保存FAT项在扇区中的偏移 mov bx, 0 ; 连续读取2个逻辑扇区号对应的FAT表扇区到内存地址es:bx add ax, SectorNoOfFAT1 mov cl, 2 call ReadSector pop dx add bx, dx ;(es:bx + dx) 保存文件的FAT12项 mov ax, [es:bx] ;读2个字节到ax cmp byte [bOdd], 1 jnz L_EVEN_2 shr ax, 4L_EVEN_2: and ax, 0fffhL_GET_FAT_ENTRY_OK: pop bx pop es ret; 功 能:; 显示引导扇信息; 输 入:; dh, dl -- y, x; es, bp -- addr of str; 输 出:; (无)ShowBootMsg push ax push bx push cx xor cx, cx mov cl, [bp] ;获得字符串字符个数 inc bp ;指向字符串中第一个字符 mov ah, 19 mov bh, 0 ;页号 mov bl, 0x0f ;白色字体,黑色背景 mov al, 1 ;光标移动到最后一个字符后面 int 10h dec bp ;恢复bp的值 pop cx pop bx pop ax ret;; 关闭软盘驱动器马达;KillMotor: push ax push dx mov dx, 03f2h mov al, 0 out dx, al pop dx pop ax ret ;补齐512字节 times (510 - $ + $$) db 0 dw 0xaa55
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -