【0】README

  • 0.0) source code from orange’s implemention of a os and for complete code , please visit https://github.com/pacosonTang/Orange-s-OS/blob/master/boot.asm
  • 0.1)本代码仅用于在 根目录区条目中寻找 与 boot代码定义的LoaderFileName 相同文件名 的 条目,仅此而已,该文件名是loader.bin,需要加载入内存继续运行的代码文件;(因为找到该文件后, 最后一句指令执行了 jmp $,所以处理器执行后就停在那里不动,所以这里没有给出运行结果示意图)
  • 0.2) 就本os而言,即orange’s os ,”在根目录区寻找某文件对应的根目录条目“这个任务 是在 引导扇区中的引导程序boot 中完成的,而且 boot 后面还要完成 ”把 os 的 加载程序loader copy 到 0x09000:0100处“的任务,注意这与linux 是不同的
  • 0.3)即是说,orange’s os 中的启动程序boot 执行了两个任务: os引导程序boot 在根目录区寻找os加载程序文件loader 对应的根目录条目 + os引导程序boot 从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)

【1】Source Code

;—————————————————————————-

; 函数名: ReadSector

;—————————————————————————-

; 作用:

; 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中, ax初始值=19

ReadSector:

; ———————————————————————–

; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 磁道=柱面号, 起始扇区, 磁头号=磁面)

; 注意扇区号和起始扇区号不同;扇区号对于整个磁盘的全局索引值,而起始扇区号是本磁道的扇区索引值

; ———————————————————————–

; 设扇区号为 x

; ┌ 柱面号 = y >> 1

; x ┌ 商 y ┤

; ————– => ┤ └ 磁头号 = y & 1

; 每磁道扇区数 │

; └ 余 z => 起始扇区号 = z + 1

 push   bp
mov bp, sp
sub esp, 2 ; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2] mov byte [bp-2], cl ; 在调用者中, cl 被赋值为1, mov cl, 1
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除数 , BPB_SecPerTrk DW 18 ; 每磁道扇区数
div ; y 在 al 中, z 在 ah 中 , div 被除数A 默认存放在AX中(16位以内) 或 AX 和 DX中(32位,DX存放高16位,AX存放低16位)
inc ah ; z ++
mov cl, ah ; cl <- 起始扇区号
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (y/BPB_NumHeads)
mov ch, al ; ch <- 柱面号
and dh, 1 ; dh & 1 = 磁头号
pop bx ; 恢复 bx
; 至此, "柱面号, 起始扇区, 磁头号" 全部得到
mov dl, [BS_DrvNum] ; 驱动器号 (0 表示 A 盘) ,BS_DrvNum DB 0; 中断 13 的驱动器号
.GoOnReading:
mov ah, 2 ; 读
mov al, byte [bp-2] ; 读 al 个扇区
int 13h
jc .GoOnReading ; 如果读取错误 CF 会被置为 1,
; 这时就不停地读, 直到正确为止
add esp, 2
pop bp ret

【2】把文件加载到内存的步骤:寻找文件 + 定位文件 + 读入内存

  • 2.1)寻找文件方法:
    • 2.1.a) 将根目录的第一个扇区(如第19个全局扇区)读入到起始地址为 es:bx=9000h:0100(该地址其实 是在软盘中的数据区去了) ,循环下去的话,读第20、21、….扇区,而es:bx=9000h:0100 永不改变;
    • 2.1.b) 因为一个 sector = 512Bytes, 而根目录条目=32Bytes,所以一个扇区就含有16个条目,我们要遍历这16个条目,并将条目中的DIR_NAME属性(即文件名)和boot 代码中静态的 LoaderFileName 做比较,如果完全匹配的话,那该DIR_NAME所在的条目就是我们要找的根目录条目, 如果不匹配话,转向 步骤c;
    • 2.1.c) add di, offeh , 使得di 指向该条目开头(因为在发现条目中的DIR_NAME 与 LoaderFileName 不等的时候,di指向的是DIR_NAME 的下一个字节),然后 add di, 20h(32个字节,一个条目大小为32字节) , di指向下一条目开头,继续循环比较;如果 第一个扇区的16个根目录条目都比较完了,转向步骤a,只不过该读当前扇区的下一个扇区了;

      Return)该步骤完成后,若寻找文件成功,返回的是 满足 DIR_NAME==LoaderFileName 的 根目录条目;

      (Attention): 你要知道根目录条目是多么 的重要,因为它存储有 (文件名 + 文件属性 + 最后一次写入时间 + 最后一次写入日期 + 此条目对应的开始簇号 + 文件大小) 等信息;这个根目录条目 ,不可小觑;
  • 2.2)定位文件方法(本代码还未涉及到):(参见 http://blog.csdn.net/pacosonswjtu/article/details/48391467 【2.2】文件分配表-FAT 看个荔枝)“

  • 如FAT所在扇区(一个扇区512字节)存储值为:F0 FF FF FF 8F 00 FF FF FF FF FF FF 09 A0 00 FF , 0F 00 00 ;

    则簇号分别为:0-FF0 1-FFF 2-FFF 3-008 4-FFF 5-FFF 6-FFF 7-FFF 8-009 9-00A A-FFF

    如果根目录去中有条目记载某文件A 的 DIR_FstClus=3的话,则对应第3个FAT项,结合上一行,我们知道FAT3==008,所以下一个簇号是8-009 , 以此类推9-00A、 A-FFF。FFF就表示这个簇是最后一个簇了。

    Conclusion:找出该文件在数据区中对应的所有簇,就定位了该文件了;

  • 2.3)读入内存方法(先定位全局扇区,再对寄存器编程):



    (上图错误更正)应该是怎样由扇区号求扇区在磁盘中的位置,不是定位文件;

  • 如何读取扇区内容到内存? 参见 source code 中的 ReadSector 函数。


