Linux-0.11 boot目录bootsect.s详解

news2024/11/27 0:41:43

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, %ds
	mov	%ax, %es
	mov	%ax, %ss
	mov	$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 0
	mov	$0x0002, %cx		# sector 2, track 0
	mov	$0x0200, %bx		# address = 512, in INITSEG
	.equ    AX, 0x0200+SETUPLEN
	mov     $AX, %ax		# service 2, nr of sectors
	int	$0x13			# read it
	jnc	ok_load_setup		# ok - continue
	mov	$0x0000, %dx
	mov	$0x0000, %ax		# reset the diskette
	int	$0x13
	jmp	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, %dl
	mov	$0x0800, %ax		# AH=8 is get drive parameters
	int	$0x13
	mov	$0x00, %ch
	#seg cs
	mov	%cx, %cs:sectors+0	# %cs means sectors is in %cs
	mov	$INITSEG, %ax
	mov	%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 pos
	xor	%bh, %bh
	int	$0x10
	
	mov	$30, %cx
	mov	$0x0007, %bx		# page 0, attribute 7 (normal)
	#lea	msg1, %bp
	mov     $msg1, %bp
	mov	$0x1301, %ax		# write string, move cursor
	int	$0x10

加载system模块到0x1000:0x0000处

接下来,要继续读system模块到内存中。

ax = 0x1000, es = 0x1000

	mov	$SYSSEG, %ax
	mov	%ax, %es		# segment of 0x010000
	call	read_it
	call	kill_motor

read_it实际上就是将system模块存放在0x1000:0x0000处。

test执行的是0x1000 & 0x0fff = 0x0000,

read_it:
	mov	%es, %ax
	test	$0x0fff, %ax
die:	jne 	die			# es must be at 64kB boundary
	xor 	%bx, %bx		# bx is starting address within segment

接下来rp_read的过程实际是逐磁道读取磁盘中system模块的过程。如下图所示共两个磁道,两个磁头,每磁道八个扇区,读取顺序如下所示,首先读取0磁头0磁道,然后读取1磁头0磁道,接着读取0磁头1磁道,最后读取1磁头1磁道。

rp_read

rp_read首先判断是否已经读入了所有的数据(system模块)。比较ax和ENDSEG的值,如果不相等,则跳转到ok1_read中执行。

rp_read:
	mov 	%es, %ax
 	cmp 	$ENDSEG, %ax		# have we loaded all yet?
	jb	ok1_read
	ret

在ok1_read中,则主要计算了当前磁道上还有多少扇区没有读取完。

ok1_read:
	#seg cs
	mov	%cs:sectors+0, %ax !获取每磁道的扇区数
	sub	sread, %ax         !减去当前磁道已读扇区数(bootsect + setup)
	mov	%ax, %cx           !cx = ax = 当前柱面未读扇区数
	shl	$9, %cx            !cx = cx * 512字节 + 段内偏移
	add	%bx, %cx
	jnc 	ok2_read       !调用ok2_read函数进行读取当前磁道上剩余扇区。
	je 	ok2_read
	xor 	%ax, %ax
	sub 	%bx, %ax
	shr 	$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 cs
	cmp 	%cs:sectors+0, %ax !如果当前磁道上还有扇区未读,则跳转到ok3_read
	jne 	ok3_read
	mov 	$1, %ax       !ax = 1
	sub 	head, %ax     !如果head = 0, ax = ax - head = 1,如果head = 1, ax = ax - head = 0, 即如果磁头号为0,则读取磁头面为1的扇区, 否则的话将读取下一个磁道上的数据。
	jne 	ok4_read
	incw    track 

如果当前磁道上还有扇区没有读,则会直接进入ok3_read,再次读取。否则先进入ok4_read,移动到下一个磁道或者下一个磁头进行读取。

ok4_read:
	mov	%ax, head        !保存当前的磁头号
	xor	%ax, %ax         !清除已读扇区数
