文章目录
前言
做实验前一定要先拍个快照!!
操作系统实验环境的搭建请看如下链接(Ubuntu系统)
一.实验内容
两个部分
1.第一个部分
改写 bootsect.s 主要完成如下功能:
bootsect.s 能在屏幕上打印一段提示信息“XXX is booting…”,其中 XXX 是你给自己的操作系统起的名字,例如 LZJos、Sunix 等(可以上论坛上秀秀谁的 OS 名字最帅,也可以显示一个特色 logo,以表示自己操作系统的与众不同。)
2.第二个部分
改写 setup.s 主要完成如下功能:
bootsect.s 能完成 setup.s 的载入,并跳转到 setup.s 开始地址执行。而 setup.s 向屏幕输出一行"Now we are in SETUP"。
setup.s 能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。
setup.s 不再加载 Linux 内核,保持上述信息显示在屏幕上即可。
二、实验内容1
步骤一:进入到如下路径:/home/你的用户名/oslab/linux-0.11/boot
步骤二:打开bootsect.s,找到第244行的msg1
步骤三:修改.ascii,我这里修改成:“Hello OS world, my name is laoye!”
步骤四:找到98行的 mov cx,#24。并修改cx的值,
这里需要修改的是字符串长度,即用需要输出的字符串长度替换 mov cx,#24 中的 24。要注意:除了我们设置的字符串 msg1 之外,还有三个换行 + 回车,一共是 6 个字符。比如这里 Hello OS world, my name is laoye! 的长度是 33,加上 6 后是 39,所以代码应该修改为 mov cx,#39。
注:es:bp 寄存器保存需要显示字符串 msg1 起始位置,cx 保存字符串 msg1 的字符数
步骤五:在此路径下打开终端
步骤六:获取root权限后,按顺序输入代码
as86 -0 -a -o bootsect.o bootsect.s
ld86 -0 -s -o bootsect bootsect.o
其中 -0(注意:这是数字 0,不是字母 O)表示生成 8086 的 16 位目标程序,-a 表示生成与 GNU as 和 ld 部分兼容的代码,-s 告诉链接器 ld86 去除最后生成的可执行文件中的符号信息。
如果这两个命令没有任何输出,说明编译与链接都通过了。
没有报错的话,会出现以下.o文件
其中 bootsect.o 是中间文件。bootsect 是编译、链接后的目标文件。
需要留意的文件是 bootsect 的文件大小是 544 字节,而引导程序必须要正好占用一个磁盘扇区,即 512 个字节。造成多了 32 个字节的原因是 ld86 产生的是 Minix 可执行文件格式,这样的可执行文件除了文本段、数据段等部分以外,还包括一个 Minix 可执行文件头部
步骤七:去掉这 32 个字节的文件头部,输入以下代码
dd bs=1 if=bootsect of=Image skip=32
生成的 Image 就是去掉文件头的 bootsect。
去掉这 32 个字节后,将生成的文件拷贝到 linux-0.11 目录下,并一定要命名为“Image”(注意大小写)。然后就“run”吧!
步骤八:输入以下代码,可以看到我们修改的结果
cp ./Image ../Image
../../run
二、实验内容2
内容2的第一部分,向屏幕输出 Now we are in setup
步骤一:进入boot目录下的setup.s文件,清除89行~224行加载SYSTEM模块的内容,避免重复启动的现象出现
步骤二:从第32行开始输入以下代码
mov ax,#0x9000
mov es,ax
mov ax,#0x0300
xor bh,bh
int 0x10
mov cx,#25
mov bp,#msg2
mov bx,#0x0007
mov ax,#0x1301
int 0x10
步骤三:在第109行开始输入如下代码,保存退出
msg2:
.byte 13,10
.ascii "Now we are in setup!"
.byte 13,10,13,10
步骤四:在linux-0.11目录下打开终端,输入以下代码,不出意外,他应该会报错
make BootImage
步骤五:打个小补丁,修改build.c的代码
上面有 Error的原因是因为 make 根据 Makefile 的指引执行了 tools/build.c,它是为生成整个内核的镜像文件而设计的,没考虑我们只需要 bootsect.s 和 setup.s 的情况。它在向我们要 “系统” 的核心代码。为完成实验,接下来给它打个小补丁。
build.c 从命令行参数得到 bootsect、setup 和 system 内核的文件名,将三者做简单的整理后一起写入 Image。其中 system 是第三个参数(argv[3])。当 “make all” 或者 “makeall” 的时候,这个参数传过来的是正确的文件名,build.c 会打开它,将内容写入 Image。而 “make BootImage” 时,传过来的是字符串 “none”。所以,改造 build.c 的思路就是当 argv[3] 是"none"的时候,只写 bootsect 和 setup,忽略所有与 system 有关的工作,或者在该写 system 的位置都写上 “0”。
↓
把第178行到第190行的内容全部注释掉
步骤6:重新运行,在路径为linux-0.11的终端下输入以下代码
make BootImage
../run
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,光标属性为停在字符串结尾处
! 属性值,7或9都可以
mov ax,#0x1301 !BIOS中断0x10功能号 ah=0x13 显示字符串
int 0x10 !执行 BIOS 0x10号中断
内容2的第二个部分,获取硬件参数
硬件参数在内存中的位置如下图所示
步骤一:进入setup.s文件,在第104行后添加如下代码并且后面所有步骤的代码都是从104行开始
mov ax,#0x9020
mov ds,ax
mov es,ax
/ /此时的数据段从setup模块开始
步骤二:打印要输出的光标位置的提示信息,输入以下代码
mov ax,#0x0300
xor bh,bh
int 0x10
mov cx,#18
mov bp,#CURSOR_POSITION
mov bx,#0x0009 / / 或者是mov bx,#0x0007
mov ax,#0x1301
int 0x10
mov ax,#0x9000
mov ds,ax
步骤三:验证一下结果,在linux-0.11路径下输入以下代码
make BootImage
../run
结果正确
步骤四:显示硬件参数具体的信息,这是关键也是难点,提供以下两份原码,以及详细解释
小贴士
1.cmp指令请看这
源码一
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 cx,#4 !4个16进制数
mov dx,[0] ! cursor 0x90000
PRINT_DIGIT1:
rol dx,#4 !循环移位 高4位变低四位
mov ax,#0xe0f !ah = 0e 显示一个字符(al)
and al,dl !去DL的低四位
add al,#0x30 !转换成 ascii
cmp al,#0x3A !大于10?
jl OUTP1
add al,#0x07 !大于10 就 +7
OUTP1:
int 0x10
loop PRINT_DIGIT1 ! CX--
不仅可以打印光标位置,其他硬件同理,也可打印
以扩展内存为例,输入以下代码
! 打印提示信息
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bp,#EXPAND_MENMORY
mov bx,#0x0007
mov ax,#0x1301
int 0x10
mov ax,#0x9000
mov ds,ax
mov es,ax
! 打印扩展内存
print_hex2:
rol dx,#4
mov ax,#0x0e0f
print_digit2:
and al,dl
add al,#0x30
cmp al,#0x3a
jl output2
add al,#0x07
output2:
int 0x10
loop print_digit2
步骤五:验证结果,linux-0.11路径下输入以下代码
make BootImage
../run