?? fat32引導扇區代碼.shtm.htm
字號:
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td width="10"></td>
<td><span id="ArticleContent1_ArticleContent1_lblContent"><p>;====================================================================<br>; <br>; FlyingDragon OS Boot Sector FOR FAT32<br>;<br>; Author: Jack<br>; V0.01 2005-07-23 17:39<br>; V0.02 2005-08-07 09:29<br>; <br>; Build : nasm -f bin FAT32.ASM -oFAT32.BIN <br>; <br>;====================================================================================<br>; <br>; BIOS在啟動中的角色:<br>; (1) BIOS裝載引導驅動器上的0扇區(CHS = 0:0:1)內容到內存線性地址7C00H處;<br>; (2) BIOS檢查所裝載的扇區是否有啟動標記(510、511字節分別為55H和AAH); <br>; (3) CPU寄存器DL被設置為分配給引導驅動器的驅動器號,00H為軟驅A,80H為硬盤C;<br>; (4) BIOS跳轉到其裝載的扇區中的代碼(即7C00H處),將控制權轉交給引導代碼。<br>; <br>; 引導代碼應該初始化以下寄存器:<br>; (1) DS:某些BIOS設置其值為0,某些設置其為40H,它應該被設置為(7C00H-BOOT_ORG)/16;<br>; 其中,BOOT_ORG為引導代碼的ORG值,該值通常為7C00H(這意味著DS應設置為0);<br>; (2) SS和SP(堆棧):這兩個寄存器的初始值依賴于BIOS;<br>; (3) CS個IP(通過JMP指令):大多數的BIOS進入啟動代碼的地址為0000:7C00H,但是某些<br>; BIOS卻跳轉到07C0:0000H。由于短跳轉和條件跳轉是IP相關的,因此如果沒有使用<br>; 遠跳轉或者絕對跳轉,則不需要重置CS和IP;然而,DS仍舊必須是正確的值。<br>; <br>;=====================================================================================<br>; <br>; 常規內存( 0000 0000H - 000F FFFFH,即0-1MB )在系統啟動時的使用情況<br>; <br>;=====================================================================================<br>; <br>; ---------------------------------<br>; | 0000 0000 - 0000 03FF | 1024B IDT read only<br>; |-------------------------------|<br>; | 0000 0400 - 0000 04FF | 256B BIOS Data Area , read only <br>; |-------------------------------|<br>; | 0000 0500 - 0000 7BFF |* 30464B Free Memory , read/write (29.75KB) <br>; |------------------------------ |<br>; | 0000 7C00 - 0000 7DFF | 512B Boot Sector , read/write <br>; |------------------------------ |<br>; | 0000 7E00 - 0000 7FFF | 512B Free Memory , read /write<br>; |------------------------------ |<br>; | 0000 8000 - 0009 FBFF | 607KB Free Memory , read / write( 32K - 639KB ) <br>; |------------------------------ |<br>;
| 0009 FC00 - 0009 FFFF
|** 1KB EBDA extended BIOS data
area <br>; |------------------------------ |<br>; | 000A 0000 - 000A FFFF | 64KB Video Memory<br>; |------------------------------ |<br>; | 000B 0000 - 000B 7FFF | 32KB Mono Video Text Memory <br>; |------------------------------ |<br>; | 000B 8000 - 000B FFFF | 32KB Color Video Text Memory<br>; |------------------------------ |<br>; | 000C 0000 - 000C 7FFF | 32KB Video BIOS , read only<br>; |------------------------------ |<br>; | 000C 8000 - 000E FFFF | 160KB Adapter ROM,read only<br>; |------------------------------ |<br>; | 000F 0000 - 000F FFFF | 64KB System BIOS, read only<br>; |------------------------------ |<br>; | 0010 0000 - 0010 FFEF |***64KB-16 High Memory Area,read/write ( 1MB開始處 )<br>; |------------------------------ |<br>; | 0010 FFF0 - | Free Extended Memory, read/write <br>; |------------------------------ |<br>; <br>; * 空閑內存實際并非從 0000 0500處開始,BIOS數據區實際上會利用從0000 0500開始的少量字節,例如<br>; 00000500處保存的是打印屏幕狀態,當按下打印屏幕(PrintScreen)鍵時,低級鍵盤BIOS初始化打印屏<br>; 幕功能,鍵盤BIOS觸發中斷5打印屏幕處理程序。正因為BIOS數據區越過了256B的界限,因此DOS實際<br>; 上是從0000 0522開始裝載的。為保險起見,可從0000 0600開始利用空閑內存。(1.5K - 31K 29.5KB)<br>; <br>; ** 有些機器上沒有這段BIOS擴展數據區。<br>; <br>; *** 如果沒有使用擴展高端內存區域程序(例如Emm386.exe),則從0010 0000 (1MB )開始的內存都是可用的。<br>; <br>; <br>;=====================================================================================<br>; </p><p>BITS 16 ; 生成16位代碼而不是32位代碼<br>SECTION .TEXT ; 代碼段<br>ORG 7C00H ; 指定程序被裝入內存的起始位置</p><p>;====================================================================<br>; <br>; 宏和常量定義<br>; <br>;====================================================================<br>? EQU 0 ; NASM不支持DW ?這樣的語法,可以使用這樣的定義<br> ; 模擬,以使代碼的可讀性更強<br>DATA_BUF_SEG EQU 0200H ; 用于讀取根目錄或文件內容的緩沖區(8K) 段地址<br>DATA_BUF_OFF EQU 2000H<br>STACK_ADDR EQU 7BD0H ; 堆棧棧頂(注意:堆棧大小約為20K) <br>OSLOADER_ADDR EQU 8000H ; FDOSLDR.BIN放入內存中的起始位置,這就意味著<br> ; 裝載程序及相關資源的尺寸不能超過608K<br> ; 8000H - A000H (32K - 640K )<br>OSLOADER_SEG EQU 0800H ; 起始段地址 <br>SECOND_SECTOR EQU 03H ; 第二個引導扇區的扇區號(第四個扇區)<br>SECOND_ADDR EQU 7E00H ; 第二個引導扇區的裝載位置</p><p>;====================================================================<br>; 用堆棧保存若干中間變量( SS = 0 BP = 7C00H )<br>;====================================================================<br>FAT_START_SECTOR EQU 4 ; FAT表的起始扇區號 DWORD<br>ROOT_START_SECTOR EQU 8 ; 根目錄的起始扇區號 DWORD<br>DATA_START_SECTOR EQU 12 ; 數據區起始扇區號 DWORD<br>FAT_ENTRY_SECTORS EQU 14 ; FAT表所占的扇區數 WORD<br>ROOT_ENTRY_SECTORS EQU 16 ; 根目錄所占的扇區數 WORD<br>DIR_PER_SECTOR EQU 17 ; 每個扇區所容納的目錄 BYTE<br>DISK_EXT_SUPPORT EQU 18 ; 磁盤是否支持擴展BIOS BYTE<br>CURRENT_CLUSTER EQU 40 ; 當前正在處理的簇號 DWORD</p><p><br>;==================================================================== <br>; 擴展磁盤服務所使用的地址包<br>;====================================================================<br>DAP_SECTOR_HIGH EQU 24 ; 起始扇區號的高32位 ( 每次調用需要重置 ) DWORD<br>DAP_SECTOR_LOW EQU 28 ; 起始扇區號的低32位 ( 每次調用需要重置 ) DWORD<br>DAP_BUFFER_SEG EQU 30 ; 緩沖區段地址 ( 每次調用需要重置 ) WORD<br>DAP_BUFFER_OFF EQU 32 ; 緩沖區偏移 ( 每次調用需要重置 ) WORD <br>DAP_RESERVED2 EQU 33 ; 保留字節<br>DAP_READ_SECTORS EQU 34 ; 要處理的扇區數(1 - 127 )<br>DAP_RESERVED1 EQU 35 ; 保留字節<br>DAP_PACKET_SIZE EQU 36 ; 包的大小為16字節</p><p>;====================================================================<br>; <br>; 目錄項結構(每個結構為32字節)<br>; <br>;====================================================================<br>OFF_DIR_NAME EQU 0 ; 目錄項的偏移 BYTE[11]<br>OFF_DIR_ATTRIBUTE EQU 11 ; 目錄屬性 BYTE<br>OFF_NT_RESERVED EQU 12 ; 保留屬性 BYTE<br>OFF_CREATE_TIME_HUNDREDTH EQU 13 ; 創建時間 BYTE<br>OFF_CREATE_TIME EQU 14 ; 創建時間 WORD<br>OFF_CREATE_DATE EQU 16 ; 創建時間 WORD<br>OFF_LAST_ACCESS_DATE EQU 18 ; 上次訪問時間 WORD<br>OFF_START_CLUSTER_HIGH EQU 20 ; 起始簇號高位 WORD<br>OFF_LAST_UPDATE_TIME EQU 22 ; 上次更新時間 WORD<br>OFF_LAST_UPDATE_DATE EQU 24 ; 上次更新時間 WORD<br>OFF_START_CLUSTER_LOW EQU 26 ; 起始簇號低位 WORD<br>OFF_FILE_SIZE EQU 28 ; 文件尺寸 DWORD</p><p>; 相關常量<br>DIR_NAME_DELETED EQU 0E5H ; 該項已經被刪除<br>DIR_NAME_FREE EQU 00H ; 該項是空閑的(其后也是空閑的)<br>DIR_NAME_DOT EQU 2EH ; 特殊目錄 . 或 ..<br>DIR_NAME_SPACE EQU 20H ; 不允許的字符<br>DIR_ENTRY_SIZE EQU 32 ; 每個目錄項的尺寸,其結構如上所示 </p><p>;文件屬性<br>DIR_ATTR_READONLY EQU 01H ; 只讀文件<br>DIR_ATTR_HIDDEN EQU 02H ; 隱藏文件<br>DIR_ATTR_SYSTEM EQU 04H ; 系統文件<br>DIR_ATTR_VOLUME EQU 08H ; 卷標號(只可能出現在根目錄中)<br>DIR_ATTR_SUBDIR EQU 10H ; 子目錄<br>DIR_ATTR_ARCHIVE EQU 20H ; 歸檔屬性<br>DIR_ATTR_LONGNAME EQU 0FH ; 長文件名<br>DIR_ATTR_LONGNAME_MASK EQU 3FH ; 長文件名掩碼</p><p>; 簇屬性<br>CLUSTER_MASK EQU 0FFFFFFFH ; 簇號掩碼(FAT32=>FAT28)<br>CLUSTER_FREE EQU 00000000H ; 簇是空閑的<br>CLUSTER_RESERVED EQU 00000001H ; 簇是保留的<br>CLUSTER_MIN_VALID EQU 00000002H ; 最小有效簇號<br>CLUSTER_MAX_VALID EQU 0FFFFFF6H ; 最大有效簇號<br>CLUSTER_BAD EQU 0FFFFFF7H ; 壞簇<br>CLUSTER_LAST EQU 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一個簇</p><p>;====================================================================<br>;<br>; 啟動扇區(512字節)<br>;<br>;====================================================================<br>_ENTRY_POINT: </p><p>; 3字節的跳轉指令<br> JMP SHORT _BOOT_CODE ; 跳轉到真正的引導代碼<br> NOP ; 空指令以保證字節數為3</p><p>; 8字節的OEMName<br>OEMName DB "FDOS1.00"</p><p>;====================================================================<br>; <br>; BPB( BIOS Parameter Block ) <br>; <br>;====================================================================<br>BytesPerSector DW ? ; 每個扇區的字節數 (512 1024 2048 4096)<br>SectorsPerCluster DB ? ; 每個簇的扇區數 ( 1 2 4 8 16 32 64 128 )<br> ; 兩者相乘不能超過32K(簇最大大小)<br>ReservedSectors DW ? ; 從卷的第一個扇區開始的保留扇區數目;<br> ; 該值不能為0,對于FAT12/FAT16,該值通常為1;<br> ; 對于FAT32,典型值為32;<br>NumberOfFATs DB ? ; 卷上FAT數據結構的數目,該值通常應為2<br>RootEntries DW ? ; 對于FAT12/FAT16,該值表示32字節目錄項的數目;<br> ; 對于FAT32,該值必須為0;<br>NumberOfSectors16 DW ? ; 該卷上的扇區總數,該字段可以為0,如果該字段<br> ; 為0,則NumberOfSectors32不能為0;對于FAT32,<br> ; 該字段必須為0<br>MediaDescriptor DB ? ; 介質類型<br>SectorsPerFAT16 DW ? ; 該字段標識一個FAT結構占有的扇區數(FAT12/FAT16),<br> ; 對于FAT32卷,該字段必須為0;<br>SectorsPerTrack DW ? ; 用于INT 0x13中斷的每個磁道的扇區數<br>HeadsPerCylinder DW ? ; 用于INT 0x13中斷的每個柱面的磁頭數<br>HiddenSectors DD ? ; 包含該FAT卷的分區之前的隱藏扇區數<br>NumberOfSectors32 DD ? ; 該字段包含該卷上的所有扇區數目,對于FAT32,該字段<br> ; 不為0;FAT12/FAT16可根據實際大小是否超過65536個扇<br> ; 區數決定是否采用該字段;</p><p>;====================================================================<br>; <br>; EBPB ( Extended BIOS Parameter Block )<br>; <br>;====================================================================<br>SectorsPerFAT32 DD ? ; 對于FAT32,該字段包含一個FAT的大小,而SectorsPerFAT16<br> ; 字段必須為0;<br>ExtFlags DW ? ; 標志 <br>FSVersion DW ? ; 這是文件系統的版本,高字節為主版本,低字節為次版本;<br>RootDirectoryStart DD ? ; 根目錄的起始簇號,通常為2;<br>FSInfoSector DW ? ; FSINFO結構在FAT32卷保留區域的扇區號 <br>BackupBootSector DW ? ; 如果該字段不為0,則表示在保留區域保存的啟動記錄的扇區號<br> ; 通常為6,不推薦其他值;<br>Reserved1 TIMES 12 DB ? ; 保留字段,格式化程序應將該字段清0<br>DriveNumber DB ? ; 用于INT 0x13的驅動器號,0x00為軟盤,0x80為硬盤<br>NTReserved DB ? ; 保留字節(用于Windows NT,即NTFS),對于FAT文件<br> ; 系統,應始終為0<br>BootSignature DB 29H ; 擴展引導標志(值為0x29)<br>VolumeId DD ? ; 卷的序列號<br>VolumeLabel times 11 DB ? ; 卷標號,該字段與根目錄中的11字節卷標相同<br> ; NASM目前尚不支持DUP語法<br>FileSystemType DB 'FAT32 ' ; 文件系統類型</p><p>;====================================================================<br>;<br>; 真正的啟動代碼從這開始( 偏移:0x3E ) <br>; 其功能是搜索磁盤的根目錄,查找FDOSLDR.BIN文件,將其讀入內存并運行。<br>;<br>;====================================================================<br>_BOOT_CODE:</p><p> ; 初始化相關寄存器及標志位<br> CLI ; 先關掉中斷<br> CLD ; 方向為向前遞增<br> XOR AX,AX ; AX = 0<br> MOV DS,AX ; 設置數據段寄存器 DS:SI<br> MOV ES,AX ; 設置附加段寄存器 ES:DI<br> MOV SS,AX ; 設置堆棧段寄存器<br> MOV BP,7C00H ; 設置基址寄存器<br> MOV SP,STACK_ADDR ; 設置堆棧棧頂<br> STI ; 允許中斷</p><p> ;====================================================================<br> ; 保存啟動的磁盤編號<br> ;====================================================================<br> MOV [DriveNumber],DL; 該值由BIOS設置,如果是從USB啟動,該值為0x80<br> ; 即為第一個硬盤的編號,該值將用于后續的磁盤<br> ; 讀取調用</p><p><br> ;==================================================================== <br> ; 準備FAT32文件系統常用的常數,以便后面的操作<br> ;====================================================================<br> ;<br> ; [隱藏扇區][保留扇區][FAT][DATA]<br> ;<br> ;====================================================================<br> <br> ;==================================================================== <br> ; 檢查是否支持磁盤中斷INT 13H的擴展<br> ;====================================================================<br> MOV BYTE [BP - DISK_EXT_SUPPORT],00H ; 00H表示不支持磁盤擴展<br> MOV DL,[DriveNumber]<br> MOV AH,41H<br> MOV BX,055AAH<br> INT 13H<br> JC _NO_DISK_EXTENSION ; 如果失敗,進位標志為1或者BX值不對( AA55 or 55AA )<br> <br> ; 設置磁盤支持擴展中斷標志<br> MOV BYTE [BP - DISK_EXT_SUPPORT],01H ; 01H表示支持磁盤擴展</p><p>; 不支持磁盤擴展<br>_NO_DISK_EXTENSION:<br> <br> ; 檢查是否為FAT32分區<br> ; 對于FAT32分區,其根目錄項為0<br> CMP WORD [RootEntries],0<br> JNZ NEAR _DISK_ERROR<br> <br> ; 檢查保留扇區數(保留扇區必須大于等于4,我們將<br> ; 第二個扇區的代碼存在第四個扇區)<br> CMP WORD [ReservedSectors],4<br> JB NEAR _DISK_ERROR <br> <br> ; 檢查每FAT扇區數<br> ; SectorsPerFAT16 == 0<br> ; SectorsPerFAT32 != 0<br> CMP WORD [SectorsPerFAT16],0<br> JNZ NEAR _DISK_ERROR<br> CMP DWORD[SectorsPerFAT32],0<br> JZ NEAR _DISK_ERROR<br> <br> ; 計算每個扇區包含的目錄項 ( 512/32 = 16 = 10H )<br> MOV AX,WORD [BytesPerSector]<br> MOV CL,DIR_ENTRY_SIZE<br> DIV CL ; AH:AL = BytesPerSector / 32 ( AH = Remainder = 0 )<br> MOV BYTE [BP - DIR_PER_SECTOR],AL ; AL = DirEntriesPerSector<br> <br> ; FAT起始扇區<br> ; FAT起始扇區 = Hidden+Reserved<br> MOV AX ,WORD [ReservedSectors]<br> CWD ; AX => DX : AX<br> ADD AX, WORD [HiddenSectors]<br> ADC DX, WORD [HiddenSectors+2] <br> MOV WORD[ BP - FAT_START_SECTOR ],AX <br> MOV WORD[ BP - FAT_START_SECTOR+2],DX <br> <br> <br> ; FAT表所占的扇區數<br> ; FAT_SECTORS = NumberOfFAT * SectorsPerFAT<br> XOR EAX,EAX<br> MOV AL, BYTE [NumberOfFATs] ; FAT的數目<br> MOV EBX,DWORD [SectorsPerFAT32]<br> MUL EBX ; 乘積放入 EDX:EAX<br> MOV DWORD [ BP - FAT_ENTRY_SECTORS ] , EAX<br> <br> ; 計算數據區起始扇區<br> ADD EAX ,DWORD[ BP - FAT_START_SECTOR ]<br> MOV DWORD [ BP - DATA_START_SECTOR ],EAX <br> <br> <br> ;====================================================================<br> ;<br> ; 初始化DiskAddressPacket<br> ; 使用時只需要修改字段:DATA_BUFFER_OFF DATA_BUFFER_SEG <br> ; DAP_SECTOR_LOW DAP_SECTOR_HIGH<br> ;<br> ;====================================================================<br> MOV DWORD [BP - DAP_SECTOR_HIGH ],00H<br> MOV BYTE [BP - DAP_RESERVED1 ],00H<br> MOV BYTE [BP - DAP_RESERVED2 ],00H<br> MOV BYTE [BP - DAP_PACKET_SIZE ],10H<br> MOV BYTE [BP - DAP_READ_SECTORS],01H<br> MOV WORD [BP - DAP_BUFFER_SEG ],00H<br> MOV BYTE [BP - DAP_READ_SECTORS],01H ; 每次只讀取一個扇區<br> <br> ; 裝載第二個啟動扇區 <br> MOV WORD [BP - DAP_BUFFER_OFF ],SECOND_ADDR <br> MOV EAX , DWORD[HiddenSectors]<br> ADD EAX , SECOND_SECTOR<br> MOV DWORD [BP - DAP_SECTOR_LOW ],EAX<br> CALL ReadSector<br> <br> <br> ; 下面開始查找根目錄并且裝載FDOSLDR.BIN<br> JMP _SEARCH_LOADER<br> <br>;====================================================================<br>; 錯誤處理<br>;====================================================================<br>_MISSING_LOADER: ; 顯示沒有裝載程序<br> MOV SI,MessageMissLoader<br> CALL ShowMessage<br> JMP _REBOOT</p><p>_DISK_ERROR: ; 顯示磁盤錯誤信息<br> MOV SI,MessageDiskError<br> CALL ShowMessage</p><p>_REBOOT: ; 重啟<br> MOV SI,MessageRestart<br> CALL ShowMessage<br> <br> ; 調用鍵盤中斷,等待用戶按鍵<br> MOV AH,00H<br> INT 16H<br> <br> ; 重啟計算機<br> INT 19H </p><p> ; 死循環<br> JMP $</p><p><br>;====================================================================<br>; <br>; 子過程<br>; <br>;====================================================================</p><p>;====================================================================<br>; <br>; 讀取一個磁盤扇區<br>; 輸入: 已經設置了DAP中相應的字段<br>; 限制: 不能讀取超過一個簇的內容 <br>; <br>;====================================================================<br>ReadSector:</p><p> PUSHA ; 保存寄存器<br> <br> ; 檢查是否使用擴展方式<br> CMP BYTE [BP - DISK_EXT_SUPPORT],00H<br> JZ .NoDiskExtension<br> <br>;====================================================================<br>; INT 13H AH = 42H 擴展磁盤調用<br>;====================================================================<br> ; 每次讀取一個扇區<br> MOV AH,42H ; 功能號 <br> LEA SI ,[BP - DAP_PACKET_SIZE] ; 地址包地址</p><p> ; 驅動器號<br> MOV DL ,[DriveNumber] ; 驅動器號<br> INT 13H<br> JC _DISK_ERROR ; 讀取失敗<br> JMP _READ_SECTOR_OK ; 讀取成功</p><p>;====================================================================<br>; <br>; INT 13H <br>; AH = 2 柱面號:0 - 1023<br>; AL = 要讀取的扇區數 磁頭號:0 - 255 <br>; CH = 柱面號低8位 扇區號:1 - 63 <br>; CL = 柱面號高2位 : 6位扇區號 <br>; DH = 磁頭號 <br>; DL = 驅動器號<br>;<br>; LBA = ( (cylinder * HeadsPerCylinder + heads ) * SectorsPerTrack ) + sector - 1<br>;<br>; Sector = LBA % SectorsPerTrack +1<br>; Head = ( LBA / SectorsPerTrack ) % HeadsPerCylinder<br>; Cylinder= ( LBA / SectorsPerTrack ) / HeadsPerCylinder<br>;<br>;==================================================================== <br>.NoDiskExtension:<br> <br> ;==================================================================== <br> ; 首先需要將扇區號轉換為CHS地址<br> ;====================================================================<br> <br> ; 首先計算扇區號<br> MOV AX,WORD [ BP - DAP_SECTOR_LOW ]<br> MOV DX,WORD [ BP - DAP_SECTOR_LOW+2 ]<br> DIV WORD [SectorsPerTrack ] ; AX = LBA / SectorsPerTrack DX = LDA % SectorsPerTrack<br> MOV CX,DX<br> INC CX ; CL = Sector<br> AND CL,3FH ; 1-63</p><p> ; 再計算磁頭號和柱面號<br> XOR DX,DX ; DX:AX = LBA / SectorsPerTrack<br> DIV WORD [HeadsPerCylinder] ; DX = ( LBA/SectorsPerTrack ) % HeadsPerCylinder = Head<br> ; AX = ( LBA/SectorsPerTrack ) / HeadsPerCylinder = Cylinder<br> MOV CH,AL ; 柱面號低8位<br> SHL AH,6<br> OR CL,AH ; CL = 柱面號高2位:6位扇區號<br> MOV DH,DL ; DL = 磁頭號<br> <br> ; 準備讀取磁盤 <br> MOV AX,WORD[ BP - DAP_BUFFER_SEG ]<br> MOV ES,AX<br> MOV BX,WORD[ BP - DAP_BUFFER_OFF ]<br> MOV AX ,0201H ; 每次只讀取一個扇區<br> <br> ; 驅動器號<br> MOV DL ,[DriveNumber] ; 驅動器號<br> INT 13H<br> JC _DISK_ERROR ; 讀取失敗</p><p>_READ_SECTOR_OK:<br> POPA ; 恢復寄存器 <br> RET <br> <br>;====================================================================<br>; <br>; 顯示一個字符串<br>; 輸入:<br>; DS:SI = 字符串的起始地址(以NULL結束)<br>; <br>;====================================================================<br>ShowMessage:<br> LODSB ; AL = DS:[SI] SI = SI+1<br> OR AL,AL ; 檢測是否遇到NULL字符串<br> JZ _SHOW_END<br> MOV AH,0EH<br> MOV BX,07H<br> INT 10H<br> JMP ShowMessage</p><p>_SHOW_END:<br> RET </p><p>;====================================================================<br>; 數據區<br>;====================================================================<br>LoaderName db "FDOSLDR BIN" ; 第二階段啟動程序 FDOSLDR.BIN<br>MessageMissLoader db "NO FDOSLDR.BIN.",0DH,0AH,00H ; 沒有找到裝載程序<br>MessageDiskError db "Disk Error.",0DH,0AH,00 ; 磁盤錯誤消息<br>MessageRestart db "Press any key to restart." ,0DH,0AH,00 ; 提示重啟消息</p><p>;====================================================================<br>; 扇區最后的標記字節(NASM不支持重復ORG)<br>;====================================================================<br>Padding TIMES 510-($-$$) db 00H<br>SectorSignature dw 0AA55H</p><p></p><p>;====================================================================<br>; 第二個扇區的代碼(該代碼位于分區的第四個扇區)<br>;====================================================================</p><p>;====================================================================<br>; 查找根目錄,檢查是否有 FDOSLDR.BIN文件<br>;====================================================================<br>_SEARCH_LOADER: </p><p><br> ; 設置緩沖區<br> MOV WORD [ BP - DAP_BUFFER_OFF ], DATA_BUF_OFF ; 0000:1000H<br> <br> ; 根目錄起始扇區號<br> MOV EAX,DWORD[RootDirectoryStart]<br> MOV DWORD[ BP - CURRENT_CLUSTER ],EAX</p><p>; 檢查下一個簇<br>_NEXT_ROOT_CLUSTER: </p><p> ; 根據簇號計算扇區號<br> DEC EAX<br> DEC EAX ; EAX = EAX - 2<br> XOR EBX,EBX <br> MOV BL, BYTE[ SectorsPerCluster]<br> MUL EBX <br> ADD EAX,DWORD[ BP- DATA_START_SECTOR]<br> MOV DWORD[ BP - DAP_SECTOR_LOW ], EAX<br> MOV DL,[SectorsPerCluster]</p><p>; 檢查下一個扇區<br>_NEXT_ROOT_SECTOR:<br> <br> ; 依次讀取每個根目錄扇區,檢查是否存在FDOSLDR.BIN文件<br> CALL ReadSector<br> <br> ; 檢查該扇區內容<br> MOV DI,DATA_BUF_OFF<br> MOV BL,BYTE [ BP - DIR_PER_SECTOR]</p><p>; 檢查每一個目錄項<br>_NEXT_ROOT_ENTRY:<br> CMP BYTE [DI],DIR_NAME_FREE<br> JZ _MISSING_LOADER ; NO MORE DIR ENTRY<br> <br> ; 檢查是否裝載程序<br> PUSH DI ; 保存DI<br> MOV SI,LoaderName<br> MOV CX,11<br> REPE CMPSB <br> JCXZ _FOUND_LOADER ; 裝載Loader并運行<br> <br> ; 是否還有下一個目錄項(內層循環)<br> POP DI<br> ADD DI,DIR_ENTRY_SIZE<br> DEC BL <br> JNZ _NEXT_ROOT_ENTRY<br> <br> ; 檢查是否還有下一個扇區可讀(外層循環)<br> DEC DL<br> JZ _CHECK_NEXT_ROOT_CLUSTER<br> INC DWORD [ BP - DAP_SECTOR_LOW ] ; 增加扇區號<br> JMP _NEXT_ROOT_SECTOR <br> <br>; 檢查下一個簇<br>_CHECK_NEXT_ROOT_CLUSTER:</p><p> ; 計算FAT所在的簇號和偏移 <br> ; FatOffset = ClusterNum*4<br> XOR EDX,EDX<br> MOV EAX,DWORD[BP - CURRENT_CLUSTER]<br> SHL EAX,2<br> XOR ECX,ECX<br> MOV CX,WORD [ BytesPerSector ]<br> DIV ECX ; EAX = Sector EDX = OFFSET<br> ADD EAX,DWORD [BP - FAT_START_SECTOR ]<br> MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX <br> <br> ; 讀取扇區<br> CALL ReadSector<br> <br> ; 檢查下一個簇<br> MOV DI,DX<br> ADD DI,DATA_BUF_OFF<br> MOV EAX,DWORD[DI] ; EAX = 下一個要讀的簇號<br> AND EAX,CLUSTER_MASK<br> MOV DWORD[ BP - CURRENT_CLUSTER ],EAX<br> CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H,則意味著沒有更多的簇了<br> JB _NEXT_ROOT_CLUSTER<br> JMP _MISSING_LOADER</p><p>;====================================================================<br>; 裝載FDOSLDR.BIN文件<br>;====================================================================<br>_FOUND_LOADER:<br> ; 目錄結構地址放在DI中<br> POP DI<br> XOR EAX,EAX<br> MOV AX,[DI+OFF_START_CLUSTER_HIGH] ; 起始簇號高32位<br> SHL AX,16<br> MOV AX,[DI+OFF_START_CLUSTER_LOW] ; 起始簇號低32位<br> MOV DWORD[ BP - CURRENT_CLUSTER ],EAX<br> MOV CX, OSLOADER_SEG ; CX = 緩沖區段地址 <br> <br> <br>_NEXT_DATA_CLUSTER:<br> <br> ; 根據簇號計算扇區號<br> DEC EAX<br> DEC EAX ; EAX = EAX - 2<br> XOR EBX,EBX <br> MOV BL, BYTE[ SectorsPerCluster]<br> MUL EBX <br> ADD EAX,DWORD[ BP- DATA_START_SECTOR]<br> MOV DWORD[ BP - DAP_SECTOR_LOW ], EAX<br> MOV DL,[SectorsPerCluster]</p><p> ; 設置緩沖區<br> MOV WORD [ BP - DAP_BUFFER_SEG ],CX<br> MOV WORD [ BP - DAP_BUFFER_OFF ],00H<br> <br> ; 每個簇需要讀取的扇區數<br> MOV BL , BYTE [SectorsPerCluster]</p><p>_NEXT_DATA_SECTOR:<br> ; 讀取簇中的每個扇區(內層循環)<br> ; 注意 : 通過檢查文件大小,可以避免讀取最后一個不滿簇的所有大小<br> ; 讀取數據扇區<br> CALL ReadSector<br> <br> ; 更新地址,繼續讀取<br> MOV AX, WORD [BytesPerSector]<br> ADD WORD [BP - DAP_BUFFER_OFF],AX <br> INC DWORD [BP - DAP_SECTOR_LOW] ; 遞增扇區號<br> DEC BL ; 內層循環計數<br> JNZ _NEXT_DATA_SECTOR<br> <br> <br> ; 檢查下一個簇<br> <br> ; 更新讀取下一個簇的緩沖區地址<br> MOV CL,BYTE [ SectorsPerCluster ]<br> MOV AX ,WORD [BytesPerSector]<br> SHR AX ,4<br> MUL CL<br> ADD AX ,WORD [ BP - DAP_BUFFER_SEG ] <br> MOV CX,AX ; 保存下一個簇的緩沖區段地址<br> <br> ;====================================================================<br> ;<br> ; 檢查是否還有下一個簇(讀取FAT表的相關信息)<br> ; LET N = 數據簇號<br> ; THUS FAT_BYTES = N*4 (FAT32)<br> ; FAT_SECTOR = FAT_BYTES / BytesPerSector<br> ; FAT_OFFSET = FAT_BYTES % BytesPerSector<br> ;<br> ;====================================================================<br> <br> ; 計算FAT所在的簇號和偏移 <br> MOV EAX,DWORD [BP - CURRENT_CLUSTER]<br> XOR EDX,EDX<br> SHL EAX,2<br> XOR EBX,EBX<br> MOV BX,WORD [ BytesPerSector ]<br> DIV EBX ; EAX = Sector EDX = Offset<br> <br> ; 設置緩沖區地址<br> ADD EAX,DWORD [BP - FAT_START_SECTOR ]<br> MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX <br> MOV WORD [BP - DAP_BUFFER_SEG ], 00H <br> MOV WORD [BP - DAP_BUFFER_OFF ], DATA_BUF_OFF ; 0000:1000H</p><p> ; 讀取扇區<br> CALL ReadSector<br> <br> ; 檢查下一個簇<br> MOV DI,DX<br> ADD DI,DATA_BUF_OFF<br> MOV EAX,DWORD[DI] ; EAX = 下一個要讀的簇號<br> AND EAX,CLUSTER_MASK<br> MOV DWORD[ BP - CURRENT_CLUSTER ],EAX<br> CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H,則意味著沒有更多的簇了<br> JB _NEXT_DATA_CLUSTER</p><p>;讀取完畢<br>_RUN_LOADER: </p><p> ; 運行FDOSLDR.BIN<br> MOV DL,[DriveNumber]<br> JMP 00:OSLOADER_ADDR</p><p>;====================================================================<br>; 調試例程<br>;====================================================================<br>%IFDEF DEBUG<br>;====================================================================</p><p>;====================================================================<br>; <br>; 顯示一個字符<br>; 輸入: AL = 待顯示字符<br>;<br>;====================================================================<br>PrintChar:<br> PUSH BX<br> MOV AH,0EH<br> MOV BX,7<br> INT 10H<br> POP BX<br> RET<br> <br>;====================================================================<br>%ENDIF ; DEBUG<br>;====================================================================</p><p><br>;====================================================================<br>; 扇區最后的標記字節(NASM不支持重復ORG)<br>;====================================================================<br>SecondPadding TIMES 1022-($-$$) db 00H<br>SecondSignature DW 0AA55H</p><p>;====================================================================<br>; 代碼結束<br>;====================================================================</p><p> </p></span>
<br>
<div style="font-size: 14px; line-height: 25px;"><strong>作者Blog:</strong><a id="ArticleContent1_ArticleContent1_AuthorBlogLink" href="http://blog.csdn.net/jackjoy/" target="_blank">http://blog.csdn.net/jackjoy/</a></div>
<div style="font-size: 14px; line-height: 25px; color: rgb(153, 0, 0);"><strong>相關文章</strong></div>
<table id="ArticleContent1_ArticleContent1_RelatedArticles" border="0" cellspacing="0">
<tbody><tr>
<td>
<a href="http://dev.csdn.net/article/78/78564.shtm">主引導扇區代碼(MBR)</a>
</td>
</tr><tr>
<td>
<a href="http://dev.csdn.net/article/78/78563.shtm">FAT32引導扇區代碼</a>
</td>
</tr><tr>
<td>
<a href="http://dev.csdn.net/article/78/78491.shtm">NTFS文件系統啟動扇區代碼(簡化版)</a>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
<a name="#Comment"></a>
<table border="0" cellpadding="0" width="100%">
<tbody><tr>
<td>
<table align="center" bgcolor="#006699" border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody><tr bgcolor="#006699">
<td id="white" align="center" bgcolor="#006699" width="556">
<font color="#ffffff">對該文的評論</font> </td>
</tr>
</tbody></table>
<div align="right">
<a id="CommnetList1_CommnetList1_Morelink" href="http://comment.csdn.net/Comment.aspx?c=2&s=78563">【評論】</a>
<a id="CommnetList1_CommnetList1_Hyperlink1" href="javascript:window.close();">【關閉】</a>
<a href="mailto:webmaster@csdn.net">【報告bug】</a>
</div>
<br>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
</form>
<!-- 版權 -->
<div align="center">
<script language="JavaScript" type="text/javascript" src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/footer_gb.js"></script><div id="CFBig" align="center"> <hr align="center"> <div id="CFContent"> <div id="CFBiaoShi"><a href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><img src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/BiaoShi.gif" alt="" border="0" height="48" width="40"></a></div> <p><a href="http://www.csdn.net/intro/intro.asp?id=2">網站簡介</a>-<a href="http://www.csdn.net/intro/intro.asp?id=5">廣告服務</a>-<a href="http://www.csdn.net/map/map.shtm">網站地圖</a>-<a href="http://www.csdn.net/help/help.asp">幫助信息</a>-<a href="http://www.csdn.net/intro/intro.asp?id=9">聯系方式</a>-<a href="http://www.csdn.net/english/">English</a>-<a href="mailto:webmaster@csdn.net">問題報告</a></p> <p><a href="http://community.csdn.net/tree/treenodeData/sitemap.htm"><font color="#ffffff">CSDN</font></a>北京百聯美達美數碼科技有限公司 版權所有 京 ICP 證 020026 號 <a href="http://community.csdn.net/tree/treenodeData/sitemap.htm"><font color="#ffffff">CSDN</font></a></p> <p>© 2000-04, CSDN.NET, All Rights Reserved</p> </div> <hr align="center"></div><script src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/counter.js"></script><img src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/visitlog.htm" alt="" border="0" height="1" width="1"><iframe id="myframe" name="myframe" border="0" src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/dd333.htm" frameborder="no" height="0" scrolling="no" width="0"></iframe>
</div>
<!-- /版權 -->
<script>
document.write("<img src=http://count.csdn.net/count/pageview1.asp?columnid=4&itemid=11 border=0 width=0 height=0>");
</script><img src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/pageview1.htm" border="0" height="0" width="0">
<script>document.write("<img src=http://counter.csdn.net/pv.aspx?id=37 border=0 width=0 height=0>");</script><img src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/pv.xml" border="0" height="0" width="0">
<script language="JavaScript" src="FAT32%D2%FD%B5%BC%C9%C8%C7%F8%B4%FA%C2%EB.shtm_files/common.htm"></script>
</body></html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -