GRUB4DOS(十二)適用於FAT32的分區引導扇區啓動代碼


  /* 這份代碼將編譯後將放到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 分區引導扇區頭部內容
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 目錄項的內容。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章