Linux-0.11 boot目录bootsect.s详解
Linux-0.11 boot目录bootsect.s详解
模块简介
bootsect.s是磁盘启动的引导程序,其概括起来就是代码的搬运工,将代码搬到合适的位置。下图是对搬运过程的概括,可以有个印象,后面将详细讲解。

bootsect.s主要做了如下的三件事:
- 搬运bootsect.s代码到0x9000:0x0000处
- 加载setup.s代码到0x9000:0x200处
- 加载system模块到0x1000:0x0000处
过程详解
搬运bootsect.s代码到0x9000:0x0000处
将ax寄存器设置为0x07c0, 接着ax寄存器的值拷贝给ds,即ds目前也为0x07c0。
将ax寄存器设置为0x9000, 接着ax寄存器的值拷贝给es,即es目前也为0x9000。
mov $BOOTSEG, %ax #将ds段寄存器设置为0x07c0
mov %ax, %ds
mov $INITSEG, %ax #将es段寄存器设置为0x9000
mov %ax, %es
接下来将ecx的值设置为256。接下来通过sub将si和di寄存器设置为0。
接下来使用rep和movsw从ds:si拷贝256个字(512字节)到es:si处。
mov $256, %cx #设置移动计数值256字
sub %si, %si #源地址 ds:si = 0x07C0:0x0000
sub %di, %di #目标地址 es:si = 0x9000:0x0000
rep #重复执行并递减cx的值
movsw #从内存[si]处移动cx个字到[di]处
接下来使用ljmp跳转到0x9000 偏移量为go处的代码执行。
ljmp $INITSEG, $go
cs寄存器的值为0x9000。接下来的操作就是将ds,es,ss都赋值为0x9000。同时将sp设置为0xFF00。
go: mov %cs, %ax #将ds,es,ss都设置成移动后代码所在的段处(0x9000)mov %ax, %dsmov %ax, %esmov %ax, %ssmov $0xFF00, %sp # arbitrary value >>512
加载setup.s代码到0x9000:0x200处
接下来这一部分用于加载setup.s的代码到0x9000:0200处。
这里利用了BIOS的0x13号中断。
下面是关于BIOS INT 0x13在使用时的说明:
ah = 0x02 读磁盘到内存 al = 4 读4个扇区
ch: 柱面号的低8位, cl: 0-5位代表开始扇区, 6-7位 代表磁道号的高2位代表柱面的高2位。
dh 磁头号 dl 驱动器号。
如果读取成功则执行ok_load_setup。 如果不成功,则对驱动器进行复位,再次读取。
load_setup:mov $0x0000, %dx # drive 0, head 0mov $0x0002, %cx # sector 2, track 0mov $0x0200, %bx # address = 512, in INITSEG.equ AX, 0x0200+SETUPLENmov $AX, %ax # service 2, nr of sectorsint $0x13 # read itjnc ok_load_setup # ok - continuemov $0x0000, %dxmov $0x0000, %ax # reset the disketteint $0x13jmp load_setup
下面依旧是使用INT 0x13去获取一些磁盘驱动器的参数。
ah = 0x08 用于获取驱动器参数。 dl为驱动器号。
返回信息:
- 如果出错则CF置为, ah=状态码
- al = 0, al = 0
- bl为驱动器的类型 AT/PS2
- ch 最大柱面号的低8位
- cl 0-5为每磁道最大扇区数, 6-7代表柱面号高2位
- dh最大磁头数
- dl驱动器数量
- es:di 软驱磁盘参数表
ok_load_setup:mov $0x00, %dlmov $0x0800, %ax # AH=8 is get drive parametersint $0x13mov $0x00, %ch#seg csmov %cx, %cs:sectors+0 # %cs means sectors is in %csmov $INITSEG, %axmov %ax, %es
下面会使用BIOS中断0x10向终端中打印信息。
0x10中断号有多个功能
(1)读光标位置:
功能号:ah=0x03
输入:
- bh = 页号
输出: - ch = 扫描开始线
- cl = 扫描结束线
- dh = 行号
- dl = 列号
(1)打印字符串:
功能号:ah=0x013
输入:
- al = 放置光标的方式和规定属性
- es:bp 字符串位置
- cx = 显示的字符串字符数
- bh = 显示页面号
- bl = 字符属性
- dh = 行号
- dl = 列号
mov $0x03, %ah # read cursor posxor %bh, %bhint $0x10mov $30, %cxmov $0x0007, %bx # page 0, attribute 7 (normal)#lea msg1, %bpmov $msg1, %bpmov $0x1301, %ax # write string, move cursorint $0x10
加载system模块到0x1000:0x0000处
接下来,要继续读system模块到内存中。
ax = 0x1000, es = 0x1000
mov $SYSSEG, %axmov %ax, %es # segment of 0x010000call read_itcall kill_motor
read_it实际上就是将system模块存放在0x1000:0x0000处。
test执行的是0x1000 & 0x0fff = 0x0000,
read_it:mov %es, %axtest $0x0fff, %ax
die: jne die # es must be at 64kB boundaryxor %bx, %bx # bx is starting address within segment
接下来rp_read的过程实际是逐磁道读取磁盘中system模块的过程。如下图所示共两个磁道,两个磁头,每磁道八个扇区,读取顺序如下所示,首先读取0磁头0磁道,然后读取1磁头0磁道,接着读取0磁头1磁道,最后读取1磁头1磁道。

