/* 这份代码将编译后将放到GRLDR文件的0x400开始的地方(即第三个扇区)
* 这个扇区的内容将被塞到分区引导扇区
* 其中0x00-0x59见文章下方表1。
* 0x5a - 0x1fc放引导代码。
* 最后两个字节固定是0xAA55。
*
* 这份代码将加载到0000:7C00执行。
* 作用是在一个fat32分区中寻找根目录下的GRLDR文件。
* 找到后将整个文件载入到2000:0000(0x20000,即128K)开始的位置,然后执行它。
*/
. = _start1 + 0x400
#define ALTERNATIVE_KERNEL
/*
* 以下基于FreeDOS,Tinybit在2004年2月对其进行了重大修改
*
* 将LBA和CHS引导扇区合并为一个FAT32引导扇区!
*
* GRLDR FAT32单阶段引导过程的内存布局:
*
* ...
* |-------| 1FE0:7E00
* |BOOTSEC| (GRUB不使用此重定位区域)
* |RELOC. | (被加载的内核覆盖)
* |-------| 1FE0:7C00
* ...
* |-------|
* |KERNEL | (覆盖bootsec重定位。)
* |LOADED | (在内核加载之前保存1个扇区目录缓冲区)
* |-------| 2000:0000
* ...
* |-------| 0000:7E00
* |BOOTSEC| GRUB始终在该sector内运行,
* |ORIGIN | 没有重定位.
* |-------| 0000:7C00
* ...
* |-------| 0060:0200
* | FAT | (仅1个扇区被缓冲)
* |-------| 0060:0000
* ...
*
*/
/*
; 这是启用了LBA的FreeDOS FAT32引导扇区(单个扇区!)。
; You can use and copy source code and binaries under the terms of the
; GNU Public License (GPL), version 2 or newer. See www.gnu.org for more.
; 基于FreeDOS内核黑客的早期工作, 由Eric Auer和Jon Gentle在2003年7月进行了重大修改。
;
; 特点:使用LBA并根据BPB / EBPB数据计算所有变量,从而使分区移动/调整大小/图像恢复更加容易。
; FreeDOS可以在> 8 GB边界的FAT32分区中从此启动扇区开始启动。 引导不需要磁盘几何知识。
;
; Windows使用2-3个扇区进行引导(扇区阶段,统计扇区,文件系统阶段)。
; 对于FreeDOS仅使用1个扇区,可以更轻松地在同一文件系统上做FreeDOS和Windows的多系统引导。
;
; 要求:LBA BIOS和386或更好的CPU。 如果要在真正旧的PC上使用FAT32,请使用较旧的仅CHS引导扇区
;(问题:如果您使用仅CHS的FAT32引导扇区在再次应用SYS之前无法从> 8 GB边界引导,无法移动/调整大小... ...)。
;
; FAT12 / FAT16提示:除非您必须从> 8 GB启动否则使用较旧的仅CHS引导扇区。 LBA和CHS FAT12 / FAT16引导扇区需要在移动/调整大小/ ...之后再次应用SYS。
; a variant of that boot sector without CHS support but with better move / resize / ...
; support would be good for use on LBA harddisks.
; FreeDOS FAT32单阶段启动过程的内存布局:
; ...
; |-------| 1FE0:7E00
; |BOOTSEC|
; |RELOC. |
; |-------| 1FE0:7C00
; ...
; |-------| 2000:0200
; | FAT | (only 1 sector buffered)
; |-------| 2000:0000
; ...
; |-------| 0000:7E00
; |BOOTSEC| overwritten by the kernel, so the
; |ORIGIN | bootsector relocates itself up...
; |-------| 0000:7C00
; ...
; |-------|
; |KERNEL | maximum size 134k (overwrites bootsec origin)
; |LOADED | (holds 1 sector directory buffer before kernel load)
; |-------| 0060:0000
; ...
*/
#define BOOTGRUB /* undef this if compiled for loading FreeDOS */
//#undef BOOTGRUB
#ifdef BOOTGRUB
#define LOADSEG 0x2000
#define FATSEG 0x0060
#else
#define LOADSEG 0x0060
#define FATSEG 0x2000
#endif
Entry_32:
jmp 1f
. = Entry_32 + 0x02
/* 默认模式是CHS。 这是为了最大程度地兼容小型磁盘(例如软盘)。
* 对于CHS模式,有效值为0x90,对于LBA模式,有效值为0x0e。
* 如果BIOS int13支持LBA,则可以将该字节安全地设置为0x0e。
* 使用CHS模式时,某些USB BIOS可能存在错误,因此格式化程序应将此字节
* 设置为0x0e。 看来(通常)所有USB BIOS具有LBA支持。
* 如果格式化程序不知道BIOS是否支持LBA,则它可以通过以下方式运行:
* 如果(partition_start + total_sectors_in_partition)超过了CHS寻址
* 能力(尤其是当它大于1024 * 256 * 63时),则调用者应将此字节设置为
* 0x0e,否则设置为0x90。
*/
.byte 0x90 /* 用于CHS,另一个可能的值为代表LBA的0x0e */
. = Entry_32 + 0x03
#ifdef BOOTGRUB
.ascii "GRLDR " /* (格式化磁盘的操作系统的)OEM名字 */
#endif
. = Entry_32 + 0x0b
.word 0x200 /* 每个扇区的字节数。 必须为512 */
. = Entry_32 + 0x0d
/* 每簇扇区数。 有效值为1、2、4、8、16、32、64和128。
* 但是不应该出现大于32K的簇大小。
*/
.byte 1 /* 每簇扇区数 */
. = Entry_32 + 0x0e
/*
* 保留扇区数(第一个FAT之前的扇区数,包括引导扇区),通常为1。
*/
.word 1 /* 保留扇区数 */
. = Entry_32 + 0x10
/* FAT数量(几乎总是2个). */
.byte 2 /* FAT数量 */
. = Entry_32 + 0x11
/* 根目录的目录(root directory entries)最大数个数必须为0。 */
.word 0 /* Max dir entries for FAT12/FAT16 */
. = Entry_32 + 0x13
/* (扇区总数,仅适用于小磁盘)必须为0。 */
.word 0 /* total sectors for FAT12/FAT16 */
. = Entry_32 + 0x15
/* 媒体描述符字节,现在已经无意义。 */
.byte 0xf8 /* media descriptor */
. = Entry_32 + 0x16
/* (每个FAT的扇区数)必须为0。 */
.word 0 /* sectors per FAT for FAT12/FAT16 */
. = Entry_32 + 0x18
.word 18 /* 每磁道扇区数 */
. = Entry_32 + 0x1a
.word 2 /* 磁头数 */
. = Entry_32 + 0x1c
/*
* 隐藏扇区的数量(引导扇区之前的扇区),也称为分区的起始扇区。对于软盘应为0。
*/
.long 0 /* hidden sectors */
. = Entry_32 + 0x20
/* 文件系统中的扇区总数。 */
.long 0 /* total sectors for FAT32 */
. = Entry_32 + 0x24
/* 每个FAT的FAT32扇区数 */
.long 0
. = Entry_32 + 0x28
/* If bit 7 is clear then all FATs are updated,
* 否则,第0-3位将给出当前的活动FAT,所有其他位保留未用。 grldr引导代码不使用该word。
*/
.word 0
. = Entry_32 + 0x2a
/*
* 高字节是主要修订版号,低字节是次要修订版号,当前两者均为0。
* grldr引导代码不使用此word。
*/
.word 0
. = Entry_32 + 0x2c
/* 根目录开始簇 */
.long 0
. = Entry_32 + 0x30
/*
* 文件系统信息扇区号。 grldr引导代码不使用该word。
*/
.word 0
. = Entry_32 + 0x32
/*
* 如果非零则是保存引导记录副本的扇区,通常为6。
* grldr引导代码不使用此word。
*/
.word 6
. = Entry_32 + 0x34
/* 保留的12个字节,设置为0. */
.long 0
.long 0
.long 0
. = Entry_32 + 0x40
/* 引导设备的驱动器号。程序将DL写入该字节。
* 调用者应在DL中设置驱动器号。我们假设所有BIOS在DL中传递正确的
* 驱动器号。也就是说不支持错误的BIOS!
*/
.byte 0
. = Entry_32 + 0x41
/*
* 引导驱动器中此文件系统的分区号。引导代码会将分区号写入该字节。 请参阅下面的Entry + 0x5d。
*/
.byte 0
. = Entry_32 + 0x42
/* 签名(必须为28h或29h才能被NT识别)。 */
.byte 0x29 /* FAT12/FAT16的扩展启动签名 */
. = Entry_32 + 0x43
.long 0x0AC4AF63 /* 卷序列号 */
. = Entry_32 + 0x47
.ascii "NO NAME " /* 卷标签,11个字节。 */
. = Entry_32 + 0x52
.ascii "FAT32 " /* 文件系统ID,8个字节。 */
/*
; bp初始化为7c00h
; %define bsOemName bp+0x03 ; OEM label (8)
; %define bsBytesPerSec bp+0x0b ; bytes/sector (dw)
; %define bsSecPerClust bp+0x0d ; sectors/allocation unit (db)
; %define bsResSectors bp+0x0e ; # reserved sectors (dw)
; %define bsFATs bp+0x10 ; # of fats (db)
; %define bsRootDirEnts bp+0x11 ; # of root dir entries (dw, 0 for FAT32)
; (Fat32在簇链(Cluster Chain)中有根目录)
; %define bsSectors bp+0x13 ; # sectors total in image (dw, 0 for FAT32)
; (if 0 use nSectorHuge even if FAT16)
; %define bsMedia bp+0x15 ; media descriptor: fd=2side9sec, etc... (db)
; %define sectPerFat bp+0x16 ; # sectors in a fat (dw, 0 for FAT32)
; (FAT32始终使用xsectPerFat)
%define sectPerTrack bp+0x18 ; # sectors/track
; %define nHeads bp+0x1a ; # heads (dw)
%define nHidden bp+0x1c ; # hidden sectors (dd)
; %define nSectorHuge bp+0x20 ; # sectors if > 65536 (dd)
%define xsectPerFat bp+0x24 ; Sectors/Fat (dd)
; +0x28 dw flags (for fat mirroring)
; +0x2a dw filesystem version (usually 0)
%define xrootClst bp+0x2c ; Starting cluster of root directory (dd)
; +0x30 dw -1 or sector number of fs.-info sector
; +0x32 dw -1 or sector number of boot sector backup
; (+0x34 .. +0x3f reserved)
%define drive bp+0x40 ; Drive number
bp+0x41 ; partition number for GRLDR
%define fat_sector bp+0x44 ; last accessed FAT sector (dd)
; (overwriting unused bytes)
%define fat_start bp+0x48 ; first FAT sector (dd)
; (overwriting unused bytes)
%define data_start bp+0x4c ; first data sector (dd)
; (overwriting unused bytes)
*/
/* not used: [0x42] = byte 0x29 (ext boot param flag)
* [0x43] = dword serial
* [0x47] = label (padded with 00, 11 bytes)
* [0x52] = "FAT32",32,32,32 (not used by Windows)
* ([0x5a]是FreeDOS开始的地方)
*/
. = Entry_32 + 0x5a
1:
cli
cld
#ifdef BOOTGRUB
. = Entry_32 + 0x5c
/* 在偏移量0x5d处的字节存储的是要读取的实际分区号(partition number)。
* 格式化程序或调用者应将其设置为正确的值。
* 对于软盘,它应该为0xff以代表整个驱动器。
*/
movb $0xff, %dh /* 引导分区号(这个0xff在0x5d处,见上面说明) */
cmpb $0xff, %dh /* 是软盘吗? */
jne 1f
movb $0, %dl /* 是的,让驱动器号= 0 */
1:
#endif
xorw %ax, %ax
movw $0x7c00, %bp /* bp = 0x7c00 */
#ifndef BOOTGRUB
movw %ax, %ds /* ds = 0 */
movw $0x1fe0, %ax
movw %ax, %es /* es = ax = 0x1fe0 */
movw %bp, %si
movw %bp, %di
movw $0x0100, %cx /* 从0000:7c00搬运一个扇区到1fe0:7c00 */
repz movsw
ljmp $0x1fe0, $(1f - Entry_32 + 0x7c00)
1:
#endif
movw %ax, %ss /* 栈和相对BP也向上移动 */
leaw -0x20(%bp), %sp
sti
movw %dx, 0x40(%bp) /* BIOS传递驱动器号到DL中 */
pushw %ss
movb $0x41, %ah
movw $0x55AA, %bx
int $0x13 /* 检查In13H扩展(即EBIOS)是否支持(41h),只有存在才可以调用int42 */
popw %ds
jc 1f /* No EBIOS */
cmpw $0xAA55, %bx
jne 1f /* No EBIOS */
testb $1, %cl
jz 1f /* No EBIOS */
/* EBIOS supported,见下面readDisk_32子函数将修改INT13指令的参数从AX=0201改为AX=4201*/
movb $0x42, (ebios_32 - 1 - Entry_32 + 0x7c00)
1:
pushw %ss
popw %es
/* 找出FAT和DATA区域的起始位置
* (修改EAX EDX,设置fat_start和data_start变量)
*/
xorl %eax, %eax
movl %eax, 0x44(%bp) /* 初始化缓冲区状态。*(bp + 44) = 0 */
/* 首先寻找fat_start */
movw 0x0e(%bp), %ax /* 取保留扇区数 */
addl 0x1c(%bp), %eax /* 加上隐藏扇区数 */
movl %eax, 0x48(%bp) /* 等于第一个FAT扇区的起始位置 */
movl %eax, 0x4c(%bp) /* 同时作为第一个数据扇区的位置的初始值(下面还要加上另一个数) */
/* 下一步寻找data_start */
movl 0x10(%bp), %eax /* fat数(number of fats), 不需要使用movzbl指令:对于fat32,0x11(%bp)所在的2个word是0 */
mull 0x24(%bp) /* 乘以每个fat的扇区数(这里EDX=0,所以下面只取EAX) */
addl %eax, 0x4c(%bp) /* 加上第一个FAT扇区的起始位置,则得到第一个DATA扇区的起始位置 */
/*
* 在根目录中搜索文件。
* 返回值:EAX=文件的第一个簇
*/
movl 0x2c(%bp), %eax /* 取根目录的簇 */
1:
pushl %eax /* 根目录所在簇入栈 */
call cluster_to_lba_32 /* 调用函数,将将簇号转换为绝对扇区号。返回值中EDX是每个簇的扇区数,EAX是扇区号 */
movw $(msg_BootError_32 - Entry_32 + 0x7c00), %si /* msg_BootError_32 = "NO GRLDR" */
jc boot_error_32 /* 遇到了EOC(EndOfChain) */
2:
lesw (loadseg_off_32 - Entry_32)(%bp), %bx /* 载入到loadseg:0,高位字放ES低位放指令中指定的BX */
call readDisk_32 /* 从磁盘中读一个扇区到ES:BX */
xorw %di, %di
/* 在目录中搜索内核文件(或者GRLDR)名,并找到文件所在的起始簇.
* 关于目录项(Directory Entry)见下方的图1
*/
3:
movw $11, %cx
movw $(filename_32 - Entry_32 + 0x7c00), %si /* ESI = "GRLDR " */
repz cmpsb
jz 1f /* 找到了,注意DI现在等于dirent+11 */
addw $0x20, %di /* 以32 Bytes划分为一个单位,每个单位称为一个目录项(Directory Entry)*/
andw $-0x20, %di /* 0xffe0 */
cmp 0x0b(%bp), %di /* 每个扇区字节数 */
jnz 3b /* 匹配下一个目录条目 */
decw %dx /* 最初DX存放每个簇的扇区数,遍历完一个扇区后递减 */
jnz 2b /* 遍历所有簇内的扇区 */
popl %eax /* 根目录所在簇出栈 */
call next_cluster_32
jmp 1b /* 读下个簇 */
#ifndef ALTERNATIVE_KERNEL
loadseg_off_32:
.word 0
.word LOADSEG
#endif
1:
/* 找到了目录项 */
pushw %es:(0x14-11)(%di) /* 文件起始簇号的高16位 */
pushw %es:(0x1a-11)(%di) /* 文件起始簇号的低16位 */
popl %eax /* 转为32位数 */
xorw %bx, %bx /* 读取内核(这里是GRLDR)文件到ES:BX=LOADSEG:0 */
/* read kernel */
2:
pushl %eax
call cluster_to_lba_32 /* 簇号转扇区号。调用后EDX是每个簇的扇区数,EAX是扇区号 */
jnc 1f
/* 遇到了EOC,循环结束(这里是上面2:和下面1:的循环出口)*/
#ifdef BOOTGRUB
movw 0x40(%bp), %dx /* boot_drive和boot_partition */
#else
movb 0x40(%bp), %bl /* FreeDOS 内核使用BL而不是DL存放引导驱动器号 */
#endif
pushw %dx /* for loading grub.exe */
ljmp *(loadseg_off_32 - Entry_32)(%bp) /* 跳到我们加载的地方执行(即执行GRLDR或者MSDOS内核) */
1:
call readDisk_32 /* 读一个扇区 */
decw %dx /* 开始的时候DX存放的是每簇扇区数 */
jnz 1b /* 遍历读取簇中的所有扇区 */
popl %eax
call next_cluster_32 /* 找到下一个簇 */
jmp 2b
/* 给定一个簇编号,找到FAT链中下一个簇的编号。
* 需要fat_start。
* input: EAX - 簇编号
* EDX = 0
* output: EAX - FAT链中下一个簇的编号。
* EDX = undefined
*/
next_cluster_32:
pushw %es
/* pushw %di */
pushw %bx /* 未使用EBX的高WORD */
#if 1
/* xorl %edx, %edx */
shll $2, %eax /* 32bit FAT */
movzwl 0x0b(%bp), %ebx /* 一个扇区中的字节数(512) */
divl %ebx /* 余数在EDX */
/* movw %dx, %di */
#else
shll $2, %eax /* 32bit FAT */
;xchgw %ax, %di /* movw %ax, %di */
movw %ax, %di
;shlw $2, %di /* 32bit FAT */
pushw %cx
movw 0x0b(%bp), %bx /* bytes per sector */
bsfw %bx, %cx
;decw %cx
;decw %cx
decw %bx
andw %bx, %di /* mask to sector size */
shrl %cl, %eax
popw %cx
#endif
addl 0x48(%bp), %eax /* add the first FAT sector number. */
/* EAX=absolute sector number */
movw $FATSEG, %bx
movw %bx, %es
xorw %bx, %bx
/* is it the last accessed and already buffered FAT sector? */
cmpl 0x44(%bp), %eax
jz 1f
movl %eax, 0x44(%bp) /* mark sector EAX as buffered */
call readDisk_32 /* read sector EAX to buffer */
1:
#if 1
//.byte 0x67, 0x26, 0x80, 0x62, 0x03, 0x0f
addr32 andb $0x0f, %es:3(%edx) /* mask out top 4 bits */
//.byte 0x67, 0x66, 0x26, 0x8b, 0x02
addr32 movl %es:(%edx), %eax /* read next cluster number */
#else
andb $0x0f, %es:3(%di) /* mask out top 4 bits */
movl %es:(%di), %eax /* read next cluster number */
#endif
popw %bx
/* popw %di */
popw %es
ret
/* 将簇号转换为绝对扇区号
* ... 如果EndOfChain则返回进位以表示错误! 需要data_start。
* 输入: EAX - 目标簇号
* 输出: EAX - 绝对扇区号
* EDX - [bsSectPerClust] (byte)
* carry clear
* (如果进位设置了而EAX/EDX不变则EndOfChain)
*/
cluster_to_lba_32:
cmpl $0x0ffffff8, %eax /* check End Of Chain */
cmc
jb 1f /* 如果EOC,进位存储 */
/* sector = (cluster-2) * clustersize + data_start */
decl %eax
decl %eax
movzbl 0x0d(%bp), %edx /* 每个簇的扇区数 */
pushw %dx /* 只有DX会变化 */
mull %edx /* 扇区数 * (簇号-2)(相乘的数字都很小所以EDX总是为0) */
popw %dx
addl 0x4c(%bp), %eax /* + data_start */
/* here, carry is cleared (unless parameters are wrong) */
1:
ret
/* 从磁盘中读一个扇区,使用LBA或CHS。
* input: EAX - 32位DOS扇区号
* ES:BX - 目标缓冲区(将用于填充一个扇区的数据)
* output: ES:BX指向最后读取的字节之后的一个字节。
* EAX - 下一扇区号
*/
readDisk_32:
/* 构建int 13h/42h或者int 13h/02h的参数*/
pushal
xorl %edx, %edx /* EDX:EAX = LBA */
pushl %edx /* 保存绝对扇区号的高32位到栈 */
pushl %eax /* 保存绝对扇区号的低32位到栈 */
pushw %es /* 保存缓冲区的节寄存器 */
pushw %bx /* 保存缓冲区的偏移 */
pushw $1 /* 读1扇区 */
pushw $16 /* 参数块的大小 */
xorl %ecx, %ecx
pushl 0x18(%bp) /* 高WORD每磁道扇区数,低WORD磁头数 */
popw %cx /* ECX = 每磁道扇区数 */
divl %ecx /* 绝对扇区数除以每磁道扇区数。余数(在磁道中的相对扇区号)在EDX中,商(磁道ID)在EAX中 */
incw %dx /* 在磁道中的相对扇区号 */
popw %cx /* ECX = 磁头数 (注意PUSHL一次,POPW两次完成赋值)*/
pushw %dx /* 入栈在磁道中的相对扇区号 */
xorw %dx, %dx /* EDX:EAX = 磁道数 * 总磁头数 + head */
divl %ecx /* 磁道ID在EAX中,这里除以磁头数得到该磁道所在的磁头号(商在EAX),以及在所在磁头中的相对磁道号(余数在EDX) */
xchgb %dl, %dh
popw %cx /* 出栈相对扇区号 */
xchgb %al, %ch /* lo 8bit cylinder should be in CH, AL = 0 */
shlb $6, %ah /* hi 2bit cylinder ... */
orb %ah, %cl /* ... should be in CL */
movw $0x201, %ax /* read 1 sector */
ebios_32: /* “ ebios_32-1”指向0x02,可以将其更改为0x42,见上面修改ebios_32-1值的代码 */
movw %sp, %si /* DS:SI指向硬盘寻址参数块(disk address packet) */
movb 0x40(%bp), %dl /* 硬盘驱动器号 */
pushw %es
pushw %ds
int $0x13 /* 调用int13h/42h或者int 13h/02h读磁盘 */
popw %ds
popw %es
popaw /* 从堆栈中删除参数块 */
popal
jc disk_error_32 /* disk read error, jc 1f if caller handles */
incl %eax /* next sector */
addw 0x0b(%bp), %bx /* bytes per sector */
jnc 1f /* 64K bound check */
pushw %dx
movw %es, %dx
addb $0x10, %dh /* add 1000h to ES */
/* here, carry is cleared */
movw %dx, %es
popw %dx
1:
/* carry stored on disk read error */
ret
// . = . - (. - readDisk_32)/91
msg_DiskReadError_32:
.ascii "disk error\0"
msg_BootError_32:
.ascii "No "
filename_32:
#ifdef BOOTGRUB
.ascii "GRLDR \0"
#else
.ascii "KERNEL SYS\0"
#endif
#ifdef ALTERNATIVE_KERNEL
filename_end_32:
. = Entry_32 + 0x1e8
loadseg_off_32:
.word 0
.word LOADSEG
. = Entry_32 + 0x1ec
boot_image_ofs_32:
.word (filename_32 - Entry_32)+(filename_end_32 - filename_32 - 1)*2048
#endif
. = Entry_32 + 0x1ee
disk_error_32:
movw $(msg_DiskReadError_32 - Entry_32 + 0x7c00), %si
boot_error_32:
/* prints string DS:SI (modifies AX BX SI) */
//print_32:
1:
lodsb (%si), %al /* get token */
//xorw %bx, %bx /* video page 0 */
movb $0x0e, %ah /* print it */
int $0x10 /* via TTY mode */
cmpb $0, %al /* end of string? */
jne 1b /* until done */
/* The caller will change this to
* ljmp $0x9400, $(try_next_partition - _start1)
*/
1: jmp 1b
. = Entry_32 + 0x1fc
.word 0, 0xAA55 /* Win9x uses all 4 bytes as magic value here */
. = Entry_32 + 0x200
1 | 0x00~0x02:3字节 | “EB5890”,跳转指令。“EB 58”,就是代表汇编语言中的“JMP 58”。 一条空的指令NOP(90H) |
2 | 0x03~0x0A:8字节 | 文件系统标志和版本号,这里为GRLDR |
3 | 0x0B~0x0C:2字节 | 每扇区字节数,512(0X02 00)。 |
4 | 0x0D~0x0D:1字节 | 每簇扇区数,8(0x08),这个值不能为0,而且必须是2的整数次方,比如1、2、4、8、16、32、64、128。规定每簇最大的容量不超过1024* 32,1024* 32/512=64 |
5 | 0x0E~0x0F:2字节 | 保留扇区数,38(0x00 26),那么就知道FAT1起始位置在38扇区。 |
6 | 0x10~0x10:1字节 | FAT表个数为2,另外一个是备份的。 |
7 | 0x11~0x12:2字节 | FAT32必须等于0,FAT12/FAT16为根目录中目录的个数; |
8 | 0x13~0x14:2字节 | FAT32必须等于0,FAT12/FAT16为扇区总数。 |
9 | 0x15~0x15:1字节 | 哪种存储介质,现在已经无意义。0xF8标准值即可移动存储介质。 |
10 | 0x16~0x17:2字节 | FAT32必须为0,FAT12/FAT16为一个FAT表所占的扇区数。 |
11 | 0x18~0x19:2字节 | 每磁道扇区数,只对于“CHS”(由磁头和柱面每 分割为若干磁道)的存储介质有效,18。 |
12 | 0x1A~0x1B:2字节 | 磁头数,只对CHS介质才有效,2 |
13 | 0x1C~0x1F:4字节 | EBR分区之前所隐藏的扇区数,0(0x00 00 00 00) |
14 | 0x20~0x23:4字节 | 此文件系统分区的总扇区数 |
15 | 0x24~0x27:4字节 | 每个FAT表占用扇区数 |
16 | 0x28~0x29:2字节 | 标记,此域FAT32 特有。 grldr引导代码不使用该word。 |
17 | 0x2A~0x2B:2字节 | FAT32版本号0.0,FAT32特有。grldr引导代码不使用该word。 |
18 | 0x2C~0x2F:4字节 | 根目录所在第一个簇的簇号,2。(虽然在FAT32文件系统 下,根目录可以存放在数据区的任何位置,但是通常情况下还是起始于2号簇)。 |
19 | 0x30~0x31:2字节 | FSINFO(文件系统信息扇区)扇区号是1,该扇区为操作系统提供关于空簇总数及下一可用簇的信息。 grldr引导代码不使用该word。 |
20 | 0x32~0x33:2字节 | 备份引导扇区的位置,通常为6。grldr引导代码不使用此word。 |
21 | 0x34~0x3F:12字节 | 保留的12个字节,设置为0。用于以后FAT 扩展使用。 |
22 | 0x40~0x40:1字节 | 与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已。 对于Grub4dos作用是保存引导设备的驱动器号。程序将DL写入该字节。调用者应在DL中设置驱动器号。我们假设所有BIOS在DL中传递正确的驱动器号。也就是说不支持错误的BIOS! |
23 | 0x41~0x41:1字节 | 与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已 。 对于Grub4dos用保存引导驱动器中此文件系统的分区号。引导代码会将分区号写入该字节。 请参阅下面的Entry + 0x5d。
|
24 | 0x42~0x42:1字节 | 扩展引导标志签名(必须为28h或29h才能被NT识别)0x29。与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已 |
25 | 0x43~0x46:4字节 | 卷序列号。通常为一个随机值。对于GRUB4DOS是0x0AC4AF63 |
26 | 0x47~0x51:11字节 | 卷标(ASCII码),如果建立文件系统的时候指定了卷标,会保存在此。对于GRUB4DOS默认是"NO NAME " |
27 | 0x52~0x59:8字节 | 文件系统格式的ASCII码”FAT32“ |
图1 目录项的内容。