操作系统实验:接管裸机的控制权

 Max.C     2020-04-29   5367 words    & views

一、实验题目

接管裸机的控制权

二、实验目的

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,即使被写入软盘,引导启动时也不会被加载至内存,运行时会发生错误。

将虚拟机的存储媒介选择为该虚拟软盘,启动,运行结果如下:

9

在屏幕的左上角实时显示运动方向,显示的字符18340011CBJ按顺序显示,在边界上反弹并改变颜色。

六、实验总结

第一次操作系统实验,可以说是一个开始。进行实验前的准备其实比实验本身花的时间更多,包括X86汇编语言的学习、计算机启动流程的学习和各种基础知识的学习,这些知识能够在实验中被运用.

在实验过程中的一大收获就是各类开发工具的熟悉,例如NASM、WinHex、VirtualBox,第一次实验本身难度不大,但也让我很好地熟悉了这几种工具的基本操作,比如进行asm文件的汇编,将二进制文件写入软盘,软盘文件的创建、浏览、编辑、格式化等。

这次实验容易被忽略的小细节:

  1. 原代码在字符运动到四个角落时会出现逻辑错误,从屏幕飞出,并不会发生反弹:这是由于原代码中只考虑了向两个位置的反弹(X轴边界或Y轴边界),如果到达角落,这两种反弹方式都会产生越界,所以需要增加一种专门相应角落的反弹机制
  2. 汇编形成的二进制文件大小不能超过512B:这一问题是在我写了较长的代码,写入软盘成功,但执行时发生错误时发现。这一错误的寻找花了不少时间,不过也因此让我印象深刻。为了减少文件的大小,需要在代码逻辑上进行优化,在原有功能的基础上删除不必要的指令。

七、参考文献

  • 李忠.《 x86 汇编语言-从实模式到保护模式》.电子工业出版社. 2012-09.