Chapter 2:撰寫MBR主啟動紀錄 === :::info 這是讀書筆記 ![book](https://hackmd.io/_uploads/H1rFFZZAkx.jpg =30%x) 作者:鄭鋼 出版社:佳魁資訊股份有限公司 出版日期:2017/05/31 ::: --- # Intel x86 Memory Map >參考資料:[Memory Map (x86)](https://wiki.osdev.org/Memory_Map_(x86)) ![截圖 2025-04-12 凌晨1.49.53](https://hackmd.io/_uploads/S15DIRIC1x.png) :::warning 可以和 ARM 架構的 memory map 作比較: [ARMv8-A Foundation Platform memory ma](https://developer.arm.com/documentation/100961/1100-00/Programming-Reference/ARMv8-A-Foundation-Platform-memory-map) ::: ## 0x7c00 的故事 Intel 最一開始的 BIOS 是按照最小記憶體 32KB 去設計的:==0x0 - 0x7FFF== 由於最前要儲存 IVT(interrupt vector table):==0x0 - 0x3FF== 所以最初設計 BIOS 將 MBR 載入到記憶體最尾端,並且保留 1KB:==0x7c00 - 0x7FFF== >相關參考資料:[[筆記] 為什麼在 x86,MBR 會被載入到 0x7C00?(完全版)](https://gist.github.com/snyiu100/b147b3175315b9e959e3a7a6281a82c1) # MBR 的撰寫 ## Intel x86 Instruction Set [x86 instruction listings](https://en.wikipedia.org/wiki/X86_instruction_listings) [x86 and amd64 instruction reference](https://www.felixcloutier.com/x86/) ## Intel x86 BIOS Interrupt >參考資料:[BIOS中斷呼叫](https://zh.wikipedia.org/zh-tw/BIOS%E4%B8%AD%E6%96%B7%E5%91%BC%E5%8F%AB) ![截圖 2025-04-12 凌晨2.51.44](https://hackmd.io/_uploads/SJNkHyvAke.png) 詳細的 int 0x10h:[INT 10H](https://zh.wikipedia.org/wiki/INT_10H) ## Intel x86 CPU Registers >參考資料:[X86 CPU 暫存器 Register 大全](https://finalfrank.pixnet.net/blog/post/22992166) https://wiki.osdev.org/CPU_Registers_x86 ![截圖 2025-04-12 凌晨2.53.11](https://hackmd.io/_uploads/BJDEB1wCJl.png) ![截圖 2025-04-12 凌晨2.56.00](https://hackmd.io/_uploads/HkhASJvC1e.png) ## 字元顯示 通常一頁的字元可以顯示 25\*80=2000,每個字元 2 bytes,總共 4000 bytes=4KB。 >[!Tip]這也是為何 Coding style 常常限制每行最多 80 個字元。 ## Source Code ```asm ;主引導程序 ;------------------------------------------------------------ SECTION MBR vstart=0x7c00 mov ax,cs mov ds,ax mov es,ax mov ss,ax mov fs,ax mov sp,0x7c00 ; 清屏 利用0x06號功能,上卷全部行,則可清屏。 ; ----------------------------------------------------------- ;INT 0x10 功能號:0x06 功能描述:上卷窗口 ;------------------------------------------------------ ;輸入: ;AH 功能號= 0x06 ;AL = 上卷的行數(如果為0,表示全部) ;BH = 上卷行屬性 ;(CL,CH) = 窗口左上角的(X,Y)位置 ;(DL,DH) = 窗口右下角的(X,Y)位置 ;無返回值: mov ax, 0x600 mov bx, 0x700 mov cx, 0 ; 左上角: (0, 0) mov dx, 0x184f ; 右下角: (80,25), ; VGA文本模式中,一行只能容納80個字符,共25行。 ; 下標從0開始,所以0x18=24,0x4f=79 int 0x10 ; int 0x10 ;;;;;;;;; 下面這三行代碼是獲取光標位置 ;;;;;;;;; ;.get_cursor獲取當前光標位置,在光標位置處打印字符. mov ah, 3 ; 輸入: 3號子功能是獲取光標位置,需要存入ah寄存器 mov bh, 0 ; bh寄存器存儲的是待獲取光標的頁號 int 0x10 ; 輸出: ch=光標開始行,cl=光標結束行 ; dh=光標所在行號,dl=光標所在列號 ;;;;;;;;; 獲取光標位置結束 ;;;;;;;;;;;;;;;; ;;;;;;;;; 打印字符串 ;;;;;;;;;;; ;還是用10h中斷,不過這次是調用13號子功能打印字符串 mov ax, message mov bp, ax ; es:bp 為串首地址, es此時同cs一致, ; 開頭時已經為sreg初始化 ; 光標位置要用到dx寄存器中內容,cx中的光標位置可忽略 mov cx, 5 ; cx 為串長度,不包括結束符0的字符個數 mov ax, 0x1301 ; 子功能號13是顯示字符及屬性,要存入ah寄存器, ; al設置寫字符方式 ah=01: 顯示字符串,光標跟隨移動 mov bx, 0x2 ; bh存儲要顯示的頁號,此處是第0頁, ; bl中是字符屬性, 屬性黑底綠字(bl = 02h) int 0x10 ; 執行BIOS 0x10 號中斷 ;;;;;;;;; 打字字符串結束 ;;;;;;;;;;;;;;; jmp $ ; 使程序懸停在此 message db "1 MBR" times 510-($-$$) db 0 db 0x55,0xaa ``` ## Compile ``` nasm -o mbr.bin mbr.S ``` ## Hard Disk Image ``` dd if=../code/mbr.bin of=./sr_hd60m.img bs=512 count=1 conv=notrunc ``` ![截圖 2025-04-12 凌晨3.56.33](https://hackmd.io/_uploads/Skmf4evC1g.png) ## Result ![截圖 2025-04-12 清晨6.19.29](https://hackmd.io/_uploads/rJR9HMD0yg.png) # MBR 大哉問 ## 是否一定存在 MBR? >參考資料:[Does every storage device have MBR?](https://superuser.com/questions/1649454/does-every-storage-device-have-mbr)