引导程序可以认为是PC加电启动后运行的第一段代码,它是一段长度为512字节的16位运行于实模式的代码。事实上,机器启动后会首先运行0xFFFF0处(也有的资料说是0xFFFFFFF0,BIOS这块我也不熟:-( )ROM中的BIOS代码,之后会跳转到0x07C00处执行引导程序。

1,首先给出一段完整的示例代码,此代码只为说明引导程序的执行流程,不具有加载实际操作系统的功能,只是在屏幕上打印一段信息。

[cpp] view plaincopy
  1. #define BOOTSEG 0x07C0
  2. .code16
  3. .section ".bstext", "ax"
  4. .global bootsect_start
  5. bootsect_start:
  6. # Normalize the start address
  7. ljmp    $BOOTSEG, $start2
  8. start2:
  9. movw    %cs, %ax
  10. movw    %ax, %ds
  11. movw    %ax, %es
  12. movw    %ax, %ss
  13. xorw    %sp, %sp
  14. sti
  15. cld
  16. movw    $bugger_off_msg, %si
  17. msg_loop:
  18. lodsb
  19. andb    %al, %al
  20. jz      bs_die
  21. movb    $0xe, %ah
  22. movw    $7, %bx
  23. int     $0x10
  24. jmp     msg_loop
  25. bs_die:
  26. # Allow the user to press a key, then reboot
  27. xorw    %ax, %ax
  28. int     $0x16
  29. int     $0x19
  30. # int 0x19 should never return.  In case it does anyway,
  31. # invoke the BIOS reset code...
  32. ljmp    $0xf000,$0xfff0
  33. bugger_off_msg:
  34. .ascii  "Hello Boot!\r\n"
  35. .ascii  "by harvey\r\n"
  36. .ascii  "\n"
  37. .byte   0
  38. .org 510
  39. .word 0xAA55

这段代码有几个地方需要注意:

1).code16伪指令指示汇编器将此段代码汇编成16位代码。

2)ljmp    $BOOTSEG, $start2指令中,BOOTSEG定义为0x07C0,并假设标号start2在所在代码段中的偏移为S。我们知道实模式地址模式为:段基址*16+偏移,那么这条ljmp指令执行后,控制会跳转到0x7C00+S处。又因为整个引导代码在之前会被加载到0x7C00处,所以此时控制“正好”跳转到标号start2处代码。

3)代码末端的伪指令.org 510,将位置计数器(location counter)设置为510,那么紧跟其后的0xAA55就被设置在第511,512字节。0xAA55是BIOS识别并加载引导程序的标志。

2,编译链接此程序

1)用as命令汇编生成目标文件。

as -gstabs -o boot.o boot.S

2)用ld命令链接生成可执行文件。

ld -o boot boot.o -Tboot.ld

boot.ld为链接脚本,内容如下:

[cpp] view plaincopy
  1. OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
  2. OUTPUT_ARCH(i386)
  3. ENTRY(bootsect_start)
  4. SECTIONS
  5. {
  6. . = 0;
  7. .boot : {*(.bstext)}
  8. . = ASSERT(. <= 512, "Boot too big!");
  9. }

此脚本指示ld将目标文件boot.o中的.text段链接拷贝到可执行文件boot中的.boot段,并且.boot段的起始VMA地址为0。.boot代码段就是我们需要的引导程序代码。更多链接脚本语法参考http://sourceware.org/binutils/docs/ld/index.html。

3,制作引导软盘镜像

1)用dd命令新建软盘镜像flp.img。

dd if=/dev/zero of=flp.img bs=512 count=2880

2)用losetup命令将flp.img与loop设备关联,这样我们可以通过/dev/loop3设备,像操作真实软盘样操作flp.img文件。

losetup /dev/loop0 flp.img

3)将可执行文件boot中的引导代码写入flp.img的第一个扇区。首先我们要确定.boot段在可执行文件boot中的位置,注意此位置不是指.boot段的VMA地址,而是指其存储在磁盘文件boot中的物理位置,我们用objdump命令查看:

objdump -h boot

输出如下:

从File off栏可知.boot段位于距boot文件头0x00001000处。然后用dd命令将.boot段写入flp.img的第一个扇区。

dd if=boot ibs=512 skip=8 of=/dev/loop0 obs=512 seek=0 count=1

其中skip * ibs = 0x00001000为待写数据,即.boot段,在输入源文件,即boot文件中的偏移距离,seek * obs = 0为待写数据将要被写入输出目标文件,即flp.img文件的起始位置,即从flp.img文件头字节开始写入数据,count*obs=512为待写数据的长度。

到这里,引导软盘镜像准备好了。关于dd,losetup,objdump命令更多信息可借助man命令,也可参考我前一篇文章。

4,借助QEMU从引导软盘镜像启动系统。

运行如下命令启动QEMU。

qemu -boot order=a -fda /dev/loop0

此时,我们应该可以在QEMU模拟器的窗口中看到Hello Boot!字样。

QEMU也提供单步调试功能。配合GDB,可以方便的调试引导程序。先用如下命令启动QEMU。

qemu -s -S -boot order=a -fda /dev/loop0

其中-s -S选项与gdb调试有关,运行此命令后QEMU模拟器会停止并等待gdb发送单步执行命令。更多QEMU信息可参考http://qemu.weilnetz.de/qemu-doc.html。

在另一个终端调用gdb命令进入gdb命令行,依次输入以下命令。

