分享

FAT32分区引导代码

 昵称9560311 2012-03-31
;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



--------转载













谪居黄城中,把盏临风,牵黄擎苍叹英雄。昔日汴河风光处,履履难重。成败任西东,此恨无穷,为了豪情谁与同?一蓑烟雨平生任,踏雪飞鸿。



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多