【0】README

  • 0.1) 本代码旨在演示 在boot 代码中,如何 通过 loader文件所在根目录条目 找出该文件的 在 软盘所有全局扇区号(簇号),并执行内存中的 loader 代码;
  • 0.2) 此代码非常重要,关系到bootloader的加载和运行(打印字母 L)(干货)
  • 0.3) 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.4) 就本os而言,即orange’s os ,”从扇区copy os加载程序 loader 到内存0x09000:0100“这个任务 是在 引导扇区中的引导程序boot 中完成的,而且在 boot 完成本任务之前,引导程序boot还完成 ”在根目录区寻找 加载程序loader 对应的根目录条目“的任务,注意这与linux 是不同的;
  • 0.5)即是说,orange’s os 中的启动程序boot 执行了两个任务: os引导程序boot 在根目录区寻找os加载程序文件loader 对应的根目录条目 + os引导程序boot 从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)
  • Attention)
    • A1) loader文件所在根目录条目 是由 p109.asm 得到的, 在查找完文件名称且匹配后,di 指向文件名的后一个字节,但di还存在于当前匹配成功的 根目录条目中;
    • A2) 要死死记住 根目录条目的数据结构存储的是:(文件名 + 文件属性 + 最后一次写入时间 + 最后一次写入日期 + 此条目对应的开始簇号 + 文件大小)

【1】SOURCE CODE

LABEL_FILENAME_FOUND: ; 找到 LOADER.BIN 后便来到这里继续

 mov    ax, RootDirSectors ; RootDirSectors=14and    di, 0FFE0h   ; di -> 当前条目的开始,每个条目=32字节,0ffe0==1111 1111 1110 0000add    di, 01Ah     ; di -> 首 Sector ,条目数据结构中,开始簇号的offset=26字节;mov    cx, word [es:di]push   cx   ; 保存此 Sector 在 FAT 中的序号 ,cx等于loader文件的开始簇号(在数据区)add    cx, axadd    cx, DeltaSectorNo   ; cl <- LOADER.BIN的起始扇区号(0-based); 这里加完之后,cx=该loader 文件相对于0号扇区的扇区号(也即相对于整个软盘而言)mov    ax, BaseOfLoadermov    es, ax   ; es <- BaseOfLoadermov    bx, OffsetOfLoader  ; bx <- OffsetOfLoadermov    ax, cx   ; ax <- Sector 号LABEL_GOON_LOADING_FILE:push   ax   ; `.push   bx   ;  | es:bp 是串地址,CX=串长度,ah= ,al= '.' 打印什么东西, bh=页号,bl=黑底红字mov    ah, 0Eh  ;  | 每读一个扇区就在 "Booting  " 后面mov    al, '.'  ;  | 打一个点, 形成这样的效果:mov    bl, 0Fh  ;  | Booting ...... int    10h  ;  |   | 一句话说完,以上对register的初始化,都是为触发10h 号中断做准备工作的, pop    bx   ;  |pop    ax   ; /mov    cl, 1

call ReadSector ; 这个ReadSector非常重要,目的就是读取cl个扇区到 es:bx中,而bx 每次都自增512字节;(这是读软盘某扇区到内存中的关键步骤)

 pop    ax  ; cur_line=154, 取出此 Sector 在 FAT 中的序号(ax <- cx),line133 push cx 已压入栈, cx=Loader文件在数据区的开始簇号;

call GetFATEntry ; 找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中

 cmp    ax, 0FFFhjz LABEL_FILE_LOADED  ; 相等,则说明 该簇号是最后一个簇号push   ax   ; 保存 Sector 在 FAT 中的序号mov    dx, RootDirSectorsadd    ax, dxadd    ax, DeltaSectorNo   ;   DeltaSectorNo equ 17add    bx, [BPB_BytsPerSec] ;  bx加上一个扇区的字节数,即跳转到下一个扇区;因为读取地址是 es:bxjmp    LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:mov    dh, 1    ; "Ready." 加载完毕 call   DispStr  ; 显示字符串;

jmp BaseOfLoader:OffsetOfLoader; 这一句正式跳转到已加载到内, 开始执行loader 代码;
; 存中的 LOADER.BIN 的开始处,
; 开始执行 LOADER.BIN 的代码。
; Boot Sector 的使命到此结束**


GetFATEntry Source Code
;—————————————————————————-
; 函数名: GetFATEntry
;—————————————————————————-
; 作用:
; 找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中
; 需要注意的是, 中间需要读 FAT 的扇区到 es:bx 处, 所以函数一开始保存了 es 和 bx

GetFATEntry:push   espush   bxpush   ax ; cur_line=269, ax 存储该文件在FAT中的开始簇号(又FAT的第0和第1项不使用,所以FAT条目的开始簇号起步价为2,且数据区的第一个簇的簇号是2)mov    ax, BaseOfLoader; `.sub    ax, 0100h   ;  | 在 BaseOfLoader 后面留出 4K 空间用于存放 FAT;  | 因为每个扇区=512B,FAT=8个扇区=4k;mov    es, ax   ; /pop    ax   ; ax恢复line269 push ax 的值,(current line=273)mov    byte [bOdd], 0   ; bOdd db  0 ; 奇数(value=1)还是偶数(value=0)mov    bx, 3mul    bx   ; dx:ax = ax * 3mov    bx, 2div    bx   ; dx:ax / 2  ==>  ax <- 商, dx <- 余数cmp    dx, 0jz LABEL_EVENmov    byte [bOdd], 1    ; 奇数(value=1)偶数(value=0)
LABEL_EVEN:;偶数; 现在 ax 是 FATEntry 在 FAT 中的偏移量,下面来; 计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区); 因为 FATEntry 占用12位,解释了line276 line278 的 乘3 和 除2 操作;cur_line=285xor    dx, dx   mov    bx, [BPB_BytsPerSec] ; div    bx ;  dx:ax / BPB_BytsPerSec;  ax <- 商 (FATEntry 所在的扇区相对于 FAT 的扇区号 , FAT共有9个扇区 );  dx <- 余数 (FATEntry 在扇区内的偏移)push   dx  ; FATEntry 在扇区内的偏移mov    bx, 0   ; bx <- 0 于是, es:bx = (BaseOfLoader - 100):00add    ax, SectorNoOfFAT1 ; 此句之后的 ax 就是 FATEntry 所在的扇区号(全局); SectorNoOfFAT1 equ 1 ; FAT1 的第一个扇区号 = BPB_RsvdSecCntmov    cl, 2   call   ReadSector  ; 读取 FATEntry 所在的扇区, 一次读两个, 避免在边界; 发生错误, 因为一个 FATEntry 可能跨越两个扇区; ReadSector 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中, es:bx = (BaseOfLoader - 100):00pop    dx   ; 将 FATEntry 在扇区内的偏移(line292) 出栈,cur_line=300  add    bx, dx   ; 因为bx=0,偏移量 -> bxmov    ax, [es:bx]  ; es:bx = (BaseOfLoader - 100):00+dx( FATEntry 在扇区内的偏移)cmp    byte [bOdd], 1  ; 奇数(value=1)偶数(value=0)jnz    LABEL_EVEN_2    ; 偶数shr    ax, 4    ; 注意,FATEntry=12bit,占用1.5Byte, 这里很好理解
LABEL_EVEN_2:and    ax, 0FFFhLABEL_GET_FAT_ENRY_OK:pop    bxpop    esret

