实验1:操作系统的引导
实验1:操作系统的引导
实验的准备工作操作
- 解压源码用
tar -zxvf hit-oslab-linux-20110823.tar.gz
可以使用-C
来指定解压路径,tar -zxvf hit-oslab-linux-20110823.tar.gz -C [path]
- 编译linux-0.11的源码,在
linux-0.11
的文件夹下运行make all
或者make
。 - 在oslab文件目录下运行
./run
运行bochs 中的linux-0.11
。 - 访问linux-0.11里面的文件,使用
sudo ./mount-hdc
来装载硬盘,然后在hdc
中访问,卸载硬盘sudo umount hdc
。
实验内容
- 阅读《Linux 内核完全注释》的第 6 章,对计算机和 Linux 0.11 的引导过程进行初步的了解;
- 按照下面的要求改写 0.11 的引导程序 bootsect.s
- 有兴趣同学可以做做进入保护模式前的设置程序 setup.s。
改写 bootsect.s 主要完成如下功能:
- bootsect.s 能在屏幕上打印一段提示信息“XXX is booting…”,其中 XXX 是你给自己的操作系统起的名字,也可以显示一个特色 logo,以表示自己操作系统的与众不同。
改写 setup.s 主要完成如下功能:
- bootsect.s 能完成 setup.s 的载入,并跳转到 setup.s 开始地址执行。而 setup.s 向屏幕输出一行"Now we are in SETUP"。
- setup.s 能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。
- setup.s 不再加载 Linux 内核,保持上述信息显示在屏幕上即可。
bootsect.s的修改
bootsect.s
的功能是将自己从0x7c00
处移动到了0x90000
处。显示字符loding system ...
,然后将磁盘上的setup.s
和system
模块加载到内存中来,最后跳转到setup.s
所在的位置,执行setup.s
。
实验内容:
-
bootsect.s 能在屏幕上打印一段提示信息“XXX is booting…”;
-
bootsect.s 能完成 setup.s 的载入,并跳转到 setup.s 开始地址执行。
1. bootsect.s 打印字符
首先使用BIOS0x10
号中断的子功能0x03
获得光标的位置,然后再利用BIOS0x10
号中断的子功能0x13
打印字符到屏幕上。代码如下:
entry start
start:
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#26
mov bl,#07
mov bp,#msg !寻址es:bp
mov ax,#0x7c0 !因为bootsect的代码放在0x7c00处
mov es,ax
mov ax,#0x1301
int 0x10
msg:
.byte 13,10 !回车和换行
.ascii "HaoOS is loading ..."
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
在BIOS中断指令int
前面的代码都是为中断设置一些参数。最后的三行是因为bootsect的大小必须为512字节,所以添加到后面使编译后的文件大小为512字节,最后两个字节为0xAA55
。
2. 载入setup并跳转
代码如下:
entry start
start:
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#26
mov bl,#07
mov bp,#msg !寻址es:bp
mov ax,#0x7c0 !因为bootsect的代码放在0x7c00处
mov es,ax
mov ax,#0x1301
int 0x10
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+4 ! service 2, nr of sectors
int 0x13 ! read it
jmpi 0,#0x07e0 ! jump to setup 0x07e0 = 0x07c0 + 0x0200
! there is set cs to 0x07e0, in the setup the cs be used.
msg:
.byte 13,10 !回车和换行
.ascii "HaoOS is loading ..."
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
在第一部分的代码中添加了load_step的部分,这一部分利用BIOS0x13
中断读入setup.s
然后利用jmpi
跳转到setup.s
模块开始的地方。
注意:
由于在bootsect中我们并没有移动bootsect的位置,所以在跳转的时候的地址是0x07c0 + 0x0200 = 0x07e0
,而不是和linux-0.11中一样跳转到0x90200
处。
setup的修改
setup的主要功能是使用BIOS中断读取系统参数,然后放到内存中的指定位置,同时将cpu从实模式转化到保护模式。
实验内容:
- setup.s 向屏幕输出一行"Now we are in SETUP"。
- setup.s 能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。
- setup.s 不再加载 Linux 内核,保持上述信息显示在屏幕上即可。
1. setup向屏幕输出字符
这一部分代码和bootsect部分类似。有的部分需要修改,比如es
寄存器的指向,还有打印的字符的长度。
2. 获取硬件参数并打印
这里如何获取硬件参数,既可以参考linux-0.11的源码,也可以自己查看BIOS中断的手册。我在这里比较迷惑的是如何将获得的参数打印到屏幕上?看了老师的实现后,发现还是比较简单的,主要问题是自己对汇编语言还是不够熟悉。老师的代码如下(大体的思路是先读参数,然后获取光标,打印,获取光标,打印…):
INITSEG = 0x9000
entry _start
_start:
! Print "NOW we are in SETUP"
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#25
mov bx,#0x0007
mov bp,#msg2
mov ax,cs
mov es,ax
mov ax,#0x1301
int 0x10
mov ax,cs
mov es,ax
! init ss:sp
mov ax,#INITSEG
mov ss,ax
mov sp,#0xFF00
! Get Params
mov ax,#INITSEG
mov ds,ax
mov ah,#0x03
xor bh,bh
int 0x10
mov [0],dx
mov ah,#0x88
int 0x15
mov [2],ax
! 这里是如何把参数保存到数据段里面的
mov ax,#0x0000
mov ds,ax
lds si,[4*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0004
mov cx,#0x10
rep
movsb
! Be Ready to Print
mov ax,cs
mov es,ax
mov ax,#INITSEG
mov ds,ax
! Cursor Position
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#18
mov bx,#0x0007
mov bp,#msg_cursor
mov ax,#0x1301
int 0x10
mov dx,[0]
call print_hex
! Memory Size
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#14
mov bx,#0x0007
mov bp,#msg_memory
mov ax,#0x1301
int 0x10
mov dx,[2]
call print_hex
! Add KB
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#2
mov bx,#0x0007
mov bp,#msg_kb
mov ax,#0x1301
int 0x10
! Cyles
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#7
mov bx,#0x0007
mov bp,#msg_cyles
mov ax,#0x1301
int 0x10
mov dx,[4]
call print_hex
! Heads
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#8
mov bx,#0x0007
mov bp,#msg_heads
mov ax,#0x1301
int 0x10
mov dx,[6]
call print_hex
! Secotrs
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#10
mov bx,#0x0007
mov bp,#msg_sectors
mov ax,#0x1301
int 0x10
mov dx,[12]
call print_hex
inf_loop:
jmp inf_loop
print_hex:
mov cx,#4
print_digit:
rol dx,#4
mov ax,#0xe0f
and al,dl
add al,#0x30
cmp al,#0x3a
jl outp
add al,#0x07
outp:
int 0x10
loop print_digit
ret
print_nl:
mov ax,#0xe0d ! CR
int 0x10
mov al,#0xa ! LF
int 0x10
ret
msg2:
.byte 13,10
.ascii "NOW we are in SETUP"
.byte 13,10,13,10
msg_cursor:
.byte 13,10
.ascii "Cursor position:"
msg_memory:
.byte 13,10
.ascii "Memory Size:"
msg_cyles:
.byte 13,10
.ascii "Cyls:"
msg_heads:
.byte 13,10
.ascii "Heads:"
msg_sectors:
.byte 13,10
.ascii "Sectors:"
msg_kb:
.ascii "KB"
.org 510
boot_flag:
.word 0xAA55
这里如何使用的bootsect还是上个实验的代码的话,需要把前面的INITSEG
改成0x07e0
。
疑问:
在上面代码的获取参数部分,不明白是如何把数据保存到特定位置的?如何循环的?
mov ax,#0x0000
mov ds,ax
lds si,[4*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0004
mov cx,#0x10
rep
movsb
试着解释:在这里是从原地址到目的地址移动1字节的内容,这里设置cs=16
,意思是移动16次,共16字节。
下一篇: 页面打印Js 代码
推荐阅读
-
Linux 操作系统的权限为什么是1,2,4 而不是 1,2,3?如何用二进制来做权限管理
-
搭建一个大型网站架构的实验环境(Squid缓存服务器篇)第1/2页
-
荐 操作系统实验:单处理器系统的进程调度(学习笔记)
-
【操作系统作业—lab1】linux shell脚本 遍历目标文件夹和所有文件 | 包括特殊字符文件名的处理
-
实习过程中学到关于各版本操作系统的知识(1)
-
C++ 实验二 NO.1_(3) 1:熟悉DEV环境,练习自己的第一个程序使用DEV集成环境来编辑,运行简单的数据输入和运算实验。(3)编写一个程序,要求:提示输入3个数;显示这3个数,求他们的平均值
-
操作系统的形成与发展(1)
-
操作系统的形成与发展(1)
-
操作系统实验:使用无缓冲的方式实现文件读\写
-
重装windows操作系统后Ubuntu11.04无法引导的解决办法