/Boot/bootsect.s解读(一)

@[TOC]Boot/bootsect.S
以下代码是从吴成兵老师整理的Linux0.11的源码中,移植过来的。如果有侵权的地方,可以通知我,然后我删除。如果没有问题的话,以后文章将不再重复说明来源。
因为我现在不会使用优快云的汇编格式块,所以使用C语言的格式来说明代码。其次,我会删除一些源代码中的一些英文注释,只保留代码部分。
如果有任何问题也可以在优快云询问我(我是真小白。),或者私聊我QQ:705318074。好的废话不多说直接开始吧

SYSSIZE = 0x3000

当时林纳斯认为0x3000也就是192KB(这里有一个问题,因为在文章中写的是196KB,而实际上应该是192KB,我不知道原因,我将按照192KB来概述),对于当时的linux系统来说是足够了的。注意这个SYSSIZE是段地址,所以需要向左偏移16位,否则会得到12KB错误的结果

/*
 *这里是汇编的格式,定义了几个全局标识符。
 */
.globl begtext, begdata, begbss, endtext, enddata, ednbss
.text
begtext:
.data
begdata:
.bss
begbss:
/*
 *下面是系统加载时的一些参数
 *SETUPLEN是setup.s这个文件编译后所占据的扇区数:4,也就是4*512Byte
 *BOOTSEG是CPU上电以后BIOS将读取到的正确的引导程序复制到内存的段地址
 *INITSEG是bootsect.s后面被复制的地址,也就是说bootsect.s会被复制到0x90000这个地址
 *SETUPLEN是setup.s会被加载的地方,刚好0x200是512byte,所以没有空袭。
 *SYSSEG是系统会被加载到的地址
 *ENDSEG是指示系统在何处停止加载。
 */
SETUPLEN	= 4
BOOTSEG		= 0x07C0
INITSEG		= 0x9000
SETUPSEG	= 0x9020
SYSSEG		= 0x1000
ENDSEG		= SYSSEG + SYSSIZE
ROOT_DEV	= 0x306

ROOT_DEV这个参数有点复杂,等到了实际引用的地方再详细讲一讲。现在放下,只需要了解这个是一个启动盘的标识。

/*
 *这段代码是将从0x07C00处复制512Byte到0x90000处,也就是把bootsect.s文件复制到0x90000处
 *因为x86汇编语言中不允许直接对段寄存器赋立即数,所以使用AX寄存器来当媒介
 *在x86中,DS:SI指向数据源地址,ES:DI指向数据目标地址,复制次数在CX寄存器中保存。
 *sub是减法指令,也就是将SI和DI置零
 *rep是重复执行这条指令下面的指令,重复次数在CX中保存,执行一遍以后CX会自减。
 *movw是指一次移动一个字(word)。
 *go是一个相对偏移,也就是只是相对于start这个标识的偏移。因此jmpi go, INITSEG这个语句是这么理解 
 *的,其中go是赋予ip的数值,是段内偏移,INITSEG是段地址。
 *因为即使在0x07C00处复制完以后,程序会执行到0x07C00:go处执行,因为上面的代码已经将整个程序复制
 *到了0x90000处,所以跳转到0x9000:go处执行是一样的,
 */
entery start
start:
	mov AX, #BOOTSEG
	mov DS, AX
	mov	AX, #INITSEG
	mov ES, AX
	mov CX, #256
	sub SI, Si
	sub DI, DI
	rep
	movw
	jmpi	go, INITSEG
/*
 *这段代码使DS和ES段寄存器变成当前CS指向的段地址了,也就是0x9000
 */
go:
	mov	AX, CS
	mov DS, AX
	mov ES, AX
/*
 *这两句代码定义了引导程序临时栈的位置也就是SS:SP(0x9000:0xFF00),linus觉得栈要远大于512字节,
 *之所以称为临时栈,是因为在后面执行中,这个位置回事system所在位置,所以肯定会被覆盖的。
 */

	mov SS, AX
	mov SP, #0xFF00
/*
 *下面这段代码负责加载setup.s这个文件,需要调用BIOS提供的0x13号中断,
 *AH中保存着13号中断的子程序编号,02h也就是读扇区。
 *AL中保存着扇区数
 *CH是柱面,CL是起始扇区
 *DH是磁头,
 *DL是驱动器,00h~7Fh是软盘,80h~FFh是硬盘
 *这里要说明一下,在我们所有编程中计数都是从0开始的,但是在扇区中却是从1开始的,
 *这就是为什么CL是2而不是1的原因。
 *因为读扇区成功后,CF标识位为0,AL为读出的扇区数。
 *读成功就跳转到ok_load_setup处执行
 *否则复位驱动器,然后重新读,毕竟现在系统都没有起来,什么都解决不了。
 */
