哈工大操作系统实验(一)操作系统启动

目录

    • 实验背景
      • 1. 实模式
      • 2. 实模式地址
      • 3. 启动流程
    • 实验目的
    • 实验内容
    • 实验报告
      • 1. bootsect.s 程序
      • 2. setup.s 程序
    • 参考资料

实验背景

1. 实模式

哈工大操作系统实验(一)操作系统启动_第1张图片
实模式 是80286及以上的微处理器采用8086的工作模式,从加电启动或复位到操作系统运行之前的运行环境。保护模式 是80386及以上的微处理器的主要工作模式,支持多任务、设置特权级、特权指令执行等,操作系统和应用程序的运行环境。因为操作系统启动处于实模式,所以以下仅涉及实模式下的寄存器和物理地址生成。

2. 实模式地址

哈工大操作系统实验(一)操作系统启动_第2张图片
① 指令指针寄存器 IP 保存一个内存地址,指向当前需要取出的指令
② 段寄存器与其它寄存器联合生成存储器地址,包括代码段寄存器 CS、数据段寄存器 DS、附加段寄存器 ES 和堆栈段寄存器 SS

哈工大操作系统实验(一)操作系统启动_第3张图片
指令寄存器 IP 为16位寄存器,寻址能力为 2 16 = 64 K 2^{16}=64K 216=64K 字节单元;地址总线;8086对外有20位地址线,寻址范围是 2 20 = 1 M 2^{20}=1M 220=1M 字节单元。1M字节的物理存储空间分成许多逻辑段,每段最长64K字节,从而可用16位地址寻址。

哈工大操作系统实验(一)操作系统启动_第4张图片
实模式下给出逻辑地址 段基值:偏移量,十进制物理地址计算方法是 物理地址=段基值×16+偏移量,二进制物理地址计算方法是 物理地址=段基址<<4+偏移量

哈工大操作系统实验(一)操作系统启动_第5张图片
BIOS运行在实模式下,段基值 CS0xF000IP 设置为 0xFFF0,从而组成BIOS入口地址 0xFFFF0

3. 启动流程

在这里插入图片描述
加电稳定后,CPU进入实模式并从BIOS入口地址 0XFFFF0 开始自动执行代码。BIOS初始化硬件并在物理地址0处放置大小为1KB的中断向量表,它将磁盘引导块程序 bootsect.s 读入内存地址 0X7C00,CPU执行跳转指令跳转到该处执行。
哈工大操作系统实验(一)操作系统启动_第6张图片
磁盘引导块程序 bootsect.s 执行时把自己移动到0X90000 处,同时将操作系统加载程序 setup.s 加载到内存 0X90200 处,操作系统内核 system 模块加载到内存 0X10000 开始的地方。

操作系统加载程序 setup.s 利用BIOS中断读取机器系统参数,并将参数覆盖保存 bootsect.s 的位置,同时将 system 模块整体向下移动到 0X0000 处覆盖BISO中断。最后,CPU进入保护模式,跳转到 system 模块前端的 head.s 继续运行,从而成功启动操作系统。

实验目的

  • 熟悉hit-oslab实验环境;
  • 建立对操作系统引导过程的深入认识;
  • 掌握操作系统的基本开发过程;
  • 能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱。

实验内容

此次实验的基本内容是:

  1. 阅读《Linux内核完全注释》的第6章,对计算机和Linux 0.11的引导过程进行初步的了解;
  2. 按照下面的要求改写0.11的引导程序bootsect.s
  3. 有兴趣同学可以做做进入保护模式前的设置程序setup.s。

实验报告

1. bootsect.s 程序

改写bootsect.s主要完成如下功能:

  1. bootsect.s能在屏幕上打印一段提示信息“XXX is booting…”,其中XXX是你给自己的操作系统起的名字,例如LZJos、Sunix等(可以上论坛上秀秀谁的OS名字最帅,也可以显示一个特色logo,以表示自己操作系统的与众不同。)

编译生成 bootsect 可执行文件:

cd ./oslab/linux-0.11/boot/				// 进入当前目录
as86 -0 -a -o bootsect.o bootsect.s		// 汇编语言源程序转换为可执行程序
ld86 -0 -s -o bootsect bootsect.o		// 链接器将库函数绑定于可执行程序

