实模式 是80286及以上的微处理器采用8086的工作模式,从加电启动或复位到操作系统运行之前的运行环境。保护模式 是80386及以上的微处理器的主要工作模式,支持多任务、设置特权级、特权指令执行等,操作系统和应用程序的运行环境。因为操作系统启动处于实模式,所以以下仅涉及实模式下的寄存器和物理地址生成。
① 指令指针寄存器 IP
保存一个内存地址,指向当前需要取出的指令
② 段寄存器与其它寄存器联合生成存储器地址,包括代码段寄存器 CS
、数据段寄存器 DS
、附加段寄存器 ES
和堆栈段寄存器 SS
指令寄存器 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位地址寻址。
实模式下给出逻辑地址 段基值:偏移量
,十进制物理地址计算方法是 物理地址=段基值×16+偏移量
,二进制物理地址计算方法是 物理地址=段基址<<4+偏移量
BIOS运行在实模式下,段基值 CS
为 0xF000
,IP
设置为 0xFFF0
,从而组成BIOS入口地址 0xFFFF0
。
加电稳定后,CPU进入实模式并从BIOS入口地址 0XFFFF0
开始自动执行代码。BIOS初始化硬件并在物理地址0处放置大小为1KB的中断向量表,它将磁盘引导块程序 bootsect.s
读入内存地址 0X7C00
,CPU执行跳转指令跳转到该处执行。
磁盘引导块程序 bootsect.s
执行时把自己移动到0X90000
处,同时将操作系统加载程序 setup.s
加载到内存 0X90200
处,操作系统内核 system
模块加载到内存 0X10000
开始的地方。
操作系统加载程序 setup.s
利用BIOS中断读取机器系统参数,并将参数覆盖保存 bootsect.s
的位置,同时将 system
模块整体向下移动到 0X0000
处覆盖BISO中断。最后,CPU进入保护模式,跳转到 system
模块前端的 head.s
继续运行,从而成功启动操作系统。
- 熟悉hit-oslab实验环境;
- 建立对操作系统引导过程的深入认识;
- 掌握操作系统的基本开发过程;
- 能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱。
此次实验的基本内容是:
- 阅读《Linux内核完全注释》的第6章,对计算机和Linux 0.11的引导过程进行初步的了解;
- 按照下面的要求改写0.11的引导程序bootsect.s
- 有兴趣同学可以做做进入保护模式前的设置程序setup.s。
改写bootsect.s主要完成如下功能:
- 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 // 启动操作系统
阅读《Linux内核完全注释》,es:bp
寄存器保存需要显示字符串 msg1
起始位置,cx
保存字符串 msg1
的字符数。
此时,msg1
字符串包括长度为18的 Loading system ...
和3对换行符13
和回车符10
,长度共计24。如果需要输出长度为20的信息 SEANos is booting…
,则修改ascii内容为 SEANos is booting…
和 cx
内容为26。
重新编译运行,输出结果如下:
改写setup.s主要完成如下功能:
- 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"
。
- 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
------------------------------------------------------------------
INT 0x15功能0x88
--------------------------------------------------------------
描述:
获取扩展内存的大小
接受参数:
AH 0x88
返回值:
AX 从绝对地址1MB开始的内存大小
-------------------------------------------------------------------
mov ah,#0x88
int 0x15 ! 调用0x15中断获取扩展内存大小
mov [2],ax ! 保存扩展内存大小至0x90002
!
! 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 操作系统的引导