博客网址:www.shicoder.top

微信:18223081347

欢迎加群聊天 :452380935

这一次我们进入操作系统实现的真实编码, 这一次主要是完善对boot.asm文件的全部实现,开始吧。。。

首先我们先来理一下boot.asm需要干什么

  • 打印出Booting System...
  • 实现磁盘读写
  • 将后续的loader.asm所在的区域读入到0x1000处,然后跳转进入loader.asm程序
  • 开始执行loader.asm程序(这一节我们下次实现)

实模式下的print

在我们平时编写c语言时候,可以直接使用,但是在boot.asm中,完全就没有可以用库函数,因此为了在开始打印处start boot,我们需要自己实现print

先来看下代码把

  1. mov si, booting
  2. call print
  3. print:
  4. mov ah, 0x0e
  5. .next:
  6. mov al, [si]
  7. cmp al, 0
  8. jz .done
  9. int 0x10
  10. inc si
  11. jmp .next
  12. .done:
  13. ret
  14. booting:
  15. db "Booting System...", 10, 13, 0; \n\r

这段程序主要使用使用BIOS的int 10h来实现一个print功能,al寄存器存储要显示的字符串

磁盘读写

因为boot.asm在主引导扇区,磁盘内存太小,不能在boot.asm中实现loader.asm的功能,因此我们将loader.asm保存在磁盘的一个地方,在boot.asm中利用磁盘读的方式,将代码读入到内存的一个区域,然后跳转到那个地方

先来看下磁盘读的功能实现

  1. ; 函数参数
  2. ; edi 将磁盘内容读到哪里
  3. ; ecx 从磁盘哪一个扇区开始
  4. ; bl 要读多少个扇区
  5. read_disk:
  6. ; 设置读写扇区的数量
  7. ; 0x1f2 是硬盘控制端口,表示读写扇区的数量
  8. mov dx, 0x1f2
  9. mov al, bl
  10. ; 写端口用OUT指令 al的值写入到dx端口
  11. out dx, al
  12. inc dx; 0x1f3 起始扇区前8位端口
  13. ; 因为ecx为起始扇区
  14. ; ecx中的cl就是0-7
  15. mov al, cl; 起始扇区前8
  16. out dx, al
  17. inc dx; 0x1f4 起始扇区中8位端口
  18. shr ecx, 8 ;右移8
  19. mov al, cl; 起始扇区中8
  20. out dx, al
  21. inc dx; 0x1f5 起始扇区高8位端口
  22. shr ecx, 8 ;右移8
  23. mov al, cl; 起始扇区高8
  24. out dx, al
  25. inc dx ;0x1f6
  26. shr ecx, 8
  27. and cl, 0b1111 ;将高4位置为0,对应起始扇区的24-27
  28. mov al,0b1110_0000 ;第4位为0,表示主盘,第6位为1,表示LBA5-7位必须为1
  29. ; alcl合二为一,放在al
  30. or al, cl
  31. out dx, al
  32. inc dx ;0x1f7
  33. mov al, 0x20 ;表示读硬盘
  34. out dx, al
  35. xor ecx, ecx ;清空ecx
  36. mov cl, bl ;得到写扇区的数量
  37. ; loop指令会检查ecx是否为0 clecx里面
  38. .read:
  39. push cx ;保存下,因为函数里面使用了
  40. call .waits ;等待数据准备完毕
  41. call .reads ;读取一个扇区
  42. pop cx ;恢复
  43. loop .read
  44. ret
  45. .waits:
  46. mov dx, 0x1f7 ;读0x1f7端口
  47. .check:
  48. in al, dx ;将dx端口的值放入al
  49. jmp $+2 ;直接跳转到下一行 其实什么都没做,就是为了延迟一下
  50. jmp $+2
  51. jmp $+2
  52. and al, 0b1000_1000 ;获得al的第3位和第7
  53. cmp al, 0b0000_1000 ;测试是否第7位为0,第3位为1 硬盘不繁忙,数据准备完毕
  54. jnz .check ;数据没准备好
  55. ret
  56. .reads:
  57. mov dx, 0x1f0 ;用于读写数据
  58. mov cx, 256 ;一个扇区256字节
  59. ; loop指定会检查ecx cxecx里面
  60. .readw:
  61. in ax, dx
  62. jmp $+2 ;直接跳转到下一行 其实什么都没做,就是为了延迟一下
  63. jmp $+2
  64. jmp $+2
  65. ; edi表示读取的目标内存
  66. mov [edi], ax
  67. ; 因为ax16bit2个字节,所以edi+2
  68. add edi, 2
  69. loop .readw
  70. ret