自己动手实现操作系统引导程序(OS bootloader)——借助QEMU/GDB/losetup/dd等工具相关推荐

  1. 自己动手写操作系统--个人实践

    近期開始看于渊的<自己动手写操作系统>这本书,刚開始看就发现做系统的引导盘居然是软盘!心里那个汗啊! 如今都是U盘了,谁还用软盘.于是考虑用U盘. 于是開始下面步骤: 1.既然书上说给先要 ...

  2. 自己动手写操作系统之环境构建篇

    自己动手写操作系统之环境构建篇 最近开始看自己动手写操作系统,但是书中采用软盘启动很是郁闷,于是想是否可以从优盘启动呢?作为一名BIOS工程师,曾经用优盘启动过dos,linux等系统,于是做了如下尝 ...

  3. 我国自主研发手机操作系统 960 OS 发布

    今天下午同洲电子在北京发布了号称是我国自主知识产权的智能手机操作系统"960 OS".在发布会上,该公司董事长袁明表示,该系统并非基于Android. 同洲官方表示,960 OS是 ...

  4. 华为正式发布自有操作系统鸿蒙OS

    央视新闻消息,华为今日正式发布自有操作系统:鸿蒙. 在今日下午举行的华为开发者大会2019上,华为消费者业务CEO余承东正式发布自有操作系统鸿蒙OS.余承东介绍称,鸿蒙是全世界第一个面向全场景微内核的 ...

  5. 「操作系统」《自己动手写操作系统》1.1前期准备工作

    一.软硬件 1.硬件 一台计算机(笔者使用的是Win7 x64操作系统) 2.软件 点击此处下载<自己动手写操作系统>的光盘配套文件以及相应工具 汇编编译器:NASM(资源文件中有) 软盘 ...

  6. 操作系统复习--OS的运行机制和体系结构

    操作系统复习–OS的运行机制和体系结构 本文章按照王道操作系统参考 文章主要分:运行机制,操作系统内核,操作系统的体系结构 运行机制 两种命令 特权指令:不允许用户直接使用的命令,如:I/O,中断命令 ...

  7. 鸿蒙系统大疆,华为操作系统“鸿蒙OS”来了!

    原标题:华为操作系统"鸿蒙OS"来了! 8月9日,华为消费者业务CEO余承东在华为开发者大会上如期发布了华为鸿蒙操作系统"HarmonyOS".据介绍,鸿蒙内核 ...

  8. 自己动手写java虚拟机_自己动手写操作系统(要了解的知识点)

    自己动手写操作系统(开篇) 自己动手写操作系统(字符显示) 说明:Intel 8086 或者不同的处理器,开机寄存器数据可能不一样,但是大致原理差不多 了解过计算机启动的同学肯定知道,当计算机启动的时 ...

  9. 《自己动手写操作系统》读书笔记——初识保护模式

    <自己动手写操作系统>读书笔记--初识保护模式 http://www.cnblogs.com/pang123hui/archive/2010/11/27/2309930.html 书本第三 ...

最新文章

  1. mysql5.7.23权限问题_部署MySQL5.7时的权限问题
  2. kernel pca与传统pca的区别
  3. Java学习福利,入门到精通学习路线分享
  4. 对现有的所能找到的DDOS代码(攻击模块)做出一次分析----UDP篇
  5. linux 如何查看应用程序进程号、端口
  6. Django(part28)--F对象
  7. RTP与RTCP协议介绍
  8. 05NumPy--5.4矩阵
  9. java数据库获取的值如何替换_java-如何将数据库中的列值获取到jLabels
  10. 1、linux网络服务实验 用PuTTY连接Linux
  11. Factstone Benchmark
  12. 两个蓝牙模块HC-05转TTL转USB上电自动配对配置过程详解
  13. cocos2d-x2.2.5走四棋儿源代码“开源”
  14. 七甲川荧光染料IR820 NHS ester,新吲哚菁绿-活化酯,New Indocyanine Green-nhs ester
  15. mysql-8.0.12_MySQL 8.0.12-winx64 安装
  16. windows10 扩容C盘空间
  17. 35岁,年入60万,我却从菊厂离职了!
  18. 简单介绍Vue使用echarts定制特殊的仪表盘
  19. Google分析统计
  20. 使用easyBCD在Win10下安装Ubuntu16.04LS双系统详细教程

热门文章

  1. 【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
  2. 【Android RTMP】RTMPDump 推流过程 ( 独立线程推流 | 创建推流器 | 初始化操作 | 设置推流地址 | 启用写出 | 连接 RTMP 服务器 | 发送 RTMP 数据包 )
  3. 【Kotlin】Lambda 表达式 ( 简介 | 表达式语法 | 表达式类型 | 表达式返回值 | 调用方式 | 完整示例 )
  4. 【Android 高性能音频】AAudio 音频流 PCM 采样 的 采样 缓冲 播放 的 连续机制 ( 数据回调机制 | 数据回调函数指针 | 实现数据回调函数 | 设置数据回调函数 )
  5. 【Java 网络编程】TCP 数据传输示例 ( 客户端参数设置 | 服务器端参数设置 | ByteBuffer 存放读取数据类型 )
  6. 【C 语言】C 语言 函数 详解 ( 函数本质 | 顺序点 | 可变参数 | 函数调用 | 函数活动记录 | 函数设计 ) [ C语言核心概念 ]
  7. 【Android 应用开发】Android之Bluetooth编程
  8. 第3节 sqoop:3、sqoop的入门测试使用
  9. Spring MVC中获取当前项目的路径
  10. 软件测试模型以及测试方法