【2】Conclusion(本代码继p109 后,接着摆)

  • 2.0)写在前面:假设这里有个内核,loader加载该内核到内存,而且内核开始执行的时候肯定已经在保护模式下了。所以loader需要做的事情有两件:

    • 2.0.a)加载内核入内存;
    • 2.0.b)跳入保护模式;
  • 2.1)下面演示 以上代码的执行步骤:
    step1)计算该文件起始簇号对应的全局扇区号:
    从根目录条目中抽取出 该文件的起始簇号(FAT专门用于存储文件在数据区的簇号,簇号等于一个或多个扇区),该簇号是相对于数据区的簇号,(因为本FAT12文件系统中,一个簇号==一个扇区,所以簇号就等于扇区的说法,但是不管怎么,知道簇号,我就可以知道扇区号,这些设置是在 FAT12 的引导扇区中定义好了的)所以,我们要算出该簇号对应的 全局簇号(扇区号),因为第一个和第2个FAT不使用,所以全局簇号最后还要减2。
    step2)从软盘上 读取该扇区到内存地址 es:bx=9000:1000处,以便进行数据分析;(当然,每次循环后,偏移地址要增加512字节,也即连续读取该文件的扇区内容到 起始位置0x9000:1000处);
    step3)找出 step1 中算出扇区号在 FAT中的条目:

    • step3.1)首先,算出该扇区在FAT的 对应条目 FATentry 在 FAT中的偏移量(一个条目= 12bits = 1.5Bytes);(注意,这里的条目是FAT条目,不是根目录区条目,不要搞混了)
    • step3.2)然后算出该偏移量在哪个扇区,以及在该扇区的偏移量;
    • step3.3)读取对应FAT条目所在扇区和相邻扇区(也即读2个扇区,因为条目占1.5个字节,可能跨扇区存储)到 es:bx= (9000h-100h): 00 处;
    • step3.4)在es:bx处 对两个扇区求出 该扇区对应的 FAT条目值(即12位值);

    step4)比较FAT条目值 是否 == fffh:

    • step4.1)如果相等,则证明该条目是最后一个条目,即over了;
    • step4.2)如果不等,将该FAT条目压栈(因为它是一个链条,不断压栈,直到 fffh 出现),然后更新该文件的下一个全局扇区号(ax+RootDirSectors+DeltaSectorNo),然后再代入step2)进行循环;最后就可以找出该文件所对应的所有FAT条目,即该文件所占用的所有簇,也即所有扇区了,即是是压栈形成的那个链条值;

    step5)找到该文件占用的所有扇区后,跳转到es:bx的地址,即 jmp BaseOfLoader:OffsetOfLoader ,该 loader文件 仅仅是 打印了 字符 ‘L’ ,(该文件内容,就是刚才step2步骤中把软盘扇区中的内容读入内存 es:bx 的内容),(因为正如step2所说的那样,在上述循环过程中,程序已经把该文件的所有扇区内容读取到起始地址为 BaseOfLoader:OffsetOfLoader=0x90000:1000 的内容空间中去了)