下面是磁盘的相关端口

Primary 通道 Secondary 通道 in 操作 out 操作
0x1F0 0x170 Data Data
0x1F1 0x171 Error Features
0x1F2 0x172 Sector count Sector count
0x1F3 0x173 LBA low LBA low
0x1F4 0x174 LBA mid LBA mid
0x1F5 0x175 LBA high LBA high
0x1F6 0x176 Device Device
0x1F7 0x177 Status Command
  • 0x1F0:16bit 端口,用于读写数据
  • 0x1F1:检测前一个指令的错误
  • 0x1F2:读写扇区的数量
  • 0x1F3:起始扇区的 0 ~ 7 位
  • 0x1F4:起始扇区的 8 ~ 15 位
  • 0x1F5:起始扇区的 16 ~ 23 位
  • 0x1F6:
    • 0 ~ 3:起始扇区的 24 ~ 27 位
    • 4: 0 主盘, 1 从片
    • 6: 0 CHS, 1 LBA
    • 5 ~ 7:固定为1
  • 0x1F7: out
    • 0xEC: 识别硬盘
    • 0x20: 读硬盘
    • 0x30: 写硬盘
  • 0x1F7: in / 8bit
    • 0 ERR
    • 3 DRQ 数据准备完毕
    • 7 BSY 硬盘繁忙

注意上面的out和in指令

读端口用IN指令,写端口用OUT指令

out a,b 将b的值写入到a端口

in a,b 将b端口的值读到a中

先来看4个起始扇区的寄存器 :0x1F30x1F40x1F50x1F6,假如此时的起始扇区ecx=123456789 ,即32位bit为00000111010110111100110100010101

  • 0-7位:00010101 => 0x1F3

  • 8-15位:11001101 => 0x1F4

  • 16-23位:01011011 => 0x1F5

  • 24-31位:00000111

    • 24-27位:0111 => 0x1F6(0-3)
    • mov al,0b1110_0000
      • 0 => 0x1F6(4) 表示主盘
      • 111 => ox1F6(5-7) 固定为1

再来看0x1F7,值为0x20,表示读磁盘

然后通过mov cl,bl,将扇区数量放在cl中,后面进行循环,汇编中循环的次数和ecx有关。因为是要读磁盘,因此需要先等待磁盘数据处理好,然后才进行读取,.wait便是这个作用,其余的相关解析可以通过代码注释看懂,这里就不赘述了

jmp $+2

可以通过反汇编看到

0000:jmp $+2

0002:xxx

所以这行代码就是跳到下一行,起到等待的作用

经过编写这个函数,我们就可以从磁盘中得到我们想要的代码啦,前面说过,我们本身就想将loader.asm代码放在磁盘的一个地方,然后再读进来,那怎么放呢,这样,我们先简单写一个loader.asm

loader.asm

代码如下

  1. [org 0x1000]
  2. ; 打印字符串
  3. mov si, loading
  4. call print
  5. ; 阻塞
  6. jmp $
  7. print:
  8. mov ah, 0x0e
  9. .next:
  10. mov al, [si]
  11. cmp al, 0
  12. jz .done
  13. int 0x10
  14. inc si
  15. jmp .next
  16. .done:
  17. ret
  18. loading:
  19. db "Loading System...", 10, 13, 0; \n\r

同样的,我们只是打印出一句话即可,那我们怎么将这些代码复制到磁盘中去呢,下面两行命令

  1. nasm -f bin loader.bin loader.asm
  2. dd if=loader.bin of=master.img bs=512 count=4 seek=2 conv=notrunc

利用dd命令,将bin文件从偏移为2的地方,写入4个到master.img中,这样就可以知道loader.bin在磁盘哪里,就可以读入了

boot.asm中代码如下

  1. ; 因为loader.bin是从第2个扇区开始写入,写了4个扇区
  2. mov edi, 0x1000;读取的目标内存
  3. mov ecx, 2 ;起始扇区
  4. mov bl, 4 ;扇区数量
  5. call read_disk

经过上面一番折腾,终于从boot跳转到loader中了,后续我们将对loader.asm进行完善,实现loader所需要的功能,下次见啦。。。

