;2011.10.20 ;FAT32 Boot Sector ;by trojancyborg ;分区引导扇区结构 ;+0 3 byte jmp ;+3 87 byte 分区信息 ;+90 420 byte 引导代码数据 ;+510 2 byte 结束标记 ;默认一个簇为4K的情况 ;在获取指定簇内容的时候,存放簇的缓冲区位置 Buffer_Cluster_Sector_Base equ 0x8100 ;获取文件起始簇的时候,存放目录项的缓冲区 Buffer_Dir_Base equ 0x8100+0x1000 Buffer_Save_DAP_Base equ 0x8100+0x1000+0x1000 Loader_Base equ Sectors_5_Base Sectors_1_Base equ 0x7c00 Sectors_2_Base equ 0x7e00 Sectors_3_Base equ 0x8100 Sectors_4_Base equ 0x8300 Sectors_5_Base equ 0x8500 fact equ 4 ;fat32目录项长度 [BITS 16] ;内存 0x7c00 扇区1 org 7c00h jmp BootEntry ;byte BS_jmpBoot[3]; //跳转指令 ;OFFSET +3 BS_OEMName times 8 db 0 ; //厂商名 ;///////// BIOS Parameter Blocks ///////////// BPB_BytePerSec dw 0; //每扇区字节数 BPB_SecPerClus db 0; //每簇扇区数 BPB_RsvdSecCnt dw 0; //Boot记录占用扇区 BPB_NumFATs db 0; //FAT表个数 BPB_RootEntCnt dw 0; //根目录文件数最大值 BPB_TotSec16 dw 0; //扇区总数 BPB_Media db 0; //介质描述符 BPB_FATSz16 dw 0; //每FAT扇区数 BPB_SecPerTrk dw 0; //每磁道扇区数 BPB_NumHeads dw 0; //磁头数 BPB_HiddSec dd 0; //隐藏扇区数 BPB_TotSec32 dd 0 ; ;//////////////////////////////////////////////// ;//下面是FAT32的结构 BPB_FATSz32 dd 0; //一个FAT表占扇区数 BPB_Flags dw 0; BPB_FSVer dw 0; //高位主板本号 低位此版本号 BPB_RootClu dd 0; //根目录的起始簇 BPB_FSInfo dw 0; //FSINFO结构占用扇区数 BPB_BkBootSec dw 0; //保留区中引导记录的备份数据所占扇区数 BPB_Reserved1 times 12 db 0; BS_DrvNum db 0; //终端13的驱动号 BS_Reserved1 db 0; BS_BootSig db 0; //扩展引导标记 BS_VolID dd 0; //卷序列号 BS_VOlLab times 11 db 0; //卷标 BS_FileSysType times 8 db 0; //文件类型 ;///////////////////////////////////////////////// ///////////// ;OFFSET +90 ;保留扇区 ;安装引导程序的时候,需要将分区表中该分区表项最后8字节复制到此处 ;其内容为改分区起始扇区,和总扇区数 ;分区表中的数据拷贝 RelativeSector dd 0;该分区起始扇区 TotalSector dd 0;分区总扇区数 ;OFFSET +90 +8 ;///////////////////////////////////////////////// //////////////////// FirstDataSector dd 0;数据区域起始扇区 FAT_Base dd 0; FAT基表地址 FAT_Size dd 0; FAT表长度(扇区总数) DirRoot_base dd 0; BytePreCluster dd 0; 每簇字节长度 ;///////////////////////////////////////////////// //////////////////// ;硬盘参数缓冲区 DriverParameters : Info_size dw 26 ;缓冲区大小标志 Flags dw 0 ; 信息标志 Cylinders dd 0 ; number of cylinders on disk Heads dd 0 ; number of heads on disk Sec_per_track dd 0 ; number of sectors per track Sectors dq 0 ; number of sectors on requested disk Sector_size dw 0 ; number of bytes per sector ;扩展 INT 13H 地址数据包 DiskAddressPacket: ; 16Byte PacketSize db 10H ;+0 数据包尺寸(16字节) Reserved db 0 ;+1 这个一定为0 BlockCount dw 8 ;+2 要传输的数据块个数(以扇区为单位),将后续保留扇区全部读入内存 BufferOff dw 0 ;+4 传输缓冲地址(segment:offset) BufferSeg dw 0 ;+6 BlockNum dq 64 ;+8 磁盘起始绝对块地址 ;///////////////////////////////////////////////// //////////////////// NotSupportEx13hMsg db "Error,Not Support Ex13h!",0 MsgError db "Load Boot Sector Error!",0 MsgReadSecError db "Read Sector Error",0 LoadFileName db "LOADER ","BIN",0 Load_Loader_Error db "can not find :",0 MsgBoot db "Boot...",0 ;引导代码开始 ;0x7cfa BootEntry : xor ax,ax mov ax,cs mov ds,ax mov ss,ax mov esp,0x7c00 mov byte [BS_DrvNum],80h call CheckInt13H ;检测是否支持扩展int13h 必须支持才能引导 ;加载后续引导扇区 mov ax,ds mov word [BufferSeg],ax ;缓冲区段地址 mov Word [BufferOff],7E00h ;将后续引导扇区放到此处 mov ah,42h ;读 mov dl,[BS_DrvNum] ;第一块硬盘 mov si,DiskAddressPacket ;DAP地址 int 13h jnc LoadSucess push MsgError call DispStr jmp $ LoadSucess : ;加载后续引导扇区成功 ;计算分区文件系统参数 mov eax,dword [RelativeSector] xor ebx,ebx mov bx,word [BPB_RsvdSecCnt] add eax,ebx mov dword [FAT_Base],eax ;FAT表起始扇区 xor edx,edx xor eax,eax mov al,byte [BPB_NumFATs] mov bx,word [BPB_FATSz32] mul bx mov word [FAT_Size],ax ;FAT表长度 mov word [FAT_Size+2],dx mov eax,dword [FAT_Base] add eax,dword [FAT_Size] mov dword [FirstDataSector],eax ;数据区起始扇区 xor bx,bx mov ax,word [BPB_BytePerSec] mov bl,byte [BPB_SecPerClus] mul bx mov word [BytePreCluster],ax mov word [BytePreCluster+2],dx ;每簇扇区数 ;jmp 7e00h ;跳到后续引导扇区 jmp SecondSector CheckInt13H: ; 检验扩展 13H 功能是否存在 mov ah,0x41 ; 功能号是 41H mov bx,55aah ; 入口参数之一 mov dl,[BS_DrvNum] ; 要测试的 驱动器 80H 是第一块硬盘 int 13H cmp bx,0xAA55 ; 如果存在扩展 13H 功能,则bx==AA55H jnz NotSupport ; 检测结果是不支持,跳到下面显示不支持的信息。 ret ; 支持扩展int 13h ,直接返回 NotSupport: push NotSupportEx13hMsg call DispStr jmp $ ret ;DispStr(char *) ;打印字符串 ;注:由于第一扇区要调用,不要将此函数放后面的扇区中 DispStr : pusha mov ah,0eh ;显示字符 xor bx,bx mov bl,02 ;前景色 mov si,[esp+12h] Print_Loop : lodsb ;al中为要显示的字符 test al,al jz Print_over int 10h jmp Print_Loop Print_over : popa ret 2 ;DispInt(short int) ;以十六进制输出整数 DispInt : pusha mov ax,[esp+12h] mov cx,4 PrintIntLoop : rol ax,4 push ax and ax,0x000F cmp al,10 JAE PrintCh ;大于等于0x0A add al,'0' jmp PrintInt2 PrintCh : add al,'A'-10 PrintInt2 : push ax xor bx,bx mov bl,02h mov ah,0eh int 10h pop ax dec cx test cx,cx pop ax jnz PrintIntLoop popa ret 2 %if (510-($-$$)) < 0 %error 超过分区引导代码容纳空间 %else times 510-($-$$) db 0 dw 0xaa55 %endif ;///////////////////////////////////////////////// //////////////////////////////// ;后续引导扇区 ;内存 0x7e00 扇区2 SecondSector : push Loader_Base ;将loader.bin加载到 0x8500 push LoadFileName call LoadFile ;jmp 0xa000 jmp Loader_Base jmp $ ;MemCpy(char *des,char *src,short int len) ;内存复制函数 MemCpy : pusha mov di,word[ esp+12h] mov si,word[ esp+14h] mov cx,word[ esp+16h] cld rep movsb popa ret 6 ;StrEqu(char *s1,char *s2,short int len) ;字符串是否相等 return 1相等 0不等 StrEqu : pusha mov di,word [esp+12h] mov si,word [esp+14h] mov cx,word [esp+16h] cld lable_cmp_loop : cmpsb jz lable_cmp_loop_next popa mov ax,0 ret 6 lable_cmp_loop_next : sub cx,1 test cx,cx jnz lable_cmp_loop popa mov ax,1 ret 6 ; long FileStartCluster(char *name) ;获取文件起始簇 FileStartCluster : pusha mov di,word [esp + 12h] ;文件名 mov ecx,Buffer_Dir_Base add ecx,dword [BytePreCluster] ;缓冲区终止地址 push dword [BPB_RootClu] ;根目录区起始簇 Label_ReadDir_next : pop eax ;目录所在的簇 test eax,eax jz Lable_No_FILE_Return cmp eax,0xFFFFFFF7 jae Lable_No_FILE_Return ;目录区是否已经读取完 push eax xor ebx,ebx xor edx,edx sub eax,2 mov bl,byte [BPB_SecPerClus] mul ebx add eax,dword [FirstDataSector] mov word [BlockCount],bx mov word [BufferOff],Buffer_Dir_Base mov dl,[BS_DrvNum] mov dword [BlockNum],eax ;起始块 mov ah,42h ;ah=42h 读 mov si,DiskAddressPacket ;DAP地址 int 13h jnc ReadDirEntrySucess push MsgReadSecError call DispStr jmp $ ReadDirEntrySucess : ;读取扇区成功,则在当前扇区寻找目录项 pusha mov si,Buffer_Dir_Base-0x20 Lable_find_file : add si,0x20 cmp si,cx jz Lable_find_no_file push 11 push si push di call StrEqu test ax,ax jz Lable_find_file mov ax,word [si+0x1a] mov [esp+10h-2],ax popa add esp,4 mov [esp+10h-2],ax popa ret 2 Lable_find_no_file : popa call ClusterContext push eax jmp Label_ReadDir_next ;寻找后面的扇区 Lable_No_FILE_Return : popa mov eax,0 ret 2 ;long ClusterContext(long ClusterNum) ;获取指定簇号内容 ClusterContext : pusha xor eax,eax mov ax,word [esp +12h] mov dx,word [esp +14h] mov bx,word [BPB_BytePerSec] shr bx,fact/2 div bx ;ax 商(在FAT表中的扇区) dx 余数 偏移 shl dx,fact/2 add eax,dword [FAT_Base] push dx ;保存偏移量 xor edx,edx mov dword [BlockNum],eax ;起始块 mov word [BlockCount],1 mov word [BufferOff],Buffer_Cluster_Sector_Base mov ah,42h ;ah=42h 读 mov dl,[BS_DrvNum] ;dl 第一块硬盘 mov si,DiskAddressPacket ;DAP地址 int 13h jnc ReadSecSucess push MsgReadSecError call DispStr jmp $ ReadSecSucess : xor edx,edx pop dx mov eax,dword [edx+Buffer_Cluster_Sector_Base] mov word [esp+10h-2],ax popa ret 4 ;LoadFile(char *name,word desbuf) ;读文件到内存 LoadFile : pusha mov si,word [esp +12h] ;取文件名 push si call FileStartCluster test eax,eax jnz Lable_find_loadfile push Load_Loader_Error call DispStr push word [esp +12h] call DispStr jmp $ Lable_find_loadfile : push eax ;文件起始簇 mov di,word [esp +14h+4] mov word [BufferOff],di ;缓冲地址 mov ax,word [BPB_BytePerSec] xor bx,bx mov bl,byte [BPB_SecPerClus] mov word [BlockCount],bx ;读取的块数 mul bx mov di,ax ;缓冲区增量 Label_load_file_next : pop eax ;文件起始簇 test eax,eax jz label_load_file_over cmp eax,0xfff7 jae label_load_file_over push eax sub eax,2 xor ebx,ebx mov bl,byte [BPB_SecPerClus] mul ebx add eax,dword [FirstDataSector] mov dword [BlockNum],eax ;起始块 push 64 push DiskAddressPacket push Buffer_Save_DAP_Base call MemCpy call ClusterContext push eax ;下次的簇 push 64 push Buffer_Save_DAP_Base push DiskAddressPacket call MemCpy mov ax,ds mov word [BufferSeg],ax mov dl,[BS_DrvNum] mov ah,42h ;ah=42h 读 mov si,DiskAddressPacket ;DAP地址 int 13h jc label_load_file_error add word [BufferOff],di jmp Label_load_file_next label_load_file_error : push MsgReadSecError call DispStr jmp $ label_load_file_over : popa ret 4 %if ($-$$) > (512+ 512 * 1) %error 引导代码超过保留扇区空间 %else times 512+512-($-$$) db 0 %endif ;//////////////////////////////////////////////// ;内存 0x8100 扇区3 扇区4 %if ($-$$) > (512+ 512) %error 缓冲区边界未对齐 %else ;内存0x8100 扇区3 ;times 512*8 db 0 ;times 512*8 db 0 %endif ;makefile # All Phony Targets IMG_PATH = ./../hd.img BOOT_PATH = ./bin/Boot.bin LOADER_PATH = ./bin/loader.bin MBR_PATH = ./bin/hdmbr.bin .PHONY : build debug build : ./bin/Boot.bin ./bin/loader.bin debug : build Write ./bin/Boot.bin : Boot_fat32.asm nasm -o $(BOOT_PATH) Boot_fat32.asm #写入jmp 指令 dd if=$(BOOT_PATH) of=$(IMG_PATH) bs=1 seek=32256 count=3 conv=notrunc #写入分区引导扇区引导代码 dd if=$(BOOT_PATH) of=$(IMG_PATH) bs=1 skip=62 seek=32318 count=450 conv=notrunc #写入分区保留扇区引导代码 dd if=$(BOOT_PATH) of=$(IMG_PATH) bs=512 skip=1 seek=64 count=1 conv=notrunc #复制分区表中的分区信息到分区引导扇区 dd if=$(IMG_PATH) of=$(IMG_PATH) bs=1 skip=454 seek=32346 count=8 conv=notrunc #fat16磁盘 dd if=$(IMG_PATH) of=$(IMG_PATH) bs=1 skip=454 seek=32318 count=8 conv=notrunc ./bin/loader.bin : loader.asm nasm -o $(LOADER_PATH) loader.asm sudo losetup -o 32256 /dev/loop0 $(IMG_PATH) sudo mount -t msdos /dev/loop0 /mnt/dvd/ sudo cp $(LOADER_PATH) /mnt/dvd/ -v sudo umount /mnt/dvd/ sudo losetup -d /dev/loop0 #安装主引导记录 Write : $(MBR_PATH) $(BOOT_PATH) dd if=$(MBR_PATH) of=$(IMG_PATH) conv=notrunc dd if=$(BOOT_PATH) of=$(IMG_PATH) bs=1 skip=510 seek=510 count=2 conv=notrunc --------转载
|
|