jmp BaseOfLoader:OffsetOfLoader ; 这一句正式跳转到已加载到内
; 存中的 LOADER.BIN 的开始处,
; 开始执行 LOADER.BIN 的代码。
; Boot Sector 的使命到此结束

Attntion)其实你发现: 这个 BaseOfLoader : OffsetOfLoader 处的内容,是 LABEL_GOON_LOADING_FILE 标识符后的 ReadSector函数每次读一个扇区读进去的,而每次的起始扇区号由 GetFATEntry 函数 提供的,而 GetFATEntry 函数的作用:找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中。就这样 ReadSector函数 + GetFATEntry 函数配合起来就把loader文件从 软盘的扇区读到了 起始内存地址 es:bx=9000h:0100 (每次循环后,偏移地址自增512字节);

Complementary)FAT的作用:当文件size 大于 512B,则FAT是找出该文件所占用的全部簇(簇:一个或多个扇区,引导扇区的BPB_SecPerClus记录该数字)

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

  1. Linux加载Linux的引导程序,Linux的引导-引导加载程序:LILO和GRUB

    打开计算机时,计算机执行存储在ROM中的引导代码,这些代码接下来尝试确定如何加载并启动内核.内核检测系统的硬件,然后产生系统的init进程,这个进程总是PID 1. 在出现登录提示符以前,要完成几项工 ...

  2. spring boot实战(第六篇)加载application资源文件源码分析

    前言 在上一篇中了解了spring配置资源的加载过程,本篇在此基础上学习spring boot如何默认加载application.xml等文件信息的. ConfigFileApplicationLis ...

  3. 启动django时报错Watching for file changes with StatReloader(使用状态加载程序监视文件更改 )...

    原因:可能是Django版本和Python版本或者PyMysql版本不一致 解决:升级或者降级Django版本 命令如下: pip install django==2.1.7 #django==版本号 ...

  4. os引导程序boot 在根目录区寻找os加载程序文件loader 对应的根目录条目

    [0]README 0.0) source code from orange's implemention of a os and for complete code , please visit h ...

  5. 【技术分享】如何解锁高通骁龙660上的安卓引导加载程序

    本文是我们在DEF CON 29大会上的演示视频的配套文章,视频的链接地址为https://www.youtube.com/watch?v=z4gIxdFfJDg. 要想在安卓手机上获得root权限, ...

  6. TA416 APT使用新的Golang版本的PlugX恶意软件加载程序进行钓鱼攻击

    TA416 APT使用新的Golang版本的PlugX恶意软件加载程序,对从梵蒂冈到非洲的外交官等一系列受害者进行了鱼叉式网络钓鱼攻击. TA416高级持续威胁(APT)攻击者又回来了,在经历了一个月 ...

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

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

  8. 检测到 LoaderLock Message Microsoft.DirectX.dll”正试图在 OS 加载程序锁内执行托管代码。...

    今天在群里有朋友问了一个"检测到 LoaderLock Message Microsoft.DirectX.dll"正试图在 OS 加载程序锁内执行托管代码."的问题,自 ...

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

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

最新文章

  1. redis常见使用场景下PHP实现
  2. 面试中关于多线程同步,你必须要思考的问题
  3. 计算机网络技术专业的规划,计算机网络技术专业建设规划
  4. python闭包与装饰器的代码解释
  5. 鸟类南飞,去的是哪个“南方”?
  6. 旅游景点人流量代码php,用 PHP 爬虫做旅游数据分析
  7. JS模块化开发_思维导图
  8. MyBatis学习总结(26)——Mybatis源码中使用了哪些设计模式?
  9. cookie和session笔记
  10. MapGuide Viewer
  11. 网站使用云服务器有什么好处?
  12. 地产大佬潘石屹宣布入坑Python,这是要来抢我们的饭碗了吗?
  13. 2018年软工第二次结对作业
  14. win10安装steam有损计算机,win10系统steam安装更新失败的解决方法
  15. AOJ-AHU-OJ-5 渊子赛马
  16. C++随机生成中文名的实例
  17. 气传导耳机排名,值得入手的气传导耳机推荐
  18. 【论文阅读笔记】High Quality Monocular Depth Estimation via Transfer Learning
  19. 国产无线充电宝哪个牌子好?国产无线充电宝品牌排行
  20. python 基础知识点 (一)

热门文章

  1. 剑指 Offer 43. 1~n 整数中 1 出现的次数(数位dp)
  2. cf1526E. Oolimry and Suffix Array(未解决)
  3. Defend Your Country
  4. Xor sum HDU - 6955
  5. 数据结构题(莫队算法)
  6. [CF1442 D] Sum(分治优化dp + 结论)
  7. P4770:你的名字(SAM、线段树合并)
  8. 欢乐纪中某B组赛【2019.1.25】
  9. P3629-[APIO2010]巡逻【树的直径】
  10. Educational Codeforces Round 94 (Rated for Div. 2)