用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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

享乐主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值