zoukankan      html  css  js  c++  java
  • 04 主引导程序的扩展-上

    参考

    https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/

    https://blog.51cto.com/13475106/category6.html

    及狄泰软件相关课程

           我们知道主引导程序只能存在第一扇区中,而BIOS只会将第一扇区拷贝到内存执行,第一扇区之后的程序是不会被BIOS加载到内存中的,而这512字节的程序不可能完成整个操作系统的功能,因此,我们要突破这种限制。

      这512字节只能完成最基本的功能,我们这样来规划它的功能:

      1、首先完成最基本的初始化;

      2、从存储介质中加载程序到内存中;

      3、将控制权交给新加载的程序。

      以上三步如下图所示:

      

      那么怎么加载存储介质中的程序呢?我们平时写应用程序时,可以使用read这种系统调用来读取文件,而这种方法是建立在操作系统之上的,此时,我们没有现成的操作系统,我们写的程序是直接运行在硬件之上的,那么我们还有办法读取存储介质中的程序吗?答案是肯定的,我们可以将存储介质格式化成一种文件系统,然后用汇编程序去查找文件并将其加载到内存中,这个文件可以认为就是操作系统的内核,只不过它现在是以一个文件的形式存储在存储介质中的(和一些ARM开发可能不同,ARM嵌入式开发中,可能是去指定的地址读取内核,并没有文件的概念),我们将它读取到内存中后,然后就可以将控制权交给它了,是不是很简单呢?

      接下来我们就先介绍要用到的文件系统和相应的工具,FAT12文件系统是软盘的专用文件系统,在DOS时代非常流行,我们就选用FAT12文件系统做实验,下面先给出FAT12文件系统的大致格式:

      将一张软盘格式化成FAT12文件系统需要用到FreeDos操作系统,现在我们已经将这个操作系统做到了虚拟软盘中,名字为freedos.img,可以将它认为是一张现成的系统盘,插到光驱中就可以用了,而我们自己的虚拟软盘文件名为a.img现在还是一张没有格式的空盘。因此,我们需要将a.img插入到运行FreeDos操作系统的机器中,然后借用FreeDos中的工具对a.img进行格式化。

      x86模拟器依然使用bochs,现在只需改一下启动文件,如下所示:

     

      我们修改了启动文件的第13、14、16行,第13行表示将带有FreeDos操作系统的虚拟软盘插入光驱中,第14行表示在另一个光驱中插入另一张空盘a.img,第16行表示将软盘a作为启动盘。

      修改了启动文件后,我们启动bochs,开始仿真,如下所示,可以看到FreeDos运行起来了。

      FreeDos的盘符是A盘,而我们的插入的空盘盘符是B,下一步,首先对B盘进行格式化,然后,切换到B盘,查看B盘下面的文件,如下所示:

      可以看到格式化成功了,格式化后的软盘中没有任何文件,是空的。

      下面我们将a.img挂载到linux下的目录下,并写入几个文件,然后卸载a.img,如下所示:

      其中,mount的-o loop选项表示将一个文件当做硬盘分区挂接到系统上。文件复制成功了,然后我们再去bochs虚拟机中查看B盘中的文件,如下所示:

      文件成功写入到了虚拟软盘a.img中。

      下面我们来具体分析一下FAT12文件系统的格式,FAT12文件系统由引导区、FAT表、根目录项表和文件数据区组成,每个区域的大小如下图所示:

       主引导区存储的比较重要的信息是文件系统的类型,文件系统逻辑扇区总数、每簇包含的扇区数等,主引导扇区最后以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文件系统引导区的详细信息完全对应了。

    修改bochrc文件,从data.img启动

    ###############################################################
    # Configuration file for Bochs
    ###############################################################
    
    # how much memory the emulated machine will have
    megs: 32
    
    # filename of ROM images
    romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
    vgaromimage: file=/usr/share/vgabios/vgabios.bin
    
    # what disk images will be used
    #floppya: 1_44=freedos.img, status=inserted
    floppya: 1_44=data.img, status=inserted
    # choose the boot disk.
    boot: a
    
    # where do we send log messages?
    # log: bochsout.txt
    
    # disable the mouse
    mouse: enabled=0
    
    # enable key mapping, using US layout as default.
    keyboard_mapping: enabled=1, map=/usr/local/share/bochs/keymaps/x11-pc-us.map  

    结果如下:

     总结:

     

  • 相关阅读:
    SQL Server2016 AlwaysOn无域高可用
    Windows Server 2016 无域故障转移群集
    SQL Server高可用实现方案
    oracle11g RMAN catalog的基本使用
    Oracle_Windows server ORA-01031: insufficient privileges
    MySQL MGR 单主模式下master角色切换规则
    SQL Server AlwaysOn原理简介
    DB2创建视图并授权给其他用户
    Oracle数据库用户的密码过期问题处理
    访问GitLab的PostgreSQL数据库
  • 原文地址:https://www.cnblogs.com/lh03061238/p/13924836.html
Copyright © 2011-2022 走看看