改写 bootsect.s 主要完成如下功能:
bootsect.s 能在屏幕上打印一段提示信息“XXX is booting…”,其中 XXX 是你给自己的操作系统起的名字,例如 LZJos、Sunix 等(可以上论坛上秀秀谁的 OS 名字最帅,也可以显示一个特色 logo,以表示自己操作系统的与众不同。)
改写 setup.s 主要完成如下功能:
这里需要修改的是字符串长度,即用需要输出的字符串长度替换 mov cx,#24 中的 24。要注意:除了我们设置的字符串 msg1 之外,还有三个换行 + 回车,一共是 6 个字符。比如这里 Hello OS world, my name is laoye! 的长度是 33,加上 6 后是 39,所以代码应该修改为 mov cx,#39。
步骤五:在此路径下打开终端
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 的文件大小是 544 字节,而引导程序必须要正好占用一个磁盘扇区,即 512 个字节。造成多了 32 个字节的原因是 ld86 产生的是 Minix 可执行文件格式,这样的可执行文件除了文本段、数据段等部分以外,还包括一个 Minix 可执行文件头部
步骤七:去掉这 32 个字节的文件头部,输入以下代码
dd bs=1 if=bootsect of=Image skip=32
cp ./Image ../Image
../../run
步骤二:从第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
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
使用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号中断
步骤一:进入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.
2.
3.
4.
5.
源码一
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