引导启动程序---bootsect

1.简介

打开电源,计算机执行的第 一句指令什么?
指针IP及其指向的内容

对于X86PC机而言:
(1)x86 PC刚开机时CPU处于实模式
(2)开机时,CS=0xFFFF; IP=0x0000
(3)寻址0xFFFF0(ROM BIOS映射区)
(4)检查RAM,键盘,显示器,软硬磁盘
(5)将磁盘0磁道0扇区读入0x7c00处
(6)设置cs=0x07c0,ip=0x0000
注:实模式和保护模式对应,实模式的寻址CS:IP(CS左移4位+IP), 和保护模式(32位汇编模式下)不一

0x7c00处存放的代码:从磁盘引导扇区读入的512个字节

1.引导扇区就是启动设备的第一个扇区(开机时按住del键可进入 启动设备设置界面,可 以设置为光盘启动!)

2.启动设备信息被设置在CMOS中(CMOS: (64B-128B)。用来存储实 时钟和硬件配置信息。)

因此,硬盘的第一个扇区上存放着开机后执行的第一段我们可以控制的程序

2.操作系统启动流程

bootsect.s 和setup.s是实时模式下运行的16位代码程序,采用近似Intel语法,而head.s使用GUN汇编格式(AT&T),并且运行到保护模式下。

当PC的电源打开后,CPU自动进入实模式,并从地址0XFFFF0开始执行程序代码,这个地址通常是ROM-BIOS中的地址,PC机的BIOS将执行某些系统检测,并在物理地址0处开始初始化中断向量。然后,它将可以启动设备的第一个扇区(磁盘引导扇区,512byte)读入内存绝对地址0x7C00处,并跳转到这个地方,启动设备通常是软驱或者硬盘。

Linux最前面部分(boot/bootsect.s),它将由BIOS读入内存绝对地址0x7C00处,当它被执行时就会把自己移动到内存绝对地址0X90000处,并把启动设备中后2kb字节代码(boot/setup.s)读入到内存0x90200处,而内核的其他部分(system模块)则被读入到内存地址0x10000开始处

setup.s将会把system模块移动到物理内存起始位置处,这样system模块中代码的地址就等于实际的物理地址,便于对内核代码和数据操作。

从机器加电开始执行顺序
在这里插入图片描述
启动引导时内核在内存中的位置和移动:
在这里插入图片描述

扫描二维码关注公众号,回复: 13155121 查看本文章

整个系统从地址0x10000移至0x0000处,进入保护模式并跳转至系统的余下部分(在0x0000chu)。此时所有的32位运行方式的设置启动被完成:IDT,GDT和LDT被加载,处理器和协处理器也确认,分页工作也设置完成。

最终调用init/main.c中main()程序

3.引导扇区代码: bootsect.s

bootsect.s代码是磁盘引导块程序,驻留在磁盘的第一个扇区中(引导扇区,0磁道(柱面),0磁头,第一个扇区)

在PC机加电ROM BIOS自检后,ROM BIOS会把引导扇区代码bootsect加载到内存地址0x7C00开始处并执行之。在bootsect代码执行期间,它会将自己移动到内存绝对地址0x90000开始处并继续执行。

该程序的主要作用是首先把从磁盘第2个扇区开始的4个扇区的setup模块(由 setupo.s编译而成)加载到内存紧接着bootsect后面位置处(0x90200),然后利用BIOS中断 0x13 ,取磁盘参数表中当前启动引导盘的参数,接着在屏幕上显示“Loading system.”字符串。

再把磁盘上setup模块后面的system模块加载到内存0x10000开始的地方。随后确定根文件系统的设备号,若没有指定,则根据所保存的引导盘的每磁道扇区数判别出盘的类型和种类并保存其设备号于 root_dev(
引导块的508地址处),最后长跳转到setup程序的开始处(0x00200)执行sctup程序。

各源文件位置
在这里插入图片描述

1.由BIOS读入内存绝对地址0x7C00处,当它被执行时就会把自己移动到内存绝对地址0X90000处

