返回介绍

实验一:显示字符的 toy bootloader

发布于 2025-02-16 22:47:44 字数 4693 浏览 0 评论 0 收藏 0

实验目标

操作系统是一个软件,也需要通过某种手段加载并运行它。在这里我们将通过另外一个更加简单的软件-bootloader 来完成这些工作。为此,我们需要完成一个能够切换到 x86 的保护模式并显示字符的 bootloader,为将来启动操作系统做准备。proj1 提供了一个非常小的 bootloader,整个 bootloader 的大小小于 512 个字节,这样才能放到硬盘的主引导扇区中。

这里对 x86 的保护模式不必太在意,后续会进一步讲解

通过分析和实现这个 bootloader,读者可以了解到:

  • 与操作系统原理相关
    • I/O 设备管理:设备管理的基本概念,涉及简单的信息输出
    • 内存管理:基于分段机制的存储管理,x86 的实模式/保护模式以及切换到保护模式的方法
  • 计算机系统和编程
    • 硬件
      • PC 加电后启动 bootloader 的过程
      • 通过串口/并口/CGA 输出字符的方法
    • 软件
      • bootloader 的文件组成
      • 编译运行 bootloader 的过程
      • 调试 bootloader 的方法
      • 在汇编级了解栈的结构和处理过程

proj1 概述

实现描述

proj1 实现了一个简单的 bootloader,主要完成的功能是初始化寄存器内容,完成实模式到保护模式的转换,在保护模式下通过 PIO 方式控制串口、并口和 CGA 等进行字符串输出。

项目组成

[要点(非 OSP):bootloader 的编译生成过程] lab1 中包含的第一个工程小例子是 proj1:一个可以切换到保护模式并显示字符串的 bootloader。proj1 的整体目录结构如下所示:

    proj1 /
    | -  boot
    |   | -  asm.h
    |   | -  bootasm.S
    |   ` -  bootmain.c
    | -  libs
    |   | -  types.h
    |   ` -  x86.h
    | -  Makefile
    ` -  tools
        | -  function.mk
        | -  gdbinit
        ` -  sign.c

    3 directories, 9 files

其中一些比较重要的文件说明如下:

  • bootasm.S :定义并实现了 bootloader 最先执行的函数 start,此函数进行了一定的初始化,完成了从实模式到保护模式的转换,并调用 bootmain.c 中的 bootmain 函数。
  • bootmain.c:定义并实现了 bootmain 函数实现了通过屏幕、串口和并口显示字符串。
  • asm.h:是 bootasm.S 汇编文件所需要的头文件,主要是一些与 X86 保护模式的段访问方式相关的宏定义。
  • types.h:包含一些无符号整型的缩写定义。
  • x86.h:一些用 GNU C 嵌入式汇编实现的 C 函数(由于使用了 inline 关键字,所以可以理解为宏)。
  • Makefile 和 function.mk:指导 make 完成整个软件项目的编译,清除等工作。
  • sign.c:一个 C 语言小程序,是辅助工具,用于生成一个符合规范的硬盘主引导扇区。
  • gdbinit:用于 gdb 远程调试的初始命令脚本

从中,我们可以看出 bootloader 主要由 bootasm.S 和 bootmain.c 组成,当你完成编译后,你会发现这个 bootloader 只有区区的 3 百多字节。下面是编译运行 bootloader 的过程。

【提示】bootloader 是一个超小的系统软件,在功能上与我们一般的应用软件不同,主要用于硬件简单初始化和加载运行操作系统。在编写 bootloader 的时候,需要了解它所处的硬件环境(比如它在内存中的起始地址,它的储存空间的位置和大小限制等)。而这些是编写应用软件不太需要了解的,因为操作系统和编译器帮助应用软件考虑了这些问题。

编译运行

【实验 编译运行 bootloader】

