bootsect.s和setup.s

内容为 李治军老师操作系统课 的部分笔记

计算机开机执行的操作

以X86 PC为例(X86为Intel处理器架构,即指令集架构ISA Instruction Set Architecture))

一个地址由段寄存器CS和段内偏移IP组成

  1. x86 PC 刚开机时,CPU初始状态为实模式。

  2. 此时CPU设置CS=0xFFFF,IP=0x0000(CS为Code Segment Register 代码段寄存器,确定起始内存段)

    物理地址 = (CS<<4)+ IP = 0xFFFF0 //所以这就是第一条内存指令
    
  3. 寻址0xFFFF0(ROM BIOS映射区,为BIOS 启动入口地址)

  4. 执行0xFFFF0的指令,检查RAM、键盘、显示器、软硬磁盘

  5. BIOS将磁盘0磁道0扇区(引导扇区BootSector)读入0x7c00处(一个扇区为512B)

  6. 设置CS=0x07c0,IP=0x0000(此时计算出的物理地址为0x7c00,寻址0x7c00,执行引导扇区的指令)

bootsect.s

引导扇区存放的代码 bootsect.s(s后缀为汇编代码),该代码来将操作系统加载到内存中

; 在 as86 汇编语言程序中,凡是以感叹号’!’或分号’;’开始的语句均为注释

;1、操作为:bootsect 把自己搬运到 0x90000,并跳转
;BOOTSEG=0x07c0   INITSEG=0x9000   SETUPSEG=0x9020
entry _start  ; 告知链接程序,程序从 start 标号开始执行
_start:
mov ax,#BOOTSEG
mov ds,ax      ! ds = 0x07c0
mov ax,#INITSEG
mov es,ax      ! es = 0x9000
mov cx,#256    ! cx为计数器,搬运 256 次
!ds为数据段,es为附加段,都为段寄存器,段寄存器需要有偏移才构成实际地址
sub si,si      ! sub为减,前减后结果给前,si-si=0,si = 0
sub di,di      ! di = 0
!si为源偏移,di为目标偏移
! ds:si = 0x07c0:0x0,实际地址:ds<<4+si=0x7c00
! es:di = 0x9000:0x0  实际地址:es<<4+di=0x90000
rep movw           ! 每次搬运1个字,即 2 字节,搬运256次,即512字节,为一个扇区大小
!将7c00处的256个字移动到90000中,7c00为bootsect.s存放的地址,此时将其移动到90000
!start位置为90000
jmpi go,INITSEG  !jmpi段内转跳,cs=INITSEG  ip=go
! INITSEG<<4+go,假设go为100,则此时地址为90100
!start为90000,start的模块为100,start进行完后正好到90100也就是go的位置
————————————————

;2、转跳到go执行下面指令,设置段寄存器和栈
go:	mov	ax,cs
	mov	ds,ax
	mov	es,ax
	mov	ss,ax   ; cs = ds = es = ss = 0x9000,
	!ss为栈段,sp为栈顶指针,栈顶地址为ss:sp,即ss<<4+sp,实模式下栈是往下长的
	mov	sp,#0xFF00		 !ss:sp = 0x9000:0xff00 ,栈的设置	0x9ff00
	
! 因为从 0x90200 地址开始处还要放置 setup 程序,setup 大约为 4 个扇区
! 0x200 * 5 = 0xA00 (512十六进制下为200),0x90200+0xA00=0x90C00
!所以setup 占用范围 = 0x90200 ~ 0x90C00
!又因为栈顶地址必须高于 setup 程序的最高地址(0x90C00)
!栈顶地址(0x9FF00) - setup 结束地址(0x90C00) = 0xF500,栈的大小为0xF500
	
————————————————
;3、加载 setup 模块到 0x90200
load_setup:
	mov	dx,#0x0000		! dh磁头号为0,dl驱动器号为0
	mov	cx,#0x0002		! cl起始扇区号2,因为bootset占了第一个扇区,故从第二个扇区读 ch柱面号0
	mov	bx,#0x0200		! 偏移地址0x200
	mov	ax,#0x0200+SETUPLEN	! 功能号ah=0x02,表示读取扇区,al=要读的扇区数目=SETUPLEN=4 
	!以上为从第二个扇区开始,读取4个扇区,因为第一个扇区地址为90000,一个扇区512字节,
	十六进制为0x200,故setup起始地址为90200
	!es:bx=内存地址,在执行go模块后,es=0x9000,bx=200,es:bx正好也为90200
	int	0x13			! BOIS读磁盘的中断
	jnc	ok_load_setup	! CF = 0 则跳转
	mov	dx,#0x0000     
	mov	ax,#0x0000		!ah功能号为0,al扇区数量为0
	int	0x13            ! 复位磁盘
	j	load_setup