ok3_read:
	mov	%ax, sread       !保存当前扇区已读扇区数
	shl	$9, %cx
	add	%cx, %bx
	jnc	rp_read
	mov	%es, %ax
	add	$0x1000, %ax
	mov	%ax, %es
	xor	%bx, %bx
	jmp	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	%bx
	push	%cx
	push	%dx
	mov	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_rt
	pop	%dx           !恢复dx,cx,bx,ax寄存器
	pop	%cx
	pop	%bx
	pop	%ax
	ret

看到这里,我们再回到调用read_it的地方, 注意到其中的ljmp $SETUPSEG, $0,这便是跳转到了setup.s中进行执行。

	mov	$SYSSEG, %ax
	mov	%ax, %es		# segment of 0x010000
	call	read_it     !读取磁盘上system模块
	call	kill_motor  !关闭驱动器马达

	#seg cs
	mov	%cs:root_dev+0, %ax
	cmp	$0, %ax
	jne	root_defined
	#seg cs
	mov	%cs:sectors+0, %bx
	mov	$0x0208, %ax		# /dev/ps0 - 1.2Mb
	cmp	$15, %bx
	je	root_defined
	mov	$0x021c, %ax		# /dev/PS0 - 1.44Mb
	cmp	$18, %bx
	je	root_defined
undef_root:
	jmp undef_root
root_defined:
	#seg cs
	mov	%ax, %cs:root_dev+0

	ljmp	$SETUPSEG, $0   !跳转到SETUPSEG模块进行执行

Q & A

https://github.com/Wangzhike/HIT-Linux-0.11/blob/master/1-boot/OS-booting.md

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/577885.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

doris---Rollup

Rollup 3.5.1基本概念 通过建表语句创建出来的表称为 Base 表(Base Table,基表) 在 Base 表之上,我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的,并且在物理上是独立存储的。 Rollup表的好处&#xff…

C#调用FreeSpire.PDF获取PDF文档中使用的字体