使用 ls -l 命令查看 bootsect 的大小为 544KB,但引导程序的大小必须为一个磁盘扇区,即 512 KB。
在这里插入图片描述
原因是 ld86 产生的是 minix 格式的可执行文件,包含一个32KB的文件头,可使用如下指令跳过文件头,生成 Image 文件。

dd bs=1 if=bootsect of=Image skip=32

在这里插入图片描述
复制 Image 文件到 linux-0.11 目录下,执行如下语句可成功启动,输出字符串 Loading system ...

cd ./oslab		// 回到oslab目录
./run			// 启动操作系统

哈工大操作系统实验(一)操作系统启动_第7张图片
阅读《Linux内核完全注释》,es:bp 寄存器保存需要显示字符串 msg1 起始位置,cx 保存字符串 msg1 的字符数。
哈工大操作系统实验(一)操作系统启动_第8张图片
此时,msg1 字符串包括长度为18的 Loading system ... 和3对换行符13和回车符10,长度共计24。如果需要输出长度为20的信息 SEANos is booting…,则修改ascii内容为 SEANos is booting…cx 内容为26。
在这里插入图片描述
重新编译运行,输出结果如下:

哈工大操作系统实验(一)操作系统启动_第9张图片

2. setup.s 程序

改写setup.s主要完成如下功能:

  1. bootsect.s能完成setup.s的载入,并跳转到setup.s开始地址执行。而setup.s向屏幕输出一行"Now we are in SETUP"。
------------------------------------------------------------------
			INT 0x10功能0x03
--------------------------------------------------------------
描述:
	在文本坐标下,读取光标各种信息
接受参数:
	AH			0x03
	BH			显示页码
返回值:
	CH			光标的起始行
	CL			光标的终止行
	DH			行(Y 坐标)
	DL			列(X 坐标)
-------------------------------------------------------------------

使用BIOS中断 int 0x10 功能号 0x03 获取光标:

mov	ah,#0x03			!BIOS中断0x10功能号 ah=0x03 获取光标的位置
xor	bh,bh				! bh寄存器清0,bh寄存器存储带获取光标的页号0
int	0x10				!执行 BIOS 0x10号中断
------------------------------------------------------------------
			INT 0x10功能0x13
--------------------------------------------------------------
描述:
	以电传打字机的方式显示字符串
接受参数:
	AH			0x13
	AL			显示模式
	BH			视频页
	BL			属性值(如果AL=0x00或0x01)
	CX			字符串的长度
	DH,DL		屏幕上显示起始位置的行、列值
	ES:BP		字符串的段:偏移地址
返回值:
	无
显示模式(AL):
	0x00:字符串只包含字符码,显示之后不更新光标位置,属性值在BL中
	0x01:字符串只包含字符码,显示之后更新光标位置,属性值在BL中
	0x02:字符串包含字符码及属性值,显示之后不更新光标位置
	0x03:字符串包含字符码及属性值,显示之后更新光标位置
-------------------------------------------------------------------

使用BIOS中断 int 0x10 功能号 0x13 显示字符串:

mov	ax,#SETUPSEG		! 将段寄存器 es 设置为 setup.s 开始位置
mov	es,ax
mov	bp,#MSG_SETUP		!es:bp 寄存器保存显示的字符串的地址

mov	cx,#25				! 字符串长度
mov	bx,#0x0007			! 页号 0,光标属性为停在字符串结尾处

mov	ax,#0x1301			!BIOS中断0x10功能号 ah=0x13 显示字符串
int	0x10				!执行 BIOS 0x10号中断

重新排列命令避免寄存器内容被覆盖,则 setup 添加输出字符串 MSG_SETUP 命令:

!print the message which wing edit
	mov	ax,#SETUPSEG		! 将段寄存器 ds 设置为 setup.s 开始位置
	mov	es,ax
	
	mov	ah,#0x03			!BIOS中断0x10功能号 ah=0x03 获取光标的位置
	xor	bh,bh				! bh寄存器清0,bh寄存器存储带获取光标的页号0
	int	0x10				!执行 BIOS 0x10号中断
	
	mov	cx,#25				! 字符串长度
	mov	bx,#0x0007			! 页号 0,光标属性为停在字符串结尾处
	mov	bp,#MSG_SETUP		!es:bp 寄存器保存显示的字符串的地址
	mov	ax,#0x1301			!BIOS中断0x10功能号 ah=0x13 显示字符串
	int	0x10				!执行 BIOS 0x10号中断

