配置環境
VSCODE
+x86 and x86_64 Assembly
插件 +hexdump for VSCode
插件- NASM
- QEMU
- Windows 10 + MingW64 8.1.0(MSYS2)
C:\WINDOWS\system32>gcc --version
gcc (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
...
安裝 NASM 並把 nasm.exe 所在目錄(默認C:\Program Files\NASM
)加入系統環境變量 PATH 里
安裝 QEMU 並同樣將其安裝目錄加入 PATH
然后關閉 VSCODE 軟件再打開,使得環境變量刷新。
首先寫一個 Day1 的 NASM 版源碼
**展開查看源碼**
; hello-os
; TAB=4
; 標准FAT12格式軟盤專用的代碼 Stand FAT12 format floppy code
DB 0xeb, 0x4e, 0x90
DB "HELLOIPL" ; 啟動扇區名稱(8字節)
DW 512 ; 每個扇區(sector)大小(必須512字節)
DB 1 ; 簇(cluster)大小(必須為1個扇區)
DW 1 ; FAT起始位置(一般為第一個扇區)
DB 2 ; FAT個數(必須為2)
DW 224 ; 根目錄大小(一般為224項)
DW 2880 ; 該磁盤大小(必須為2880扇區1440*1024/512)
DB 0xf0 ; 磁盤類型(必須為0xf0)
DW 9 ; FAT的長度(必須是9扇區)
DW 18 ; 一個磁道(track)有幾個扇區(必須為18)
DW 2 ; 磁頭數(必須是2)
DD 0 ; 不使用分區,必須是0
DD 2880 ; 重寫一次磁盤大小
; 書中作者說原因不明的兩行代碼我查到了,see https://www.ntfs.com/fat-partition-sector.htm
DB 0 ; BPB_Physical_Disk_Number DB (This is related to the BIOS physical disk number. Floppy drives are numbered starting with 0x00 for the A disk. Physical hard disks are numbered starting with 0x80. The value is typically 0x80 for hard disks, regardless of how many physical disk drives exist, because the value is only relevant if the device is the startup disk.)
DB 0 ; BPB_Current_Head DB (Not used by FAT file system)
DB 0x29 ; BPB_Signature DB (Must be either 0x28 or 0x29 in order to be recognized by Windows NT.)
DD 0xffffffff ; BPB_Volume_Serial_Number DD
DB "HELLO-OS " ; 磁盤的名稱(必須為11字節,不足填空格)
DB "FAT12 " ; 磁盤格式名稱(必須是8字節,不足填空格)
TIMES 18 DB 0 ; 先空出18字節
; 程序主體
DB 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB 0xee, 0xf4, 0xeb, 0xfd
; 信息顯示部分
DB 0x0a, 0x0a ; 換行兩次
DB "hello, world"
DB 0x0a ; 換行
DB 0
TIMES 0x1fe-($-$$) DB 0x00 ; 填寫0x00直到0x001fe
DB 0x55, 0xaa
; 啟動扇區以外部分輸出
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 4600 DB 0
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 1469432 DB 0
; 只是把 RESB 20 改成了 TIMES 20 DB 0
測試
編譯命令,VSCODE->New Terminal
輸入
nasm -f bin day1.asm -o day1.img
-f 參數指定輸出格式為 bin,即二進制文件。 詳見 nasm -h 幫助命令
拿 day1.img
和 helloos.img
十六進制對比一下(工具 Beyond Compare),發現文件內容完全一致
然后用 QEMU(32位虛擬) 測試一下 qemu-system-i386 day1.img
參考:制作可啟動IMG鏡像並用QEMU虛擬機測試
另外我寫了個腳本命名為 run.bat
當然你也可以搭配 VSCode 的 Code Runner 插件使用
@echo OFF
nasm -f bin %1.asm -o %1.img
qemu-system-i386 %1.img
放在源碼同目錄下(如和 day1.asm
放在一起),然后執行命令 run day1
即可編譯生成img並通過 QEMU 運行。
FAT32 版的啟動鏡像
初步寫好了 FAT32 格式的 BPB
資料參考:Fat32 白皮書 及 https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc776720(v=ws.10)#fat32-boot-sector
對了,NASM 語法中的標簽是可以不加冒號的,也就說label1: MOV AX, 0
和 label1 MOV AX, 0
是一樣的
; hello-os
; TAB=4
; author: https://www.cnblogs.com/yucloud/p/10943215.html#Reference
; see1: Hardware White Paper - Microsoft Extensible Firmware Initiative FAT32 File System Specification (Version 1.03, December 6, 2000)
; see2: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc776720(v=ws.10)
; Offset Length Name
; 0x00 3 B Jump instruction
; 0x03 8 B OEM ID
; 0x0B 53 B BPB
; 0x40 26 B Extended BPB
; 0x5A 420B Bootstrap code
; 0x01FE 2 B End of sector marker
; B(Bytes) b(bits) 1B=8bits
; 存儲容量 = 磁頭數 × 磁道(柱面)數 × 每道扇區數 × 每扇區字節數
; 扇區(sector) 柱面(cylinders) 磁道(Track) 磁頭(head) 卷/分區(Volume) BPB()
; 簇/塊(cluster)由多個扇區組成,是操作系統所使用的邏輯概念,而非磁盤的物理特性。
; DB (Byte 1B) 8bit
; DW (DWord 2B) 16bits
; DD (DDoubleWord 4B) 32bits
ORG 0x7c00
; FAT32 Boot Sector {0th sector}
; jump instruction [0x00-0x02]
BS_jmpBoot
JMP SHORT entry
NOP
; DB 0xeb, 0x5A, 0x90 ; (3B) 啟動區跳轉,短跳轉只需要 4bit 地址,所以用 0x90(NOP,即空指令)。長跳轉需要 8bit 地址
; OEM ID [0x03-0x0A]
BS_OEMName DB "HELLOIPL" ; [ 8_Bytes] OEM_ID 啟動扇區名稱
; BPB (BIOS Paramter Block, 53 Bytes) [0x0B-0x3F]
BPB_BytsPerSec DW 512 ; Bytes_Per_Sector (only 512, 1024, 2048, 4096)
BPB_SecPerClus DB 1 ; Sector_Per_Cluster
BPB_RsvdSecCnt DW 0x03F8 ; BPB_Reserved_Sectors_Counts
BPB_NumFATs DB 2 ; Number_of_FATs
BPB_RootEntCnt DW 0 ; Root_Entries_Counts (FAT12/FAT16 only, Fat32=0)
BPB_TotSec16 DW 0 ; old 16-bit total count of sectors Small_Sectors (FAT12/FAT16 only, Fat32=0)
BPB_Media DB 0xf8 ; Media_Descriptor (HardDisk=f8)
BPB_FatSz16 DW 0 ; Sectors_Per_FAT (FAT12/FAT16 only, Fat32=0)
BPB_SecPerTrk DW 0x3F ; Sectors_Per_Track
BPB_NumHeads DW 2 ; Number_of_Heads
BPB_HiddSec DD 0 ; Hidden_Sectors
BPB_TotSec32 DD 2880 ; 32-bit total count of sectors on the volume, Large_Sectors (卷中的扇區總數)
; offset 36(0x24)
BPB_FATSz32 DD 9 ; Sectors_Per_FAT_32 (Fat32 only)
BPB_ExtFlags DW 0 ; Extended_Flags 標志活躍的 FAT 文件分配表,Not_Used_By_WindowsServer2003
BPB_FSVer DW 0 ; File_System_Version (Fat32 only)
BPB_RootClus DD 2 ; Root_Cluster_Number (Fat32 only)
BPB_FSInfo DW 1 ; (Fat32 only, File_System_Information_Sector_Number)
BPB_BkBootSec DW 6 ; Backup_Boot_Sector (FAT32 only)
BPB_Reserved DW 0,0,0 ; [12_Bytes] (FAT32 only)
; Extended BPB (26 Bytes)[0x40-0x59]
BS_DrvNum DB 0x80 ; Physical_Disk_Number (HD=0x80)
BS_Reserved1 DB 0 ; (Fat32=0)
BS_BootSig DB 29 ; Extended_Boot_Signature (0x28 or 0x29 to be recognized by WinServer 2003)
BS_VolID DD 0xffffffff ; Volume_Serial_Number
BS_VolLab DB "MYOS-VOLUME" ; [11_Bytes] Volume_Label (default="NO NAME ")
BS_FilSysType DB "FAT32 " ; [ 8_Bytes] System_ID (分區的格式, the fileSystem ID such as "FAT32 ")
; Bootstrap Code [0x5A ~ 0x01FD]
TIMES 18 DB 0 ; 先空出18字節
; 程序主體
entry:
MOV AX, 0
MOV SS, AX
MOV SP, 0x7c00
MOV DS, AX
MOV ES, AX
MOV SI, msg
putloop:
MOV AL, [SI]
ADD SI, 1
CMP AL, 0
JE fin
MOV AH, 0x0e
MOV BX, 15
INT 0x10
JMP SHORT putloop
fin:
HLT
JMP SHORT fin
; 信息顯示部分
msg:
DB 0x0a, 0x0a ; 換行兩次
DB "hello, world"
DB 0x0a ; 換行
DB 0
TIMES 0x1fe-($-$$) DB 0 ; 這里要使用 0x1fe(即十進制數510)(NASK的是0x7dfe,具體不清楚)
; EndOfSector Marker [0x01FE]
DB 0x55, 0xaa
; FAT32 Data Structure (the first data cluster is 2, and not 0 or 1)
; RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec;
; Note that on a FAT32 volume, the BPB_RootEntCnt value is always 0;
; so on a FAT32 volume, RootDirSectors is always 0.
; Next, we determine the count of sectors in the data region of the volume:
; DataSec = TotSec – (BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors);
; CountofClusters = DataSec / BPB_SecPerClus;
; 啟動扇區以外部分輸出
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 4600 DB 0
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 1469432 DB 0
; 只是把 RESB 20 改成了 TIMES 20 DB 0
把編譯得到的 img 用 磁盤精靈/WinHex模板 加載一下
發現還沒有文件系統... 一定是哪里出錯了,下午再改
這里的難度在於 BPB 中磁盤參數的計算和分配
NASM - NASK 語法對照
NASM TIMES 0x1fe-($-$$) db 0
NASK RESB 0x1fe-$