load_setup:
	mov DX, #0x0000
	mov CX, #0x0002
	mov BX, #0x0200
	mov AX, #0x0200 + SETUPLEN
	int 0x13
	jnc ok_load_setup
	mov DX, #0x0000
	mov AX, #0x0000
	int 0x13
	j	load_setup
/*
 *下面这段得到磁盘驱动器的参数,
 *0x13号中断的08H功能,
 *CH保存着柱面低8位, CL的位7-6为柱面的高2位,CL的5-0为扇区数
 *seg会影响下面的一条语句,也就是
 *mov CS:[sectors], CX,
 *在sectors这个变量中保存了一个柱面的扇区个数。
 *因为这个功能也会更改ES段寄存器,所以要更改回来
 */
ok_load_setup:
	mov DL, #0x00
	mov AX, #0x0800
	int 0x13
	mov CH, #0x00
	seg cs
	mov sectors, CX
	mov AX, #INITSEG
	mov ES, AX

至于0x13号中断有什么其他功能,为什么会改变ES段寄存器,有兴趣的可以自己去学习,我这里给一个参考网址:0x13号中断介绍

/*
 *这段代码是读取显示器的坐标信息。
 *使用03h功能,读光标位置,BH=页号,DH=行,DL=列
 */
	mov AH, #0x03
	xor BH, BH
	int 0x10
/*
 *这段代码是向屏幕输出Loading ststem ...
 *13h号功能是显示字符串
 *CX=字符串长度,BH=页号,BL=属性
 *ES:BP=字符串地址
 *AL设置光标属性,这里是光标跟随移动
 */
	mov CX, #24
	mov BX, #0007
	mov BP, #msg1
	mov AX, #0x1301
	int 0x10

从这里开始,代码变的有一点难度了,我尽量写的通俗易懂。

/*
 *因为上面写字符串修改过ES段寄存器,所以在使用的时候需要重新赋值。
 *在一切都准备好以后,开始加载system了
 *读取完成以后停止驱动器马达	
 */
	mov AX, #SYSSEG
	mov ES, AX
	call read_it
	call kill_motor
/*
 *这里判断启动盘是什么类型的软盘,360K, 1.2Mb, 1.44Nb
 *在CS:[root_dev]中保存了磁盘驱动器类型,将这个值传给AX
 *如果AX不等于0,也就是说root_dev已经被定义了,启动盘已经被设置了,什么都不动
 *直接跳转到root_defined处
 *如果AX为0,说明驱动器没有定义,然后我们就需要判断这个驱动器是什么类型的了,因为当时linus只有
 *软盘,所以判断了常用的两种软盘。
 *先读1.2Mb类型的软盘参数到AX中,然后将CS:[sectors]所保存的驱动器扇区数传入BX
 *判断BX是否等于15,如果相等,说明这个磁盘驱动器是1.2Mb的磁盘,跳转到root_defined处执行
 *否则传入1.44Mb软盘参数到AX中,判断扇区数是否为18,是就跳转到root_defined处执行
 *如果都不是,那就不知道怎么办了,就让他在这里死循环死机吧
 */
	seg CS
	mov AX, root_dev
	cmp AX, #0
	jne root_defined
	seg CS
	mov BX, sectors
	mov AX, #0x0208
	cmp BX, #15
	je	root_defined
	mov AX, #0x021C
	cmp BX, #18
	je root_defined
undef_root:
	jmp undef_root
/*
 *执行到这里,说明驱动器是已知了的,参数保存在AX中,所以我们需要保存驱动器参数
 */
root_defined:
	seg CS
	mov root_dev, AX
/*
 *到这里来,bootsect.s的任务已经完成了,剩下的任务就让setup.s来完成了
 */
	jmpi 0, SETUPSEG

大头来了,这里是一大堆重复头疼的环节。

sread:	.word 1+  SETUPLEN
head:	.word 0
track:	.word 0

本来准备再写一点的,但是发现后面的是一个整体,所以就不分开了,直接一个整体放到下一篇文章去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值