; bootsect启动程序将它自身从内容0x07c00(BOOTSEG)处复制至内存0x9000(INITSEG)处
entry start            ;关键字entry告诉链接器"程序入口"
start:
	mov	ax,#BOOTSEG    ;BOOTSEG = 0x07c0 赋值给ax,
	mov	ds,ax          ;源地址
	mov	ax,#INITSEG    ;INITSEG = 0x9000 赋值给bx
	mov	es,ax		   ;目标地址
	mov	cx,#256        ;循环次数,每次循环完次数减一
	sub	si,si          ;清零
	sub	di,di          ;清零
	rep				   ;rep是repeat,rep配合 movw(movsb) 就是多次复制直到cx=0为止 复制的次数放在cx中
	movw               ;用于把内容从ds:si 复制es:di  以字位单位
	jmpi	go,INITSEG ;间接跳转 即程序跳到9000:0 去继续执行  CS=INITSEG,IP=go(偏移地址)

; 从这里开始cpu已经跳到内存0x90000去执行,
; BIOS把引导扇区加载到0x7c00处并把执行权交给引导程序,(ss=0x00,sp=0xfffe)
; 将ds,es,ss,都设置成移动后代码所在段(0x9000)
go:	mov	ax,cs          ;ax = cs = INITSEG = 0x9000
	mov	ds,ax          ;数据段地址
	mov	es,ax          ;附加段地址


! put stack at 0x9ff00. ;将堆栈指针sp指向0x9fff00(0x9000:0xff00)
	mov	ss,ax           ;栈段地址
; 保证栈指针sp只要指向远大于512byte字节偏移(即地址0x90200)
; 因为在0x90200后要存放setup程序,大约为4个扇区 sp指向大于(0x200+0x200*4+堆栈大小)
	mov	sp,#0xFF00		! arbitrary value >>512  

! load the setup-sectors directly after the bootblock.
; 在bootsect程序紧跟着加载setup程序
! Note that 'es' is already set up.
; es在移动代码时设置好了指向目的地址0x9000

2.利用BIOS中断 INT 0x13 将setup模块从磁盘第2个扇区开始读到0x90200,然后取磁盘参数表中当前启动引导盘的参数,接着在屏幕上显示“Loading system.”字符串

; 这一段主要是利用BIOS中断 INT 0x13 将setup模块从磁盘第2个扇区开始读到0x90200,
; 一个四个扇区,如果读错,则复位驱动器,并重试
; INT 0x13 使用方法:
; 读扇区:
; ah = 0x02 --读磁盘扇区到内存
; al = 需要读出的扇区数量
; ch = 磁道(柱面)号低8; cl = 开始扇区(0-5),磁道号高两位(6-7)
; dh = 磁头号
; dl = 驱动器号(如果是硬盘则位7要置位)
; es:bx-->指向数据缓存区 ,如果出错则CF标志置位,ah中是出错码
load_setup:
	mov	dx,#0x0000		! drive 0, head 0
	mov	cx,#0x0002		! sector 2, track 0
	mov	bx,#0x0200		! address = 512, in INITSEG
	mov	ax,#0x0200+SETUPLEN	! service 2, nr of sectors
	int	0x13			! read it
; JNC:Jump Not Carry 没进位时跳转 正确读取时CF=0
	jnc	ok_load_setup		! ok - continue

; 读取出错,对驱动器0进行读操作 并重新读取加载setup程序
	mov	dx,#0x0000
	mov	ax,#0x0000		! reset the diskette
	int	0x13
	j	load_setup      ! jmp指令  返回到重新加载setup处

ok_load_setup:

! Get disk drive parameters, specifically nr of sectors/track
; 取磁盘驱动器的参数,特别是每道的扇区数量
; 取磁盘驱动器的参数 INT 0x13调用格式和返回信息:
; 调用格式:
; ah = 0x08        dl = 驱动器号(如果是硬盘则位7要置位)
; 返回信息:
; 如果出错,则CF值位,并且ah = 状态码
; ah = 0, al = 0  bl = 驱动器类型(AT/PS2)
; ch = 磁道(柱面)号低8; cl = 开始扇区(0-5),磁道号高两位(6-7)	
; dh = 最大磁头数 ,   dl = 驱动器数量
; es:di--->软驱磁盘参数表
	mov	dl,#0x00
	mov	ax,#0x0800		! AH=8 is get drive parameters
	int	0x13
	mov	ch,#0x00

; 这条指令表示下一条指令的操作数在cs段寄存器所指的段中
	seg cs
