0.实验指导
- https://hoverwinter.gitbooks.io/hit-oslab-manual/content/sy1_boot.html
- https://github.com/hoverwinter/HIT-OSLab
- 《Linux内核完全注释》
代码仓:https://gitee.com/zgw_yixi/linux-0.11-os-lab.git
1.实验目的
- 熟悉实验环境;
- 建立对操作系统引导过程的深入认识;
- 掌握操作系统的基本开发过程;
- 能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱。
2.实验要求
改写bootsect.s主要完成如下功能:
- bootsect.s能在屏幕上打印一段提示信息“XXX is booting…”,其中XXX是你给自己的操作系统起的名字,例如LZJos、Sunix等
- bootsect.s能完成setup.s的载入,并跳转到setup.s开始地址执行。而setup.s向屏幕输出一行"Now we are in SETUP"。
- setup.s能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。
- setup.s不再加载Linux内核,保持上述信息显示在屏幕上即可。
3.实现
显示、获取硬件参数都要用BIOS中断,相关参数自行查询。
(1)打印加载信息
实现这个功能要明白两点:一是原始代码是在哪里显示正在加载操作系统的,即要知道操作系统的启动过程;二是要知道如何在屏幕上显示字符。
第一问题,原始代码中在bootsect中加载操作系统,并打印出正在加载操作系统的信息。第二问题,因为此时操作系统还没有建立,只能使用BIOS中断来显示。
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#29
mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
int 0x10
msg1:
.byte 13,10
.ascii "x-bit os is loading ..."
.byte 13,10,13,10
编译执行:
make all
make start
(2) 打印"Now we are in SETUP"
仿照上面的显示方式即可,代码是现在setup.s文件中。
mov ax, cs
mov ds, ax
mov es, ax
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#26
mov bx,#0x000c ! page 0, attribute 7 (normal)
mov bp,#msg2
mov ax,#0x1301 ! write string, move cursor
int 0x10
msg2:
.byte 13,10
.ascii "Now we are in SETUP "
.byte 13,10,13,10
(3)获取硬件参数
显示2字节的16进制的函数,数据放在dx寄存器中:
print_hex:
mov cx, #4 ! 2字节,一次显示4bit,需要显示4次
!mov dx, (bp)
print_digit:
rol dx, #4 ! 循环左移4位,最高4位就移动到了最低4位上
mov ax, #0x0e0f ! 0x10中断的参数,AH=0x0e表示显示一个字符,AL=字符,这里先赋值为f,后面会相与
and al, dl ! 取出最低4位放到al上
add al, #0x30 ! 转化为ASCII码,0x30是字符'0'的ASCII码
cmp al, #0x3a ! 判断数字范围,如果是10-16,需要再加上7;0x39是字符'9'的ASCII码
jl outp ! jl指令:当cmp x,y指令中的x < y时则跳转到outp位置
add al, #0x07 ! 转化为'A' - 'F'
outp:
int 0x10 ! 调用BIOS中断显示字符
loop print_digit ! 执行loop会先将cx寄存器减一然后判断cx是否为0,如果不是则跳转
ret ! 函数调用返回
打印换行和回车:
print_nl:
mov ax, #0x0e0d
int 0x10
mov al, #0x0a
int 0x10
ret
读取光标位置和扩展内存的大小:
! 获取硬件参数
mov ax, #INITSEG
mov ds, ax
! 获取光标位置,写入到0x90000
mov ah, #0x03
xor bh, bh
int 0x10
mov [0], dx
! 读取扩展内存大小,写入到0x90002
mov ah, #0x88
int 0x15
mov [2], ax
显示光标位置和扩展内存大小:
! 打印硬件信息
! 读取光标位置
mov ah, #0x03
xor bh, bh
int 0x10
! 在当前光标位置显示cur_pos位置的字符串
mov ax, #0x1301
mov bx, #0x7
mov cx, #17
mov bp, #cur_pos
int 0x10
! 打印16进制的光标位置
mov dx, [0] ! 把之前保存的位置数据读出来,这里显示的位置为这行的开头
call print_hex
call print_nl
! 读取光标位置
mov ah, #0x03
xor bh, bh
int 0x10
! 显示mem_size位置处的字符串
mov ax, #0x1301
mov bx, #0x7
mov cx, #12
mov bp, #mem_size
int 0x10
! 显示16进制的扩展内存大小
mov dx, [2] ! 从0x90002位置处读出扩展内存大小
call print_hex
call print_nl
cur_pos:
.ascii "current position:"
mem_size:
.ascii "memory size:"
显示效果:
不再加载setup.s,停住:
_loop:
jmp _loop