第三載、FAT12文件系統剖析1

在上一篇文章中,我們完成了一個簡單的主引導程序的編寫及運行,但有限制的是:主引導程序不能超過512字節!然而操作系統的程序,明顯不止512字節,爲了突破這個限制,主引導可以採用如下改造策略:
        1、完成最基本的初始化工作
        2、從存儲介質加載程序到內存中
        3、將控制權交給新加載的程序執行
在這裏,主引導程序主要做簡單初始化、加載程序到內存,跳到加載的程序處執行即可,這些在512字節內是可以完成的。
           如下是一個基本的思路圖:

在上述的思路中,面臨的問題是:如何加載存儲介質的文件(可執行程序)到內存中
爲了解決這個問題,需要引入文件系統,文件系統就是存儲介質上組織文件數據的方式,這裏我們採用FAT12文件系統,原因簡單易學。文件數據在FAT12文件系統的組織方式如下圖:
                                              
       FAT12的基本組織單位爲:
       1、字節(Byte) : 基本數據單位
       2、扇區(Sector):磁盤中的最小數據單元
       3、(Cluster):一個或多個扇區 

所以最終的解決方案爲:
       1、使用FAT12文件系統對軟盤(a.img)格式化,之後a.img軟盤的文件數據組織方式就是FAT12格式
       2、編寫可執行程序(loader),並拷貝到軟盤a.img中
       3、主引導程序(boot)在軟盤a.img中查找可執行程序loader
       4、將loader程序拷貝到內存中,然後跳轉(jmp)到入口處執行

在此之前先來熟悉下FAT12文件系統,下邊要做的實驗是,使用FAT12文件系統格式化軟盤a.img,之後將a.img掛載到linux中,並向其寫入一個文件,這裏我們用來對a.img進行格式化的工具爲freeDos(一個遠古的FAT12文件系統組織數據的操作系統)

第一步:創建一個虛擬軟盤data.img

第二步、bochsrc配置文件中將data.img軟盤設置爲freeDos操作系統的B盤符

第三步、運行bochsrc虛擬機,用FreeDos格式化B盤符(即data.img軟盤)

第四步、將data.img掛載到linux上(此處爲/mnt/hgfs),並將兩個文件loader.bin、test.txt拷貝到data.img軟盤裏

第五步、重啓freeDos,查看B盤符內容(即軟盤data.img內容)

可以看到data.img軟盤裏已經有了我們拷貝的兩個文件test.txt、loader.bin,並且也打印了兩個文件的內容。
這個實驗說明這樣的思路是可行,不過我們還是要更近一步瞭解FAT12文件系統



以上三張圖片主要展示了FAT12文件系統與主引導程序的組織方式,需要了解的是:
1、主引導程序在主引導區中,主引導區在FAT12文件系統的第0扇區,並以0x55AA結束
2、主引導區同時保存了文件系統信息,與主引導程序共用一個扇區

下邊代碼就是讀取軟盤data.img(將data.img從linux拷貝到Windows桌面)系統文件信息,並打印

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QDebug>

#pragma pack(push)
#pragma pack(1)

struct Fat12Header
{
    char BS_OEMName[8];
    ushort BPB_BytsPerSec;
    uchar BPB_SecPerClus;
    ushort BPB_RsvdSecCnt;
    uchar BPB_NumFATs;
    ushort BPB_RootEntCnt;
    ushort BPB_TotSec16;
    uchar BPB_Media;
    ushort BPB_FATSz16;
    ushort BPB_SecPerTrk;
    ushort BPB_NumHeads;
    uint BPB_HiddSec;
    uint BPB_TotSec32;
    uchar BS_DrvNum;
    uchar BS_Reserved1;
    uchar BS_BootSig;
    uint BS_VolID;
    char BS_VolLab[11];
    char BS_FileSysType[8];
};

#pragma pack(pop)

void PrintHeader(Fat12Header& rf, QString p)
{
    QFile file(p);

    if( file.open(QIODevice::ReadOnly) )
    {
        QDataStream in(&file);

        file.seek(3);   //偏移開頭3字節

        in.readRawData(reinterpret_cast<char*>(&rf), sizeof(rf));

        rf.BS_OEMName[7] = 0;
        rf.BS_VolLab[10] = 0;
        rf.BS_FileSysType[7] = 0;

        qDebug() << "BS_OEMName: " << rf.BS_OEMName;
        qDebug() << "BPB_BytsPerSec: " << hex << rf.BPB_BytsPerSec;
        qDebug() << "BPB_SecPerClus: " << hex << rf.BPB_SecPerClus;
        qDebug() << "BPB_RsvdSecCnt: " << hex << rf.BPB_RsvdSecCnt;
        qDebug() << "BPB_NumFATs: " << hex << rf.BPB_NumFATs;
        qDebug() << "BPB_RootEntCnt: " << hex << rf.BPB_RootEntCnt;
        qDebug() << "BPB_TotSec16: " << hex << rf.BPB_TotSec16;
        qDebug() << "BPB_Media: " << hex << rf.BPB_Media;
        qDebug() << "BPB_FATSz16: " << hex << rf.BPB_FATSz16;
        qDebug() << "BPB_SecPerTrk: " << hex << rf.BPB_SecPerTrk;
        qDebug() << "BPB_NumHeads: " << hex << rf.BPB_NumHeads;
        qDebug() << "BPB_HiddSec: " << hex << rf.BPB_HiddSec;
        qDebug() << "BPB_TotSec32: " << hex << rf.BPB_TotSec32;
        qDebug() << "BS_DrvNum: " << hex << rf.BS_DrvNum;
        qDebug() << "BS_Reserved1: " << hex << rf.BS_Reserved1;
        qDebug() << "BS_BootSig: " << hex << rf.BS_BootSig;
        qDebug() << "BS_VolID: " << hex << rf.BS_VolID;
        qDebug() << "BS_VolLab: " << rf.BS_VolLab;
        qDebug() << "BS_FileSysType: " << rf.BS_FileSysType;

        file.seek(510);  //偏移512字節的最後兩字節處

        uchar b510 = 0;
        uchar b511 = 0;
        //讀取最後兩字節
        in.readRawData(reinterpret_cast<char*>(&b510), sizeof(b510));
        in.readRawData(reinterpret_cast<char*>(&b511), sizeof(b511));

        qDebug() << "Byte 510: " << hex << b510;
        qDebug() << "Byte 511: " << hex << b511;
    }

    file.close();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Fat12Header f12;

    PrintHeader(f12, "C:\\Users\\lms\\Desktop\\data.img");

    return a.exec();
}

編譯運行的結果爲:

從結果看到,data.img軟盤已經採用FAT12文件系統來組織數據,且主引導區最後兩字節爲0x55AA。

既然上邊說了,主引導程序與主引導區共用一個扇區,並且在第0扇區,也就是在data.img的開始位置處,那麼接着改bochsrc配置文件,將data.img作爲啓動盤:

運行bochsrc虛擬機

可以看到,data.img其實已經有主引導程序了,這個主引導程序只是打印一段字符串。這個主引導程序就是freeDos在格式化data.img時候自動生成的。

總結:
        1、可以通過主引導程序加載新程序突破主引導程序512字節的限制
        2、加載新程序需要藉助文件系統
        3、FAT12文件系統的主要系統信息主引導程序都存儲於第0扇區
 

學自 --《狄泰軟件學院》- 門徒操作系統

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