操作系统实现-boot.asm实现的更多相关文章

  1. Ubuntu Bochs boot.asm 测试

    /********************************************************************* * Ubuntu Bochs boot.asm 测试 * ...

  2. 操作系统Lab1 详解(boot|kern/debug)

    总体 : boot kern libs tools boot asm.h bootmain.c bootasm.S asm.h 汇编头文件 SEG_NULLASM 定义一个空段描述符 SEG_ASM ...

  3. 操作系统篇-hello world(免系统运行程序)

     || 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言     今天起开始分享关于操作系统的相关知识,本人也是菜鸟一个,正处于学习阶段,这整个操作系统篇也是我边学习边总结的一些结果,希 ...

  4. MIT 6.828 JOS学习笔记4. Lab 1 Part 2.1: The Boot Loader

    Part 2: The Boot Loader 对于PC来说,软盘,硬盘都可以被划分为一个个大小为512字节的区域,叫做扇区.一个扇区是一次磁盘操作的最小粒度.每一次读取或者写入操作都必须是一个或多个 ...

  5. 《30天自制操作系统》笔记(02)——导入C语言

    <30天自制操作系统>笔记(02)——导入C语言 进度回顾 在上一篇,记录了计算机开机时加载IPL程序(initial program loader,一个nas汇编程序)的情况,包括IPL ...

  6. 自制操作系统 (三) 从启动区执行操作系统并进入C世界

    qq:992591601 欢迎交流 2016.04.03 2016.05.31 2016.06.29 这一章是有些复杂的,我不太懂作者为什么要把这么多内容都放进一天. 1读入了十个柱面 2从启动区执行 ...

  7. 操作系统开发系列—9.Loader

    一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列 ...

  8. [自制简单操作系统] 2、鼠标及键盘中断处理事件[PIC\GDT\IDT\FIFO]

    1.大致介绍: >_<" 大致执行顺序是:ipl10.nas->asmhead.nas->bootpack.c PS: 这里bootpack.c要调用graphic. ...

  9. [自制简单操作系统] 1、从0-1到汇编再到c语言的奥秘

    目录: 1.用0-1编写最简单的操作系统 2.用汇编改写上面0-1程序 2.1 只用DB的汇编改写版  2.2 加入RESB汇编的改写版  2.3 进一步使用汇编替换0-1文件  2.4 核心程序也用 ...

随机推荐

  1. java-IO异常处理

    以前的异常处理 public class Demo3 { public static void main(String[] args) { //提高fw的作用域 //变量定义的时候可以没有值,但是使用 ...

  2. java后台解决上传图片翻转90的问题,有demo,经过测试可用

    1.需要加入 依赖 metadata-extractor.jar 依赖如下 <dependencies> <!-- Extracts Exif, IPTC, XMP, ICC and ...

  3. 关于disabled的事,你用对了吗?

    大家都知道disabled属性用来禁用表单里的元素.如果让你来禁用一个表单元素,你会怎么做么,下面提供几种写法,各位看官请看 html: <button type='button'>tes ...

  4. js中的bool值转换及"&&" 、"||"、 "!!"详解

    bool值转换 数据类型 bool值转化 undefined undefined 转化为 false Object null 转化为false,其他为 true Boolean false 转化为 f ...

  5. 论文解读(XR-Transformer)Fast Multi-Resolution Transformer Fine-tuning for Extreme Multi-label Text Classification

    Paper Information Title:Fast Multi-Resolution Transformer Fine-tuning for Extreme Multi-label Text C ...

  6. 【Android开发】控件外边框自定义

    1.在drawable里面新建自定义的资源文件shape <?xml version="1.0" encoding="utf-8"?> <sh ...

  7. 用Python爬取斗鱼网站的一个小案例

    思路解析: 1.我们需要明确爬取数据的目的:为了按热度查看主播的在线观看人数 2.浏览网页源代码,查看我们需要的数据的定位标签 3.在代码中发送一个http请求,获取到网页返回的html(需要注意的是 ...

  8. Exchange 2013 中 NDR 常见的失败返回状态代码

    增强状态代码 描述 可能的原因 其他信息 4.3.1 Insufficient system resources 发生内存不足错误.资源问题(例如磁盘已满)可能导致该问题.您可能会收到内存不足错误,而 ...

  9. Ubuntu安装开发者平台Backstage

    Ubuntu安装开发者平台Backstage 什么是Backstage? Backstage是一个构建开发者门户的开源平台.通过支持一个集中的软件分类,Backstage可以保存并发布你的微服务和基础 ...

  10. Python入门-字符串格式化

    一.不推荐使用:%号 #正常按照位置传递参数 print('%s asked %s to do something' % ('egon', 'lili')) #先后顺序不能乱 #字典传递参数 prin ...