rp_read首先判断是否已经读入了所有的数据(system模块)。比较ax和ENDSEG的值,如果不相等,则跳转到ok1_read中执行。
rp_read:mov %es, %axcmp $ENDSEG, %ax # have we loaded all yet?jb ok1_readret
在ok1_read中,则主要计算了当前磁道上还有多少扇区没有读取完。
ok1_read:#seg csmov %cs:sectors+0, %ax !获取每磁道的扇区数sub sread, %ax !减去当前磁道已读扇区数(bootsect + setup)mov %ax, %cx !cx = ax = 当前柱面未读扇区数shl $9, %cx !cx = cx * 512字节 + 段内偏移add %bx, %cxjnc ok2_read !调用ok2_read函数进行读取当前磁道上剩余扇区。je ok2_readxor %ax, %axsub %bx, %axshr $9, %ax
ok2_read实际的作用就是将当前磁道上的所有扇区全部读完。更具体的,就是读取开始扇区cl和需读扇区数al的数据到es:bx开始处。
ok2_read:call read_track !读当前柱面上指定开始扇区和要读的扇区数mov %ax, %cx !ax代表本次读取的扇区数,复制到cx中add sread, %ax !ax = ax + sread#seg cscmp %cs:sectors+0, %ax !如果当前磁道上还有扇区未读,则跳转到ok3_readjne ok3_readmov $1, %ax !ax = 1sub head, %ax !如果head = 0, ax = ax - head = 1,如果head = 1, ax = ax - head = 0, 即如果磁头号为0,则读取磁头面为1的扇区, 否则的话将读取下一个磁道上的数据。jne ok4_readincw track
如果当前磁道上还有扇区没有读,则会直接进入ok3_read,再次读取。否则先进入ok4_read,移动到下一个磁道或者下一个磁头进行读取。
ok4_read:mov %ax, head !保存当前的磁头号xor %ax, %ax !清除已读扇区数
ok3_read:mov %ax, sread !保存当前扇区已读扇区数shl $9, %cxadd %cx, %bxjnc rp_readmov %es, %axadd $0x1000, %axmov %ax, %esxor %bx, %bxjmp rp_read
接下来的read_track在ok2_read中被调用,其作用是读取当前磁道上的扇面到es:bx处。
回顾一下INT 0x13读取磁盘数据时的参数:
- ah = 0x02 功能号,代表读磁盘到内存
- al = 需要读出的扇区总数
- ch = 磁道(柱面)号的低8位
- cl = 0-5位代表开始扇区, 6-7位代表磁道号的高2位代表柱面的高2位。
- dh = 磁头号
- dl = 驱动器号
- es:bx = 指向数据缓冲区
- 如果出错,则CF标志位置位,ah中将存放出错码
read_track:push %ax !保存ax,bx,cx,dx寄存器push %bxpush %cxpush %dxmov track, %dx !获取当前的磁道号mov sread, %cx !获取当前磁道上的已读扇区数inc %cx !cl = 开始读的扇区号mov %dl, %ch !ch = 当前磁道号mov head, %dx !dx = 当前磁头号, 目前磁头号还在dl中,后面会挪动到dh中。mov %dl, %dh !将磁头号从dl挪动到dh中mov $0, %dl !dl = 驱动器号and $0x0100, %dx !将dx与0x0100进行按位与,实际就是使得磁头号小于等于1。mov $2, %ah !ah = 2,读磁盘扇区的功能号int $0x13 !0x13号中断, 读取磁盘数据。jc bad_rt !如果出错,则跳转运行bad_rtpop %dx !恢复dx,cx,bx,ax寄存器pop %cxpop %bxpop %axret
看到这里,我们再回到调用read_it的地方, 注意到其中的ljmp $SETUPSEG, $0,这便是跳转到了setup.s中进行执行。
mov $SYSSEG, %axmov %ax, %es # segment of 0x010000call read_it !读取磁盘上system模块call kill_motor !关闭驱动器马达#seg csmov %cs:root_dev+0, %axcmp $0, %axjne root_defined#seg csmov %cs:sectors+0, %bxmov $0x0208, %ax # /dev/ps0 - 1.2Mbcmp $15, %bxje root_definedmov $0x021c, %ax # /dev/PS0 - 1.44Mbcmp $18, %bxje root_defined
undef_root:jmp undef_root
root_defined:#seg csmov %ax, %cs:root_dev+0ljmp $SETUPSEG, $0 !跳转到SETUPSEG模块进行执行
Q & A
https://github.com/Wangzhike/HIT-Linux-0.11/blob/master/1-boot/OS-booting.md
文中如有表达不正确之处,欢迎大家与我交流

