用qemu模擬Intel x86平臺實驗環境 —— 啓動系統

文章系列:
用qemu模擬Intel x86平臺實驗環境 —— 概述
用qemu模擬Intel x86平臺實驗環境 —— 啓動系統
用qemu模擬Intel x86平臺實驗環境 —— 加載並運行app

本章目標

  • 我們的大目標是製作一個光盤,該光盤實現兩個功能:
  1. 存放引導代碼,用來加載應用程序到內存,並跳轉到應用程序處執行程序
  2. 存放應用程序,這個引用程序是作爲一個文件放到光盤中
  • 爲了實現這個目標,本章作兩個預備工作:
  1. 製作一個光盤並格式化成文件系統,可以存放應用程序,我們選取FAT12格式的文件系統
  2. 在格式化成文件系統後的光盤的第一個扇區中,寫入引導代碼,這段引導代碼將用作加載應用程序到內存,本章暫時不作,只實現點亮屏幕的功能。

實現原理

文件存放

  • 要存放文件,通常做法是把存儲介質格式化成操作系統可以識別的文件系統,比如windows的FAT12/16/32,ExFAT,VFAT,NTFS或者linux的ext2/3/4等。我們採用同樣的做法,首先製作一個空的磁盤介質,然後將其格式化成FAT12文件系統,如下:
dd if=/dev/zero of=floopy bs=512 count=2880
losetup /dev/loop0 floopy
mkdosfs -F 12 /dev/loop0
losetup -d /dev/loop0
  • 查看其內容,前512字節是一個引導扇區(Boot Sector),前62字節是BPB的結構,BPB數據結構的字段是windows文件系統和操作系統約定好的,用於描述磁盤的物理佈局,可以適用於FAT系列文件系統和NTFS文件系統。這裏我們看到最後的文件系統類型爲FAT12
    在這裏插入圖片描述
  • linux下的也有自己引導扇區,叫做MBR,引導扇區裏是自己設計的數據結構,比如分區表。
    在這裏插入圖片描述

引導原理

  • 光盤格式化之後,掛載光盤,就可以拷貝應用程序到文件系統了,但這個光盤只有存放文件的功能,還不能引導代碼,因此我們需要把引導代碼也拷貝到引導扇區中。這裏有兩種方法,一種是保留格式化時工具留下的BPB數據結構信息,只將引導代碼dd到62自己之後,另一種就是將讓引導代碼中包含BPB數據結構,dd引導代碼的時候從偏移0開始,直接覆蓋BPB數據結構。我們選用者。
    在這裏插入圖片描述
  • 上圖描述了FAT12文件系統引導扇區的數據結構。

具體實現

  • BPB(BIOS Parameter Block)
    # BS_jmpBoot  短跳轉指令
    jmp label_init          
    nop
    # BS_OEMName 廠商名字
    .ascii  "ForrestY"      
    # BS_BytsPerSec 每扇區字節數
    .word   512             
    # BPB_SecPerClus 每簇扇區數
    .byte   1               
    # BPB_RsvdSecCnt 引導記錄(MBR)佔用的扇區數
    .word   1               
    # PBP_NumFATs FAT表數目
    .byte   2               
    # PBP_RootEntCnt 根目錄文件最大數
    .word   0xe0             
    # PBP_TotSec16 扇區總數
    .word   2880            
    # PBP_Media 介質描述符
    .byte   0xf0            
    # PBP_FATSz16 每FAT扇區數
    .word   9               
    # PBP_SecPerTrk 每磁道扇區數
    .word   18              
    # PBP_NumHeads 磁頭數
    .word   2               
    # PBP_HiddSec 隱藏扇區數
    .long   0               
    # PBP_TotSec32 如果PBP_TotSec16爲0,該域記錄扇區數
    .long   0               
    # BS_DrvNum 中斷13的驅動器號
    .byte   0               
    # BS_Reserved1 未使用
    .byte   0               
    # BS_BootSig 擴展引導標記
    .byte   0x29            
    # 卷序列號
    .long   0               
    # 卷標
    .ascii  "VirtualBoot"
    # 文件系統類型  
    .ascii  "FAT12   "
  • 引導代碼,點亮屏幕
label_init:
    movw    $0x7c0, %ax
    movw    %ax, %ds
    movw    %ax, %es
    movw    %ax, %ss
    movw    $0x180, %sp
    call    DispStr

loop:
    jmp     loop

