1. 程式人生 > 實用技巧 >04 主載入程式的擴充套件-上

04 主載入程式的擴充套件-上

一.主載入程式上

從之前的幾章可以知道,主載入程式的程式碼量不能超過512位元組,但是在實際中我們需要突破512位元組的限制
突破限制的思路-主載入程式
1.完成最基本的初始化工作
2.從儲存介質中載入程式到記憶體中
3.將控制權交由新載入的程式執行
但是在這會出現問題-主載入程式如何載入儲存介質中的其它程式?
檔案系統--儲存介質上組織檔案資料的方法-主要包含資料區、根目錄、FAT2、FAT1、引導扇區如圖所示

A.檔案系統示例(用到的虛擬網盤時F12)
1.FAT12是DOS時代的早期檔案系統
2.FAT12結構非常簡單,一直沿用於軟盤
3.FAT12的基本組織單位-位元組:基本資料單位、扇區:磁碟中的最小資料單元、簇:一個或者多個扇區
通過之前的介紹,可以得出解決方案
1.使用FAT12對軟盤(data..img自定義的)進行格式化
2.編寫可執行程式(Loader),並將其拷貝到軟盤中
3.主載入程式(Boot)在檔案系統中查詢Loader
4.將Loader複製到記憶體中,並跳轉到入口處執行
實驗-往虛擬軟盤中寫入檔案,在這裡我們需要一些準備的基本bochs、FreeDos、bximage,主要步驟是建立虛擬軟盤然後在FreeDos中進行格式化,最後將data.img掛載Linux中,並寫入檔案

通過bximage命令生成data.img,並在配置中將其併入到freeDos.img上

通過執行之後生成,然後通過format B命令對B盤進行格式化,B盤就是虛擬軟碟機,將其格式化虛擬軟盤data.img就有了檔案系統就是Fata12檔案系統,然後通過終端以及命令生成之前提到的原材料並將其拷貝至軟盤中

最後通過命令進行檢視虛擬軟盤下的檔案,以及檔案內的內容

B.對FAT12進行深入的理解


FAT12檔案系統由引導區,FAT表,根目錄項表和檔案資料區組成

FAT12的主引導區--主引導區儲存的比較重要的資訊是檔案系統的型別,檔案系統邏輯扇區總數,每簇包含的扇區數,等。主引導區最後以0x55AA兩個位元組作為結束,共佔用一個扇區

怎麼來驗證一下我們格式化後的a.img虛擬軟盤中就是這些資訊呢?我們可以將a.img當成一個普通的檔案,然後寫一個程式進行讀取,讀取程式使用Qt creater來寫,因為Qt中提供了很多好用的工具類,方便我們來驗證程式如下

#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);

        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);

        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;
    }
    else
    {
        qDebug() << "file not found";
    }

    file.close();
}

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

    Fat12Header f12;

    PrintHeader(f12, "data.img");
    
    return a.exec();
}

我們定義的Fat12Header結構體是和主載入程式一一對應的,執行以上程式碼,輸出如下所示:

 可以看到,我們讀出的資訊和FAT檔案系統引導區的詳細資訊完全對應了。