末尾添加字符串 MSG_SETUP 内容:

MSG_SETUP:
    .byte 13,10
	.ascii "Now we are in SETUP"
	.byte 13,10,13,10

同时需要清除89行~224行加载SYSTEM模块的内容,避免重复启动的现象出现,按照实验指导书编译执行,成功让 setup.s 向屏幕输出一行 "Now we are in SETUP"
哈工大操作系统实验(一)操作系统启动_第10张图片

  1. setup.s能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。

光标位置信息保存至内存:

		mov	ah,#0x03	
		xor	bh,bh
		int	0x10		! 使用BIOS中断 int 0x10 功能号 0x03 获取光标
		mov	[0],dx		! 返回光标行列保存在寄存器dx,转存到0x90000

打印提示信息 Cursor Pos:

		mov	ah,#0x03
		xor	bh,bh
		int	0x10
	
		mov	cx,#13
		mov	bx,#0007
		mov	bp,#MSG_CURSOR
		mov	ax,#0x1301
		int	0x10
MSG_CURSOR:
        .byte 13,10
		.ascii "Cursor POS:"

打印硬件参数:

------------------------------------------------------------------
			INT 0x10功能0x0E
--------------------------------------------------------------
描述:
	显示一个字符(光标前移)
接受参数:
	AH			0x0E
	AL			要显示字符的ASCII
返回值:
	无
mov	ax,#0xe0f
int	0x10

硬件参数以二进制的形式保存在寄存器 dx,输出时十六进制形式需要每次循环左移4位,获取该左移4位(即1位十六进制数)求其ASCII码。求ASCII码时需要判断它是数字还是字母,数字则加 0X30 得对应ASCII,字母则加 0x37 得对应ASCII码,最后送显示器输出。下面以光标位置为例:

!十六进制输出光标位置
print_hex:
	mov	cx,#4			! 循环计数器
    mov	dx,[0]
print_digit1:	
	rol	dx,#4			! 循环左移4位
	mov	ax,#0xe0f		! BIOS中断0x10功能号 ah=0x0E 显示一个字符
	and	al,dl			! 获取dl的低4比特值
	add	al,#0x30		! 数字加0x30
	cmp	al,#0x3a
	jl	outp1				
	add	al,#0x07		! 字母多加0x37
outp1:
   	int	0x10			! 执行 BIOS 0x10号中断
   	loop	print_digit1		! loop指令:cx减1,然后判断cx是否等于0

打印回车换行:

print_nl:
   	mov	ax,#0xe0d	! CR
   	int	0x10
   	mov	al,#0xa	! LF
   	int	0x10	

哈工大操作系统实验(一)操作系统启动_第11张图片
同理,可获取并打印扩展内存的大小。

------------------------------------------------------------------
			INT 0x15功能0x88
--------------------------------------------------------------
描述:
	获取扩展内存的大小
接受参数:
	AH			0x88
返回值:
	AX			从绝对地址1MB开始的内存大小
-------------------------------------------------------------------
mov	ah,#0x88
int	0x15	! 调用0x15中断获取扩展内存大小
mov	[2],ax	! 保存扩展内存大小至0x90002

哈工大操作系统实验(一)操作系统启动_第12张图片
完整 setup.s 源码:

!
!	setup.s		(C) 1991 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! both setup.s and system has been loaded by the bootblock.
!
! This code asks the bios for memory/disk/other parameters, and
! puts them in a "safe" place: 0x90000-0x901FF, ie where the
! boot-block used to be. It is then up to the protected mode
! system to read them from there before the area is overwritten
! for buffer-blocks.
!

! NOTE! These had better be the same as in bootsect.s!

INITSEG  = 0x9000	! we move boot here - out of the way
SYSSEG   = 0x1000	! system loaded at 0x10000 (65536).
SETUPSEG = 0x9020	! this is the current segment
	
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

entry start
start:

!print the message which wing edit
	mov	ax,#SETUPSEG
	mov	es,ax
	mov	ah,#0x03
	xor	bh,bh
	int	0x10
	
	mov	cx,#25
	mov	bx,#0x0007
	mov	bp,#MSG_SETUP
	mov	ax,#0x1301
	int	0x10
	