; 保持每磁道扇区数 (cx = 每磁道扇区数)
	mov	sectors,cx
	mov	ax,#INITSEG
; 由于上面取磁道参数中断改掉了es的值,这里重新复制, 	
	mov	es,ax

! Print some inane message
; 显示信息:"'Loading system ...'回车换行" 包括回车换行一共24个字符
; BIOS中断0x10功能号 ah= 0x03,读光标的位置
; 输入:bh = 页号
; 返回:ch = 扫描开始线,cl = 结束开始线,dh = 行号(0x00顶端),dl=列号(0x00最左边); BIOS中断0x10功能号 ah= 0x13,显示字符串
; 输入:al=放置光标的方式及规定属性,0x01--表示使用bl中的属性,光标停在字符串结尾处
; es:bp 此寄存器指向要显示字符串起始位置处
; cx = 显示的字符串字符数
; bh = 显示页面号 bl = 字符属性 dh = 行号,dl=列号
	mov	ah,#0x03		! read cursor pos
	xor	bh,bh           ! 首先读光标的位置,返回光标位置值在dx
	int	0x10            !dh =(0-23)  dl =(0-79) 显示字符串使用

	mov	cx,#24          ! 显示24个字符
	mov	bx,#0x0007		! page 0, attribute 7 (normal)
	mov	bp,#msg1		! es:bp 寄存器指向要显示字符串起始位置处
	mov	ax,#0x1301	 	! write string, move cursor 
	int	0x10

! ok, we've written the message, now
! we want to load the system (at 0x10000)
; 将system加载到0x10000
	mov	ax,#SYSSEG
	mov	es,ax		! segment of 0x010000 
	call	read_it      ; 读磁盘上system模块,es为输入参数
	call	kill_motor   ; 关闭驱动器马达,这样就可以知道驱动器的状态

3.检测使用的根文件系统

; 检测使用的根文件系统
; 如果已经指定了设备并且不等于0,就直接使用给定的设备,否则就需要报道的每磁道扇区数来
; 确定是使用/dev/PS0(2,28) 还是/dev/at0(2,8)
; 在Linux中软驱的主设备是2,次设备 = type*4 + nr 
; type是软驱的类型(2-->1.2MB,7-->1,44MB)
; nr(0-3)对应软驱A,B,C,D
; /dev/PS0(2,28)--->1.44mb A驱动器,设备号0x21c  7*4+0 =28
; /dev/at0(2,8)--->1.2MB A驱动器,设备号0x0208
	seg cs
	mov	ax,root_dev     !取508509 byte处的根设备号,root_dev定义在这里
	cmp	ax,#0
	jne	root_defined    !判断是否被定义,每定义跳到定义处
	seg cs
	mov	bx,sectors
	mov	ax,#0x0208		! /dev/ps0 - 1.2Mb
	cmp	bx,#15			! 判断每磁道扇区数是否等于15 ,sectors等于15则是1.2Mb驱动器
	je	root_defined
	mov	ax,#0x021c		! /dev/PS0 - 1.44Mb
	cmp	bx,#18          ! sectors等于18则是1.44Mb驱动器
	je	root_defined

; 如果都不一样,则死循环(死机)
undef_root:
	jmp undef_root

root_defined:
	seg cs
	mov	root_dev,ax      !将检测到的设备号保存到root_dev

! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:
; 到这里,所有的程序都加载完毕,然后跳转到加载到bootsect后面的setup程序

	jmpi	0,SETUPSEG    !!!!!!本程序结束

4.剩余的程序两个子程序,(read_it)用于读取system模块,(kill_moter)用于关闭软件的马达,就不一一介绍了。

4.完整的bootsect.s源码:

!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
SYSSIZE = 0x3000
;SYS_SIZE是要加载的系统模块长度,单位是节,16 bytes为1;0x3000字节 = 196kB
!
;操作系统启动流程
!	bootsect.s		(C) 1991 Linus Torvalds
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts. 
!
! NOTE! currently system is at most 8*65536 bytes long. This should be no
! problem, even in the future. I want to keep it simple. This 512 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix
!
! The loader has been made as simple as possible, and continuos
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole sectors at a time whenever possible.


