os引导程序boot 在根目录区寻找os加载程序文件loader 对应的根目录条目
【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.1.c) add di, offeh , 使得di 指向该条目开头(因为在发现条目中的DIR_NAME 与 LoaderFileName 不等的时候,di指向的是DIR_NAME 的下一个字节),然后 add di, 20h(32个字节,一个条目大小为32字节) , di指向下一条目开头,继续循环比较;如果 第一个扇区的16个根目录条目都比较完了,转向步骤a,只不过该读当前扇区的下一个扇区了;
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 对应的根目录条目的更多相关文章
- os引导程序boot从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)
[0]README 0.1) 本代码旨在演示 在boot 代码中,如何 通过 loader文件所在根目录条目 找出该文件的 在 软盘所有全局扇区号(簇号),并执行内存中的 loader 代码: 0.2 ...
- CAD调试时抛出“正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码”异常的解决方法
这些天重装了电脑Win10系统,安装了CAD2012和VS2012,准备进行软件开发.在调试程序的时候,CAD没有进入界面就抛出 “正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain ...
- 正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样...
出错提示: 正尝试在 OS 加载程序锁内执行托管代码.不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起. 原因分析: .NET2.0中增加了42种非常强大的调试助手 ...
- 检测到 LoaderLock:DLL"XXXX"正试图在OS加载程序锁内执行
解决方法: ctrl+D+E或alt+ctl+e或使用菜单调试——>异常——>异常窗口——>Managed Debugging Assistants——>去掉LoaderLoc ...
- 正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码
来自:http://www.cnblogs.com/lcxu2/archive/2011/01/16/2004016.html 正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain 或 ...
- 在AE二次开发中出“正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。”异常解决方案
今天的一个项目总用到了AE的开发组件,也就是ESRI公司提供的一系列的开发包(组件)都是以dll(动态链接库的形式)然后今天在调试的时候却出现了“正试图在 OS 加载程序锁内执行托管代码.不要尝试在 ...
- 正试图在 os 加载程序锁内执行托管代码
正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain 或映像初始化函数内运行托管代码... 当我在窗体初始化的时候,调用了一个外部的dill时,它就不知什么原因的 抛出一个“正试图在 ...
- spring boot 加载配置 文件
在springboot启动的过程中,默契情况下会在classpath路径下加载application.properties当做系统配置文件,但有时候我们想要替换成另一个文件,可以 通过以下方式: ...
- Spring boot 国际化自动加载资源文件问题
Spring boot 国际化自动加载资源文件问题 最近在做基于Spring boot配置的项目.中间遇到一个国际化资源加载的问题,正常来说只要在application.properties文件中定义 ...
随机推荐
- StringTokenizer:字符串分隔用法简介
StringTokenizer:字符串分隔解析类型 属于:java.util包. 1.构造函数. 1. StringTokenizer(String str) :构造一个用来解析str的StringT ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---2
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下: <Linux命令行与shell脚本 ...
- UnionFind(PYthon实现)
UnionFind用于解决图的连通性问题,不需要给出具体路径的情况,可用来计算连通分支数 参考链接: https://blog.csdn.net/dm_vincent/article/details/ ...
- 转:C#制作ORM映射学习笔记三 ORM映射实现
现在开始实现ORM的主体模块,首先需要在项目中新建一个类,命名为DbAccess,然后在项目的引用中添加两个dll,分别是MySql.Data.dll和System.Data.SQLite.dll,这 ...
- 在Alfred添加自定义站内搜索
1.Google的站内搜索和渣度的对比,懒得吐槽了 2.在Alfred添加自定义站内搜索步骤 Add Custome Search 把搜索某个关键词的url复制到里面,把url里的关键词替换成{que ...
- 三、Ubuntu 使用Xshell
1.下载一个Xshell 2.输入命令:ssh root@Ubuntu的ip地址 输入密码,即可连接 如果遇到不可连接.在Ubuntu中输入命令 vim /etc/ssh/sshd_config 更 ...
- [Python Debug] How to install external python package? MAC系统下的xgboost安装
从昨天晚上开始安装xgboost,经历了各种稀奇古怪的错误,终于现在程序可以跑起来了.整个过程对python编译环境,路径设置,package安装方法有了一定了解,当然还有一些疑惑,所以姑且做个记录. ...
- koa2 从入门到进阶之路 (二)
之前的文章我们已经能够在本地启动一个简单的项目,本章我们来看一下 koa 路由,get 传值,动态路由. 一.Koa 路由 路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP ...
- Vue中this.$router.push参数获取
传递参数的方法:1.Params 由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效.需要用name来 ...
- Kali Linux 2017中Scapy运行bug解决
Kali Linux 2017中Scapy运行bug解决 Scapy是一款强大的网络数据包构建工具.在Kali Linux 2017中,当在scapy的命令行中,运行res.graph()生成图形 ...