! ok, the read went well so we get current cursor position and save it for
! posterity.

	mov	ax,#INITSEG	! this is done in bootsect already, but...
	mov	ds,ax
	mov	ah,#0x03	! read cursor pos
	xor	bh,bh
	int	0x10		! save it in known place, con_init fetches
	mov	[0],dx		! it from 0x90000.
! Get memory size (extended mem, kB)

	mov	ah,#0x88
	int	0x15
	mov	[2],ax

! Get video-card data:

	mov	ah,#0x0f
	int	0x10
	mov	[4],bx		! bh = display page
	mov	[6],ax		! al = video mode, ah = window width

! check for EGA/VGA and some config parameters

	mov	ah,#0x12
	mov	bl,#0x10
	int	0x10
	mov	[8],ax
	mov	[10],bx
	mov	[12],cx

! Get hd0 data

	mov	ax,#0x0000
	mov	ds,ax
	lds	si,[4*0x41]
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0080
	mov	cx,#0x10
	rep
	movsb

! Get hd1 data

	mov	ax,#0x0000
	mov	ds,ax
	lds	si,[4*0x46]
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0090
	mov	cx,#0x10
	rep
	movsb
	
	mov	ax,#SETUPSEG
	mov ds,ax
	mov es,ax

!print some datas about the hard ware:
	
	!输出提示信息
	mov	ah,#0x03
	xor	bh,bh
	int	0x10
	
	mov	cx,#13
	mov	bx,#0007
	mov	bp,#MSG_CURSOR
	mov	ax,#0x1301
	int	0x10
	

	mov	ax,#INITSEG
	mov	ds,ax

!十六进制输出光标位置
print_hex1:
	mov	cx,#4			! 循环计数器
    mov	dx,[0]
     	
print_digit1:	
	rol	dx,#4			! 循环左移4位
	mov	ax,#0xe0f		! BIOS中断0x10功能号 ah=0x0E 显示一个字符
	and	al,dl			! 获取dl的低4比特值
	add	al,#0x30		! 数字加0x30
	cmp	al,#0x3a
	jl	outp1				
	add	al,#0x07		! 字母多加0x37
outp1:
   	int	0x10			! 执行 BIOS 0x10号中断
   	loop	print_digit1		! loop指令:cx减1,然后判断cx是否等于0
   	
	!输出提示信息
	mov	ah,#0x03
	xor	bh,bh
	int	0x10
	
	mov	cx,#14
	mov	bx,#0007
	mov	bp,#MSG_MEMORY
	mov	ax,#0x1301
	int	0x10
	

	mov	ax,#INITSEG
	mov	ds,ax

!十六进制输出光标位置
print_hex2:
	mov	cx,#4			! 循环计数器
     	mov	dx,[2]
     	
print_digit2:	
	rol	dx,#4			! 循环左移4位
	mov	ax,#0xe0f		! BIOS中断0x10功能号 ah=0x0E 显示一个字符
	and	al,dl			! 获取dl的低4比特值
	add	al,#0x30		! 数字加0x30
	cmp	al,#0x3a
	jl	outp2				
	add	al,#0x07		! 字母多加0x37
outp2:
   	int	0x10			! 执行 BIOS 0x10号中断
   	loop	print_digit2		! loop指令:cx减1,然后判断cx是否等于0

! 打印回车换行
print_nl:
	mov	ax,#0xe0d	! CR
	int	0x10
	mov	al,#0xa	! LF
	int	0x10		
	
MSG_SETUP:
        .byte 13,10
	.ascii "Now we are in SETUP"
	.byte 13,10,13,10
	
MSG_CURSOR:
        .byte 13,10
	.ascii "Cursor POS:"

MSG_MEMORY:
        .byte 13,10
        .ascii "Memory SIZE:"
	
.text
endtext:
.data
enddata:
.bss
endbss:

参考资料

北京大学《计算机组成》x86体系结构
清华大学《操作系统》BIOS、系统启动流程
《Linux内核完全注释》
哈工大李志军操作系统实验1
哈工大操作系统试验1 操作系统的引导

你可能感兴趣的:(操作系统,操作系统启动,哈工大,HIT)