;伪指令, .globl用于定义随后的标识符是外部或者全局的
.globl begtext, begdata, begbss, endtext, enddata, endbss  !全局标识符,供ld86链使用
.text                                                      !正文段
begtext:                                                   !标号 代表其所在的位置,通常指明一个跳转命令的目标地址
.data                                                      !数据段
begdata:
.bss                                                       !未初始化数据段
begbss:         
.text                                                      !正文段

SETUPLEN = 4				! nr of setup-sectors
							!setup程序的扇区数值

BOOTSEG  = 0x07c0	   		! original address of boot-sector
							!BIOS加载bootsect代码的原始段地址

INITSEG  = 0x9000			! we move boot here - out of the way
							!将bootsect移动到这里

SETUPSEG = 0x9020			! setup starts here
							!setup程序从这里开始

SYSSEG   = 0x1000			! system loaded at 0x10000 (65536).
							!system模块加载到0x010000(64kb).

ENDSEG   = SYSSEG + SYSSIZE		! where to stop loading
								! 停止加载的段地址

! ROOT_DEV:	0x000 - same type of floppy as boot.
; 根文件系统设备使用与引导时相同的软驱设备
!		0x301 - first partition on first drive etc
; 根文件系统设备在第一个硬盘的第一个分区上
ROOT_DEV = 0x306
; 设备号0x36指定根文件系统时第2个硬盘的第一个分区
; 设备号命名方式:
; 设备号 = 主设备号*256 + 次设备号 (dev_no = (major<<8)+minor)
; 主设备号:1-内存,2-磁盘,3-硬盘,4-ttyx,5-tty,6-并行口,7-非命名管道
; 0x300 - /dev/hd0  --代表整个第一个硬盘
; 0x30(1-4) - /dev/hd(1-4)  --代表第一个盘的1-4个分区
; 0x305 - /dev/hd5  --代表整个第二个硬盘
; 0x30(6-9) - /dev/hd(6-9)  --代表第二个盘的1-4个分区

; bootsect启动程序将它自身从内容0x07c00(BOOTSEG)处复制至内存0x9000(INITSEG)处
entry start            ;关键字entry告诉链接器"程序入口"
start:
	mov	ax,#BOOTSEG    ;BOOTSEG = 0x07c0 赋值给ax,
	mov	ds,ax          ;源地址
	mov	ax,#INITSEG    ;INITSEG = 0x9000 赋值给bx
	mov	es,ax		   ;目标地址
	mov	cx,#256        ;循环次数,每次循环完次数减一
	sub	si,si          ;清零
	sub	di,di          ;清零
	rep				   ;rep是repeat,rep配合 movw(movsb) 就是多次复制直到cx=0为止 复制的次数放在cx中
	movw               ;用于把内容从ds:si 复制es:di  以字位单位
	jmpi	go,INITSEG ;间接跳转 即程序跳到9000:0 去继续执行  CS=INITSEG,IP=go(偏移地址)

; 从这里开始cpu已经跳到内存0x90000去执行,
; BIOS把引导扇区加载到0x7c00处并把执行权交给引导程序,(ss=0x00,sp=0xfffe)
; 将ds,es,ss,都设置成移动后代码所在段(0x9000)
go:	mov	ax,cs          ;ax = cs = INITSEG = 0x9000
	mov	ds,ax          ;数据段地址
	mov	es,ax          ;附加段地址


! put stack at 0x9ff00. ;将堆栈指针sp指向0x9fff00(0x9000:0xff00)
	mov	ss,ax           ;栈段地址
; 保证栈指针sp只要指向远大于512byte字节偏移(即地址0x90200)
; 因为在0x90200后要存放setup程序,大约为4个扇区 sp指向大于(0x200+0x200*4+堆栈大小)
	mov	sp,#0xFF00		! arbitrary value >>512  

! load the setup-sectors directly after the bootblock.
; 在bootsect程序紧跟着加载setup程序
! Note that 'es' is already set up.
; es在移动代码时设置好了指向目的地址0x9000



; 这一段主要是利用BIOS中断 INT 0x13 将setup模块从磁盘第2个扇区开始读到0x90200,
; 一个四个扇区,如果读错,则复位驱动器,并重试
; INT 0x13 使用方法:
; 读扇区:
; ah = 0x02 --读磁盘扇区到内存
; al = 需要读出的扇区数量
; ch = 磁道(柱面)号低8; cl = 开始扇区(0-5),磁道号高两位(6-7)
; dh = 磁头号
; dl = 驱动器号(如果是硬盘则位7要置位)
; es:bx-->指向数据缓存区 ,如果出错则CF标志置位,ah中是出错码
load_setup:
	mov	dx,#0x0000		! drive 0, head 0
	mov	cx,#0x0002		! sector 2, track 0
	mov	bx,#0x0200		! address = 512, in INITSEG
	mov	ax,#0x0200+SETUPLEN	! service 2, nr of sectors
	int	0x13			! read it
