开机后为啥计算机要把引导程序加载来加载去


entry start
start:
	mov	ax,#BOOTSEG    ;#1
	mov	ds,ax          ;#2
	mov	ax,#INITSEG    ;#3
	mov	es,ax          ;#4
	mov	cx,#256        ;#5
	sub	si,si          ;#6
	sub	di,di          ;#7
	rep   movw         ;#8
	jmpi	go,INITSEG ;#9
go:	mov	ax,cs
	mov	ds,ax
	mov	es,ax
; put stack at 0x9ff00.
	mov	ss,ax
	mov	sp,#0xFF00		; arbitrary value >>512

在bootsect.s中,最开始需要运行上面的一段代码,下面详细讲一下这段代码。
entry_start是一个汇编伪指令。伪指令不是是一种在汇编语言中使用的特殊指令,它们不是真正的机器指令。而是在汇编过程中被转换为一个或多个真正的机器指令。 这个伪指令的作用作用是将start标签作为作为入口标签。标签是用于标识程序中位置的符号,它们可以用于标识指令、数据、子程序和其他程序元素的位置start标记的这段代码一共有9行,第一行的BOOTSEG是一个符号常量,在bootsect.s中的前部分已经定义过该符号常量 BOOTSEG = 0x07c0。那么前两行的意思就是将0x07c0这个常量加载到AX寄存器中,再将AX寄存器中的值复制给DS寄存器。那为什么不直接把常量加载到DS寄存器中,而是将AX寄存器作为中间寄存器进行缓存呢?原因是将常量值先加载到中间寄存器中,再复制到数据段寄存器DS中,可以确保程序各个寄存器中的值同步,避免出现错误。第三行和第四行的作用相似。第五行是将立即数256加载到CX寄存器中,CX寄存器叫做计数寄存器,通常用来放置循环数,而且该行使用十进制而不是十六进制,是为了更好的可读性。第六行和第七行是固定用法,用来将寄存器进行清零。第八行中rep表示一个重复指令,通常和其他指令搭配使用,这这一句中,rep movw表示对movw指令进行重复,那重复多少次呢?这就要根据CX中的值来定。在第五行中,CX已经寄存器中已经变成256,这表示需要将movw指令循环执行256遍。而movw指令表示将DS:SI处的两个字节数据复制到ES:DI处,要注意在重复过程成会对SI和DI进行自增,对CX进行自减。简单来说第八行指令的意思就是将内存0x7c00开始往后512个字节复制到0x90000开始的后512个字节处。那为何又要将引导程序挪窝呢?因为0x0000开始的后面一段内存是属于内核和系统预留空间,用来防止中断向量表和一些其他的数据。如果不把引导程序挪窝,就会被后续加载系统给覆盖。之所以先加载到0x7c00而不是直接加载到0x90000是因为历史包袱,这个要追溯到IBM的bios中。第九行的意思是进行跳转,跳转到go标签处,INITSEG则是基地址,此时为0x9000
在这里插入图片描述
go标签处的代码主要作用是在把bootsect.s程序进行挪窝后为各个寄存器重新加载值。但是这里需要注意的是,前面的代码中并没有显式的给CS寄存器加载值,那这个值又是从哪里来的呢?原来在上面执行jmpi go,INITSEG指令的时候,CS寄存器也参与了过程,在执行该指令过程中CS被加载的值为0x9000
look_set_upok_load_setup标签处的代码的作用是加载


以下是linux 0.11 中bootsec.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
;
;	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 begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

SETUPLEN = 4				; nr of setup-sectors
BOOTSEG  = 0x07c0			; original address of boot-sector
INITSEG  = 0x9000			; we move boot here - out of the way
SETUPSEG = 0x9020			; setup starts here
SYSSEG   = 0x1000			; system loaded at 0x10000 (65536).
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

entry 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
go:	mov	ax,cs
	mov	ds,ax
	mov	es,ax
; put stack at 0x9ff00.
	mov	ss,ax
	mov	sp,#0xFF00		; arbitrary value >>512

; load the setup-sectors directly after the bootblock.
; Note that 'es' is already set up.

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	ok_load_setup		; ok - continue
	mov	dx,#0x0000
	mov	ax,#0x0000		; reset the diskette
	int	0x13
	j	load_setup

ok_load_setup:

; Get disk drive parameters, specifically nr of sectors/track

	mov	dl,#0x00
	mov	ax,#0x0800		; AH=8 is get drive parameters
	int	0x13
	mov	ch,#0x00
	seg cs
	mov	sectors,cx
	mov	ax,#INITSEG
	mov	es,ax

; Print some inane message

	mov	ah,#0x03		; read cursor pos
	xor	bh,bh
	int	0x10
	
	mov	cx,#24
	mov	bx,#0x0007		; page 0, attribute 7 (normal)
	mov	bp,#msg1
	mov	ax,#0x1301		; write string, move cursor
	int	0x10

; ok, we've written the message, now
; we want to load the system (at 0x10000)

	mov	ax,#SYSSEG
	mov	es,ax		; segment of 0x010000
	call	read_it
	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.

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

; after that (everyting loaded), we jump to
; the setup-routine loaded directly after
; the bootblock:

	jmpi	0,SETUPSEG

; 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)
;
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
	mov al,#0
	outb
	pop dx
	ret

sectors:
	.word 0

msg1:
	.byte 13,10
	.ascii "Loading system ..."
	.byte 13,10,13,10

.org 508
root_dev:
	.word ROOT_DEV
boot_flag:
	.word 0xAA55

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值