一、实验题目
接管裸机的控制权
二、实验目的
1、了解原型操作系统设计实验教学方法与要求
2、了解计算机硬件系统开机引导方法与过程
3、掌握操作系统的引导程序设计方法与开发工具
4、复习加强汇编语言程序设计能力
三、实验要求
1、 知道原型操作系统设计实验的两条线路和前6个实验项目的差别
2、 掌握PC电脑利用1.44MB软驱的开机引导方法与过程的步骤
3、 在自己的电脑上安装配置引导程序设计的开发工具与环境
4、 参考样版汇编程序,完成在PC虚拟机上设计一个1.44MB软驱的引导程序的完整工作。
5、 编写实验报告,描述实验工作的过程和必要的细节,以证实实验工作的真实性。
四、实验方案
实验要求我们完成的任务有以下两个:
1. 搭建和应用实验环境
虚拟机安装,生成一个基本配置的虚拟机XXXPC和多个1.44MB容量的虚拟软盘,将其中一个虚拟软盘用DOS格式化为DOS引导盘,用WinHex工具将其中一个虚拟软盘的首扇区填满个人信息。
2. 接管裸机的控制权
设计IBM_PC的一个引导扇区程序,程序功能是:用字符‘A’从屏幕左边某行位置45度角下斜射出,保持一个可观察的适当速度直线运动,碰到屏幕的边后产生反射,改变方向运动,如此类推,不断运动;在此基础上,增加你的个性扩展,如同时控制两个运动的轨迹,或炫酷动态变色,个性画面,如此等等,自由不限。还要在屏幕某个区域特别的方式显示你的学号姓名等个人信息。将这个程序的机器码放进放进第三张虚拟软盘的首扇区,并用此软盘引导XXXPC,直到成功。
1、实验环境
实验所使用的计算机配置为:
- CPU:Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
- RAM:8.00GB
- 系统:Windows 10 - x64 10.0.17763
使用的开发工具如下:
- Oracle VM VirtualBox - 6.0.14 r133895 (Qt5.6.2):虚拟机软件,相比起VMware,有着小巧轻便的特点,功能也很齐全。用于创建、运行虚拟机,创建虚拟软盘,引导虚拟软盘启动。
- WinHex - 19.6 x64:16进制文件编辑器,用于查看、编辑虚拟软盘文件的内容。
- Visual Studio Code - 1.44.2 :代码编辑器,可以根据需要配置插件,用于编辑
.asm
代码。 - NASM version 2.14.02 :汇编语言编译程序,安装在Windows 10环境下;利用命令行操作,将
.asm
代码汇编成.bin
二进制文件。 - FloppyWriter:轻量级的软盘写入工具,用于将
.bin
二进制文件写入.img
软盘文件。
2、实验思路
根据实验要求和相关知识,我们按照以下思路完成实验:
- 创建虚拟机,并创建、格式化几个用于实验的虚拟软盘;
- 完成引导扇区的汇编指令编写,使用NASM进行汇编,使用FloppyWriter将二进制文件写入虚拟软盘的引导扇区;
- 在虚拟机上搭载该虚拟软盘,运行并查看结果,根据结果进行调试。
五、实验过程
1、虚拟机配置、软盘创建
使用VirtualBox创建虚拟机,具体设置如下:
- 虚拟机类型、版本分别选择“Other”与“DOS”
- 内存大小分配64MB(由于只执行软盘的引导扇区指令,实际上可以更小)
- 创建时选择“不添加虚拟硬盘”,创建后在“设置”中调整虚拟机的启动顺序,仅勾选“软驱”;
- 打开“设置”-“存储”界面,创建一张1.44MB大小的虚拟软盘,并添加至虚拟机的存储媒介中;
完成软盘创建后,使用WinHex打开,可以看到软盘已经按照FAT12文件系统格式被格式化。
2、填满个人信息
实验要求将虚拟软盘的首扇区填满个人信息,这里直接使用WinHex进行操作:
软盘文件test1.img
中,在空白位置直接键入个人信息,选择数据选块,ctrl+C
复制选块,ctrl+B
写入选块,几次操作后即可完成整个首扇区的充填,效果如下:
3、引导扇区程序设计
实验要求为:
用字符‘A’从屏幕左边某行位置45度角下斜射出,保持一个可观察的适当速度直线运动,碰到屏幕的边后产生反射,改变方向运动,如此类推,不断运动。
通过阅读老师给的参考程序代码,我理解了程序实现思路:
- 使用常数1、2、3、4分别表示四个运动方向,使用变量rdul存储当前的运动方向;
- 使用变量x、y表示当前位置,并根据当前运动方向对x/y进行自增/自减处理;
- 使用两个延迟计数器的组合控制运动速度的快慢;
- 每一次循环都包含以下步骤:
- 根据当前的运动方向处理坐标x、y;
- 判断是否到达边界,若是,改变运动方向;
- 将更新后的字符显示出来;
理解了代码的思路,就可以按照NASM汇编语法重新完成并扩展代码,对原代码做出了以下修改与扩展:
- 将两个延迟计数器修改为一个,并将其数据宽度修改为dd(4B),保证了速度的合适且不会发生溢出。
- 修改了改变运动方向的逻辑:
- 原逻辑为若坐标越界,修改方向并重新修改坐标;
- 修改后的逻辑为若坐标刚好临界,修改方向;
- 同时,原代码在字符运动到四个角落时会出现逻辑错误,从屏幕飞出,并不会发生反弹;通过对这一逻辑的修改,进行了运动到四个角落时按原路径反弹的修复。
- 在屏幕左上角显示当前的运动方向信息:DR(右下)、DL(左下)、UR(右上)、UL(左上)
- 字符在边界反弹时改变字符的颜色;
- 显示的字符为个人学号信息
18340011CBJ
,并进行循环显示;
扩展后代码的具体说明如下:
- 相关常数和数据区:
Dn_Rt equ 1 ;D-Down,U-Up,R-right,L-Left
Up_Rt equ 2 ;
Up_Lt equ 3 ;
Dn_Lt equ 4 ;
LENGTH equ 11 ;显示字符串长度
delay equ 50000000 ;计时器延迟计数,用于控制运动速度
org 7c00h ;程序加载到100h,可用于生成COM/7c00H引导扇区程序
;code....
datadef:
count dd delay
Y dw 0 ; y轴
X dw 0 ; x轴
rdul db Dn_Rt ; 向右下运动
color db 0x8 ; 颜色
char db '18340011CBJ', 0x0 ; 显示字符
- 核心循环部分:每次都根据rdul的值确定运动方向,跳转到指定位置执行指令。
loop1:
dec dword[count] ; 循环计数
jnz loop1 ; >0:跳转
mov dword[count],delay
xor ax,ax ; 根据rdul的值确定运动方向
mov al,1
cmp al,byte[rdul]
je DnRt
mov al,2
cmp al,byte[rdul]
je UpRt
mov al,3
cmp al,byte[rdul]
je UpLt
mov al,4
cmp al,byte[rdul]
je DnLt
jmp $ ;end
- 运动的实现逻辑,以左下运动为例:
对坐标进行更新后需要考虑是否到达边界,这里的边界包括角落、下边界、右边界三种情况,其中下边界、右边界仅通过X坐标或Y坐标判断,角落的判断需要通过X、Y坐标的和或者差(左上、右下需要求和,左下、右上需要作差,才能正确判断角落的情况)判断;
判断后更新运动方向和字符颜色即可。
DnRt:
mov byte [gs:0x00],'D' ; 在屏幕左上角显示运动方向
mov byte [gs:0x02],'R'
inc word[Y] ; 更新坐标
inc word[X]
mov ax,word[Y] ; 判断是否到达角落
add ax,word[X]
cmp ax,25+80-2
jz dr2ul
mov bx,word[Y] ; 判断是否到达下边界
mov ax,25-1
sub ax,bx
jz dr2ur
mov bx,word[X] ; 判断是否到达右边界
mov ax,80-1
sub ax,bx
jz dr2dl
jmp show ;显示字符
dr2ul:
mov byte[rdul],Up_Lt
jmp setcolor
dr2ur:
mov byte[rdul],Up_Rt
jmp setcolor
dr2dl:
mov byte[rdul],Dn_Lt
jmp setcolor
- 颜色更新:
setcolor: ; 更新颜色
add byte[color], 1
cmp byte[color], 0x10
jz resetcolor
jmp show
resetcolor: ; 颜色超过范围,重新初始化
mov byte[color],0x8
jmp show
- 字符显示:首先根据X、Y坐标计算显存地址,然后更新显示的字符,将其存入显存。
show:
mov ax,word[Y] ; 根据坐标计算显存地址
mov bx,80
mul bx
add ax,word[X]
mov bx,2
mul bx
mov bx,ax ; bx = position
; 字符更新
inc si
cmp si, LENGTH
jne show2
mov si, 0
show2:
mov ah,byte[color] ; ax高八位为字符颜色
mov al,byte[char+si] ; ax低八位为显示字符
mov [gs:bx],ax ; 存入显存
jmp loop1 ; 进行下一次循环
4、软盘引导虚拟机
完成代码后,使用命令行执行nasm -f bin stone2.asm -o stone2.bin
,将代码文件stone2.asm
汇编形成二进制文件stone2.bin
;并使用FloppyWriter工具将二进制文件写入刚刚创建的虚拟软盘stone2.img
中。
需要注意的是,形成的二进制文件大小不能超过512B,这是由于写入虚拟软盘后,在软盘引导虚拟机时只会将首扇区载入内存,即载入512B的数据;如果二进制文件大小大于512B,即使被写入软盘,引导启动时也不会被加载至内存,运行时会发生错误。
将虚拟机的存储媒介选择为该虚拟软盘,启动,运行结果如下:
在屏幕的左上角实时显示运动方向,显示的字符18340011CBJ
按顺序显示,在边界上反弹并改变颜色。
六、实验总结
第一次操作系统实验,可以说是一个开始。进行实验前的准备其实比实验本身花的时间更多,包括X86汇编语言的学习、计算机启动流程的学习和各种基础知识的学习,这些知识能够在实验中被运用.
在实验过程中的一大收获就是各类开发工具的熟悉,例如NASM、WinHex、VirtualBox,第一次实验本身难度不大,但也让我很好地熟悉了这几种工具的基本操作,比如进行asm
文件的汇编,将二进制文件写入软盘,软盘文件的创建、浏览、编辑、格式化等。
这次实验容易被忽略的小细节:
- 原代码在字符运动到四个角落时会出现逻辑错误,从屏幕飞出,并不会发生反弹:这是由于原代码中只考虑了向两个位置的反弹(X轴边界或Y轴边界),如果到达角落,这两种反弹方式都会产生越界,所以需要增加一种专门相应角落的反弹机制。
- 汇编形成的二进制文件大小不能超过512B:这一问题是在我写了较长的代码,写入软盘成功,但执行时发生错误时发现。这一错误的寻找花了不少时间,不过也因此让我印象深刻。为了减少文件的大小,需要在代码逻辑上进行优化,在原有功能的基础上删除不必要的指令。
七、参考文献
- 李忠.《 x86 汇编语言-从实模式到保护模式》.电子工业出版社. 2012-09.