; JNC:Jump Not Carry 没进位时跳转 正确读取时CF=0
	jnc	ok_load_setup		! ok - continue

; 读取出错,对驱动器0进行读操作 并重新读取加载setup程序
	mov	dx,#0x0000
	mov	ax,#0x0000		! reset the diskette
	int	0x13
	j	load_setup      ! jmp指令  返回到重新加载setup处

ok_load_setup:

! Get disk drive parameters, specifically nr of sectors/track
; 取磁盘驱动器的参数,特别是每道的扇区数量
; 取磁盘驱动器的参数 INT 0x13调用格式和返回信息:
; 调用格式:
; ah = 0x08        dl = 驱动器号(如果是硬盘则位7要置位)
; 返回信息:
; 如果出错,则CF值位,并且ah = 状态码
; ah = 0, al = 0  bl = 驱动器类型(AT/PS2)
; ch = 磁道(柱面)号低8; cl = 开始扇区(0-5),磁道号高两位(6-7)	
; dh = 最大磁头数 ,   dl = 驱动器数量
; es:di--->软驱磁盘参数表
	mov	dl,#0x00
	mov	ax,#0x0800		! AH=8 is get drive parameters
	int	0x13
	mov	ch,#0x00

; 这条指令表示下一条指令的操作数在cs段寄存器所指的段中
	seg cs
; 保持每磁道扇区数 (cx = 每磁道扇区数)
	mov	sectors,cx
	mov	ax,#INITSEG
; 由于上面取磁道参数中断改掉了es的值,这里重新复制, 	
	mov	es,ax

! Print some inane message
; 显示信息:"'Loading system ...'回车换行" 包括回车换行一共24个字符
; BIOS中断0x10功能号 ah= 0x03,读光标的位置
; 输入:bh = 页号
; 返回:ch = 扫描开始线,cl = 结束开始线,dh = 行号(0x00顶端),dl=列号(0x00最左边); BIOS中断0x10功能号 ah= 0x13,显示字符串
; 输入:al=放置光标的方式及规定属性,0x01--表示使用bl中的属性,光标停在字符串结尾处
; es:bp 此寄存器指向要显示字符串起始位置处
; cx = 显示的字符串字符数
; bh = 显示页面号 bl = 字符属性 dh = 行号,dl=列号
	mov	ah,#0x03		! read cursor pos
	xor	bh,bh           ! 首先读光标的位置,返回光标位置值在dx
	int	0x10            !dh =(0-23)  dl =(0-79) 显示字符串使用

	mov	cx,#24          ! 显示24个字符
	mov	bx,#0x0007		! page 0, attribute 7 (normal)
	mov	bp,#msg1		! es:bp 寄存器指向要显示字符串起始位置处
	mov	ax,#0x1301	 	! write string, move cursor 
	int	0x10

! ok, we've written the message, now
! we want to load the system (at 0x10000)
; 将system加载到0x10000
	mov	ax,#SYSSEG
	mov	es,ax		! segment of 0x010000 
	call	read_it      ; 读磁盘上system模块,es为输入参数
	call	kill_motor   ; 关闭驱动器马达,这样就可以知道驱动器的状态

! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
! on the number of sectors that the BIOS reports currently.