相关文章:
Linux-0.11 boot目录bootsect.s详解
Linux-0.11 boot目录bootsect.s详解 模块简介 bootsect.s是磁盘启动的引导程序,其概括起来就是代码的搬运工,将代码搬到合适的位置。下图是对搬运过程的概括,可以有个印象,后面将详细讲解。 bootsect.s主要做了如下的三件事: 搬…...
django组件552
前言:相信看到这篇文章的小伙伴都或多或少有一些编程基础,懂得一些linux的基本命令了吧,本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python:一种编程语言&…...
【枚举算法的Java实现及其应用】
文章目录 枚举算法概述枚举算法的实现步骤Java实现枚举算法枚举算法的底层工作原理枚举算法的底层代码讲解枚举算法的实际应用场景枚举算法在场景中解决的问题总结 枚举算法概述 枚举算法是一种通过列举所有可能情况来解决问题的方法。这种算法在解决一些特定类型的问题时非常…...
linux led 驱动
前言 今天是儿童节,挣个奖牌给小孩玩玩。 在 linux 驱动大家庭中,LED 驱动算是个儿童,今天就写写他吧。正好之前写过他的婴儿时期《i.MX6ULL 裸机点亮 LED》,记得那时候他还穿着开裆裤呢,裸鸡嘛。 ioremap() 裸机程…...
平面最近点对(分治算法)
文章目录 平面最近点对(分治算法)Solution流程完整模板代码 平面最近点对(分治算法) 文章首发于我的个人博客:欢迎大佬们来逛逛 平面最近点对(加强版) - 洛谷 给你一些点,求两点之…...
【基于前后端分离的博客系统】Servlet版本
🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一. 项目简介 1. 项目背景 2. 项目用到的技…...
在线Excel绝配:SpreadJS 16.1.1+GcExcel 6.1.1 Crack
前端:SpreadJS 16.1.1 后端: GcExcel 6.1.1 全能 SpreadJS 16.1.1此版本的产品中包含以下功能和增强功能。 添加了各种输入掩码样式选项。 添加了在保护工作表时设置密码以及在取消保护时验证密码的支持。 增强了组合图以将其显示为仪表图。 添加了…...
一个轻量的登录鉴权工具Sa-Token 集成SpringBoot简要步骤
Sa-Token 集成SpringBoot简要步骤 1.1 简单介绍 Sa-Token是一个轻量级Java权限认证框架。 主要解决的问题如下: 登录认证 权限认证 单点登录 OAuth2.0 分布式Session会话 微服务网关鉴权等一系列权限相关问题。 1.2 登录认证 设计思路 对于一些登录之后…...
day 44 完全背包:518. 零钱兑换 II;377. 组合总和 Ⅳ
完全背包:物品可以使用多次 完全背包1. 与01背包区别 518. 零钱兑换 II1. dp数组以及下标名义2. 递归公式3. dp数组如何初始化4. 遍历顺序:不能颠倒两个for循环顺序5. 代码 377. 组合总和 Ⅳ:与零钱兑换类似,但是是求组合数1. dp数组以及下标名义2. 递归…...
K8s in Action 阅读笔记——【5】Services: enabling clients to discover and talk to pods
K8s in Action 阅读笔记——【5】Services: enabling clients to discover and talk to pods 你已了解Pod以及如何通过ReplicaSets等资源部署它们以确保持续运行。虽然某些Pod可以独立完成工作,但现今许多应用程序需要响应外部请求。例如,在微服务的情况…...
牛客网DAY2(编程题)
圣诞节来啦!请用CSS给你的朋友们制作一颗圣诞树吧~这颗圣诞树描述起来是这样的: 1. "topbranch"是圣诞树的上枝叶,该上枝叶仅通过边框属性、左浮动、左外边距即可实现。边框的属性依次是:宽度为100px、是直线、颜色为gr…...
Java经典笔试题—day14
Java经典笔试题—day14 🔎选择题🔎编程题🍭计算日期到天数转换🍭幸运的袋子 🔎结尾 🔎选择题 (1)定义学生、教师和课程的关系模式 S (S#,Sn,Sd,Dc,SA )(其属性分别为学号、姓名、所…...
一个帮助写autoprefixer配置的网站
前端需要用到postcss的工具,用到一个插件叫autoprefixer,这个插件能够给css属性加上前缀,进行一些兼容的工作。 如何安装之类的问题在csdn上搜一下都能找到(注意,vite是包含postcss的,不用在项目中安装pos…...
C语言中的类型转换
C语言中的类型转换 隐式类型转换 整型提升 概念: C语言的整型算术运算总是至少以缺省(默认)整型类型的精度来进行的为了获得这个精度,表达式中字符和短整型操作数在使用之前被转换为普通整型,这种转换成为整型提升 如…...
String底层详解(包括字符串常量池)
String a “abc”; ,说一下这个过程会创建什么,放在哪里? JVM会使用常量池来管理字符串直接量。在执行这句话时,JVM会先检查常量池中是否已经存有"abc",若没有则将"abc"存入常量池,否…...
C++ 里面lambda和函数指针的转换
问题说明 原始问题,代码如下会编译报错: using DecisionFn bool(*)();class Decide { public:Decide(DecisionFn dec) : _dec{dec} {} private:DecisionFn _dec; };int main() {int x 5;Decide greaterThanThree{ [x](){ return x > 3; } };retur…...
前端Rust开发WebAssembly与Swc插件快速入门
前言 现代前端对速度的追求已经进入二进制工具时代,Rust 开发成为每个人的必修课。 一般我们将常见的前端 Rust 开发分为以下几类,难度由上至下递增: 开发 wasm 。 开发 swc 插件。 开发代码处理工具。 我们将默认读者具备最简单的 Rus…...
【C++ 学习 ⑧】- STL 简介
目录 一、什么是 STL? 二、STL 的版本 三、STL 的 6 大组件和 13 个头文件 四、学习 STL 的 3 个境界 五、STL 的缺陷 参考资料: STL教程:C STL快速入门(非常详细) (biancheng.net)。 C STL是什么,有…...
论文笔记--Deep contextualized word representations
论文笔记--Deep contextualized word representations 1. 文章简介2. 文章概括3 文章重点技术3.1 BiLM(Bidirectional Language Model)3.2 ELMo3.3 将ELMo用于NLP监督任务 4. 文章亮点5. 原文传送门 1. 文章简介 标题:Deep contextualized word representations作者…...
【MySQL高级篇笔记-性能分析工具的使用 (中) 】
此笔记为尚硅谷MySQL高级篇部分内容 目录 一、数据库服务器的优化步骤 二、查看系统性能参数 三、统计SQL的查询成本:last_query_cost 四、定位执行慢的 SQL:慢查询日志 1、开启慢查询日志参数 2、查看慢查询数目 3、慢查询日志分析工具…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