【3】总结

  • 3.1)首先你要想,寻找文件? 为什么要寻找文件,是因为,我们boot代码要加载loader 代码进入内存,而loader代码在软盘上(硬盘)上,所以我们就要在软盘上寻找该文件。

    为什么boot和loader 不写在同一个程序中?因为 引导扇区只装的下最多 512B,所以要把boot程序和 loader 程序分开来存放,然后再由 boot 跳转到 loader程序去执行;

  • 3.2)怎样寻找? 要知道FAT12软盘中的 根目录区条目存储有 所有文件的相关信息,最重要的就是文件名。通过 利用ReadSector函数 实现 “怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 磁道=柱面号, 起始扇区, 磁头号=磁面)”的功能【暂且叫定位扇区功能,因为一个扇区最直观的表示是全局扇区号,而扇区在软盘中的表示是由3个维度来进行:磁头号(盘面号0,1),磁柱=磁道号,该磁道的上的扇区号来确定】,

    我们就把根目录区的第一个全局扇区号(循环,就进入当前扇区的下一个扇区号),如FAT12 的根目录区第一个扇区号为19(相对于根目录区而言是1,而对于全局而言是19),传入ReadSector函数,将传入的扇区内容读入到 es:bx;下一步,我们就把 es:bx中的根目录条目的FIR_NAME 和 boot代码中静态写死的文件名LoaderFileName 进行比较;

    • 3.2.1)若相等,则文件寻找成功,返回当前所比较的根目录条目(即是LoaderFileName ==DIR_NAME所在的条目)。要知道一个扇区=512Bytes,一个根目录条目=32Bytes,所以一个扇区==16个根目录条目, 所以要在es:bx 处比较16次,是个循环比较;
    • 3.2.2)如果比较不成功,全局扇区号加1(当前为19,加1为20,以此类推),循环下去,直到找到与LoaderFileName 相等的 根目录条目,或者,遍历完 根目录条目的所有扇区(如 根目录条目扇区数量为14,当然,这个是由FAT12的引导扇区设置的,可以变化的)
  • (Attention):其实,你也看到了,要寻找文件,免不了要去定位全局扇区号(磁头号,磁道号,该磁道上的扇区号),定位后,还要读取该扇区到内存的某个位置,读入后,还要对该内存的某些特定值进行比较操作,比较结果有成功,有失败;成功后,返回的是比较成功的当前根目录条目值;这就知道了Loader文件在 根目录区的描述了,包括(文件名 + 文件属性 + 最后一次写入时间 + 最后一次写入日期 + 此条目对应的开始簇号 + 文件大小),接下来,我们就把 Loader 文件加载到内存,准备开始运行该Loader文件了。source code 参见 p114.asm >> https://github.com/pacosonTang/Orange-s-OS/blob/master/p114.asm

版权声明:本文为博主原创文章,未经博主允许不得转载。