————————————————


ok_load_setup:
;4、获得磁盘驱动器参数(主要是每磁道的扇区数)
	mov	dl,#0x00    !驱动器号为0,说明是软盘
	mov	ax,#0x0800	!ah功能号为0x08,为获取驱动器参数
	int	0x13
	mov	ch,#0x00    !这里用不上软盘的最大磁道号,可以使CH=0      
	mov	sectors,cx  !存下磁道的扇区数
	
	;5、打印一段开机logo
	mov	ah,#0x03	!功能号,读光标的位置
	xor	bh,bh       !bh=页号=0
	int	0x10   !ah为03,故读光标
	mov	cx,#24          ! 24个字符
	mov	bx,#0x0007		! bh页号为0, bl属性为07 , 黑底浅灰字
	mov	bp,#msg1  !bp为显示的字符在内存的什么地方,#msg1为偏移,在bootsect.s尾部
	mov	ax,#0x1301		!功能号ah为13,为在屏幕上显示字符串
	!功能号子参数为01,为使用指定属性,光标更新
	int	0x10  !ah为13,故为显示字符,同一中断号调用不同功能
	
	;6、加载 system 模块
	mov	ax,#SYSSEG  ! SYSSEG=0x1000
	mov	es,ax		! segment of 0x010000
	call	read_it  !读入system模块
	
	;7、跳转到 setup.s 执行
	jmpi 0,SETUPSEG //转入0x9020:0x0000,即90200执行setup.s

!bootsect.s文件尾部:
sectors: .word 0 !扇区磁道数
msg1:
	.byte 13,10
	.ascii "Loading system ..."  !开机时屏幕显示的logo,共cx个字符
	.byte 13,10,13,10

!以上操作为在内存为bp的地方,读取24个字符,页号为0,颜色为黑底浅灰色字

总结,以上代码作用为: 把 bootsect 自己从0x7c00 拷贝到0x90000,设置段寄存器和栈,然后从磁盘加载 setup 模块到0x90200,再打印一段提示信息,最后加载 system 模块,并跳转到 setup 的入口执行。

setup.s

操作系统的代码,完成启动前的操作

INITSEG  = 0x9000	! bootsect.s 的段地址
SYSSEG   = 0x1000	! 系统加载在 0x10000 
SETUPSEG = 0x9020	! 本程序的段地址

start: mov ax,#INITSEG 
mov ds,ax   ;ds=0x9000
mov ah,#0x03    ;0x10中断下ah=0x03为 读取光标位置返回给dx
xor bh,bh int 0x10  
dx mov [0],dx  ;即mov WORD PTR [ds:0], dx  从上可知ds为9000
[0]前面默认有个段寄存器,当前段都指向9000,9000<<4 +0=0x90000
;故将dx给0x90000
mov ah,#0x88 ;0x15中断下,ah=0x88为获取扩展内存大小,返回给ax
int 0x15 
mov [2],ax ... ;[2]为9000<<4+2=0x90002,将扩展内存数存在0x90002处
cli                 //不允许中断
mov ax,#0x0000   cld
do_move: mov es,ax ;es为0x0000 ,do_move类似do while循环,此处进入循环
add ax,#0x1000  ;ax为0x1000
cmp ax,#0x9000  ;ax-9000!=0,故zf=0
jz end_move   ;因zf=0,所以不相等,不跳转,直到ax==0x9000,此时zf=1,终止循环  
;end_move为循环终止
mov ds,ax   ;ds=0x1000
sub di,di  
sub si,si  ;di=si=0x0000
;此时ds:si源地址0x10000   es:di目标地址0x00000
mov cx,#0x8000   ;cx为计数器
rep                 
movsw   ;从0x10000到0x00000移动字,搬运32768次,每次搬运1字,即2字节,2*32768=65536字节
即移动0x10000字节,故是0x10000~0x20000移动到0x00000~0x10000
;最后一次循环es:di为0x70000,di:si为0x80000,故是0x80000~0x90000移动到0x70000~0x80000
jmp do_move  ;跳转do_move继续循环
;以上循环结果为,0x10000~0x90000内容搬运到0x00000~0x80000

;以上结果为操作系统往后一直处于0地址开头,并获取硬件参数,为操作系统管理硬件做准备

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值