前言

上篇文章中,我们写了一个简单的 loader 作为被加载的演示对象。我们知道 loader 是用来加载 kernel 的,今天我们就编写 loader 代码完成这件事情。

实模式下的内存地址

我们计划把 kernel 加载到内存的 0x10000 地址处。

不过面临一个挑战,实模式下地址线为 20 位,寄存器只有 16 位,要想通过寄存器去构成这 20 位的主存地址,必须采取一种特殊的方式。
当指令要想访问某个内存地址时,它通常需要用下面的这种格式来表示:
(段基址:段内偏移)
其中第一个字段是段基址,它的值由段寄存器来提供(一般来说,段寄存器有 6 种,分别为 cs、ds、ss、es、fs、gs),其中 cs 不可以直接通过汇编指令赋值,其它可以。
最终:
物理地址 = (段基址 << 4) + 段内偏移

段基址

我们想要把 kernel 加载到 0x10000 处,就要计算段基址和段内偏移,可知段基址为 0x1000,段内偏移为 0x0。
所以就要给段基址寄存器赋值 0x1000,段偏移寄存器赋值 0x0。

代码

loader.S

.code16
.global _start_start:mov $0x1000, %axmov %ax, %dsmov %ax, %ssmov %ax, %esmov %ax, %fsmov %ax, %gs# 加载 kernel 到内存mov $0x0000, %bx    # 要加载到的内存地址mov $0x0003, %cx    # ch:磁道号(0x00),cl:起始扇区号(0x03),(扇区 0x01 为 MBR, 扇区 0x02 为 loader)mov $0x02, %ah      # ah:读磁盘命令mov $1, %al         # al:读取的扇区数量,必须小于128,暂时设置成 1 个扇区mov $0x0080, %dx    # dh:磁头号,dl:驱动器号0x80(磁盘1)int $0x13# 跳转到 kerneljmp $0x1000, $0x0000jmp .

我们可以通过 mov 指令,向 ds、ss、es、fs、gs 段寄存器赋值 0x1000,但是 cs 段基址寄存器就不可以使用 mov 指令赋值了,需要使用 jmp 指令。如 jmp $0x1000, $0x0000 就会将 cs 赋值为 0x1000。

start.S

.code16
.global _start_start:jmp .

kernel 的代码目前作为演示就写个简例。
不过注意要在链接时指定代码入口地址为 0x0000(为调试做准备)。
Makefile