DispStr:
    movw    $BootMsg, %ax
    movw    %ax, %bp
    movw    $16, %cx
    movw    $0x1301, %ax
    movw    $0xc, %bx
    movb    $0, %dl
    int     $0x10
    ret

BootMsg:
    .ascii  "Hello, OS World!"
    .org 510
    .word 0xAA55

實驗結果

引導固件

引導固件包含了BPB數據結構和引導代碼兩部分,名爲boot.bin

  • 寫一個run.sh的腳本,方便測試:
[root@hy b]# cat run.sh 
#!/bin/bash
DEBUG="false"
PWD="$(cd `dirname $0`;pwd)"

[ $# -eq 1 ] && [ "X$1" == "X-h" ] && echo "$(basename $0) debug --for debug" && exit 0
[ $# -eq 1 ] && [ "X$1" == "Xdebug" ] && DEBUG="true"

if [ "X$DEBUG" == "Xtrue" ]; then
    echo "waiting for connect gdb server..."
    qemu-system-x86_64 -machine pc-i440fx-4.0 -m 2G -smp 2,sockets=2,cores=1,threads=1  \
                       -boot strict=on -drive file=$PWD/a.img,format=raw,if=none,id=drive-fdc0-0-0 \
                       -global isa-fdc.driveA=drive-fdc0-0-0 -global isa-fdc.bootindexA=1 -S -s
else
    qemu-system-x86_64 -machine pc-i440fx-4.0 -m 2G -smp 2,sockets=2,cores=1,threads=1  \
                       -boot strict=on -drive file=$PWD/a.img,format=raw,if=none,id=drive-fdc0-0-0 \
                       -global isa-fdc.driveA=drive-fdc0-0-0 -global isa-fdc.bootindexA=1
fi
  • make後,運行run.sh
    在這裏插入圖片描述
  • 運行run.sh debug,qemu啓動後暫停,等待gdb連接
    Screenshot at 2019-05-04 02-10-07
  • 連接gdbserver,可以在0x7c00處斷住,查看寄存器信息等
    在這裏插入圖片描述

工具格式化和固件格式化對比

  • 拷貝之前,使用mkdofs工具已經將a.img格式化成了FAT12文件系統。可以看到前62字節的BPB數據結構。
    在這裏插入圖片描述
  • dd命令寫入固件後,格式化引導扇區dd if=boot.bin ibs=512 skip=4096 of=a.img obs=512 seek=0 count=1 conv=notrunc後,可以看到BPB結構的字段有了變化,說明BPB信息被覆蓋了,並且BPB之後多了數據,這是引導代碼。
    在這裏插入圖片描述
  • 拷貝測試文件test.txt,可以看到,重新被覆蓋的BPB數據結構,仍然可以被操作系統識別,作爲文件系統。擁有正常的文件保存功能。
    在這裏插入圖片描述

下一步工作

  • 根據根目錄表項和FAT表找到特定文件名的文件
    分析test.txt文件的位置: 引導扇區中定義了根目錄條目最大數0xe0=224,每個根目錄條目大小32 byte,根目錄所佔扇區數
    RootDirSectors = ((PBP_RootEntCnt * 32) + (BS_BytsPerSec - 1)) / BS_BytsPerSec = (224 * 32) + 511 / 512 = 14。
    FAT12文件系統佈局如上圖,可以看到引導扇區+ FAT1 + FAT2一共佔用了1+9+9 = 19個扇區,根目錄佔了14個扇區,因此數據區從第19+14=33個扇區開始,開始於第33個扇區,偏移33 * 512 = 0x4200。注意數據區的第一個簇的號是2,不是0或者1。
    從根目錄表項中看到,test.txt的文件內容從簇號3開始,對應數據區的第二個簇號,偏移0x4400。可以對上。
    再看FAT1表的位圖F0 FF FF 00 F0 FF ,它表示文件的下一個簇號。
    前三個字節是簇號0和簇號1的位圖,忽略

    entry_2 = 0x000 // 簇號2中沒有文件
    entry_3 = 0xFFF // 簇號3中文件的下一個簇號是0xFFF,這是特殊簇號,表示這個簇是文件的最後一個簇。
    現在,用xxd查看鏡像文件,根據FAT12文件系統規範,可以通過根目錄的表項和FAT表找到文件在鏡像中的偏移和佔用簇的數目,下一章,介紹怎麼在boot.bin的代碼中找到這個test.txt的文件。

完整代碼見 my github

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