os引导程序boot 在根目录区寻找os加载程序文件loader 对应的根目录条目的更多相关文章

  1. os引导程序boot从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)

    [0]README 0.1) 本代码旨在演示 在boot 代码中,如何 通过 loader文件所在根目录条目 找出该文件的 在 软盘所有全局扇区号(簇号),并执行内存中的 loader 代码: 0.2 ...

  2. CAD调试时抛出“正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码”异常的解决方法

    这些天重装了电脑Win10系统,安装了CAD2012和VS2012,准备进行软件开发.在调试程序的时候,CAD没有进入界面就抛出 “正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain ...

  3. 正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样...

    出错提示: 正尝试在 OS 加载程序锁内执行托管代码.不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起. 原因分析: .NET2.0中增加了42种非常强大的调试助手 ...

  4. 检测到 LoaderLock:DLL"XXXX"正试图在OS加载程序锁内执行

    解决方法: ctrl+D+E或alt+ctl+e或使用菜单调试——>异常——>异常窗口——>Managed Debugging Assistants——>去掉LoaderLoc ...

  5. 正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码

    来自:http://www.cnblogs.com/lcxu2/archive/2011/01/16/2004016.html 正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain 或 ...

  6. 在AE二次开发中出“正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。”异常解决方案

    今天的一个项目总用到了AE的开发组件,也就是ESRI公司提供的一系列的开发包(组件)都是以dll(动态链接库的形式)然后今天在调试的时候却出现了“正试图在 OS 加载程序锁内执行托管代码.不要尝试在 ...

  7. 正试图在 os 加载程序锁内执行托管代码

    正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain 或映像初始化函数内运行托管代码... 当我在窗体初始化的时候,调用了一个外部的dill时,它就不知什么原因的 抛出一个“正试图在 ...

  8. spring boot 加载配置 文件

    在springboot启动的过程中,默契情况下会在classpath路径下加载application.properties当做系统配置文件,但有时候我们想要替换成另一个文件,可以 通过以下方式:   ...

  9. Spring boot 国际化自动加载资源文件问题

    Spring boot 国际化自动加载资源文件问题 最近在做基于Spring boot配置的项目.中间遇到一个国际化资源加载的问题,正常来说只要在application.properties文件中定义 ...

随机推荐

  1. Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法

    Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法跟Ubuntu 12.04 - 13.10 以及jellybean编译环境配置没多大区别, 顺便记录下而已: Ub ...

  2. AC日记——换教室 洛谷 P1850

    题目描述 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 i ( 1≤ i≤n)个时同段上, 两节内容相同的课 ...

  3. Axure基础操作

    一  简介 Axure RP就是一个快速原型(Rapid Prototyping)设计工具. 快速原型(快速模型demo)在真正的开发之前,构造一个原型.把需求模块进行落实.实现部分交互. 二  Ax ...

  4. Java原子操作类,你知道多少?

    原子操作类简介 由于synchronized是采用的是悲观锁策略,并不是特别高效的一种解决方案. 实际上,在J.U.C下的atomic包提供了一系列的操作简单,性能高效,并能保证线程安全的类去 更新基 ...

  5. Spring Cloud学习总结(非原创)

    文章大纲 一.课程内容总结二.课程学习地址三.学习资料下载四.参考文章 一.课程内容总结   二.课程学习地址 第一天:https://www.jianshu.com/p/a086421f4bfd第二 ...

  6. Ruby on rails初体验(一)

    接触ruby on rails 已经有一段时间了,想记录一下自己的rails历程.自己写一些小例子来帮助学习.  Rails 适用于那些以数据为中心的应用,很多应用的核心部分包括一个数据库,这些引用的 ...

  7. MyBatis动态SQL底层原理分析 与 JavaScript中的Date对象,以及UTC、GMT、时区的关系

    http://fangjian0423.github.io/categories/mybatis/ http://xtutu.me/the-date-object-in-js/

  8. 报错:LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 1>

    这段时间忙于看文献,没用过VS了. 今天用着用着就报错了: LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 1> 问度娘,大神给出了解决方法 ...

  9. Object-C 类

    Classes 类 像其它的面向对象的语言一样,Object-C也提供创建对象的蓝本.即类. 首先我们在类中定义一些能够反复使用的属性和方法. 然后,我们实例化类,即对象,之后就能够使用属性和訪问. ...

  10. 控制面板的cpl程序列表

    控制面板的cpl程序列表 学习了:https://zhidao.baidu.com/question/2141898537654796628.html 最近用来sysdm.cpl: 辅助功能选项:ac ...