OUTPUT=../_build/kernelall:mkdir -p ${OUTPUT}as --32 -g -o ${OUTPUT}/start.o start.Sld -m elf_i386 -Ttext=0x00000 ${OUTPUT}/start.o -o ${OUTPUT}/start.elfobjcopy -O binary ${OUTPUT}/start.elf ${OUTPUT}/kernel.bin  objdump -x -d -S  ${OUTPUT}/start.elf > ${OUTPUT}/start_dis.txtclean:-rm ${OUTPUT}/*

调试

最终 loader 将 kernel 加载到内存的 0x10000 处,并跳转到该位置运行。
可以看到,段寄存器值全为 0x1000,段内偏移为 0x0(eip),该位置对应的汇编代码为 start.S:5 jmp .

自己动手写一个操作系统——loader(1)相关推荐

  1. 自己动手写一个操作系统——MBR(1)

    文章目录 前言 MBR 1) 512 字节镜像 2) 0x55 和 0xAA qemu 运行 参考 前言 上篇<自己动手写一个操作系统--我们能做什么,我们需要做什么>我们介绍到 BIOS ...

  2. 自己动手写一个操作系统——MBR(2)

    前言 上篇文章<自己动手写一个操作系统--MBR(1)>,我们使用 dd 生成了一个 512 字节的镜像,并用 vim 将其最后两个字节修改成了 55 AA,以此来完成了 MBR 的构建. ...

  3. 自己动手写一个操作系统——MBR(4)_调试_elf_bin

    文章目录 前言 elf 文件 指定代码入口地址 添加调试信息 代码 检验 调试 小结 前言 通过 GDB 我们可以跟踪程序的执行, 并且能够看到寄存器的状态, 但是,上面这种调试方式,没有和代码对应起 ...

  4. 自己动手写一个操作系统——我们能做什么,我们需要做什么

    文章目录 计算机启动流程 第一条指令 BIOS MBR loader kernel 总结 计算机启动流程 第一条指令 在开机的一瞬间,也就是上电的一瞬间,CPU 的 CS:IP 寄存器被硬件强制初始化 ...

  5. 写一个操作系统有多难?自制 os 极简教程

    不知道正在阅读本文的你,是否是因为想自己动手写一个操作系统.我觉得可能每个程序员都有个操作系统梦,或许是想亲自动手写出来一个,或许是想彻底吃透操作系统的知识.不论是为了满足程序员们自带的成就感,还是为 ...

  6. 学习较底层编程:动手写一个C语言编译器

    动手编写一个编译器,学习一下较为底层的编程方式,是一种学习计算机到底是如何工作的非常有效方法. 编译器通常被看作是十分复杂的工程.事实上,编写一个产品级的编译器也确实是一个庞大的任务.但是写一个小巧可 ...

  7. (1)从1开始写一个操作系统

    第一章 前言 偶然间使用到了RTX51-tiny做一些东西,它是keil自带的51操作系统,以小巧占用资源少著称,这里不细谈它是如何实现的,反正是一个真正的基于时间片的多任务系统. 往往我们在使用单片 ...

  8. 自己动手写一个简单的bootloader

    自己动手写一个简单的bootloader 15年10月31日19:44:27 (一) start.S 写这一段代码前,先要清楚bootloader开始的时候都做什么了.无非就是硬件的初始化,我们想要写 ...

  9. [从 0 开始写一个操作系统] 一、准备知识

    从 0 开始写一个操作系统 作者:解琛 时间:2020 年 8 月 29 日 从 0 开始写一个操作系统 一.准备知识 1.1 实现方案 1.2 gcc 1.2.1 AT&T 汇编基本语法 1 ...

最新文章

  1. 分布式事务——消息最终一致性方案
  2. python的xlwt模块的常用方法
  3. python 多个列表合并_Python对两个有序列表进行合并和排序的例子
  4. [html] 写一个布局,当页面滚动一定高时,导航始终固定在顶部,反之恢复原位
  5. MESSAGE消息发送失败
  6. 2018尚硅谷大数据视频_韩顺平_Linux视频教程
  7. 关于冒泡、快排、二分排序算法分析
  8. HiveQL(三):修改表ALTER TABLE
  9. .Net Framework4 与.Net Framework4.0 client profile区别问题
  10. IAR各版本下载链接
  11. GET 请求能传图片吗?
  12. 请帮我写一封情书,500字左右
  13. NPDP产品经理证书在中国有用吗?
  14. 手机兼职赚钱,分享2个手机可操作的项目给你!
  15. Asio Streams, Short Reads and Short Writes
  16. 你要的所有数据源都在这里了!
  17. C#ObjectArx Cad创建点线块
  18. Win10+Debian11双系统的配置小记
  19. 最长回文子串Java
  20. 微型计算机的外存储器 现在普遍采用什么,当前微型计算机上大部分采用的外存储器,不包含下列哪些?1.硬盘 2.光盘 3.软盘 4.磁带。...

热门文章

  1. python基于百度智能云实现批量身份证信息识别(附完整代码,可直接使用)
  2. 40 个让你的网站更加友好的 jQuery 插件
  3. Windows Thin PC体验 语言包更改(win 7 included)
  4. 易灵思FPGA-项目设计指南一
  5. 文本数据增强二(EDA、同义词替换-新增-交换-删除-生成同义句)
  6. excel2016 卡_Excel情人节卡2016
  7. 原生1.1.2固件iPhone降级至1.0.2教程
  8. opera创建房间—比较详细
  9. Windows 无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目
  10. QIIME2-单端数据Deblur