; 检测使用的根文件系统
; 如果已经指定了设备并且不等于0,就直接使用给定的设备,否则就需要报道的每磁道扇区数来
; 确定是使用/dev/PS0(2,28) 还是/dev/at0(2,8)
; 在Linux中软驱的主设备是2,次设备 = type*4 + nr 
; type是软驱的类型(2-->1.2MB,7-->1,44MB)
; nr(0-3)对应软驱A,B,C,D
; /dev/PS0(2,28)--->1.44mb A驱动器,设备号0x21c  7*4+0 =28
; /dev/at0(2,8)--->1.2MB A驱动器,设备号0x0208
	seg cs
	mov	ax,root_dev     !取508509 byte处的根设备号,root_dev定义在这里
	cmp	ax,#0
	jne	root_defined    !判断是否被定义,每定义跳到定义处
	seg cs
	mov	bx,sectors
	mov	ax,#0x0208		! /dev/ps0 - 1.2Mb
	cmp	bx,#15			! 判断每磁道扇区数是否等于15 ,sectors等于15则是1.2Mb驱动器
	je	root_defined
	mov	ax,#0x021c		! /dev/PS0 - 1.44Mb
	cmp	bx,#18          ! sectors等于18则是1.44Mb驱动器
	je	root_defined

; 如果都不一样,则死循环(死机)
undef_root:
	jmp undef_root

root_defined:
	seg cs
	mov	root_dev,ax      !将检测到的设备号保存到root_dev

! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:
; 到这里,所有的程序都加载完毕,然后跳转到加载到bootsect后面的setup程序

	jmpi	0,SETUPSEG    !!!!!!本程序结束


; 下面是两个子程序,(read_it)用于读取system模块,(kill_moter)用于关闭软件的马达
! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in:	es - starting address segment (normally 0x1000)
!
; 该子程序将系统模块加载到内存地址0x10000处,并确定没有跨越64kb内存边界
; 尽快可能的加载,每次加载整条磁道的数据
; 输入:es开始内存地址段值(一般0x1000)

; .word定义一个字内存
; (1+SETUPLEN)表示开始已经读进一个引导扇区和setup程序所占的扇区数SETUPLEN 
sread:	.word 1+SETUPLEN	! sectors read of current track 当前磁道中已读扇区数
head:	.word 0			! current head  当前磁头号
track:	.word 0			! current track 当前磁道号

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



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


ok1_read:
	seg cs
	mov ax,sectors
	sub ax,sread
	mov cx,ax
	shl cx,#9
	add cx,bx
	jnc ok2_read
	je ok2_read
	xor ax,ax
	sub ax,bx
	shr ax,#9


ok2_read:
	call read_track
	mov cx,ax
	add ax,sread
	seg cs
	cmp ax,sectors
	jne ok3_read
	mov ax,#1
	sub ax,head
	jne ok4_read
	inc track


ok4_read:
	mov head,ax
	xor ax,ax


ok3_read:
	mov sread,ax
	shl cx,#9
	add bx,cx
	jnc rp_read
	mov ax,es
	add ax,#0x1000
	mov es,ax
	xor bx,bx
	jmp rp_read

read_track:
	push ax
	push bx
	push cx
	push dx
	mov dx,track
	mov cx,sread
	inc cx
	mov ch,dl
	mov dx,head
	mov dh,dl
	mov dl,#0
	and dx,#0x0100
	mov ah,#2
	int 0x13
	jc bad_rt
	pop dx
	pop cx
	pop bx
	pop ax
	ret
	
bad_rt:	mov ax,#0
	mov dx,#0
	int 0x13
	pop dx
	pop cx
	pop bx
	pop ax
	jmp read_track  

/*
 * This procedure turns off the floppy drive motor, so
 * that we enter the kernel in a known state, and
 * don't have to worry about it later.
 */

 ; 这个程序用于关闭软件马达,这样进入内核就可以知道它所处的状态
kill_motor:
	push dx
	mov dx,#0x3f2         !软件控制卡的数字输出寄存器(DOR)端口,只写
	mov al,#0
	outb
	pop dx
	ret

sectors:
	.word 0

msg1:                           ! 调用BIOS中断显示信息
	.byte 13,10                 ! 回车换行的ascii码
	.ascii "Loading system ..." ! 显示字符串
	.byte 13,10,13,10           !一个24个字符

; 表示下面语句从地址508(0x1fc)开始,所以root_dev在启动扇区的第508开始的2个字节中
.org 508
root_dev:
	.word ROOT_DEV               !存放根文件系统所在设备号(init/main.c中会用)

; 下面是启动盘具有有效引导扇区的标志,在BIOS程序加载引导扇区时识别使用,
; 它必须位于引导扇区的最后两个字节中
boot_flag:
	.word 0xAA55

.text
endtext:
.data
enddata:
.bss
endbss:

猜你喜欢

转载自blog.csdn.net/qq_53144843/article/details/120355607