除了图片之外,电子文件中使用的字体都必须要在本机中安装才能正常查看文字(word缺少字体的话会自动使用相似或默认字体),要想知道电子文件中使用的字体,可以将电子文件转换为PDF文件(如果是打印成PDF的话&a…

chatgpt赋能python:Python收集数据在SEO中的重要性

Python 收集数据在 SEO 中的重要性 随着互联网的发展,搜索引擎对于用户获取信息的重要性日益增加。SEO(搜索引擎优化)一直是每个网站必须考虑的问题。Python 收集数据在 SEO 中可以发挥重要的作用,帮助网站提高排名。下面我们来详…

Solidity拓展:数学运算过程中数据长度溢出的问题

在数学运算过程中假如超过了长度则值会变成该类型的最小值,如果小于了该长度则变成最大值 数据上溢 uint8 numA 255; numA;uint8的定义域为[0,255],现在numA已经到顶了,numA会使num变成0(由于256已经超过定义域,它会越过256&…

结构体 --- C语言

目录 1.结构体的声明 2.结构体变量的定义和初始化 3.结构体成员访问 4.结构体传参 1.结构体的声明 结构是一些值的集合,这些称为成员变量,结构的每个成员可以是不同类型的变量。 而数组是一组类型相同的元素的集合。 生活中的描述 人:名…

测试C#分词工具jieba.NET(续1:提取关键词及并行分词)

jieba.NET支持通过两种算法提取文本关键词:TF-IDF算法和TextRank算法,关于这两种算法的介绍详见参考文献10-11,在jieba.NET中对应的类为TfidfExtractor和TextRankExtractor,这两个分词都都支持调用ExtractTags和ExtractTagsWithWe…

文件上传至公有云Nos及对接CDN

项目开发中,需要将图片文件上传至网易公有云的Nos,并且结合CDN做加速服务,记录一下开发过程。流程图: 1. 文件上传到公有云Nos 网易对象存储服务(Netease Object Storage,简称NOS)是网易数帆提供的高可用…

pycharm环境下打开Django内置的数据库Sqlite出错问题解决

问题描述 在数据库库文件中写入一条记录后,在pycharm的terminal终端下执行查看表的命令出错 执行语句为: 连接数据库报错 python manage.py dbshell CommandError: You appear not to have the sqlite3 program installed or on your path. Error:…

JavaScript之DOM基础

1. 初识DOM DOM: 文档对象模型 是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口。 w3c已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容,结构和样式。 DOM树:文档:一个页面就是一个文档, DOM中使用d…

Android逆向猿人学2022年app比赛第四题grpc与Protobuf使用(步步验证)

教程 前言一、起步二、抓包三、分析四、验证五、HOOK借鉴 前言 前面2-3题和第一题解题思路基本上一样的,这里就不出教程了,这篇文章比较繁琐,基本上描述了我做这题的思路,有很多走不通的地方也有对应的方法,所以会比较…

linux网络初探

linux网络 1.1查看本机ip IP地址 IP地址网络地址主机地址,网络地址(网络号)相同的主机为本地网络中的主机,可以直接相互通信,而网络地址不同的主机为远程网络中的主机,相互通信必须通过本地网关&#xf…

Flutter Windows开发环境搭建教程与学习资料推荐

Windows应用软件开发有很多框架可以选择,例如比较流行的Electron、Qt、CEF、WPF、WinForm、MFC、DuiLib、SOUI等等。Flutter是近几年流行的全平台应用开发框架,可以进行Android、IOS、Web、MacOS、Windows、Linux等平台的应用软件开发。 一、Flutter介绍…

启动U盘制作工具Rufus 4.0.2035

Rufus是是一款小巧实用免费开源的帮助格式化和创建可启动USB闪存驱动器的工具,如USB钥匙/软盘、记忆棒等,可快速制作linux系统或者win启动u盘,可快速的将ISO镜像文件制作成可引导启动的USB启动盘,支持ISO镜像、GPT和UEFI&#xff…

设置参考文献编号与文中插入引用的具体步骤

目录 一、前言 二、操作步骤 (一)参考文献设置编号 (二)文章中引用参考文献方式 一、前言 本教程使用的软件是WPS 二、操作步骤 (一)参考文献设置编号 1.把引用文献的这个编号全部删掉 2.右键点击段…

学习笔记——vue中使用el-dropdown组件报错

今天在工作中,发现使用el-select做的下拉框,下拉菜单展开后,鼠标点击下拉框之外的区域时,下拉菜单没有收起。然后,我打开控制台,发现了这个错误。 Uncaught TypeError: Cannot read properties of null (re…

《Linux0.11源码解读》理解(四) head之重新设置IDT/GDT

上节提到,现在cs:ip指向0地址,此处存储着作为操作系统核心代码的system模块,是由head.s和 main.c以及后面所有源代码文件编译链接而成。head.s(以下简称head)紧挨着main.c,我们先执行head。 重新设置内核栈 _pg_dir: _startup_3…

堆(堆排序 模拟堆)

目录 一、堆的数据结构二、堆的操作方法往下调整的示意图往上调整的示意图相关功能的实现思路1.插入一个数2.求最小值3.删除最小值4.删除任意一个元素5.修改任意一个元素 三、堆的实战运用堆排序模拟堆 一、堆的数据结构 堆是一个完全二叉树:除了最后一层结点以外&…

C语言三子棋,五子棋,n子棋的代码实现

C语言三子棋,五子棋,n子棋的代码实现 这里以五子棋为例,来说明开发过程开发思路菜单打印棋盘的打印棋子的打印电脑下棋(随机数)判断输赢代码整合注意事项 这里以五子棋为例,来说明开发过程 其中该项目包含…

《用户增长方法论》从产品、渠道、营销创意等多个维度,搭建了一套完整的用户增长方法体系

关于作者 黄永鹏,目前在阿里巴巴担任高级用户增长专家。黄永鹏是一个典型的 “ 斜杠青年 ” ,十年前从广告咨询行业转战互联网,在 BAT 三家 公司都待过,负责过多款用户和日活过亿的产品,比如腾讯手机管家、百度地图…

chatgpt赋能python:Python练手:提高你的SEO技能

Python练手:提高你的SEO技能 在当今数字化时代,搜索引擎优化(SEO)成为了网站和企业在线成功的关键。优化技巧既可以提高网站的排名,还可以增加网站的可见性,从而吸引更多的流量和潜在客户。Python是一个适…