Linux源码学习笔记day2 开机后BIOS是怎么从硬盘复制到内存?

在这篇文章 Linux源码学习笔记 day1 开机时如何加载系统?我们学习到开机后会修改段寄存器ds为 0x07c0,方便之后利用这个段基址进行内存寻址。

这次我们主要学习以下几行代码:

.equ INITSEG, 0x9000
mov	$INITSEG, %ax	#将es段寄存器设置为0x900
mov	%ax, %es
mov	$256, %cx		
sub	%si, %si		
sub	%di, %di		
rep				
movsw

第一行先 定义常量INITSEG 为0x9000。

然后取出INITSEG的值 给到通用寄存器ax。

接着把ax给到了 段寄存器es。这时候es里的值就是0x9000了。

然后把立即数 256 给到了 通用寄存器 cx(一般cx 用作计数器)。

接下来2个 sub 指令,就是把 si 和 di都清零了。

现在ds, es, cx, si, di都有值了。

ds = 0x07c0
es = 0x9000
cx = 256
si = 0
di = 0

关键寄存器就变成了这样。

接下来的指令:

rep movsw

这里rep 是重复的意思,movsw是复制一个字。就是不断地复制一个字。


这里扩展一下:


MOVS 是串指令里的串传送:



一般来说 cx里有值,就意味要有循环了。

循环的次数:就是cx的值256。退出条件就是cx == 0

从哪儿复制到哪儿:从ds:si 复制到es:di,也就是0x7c00 复制到0x90000。


一次复制2个字节,复制256次 正好是复制了512个字节!也就是说将内存地址 0x7c00 处开始往后的 512 字节的数据,复制到 0x90000 处开始的后面 512 字节的地方


也就是这里的第二步:

接下来是一个跳转指令:

ljmp	$INITSEG, $go	#段间跳转,这里INITSEG指出跳转到的段地址,解释了cs的值为0x9000
go:	mov	%cs, %ax		#将ds,es,ss都设置成移动后代码所在的段处(0x9000)
	mov	%ax, %ds

作者那里是8086的指令里是jmpi,我看的这个是AT&T指令,这里是ljmp。

反正意思都是段间跳转。这里由于INITSEG是0x9000 所以就是要跳转到0x9000:go的地址。段基址要左移4位,所以最后要跳转到0x90000 + go的内存地址。

这个go: 在这里是一个标签(label),编译成机器码的时候会变成一个值,就是段内偏移地址。

这时候,假设偏移量是0x10,其实就是这一行代码

mov	%cs, %ax

所在的内存地址就是 0x90000 + 0x10 = 0x90010 CPU最终就会跳转到0x90010处。

下一次,我们一起看看go里面又发生了哪些”精彩“?

如果你觉得有点收获,欢迎点个关注, 也欢迎分享给你身边的朋友。

#头条创作挑战赛# #程序员# #Linux#

展开阅读全文

页面更新:2024-04-25

标签:基址   机器码   内存   寄存器   字节   指令   源码   这时候   也就是   硬盘   代码   地址

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top