在 proj1 下执行 make,在 proj1/bin 目录下可生成一个 ucore.img。ucore.img 是一个包含了 bootloader 或 OS 的硬盘镜像,通过执行如下命令可在硬件虚拟环境 qemu 中运行 bootloader 或 OS:

  make                     //生成 bootloader 和对应的主引导扇区
  make qemu          //通过 qemu 硬件模拟器来运行 bootloader
  make clean          //清除生成的临时文件,bootloader 和对应的主引导扇区

qemu_img

我们除了需要了解 bootloader 的功能外,还需要进一步了解 bootloader 的编译链接和最终执行码的生成过程,从而能够清楚生成的代码是否是我们所期望的。proj1 中的 Makefile 是一个配置脚本,make 软件工具能够通过 Makefile 完成管理 bootloader 的 C/ASM 代码生成执行码的整个过程。Makefile 的内容比较复杂,不过读者在前期只需会执行 make [参数]来生成代码和清除代码即可。对于本实验的 make 的执行过程如下所示:

    1. gcc -O2 -o tools/sign tools/sign.c
    2. i386-elf-gcc -fno-builtin -Wall -MD -ggdb -m32 -fno-stack-protector -O -nostdinc -Iinclude -Iinclude/x86 -c bootloader/bootmain.c -o obj/bootmain.o
    3. i386-elf-gcc -fno-builtin -Wall -MD -ggdb -m32 -fno-stack-protector -nostdinc -Iinclude -Iinclude/x86 -c bootloader/bootasm.S -o obj/bootasm.o
    4. i386-elf-ld  -N -e start -Ttext 0x7C00 -o obj/bootblock.o obj/bootasm.o obj/bootmain.o
    5. i386-elf-objdump -S obj/bootblock.o > obj/bootblock.asm
    6. i386-elf-objcopy -S -O binary obj/bootblock.o obj/bootblock.out
    7. sign.exe obj/bootblock.out obj/bootblock
       obj/bootblock.out size: 380 bytes
       build 512 bytes boot sector: obj/bootblock success!
    8. dd if=/dev/zero of=obj/ucore.img count=10000
       10000+0 records in
       10000+0 records out
       5120000 bytes (5.1 MB) copied, 0.509 s, 10.1 MB/s
    9. dd if=obj/bootblock of=obj/ucore.img conv=notrunc
       1+0 records in
       1+0 records out
       512 bytes (512 B) copied, 0.011 s, 46.5 kB/s

这 9 步的含义是:

1. 编译生成 sign 执行程序,用于生成一个符合规范的硬盘主引导扇区;
2. 用 gcc 编译器编译 bootmain.c,生成 ELF 格式的目标文件 bootmain.o;
3. 用 gas 汇编器(gcc 只是一个包装)编译 bootasm.S,生成 ELF 格式的目标文件 bootasm.o;
4. 用 ld 链接器把 bootmain.o 和 bootasm.o 链接在一起,形成生成 ELF 格式的执行文件 bootblock.o;
5. 目标文件信息导出工具 objdump 反汇编 bootblock.o,生成 bootblock.asm,通过查看 bootlock.asm 内容,可以了解 bootloader 的实际执行代码;
6. 文件格式转换和拷贝工具 objcopy 把 ELF 格式的执行文件 bootblock.o 转换成 binary 格式的执行文件 bootblock.out;
7. 通过 sign 执行程序,把 bootblock.out(本身大小需要小于 510 字节)扩展到 512 字节,形成一个符合规范的硬盘主引导扇区 bootblock;
8. 设备级转换与拷贝工具 dd 生成一个内容都为“0”的磁盘文件 ucore.img;
9. 设备级转换与拷贝工具 dd 进一步把 bootblock 覆盖到 ucore.img 的前 512 个字节空间中,这样就可以把 ucore.img 作为一个可启动的硬盘被硬件模拟器 qemu 使用。

如果需要了解 Makefile 中的内容,需要进一步看看附录“ucore 实验中的常用工具”一节。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文