实验一 最简单的监控程序一实验题目与要求监控程序是最早的、最简单的操作系统。监控程序最基本的功能就是启动程序的执行和处理程序的结束。在这个实验中,我们给前面的自启程序(参见附录)增加一点功能,使之成为一个最简单的监控程序:该自启程序启动执行后,在屏幕上显示一个简单的菜单: - 执行程序1
- 执行程序2
- 退出
然后,等待并接收用户的选择,并加载、启动相应的程序1或2,当程序1或2结束后,回到该自启程序,重复显示菜单并接收新的选择,如此重复…… 其中,程序1和程序2是由你预先编制好并与自启程序在同一张软盘上连续、静态地存放着的用户程序。它们的功能可以很简单,如help、echo、helloworld等。 不要求中文输入和显示,菜单项可以是具体的程序名,如直接用 help、echo、shutdown等。 二总的设计思想、环境语言、工具等工具:二进制文件编辑器(010Editor.exe),虚拟机(Vmware),汇编程序编辑器(RadASM),编译工具(NASM) 环境语言:windowsXP,汇编 总的设计思想:- 分模块:首先要有一个引导程序来带领计算机进入监控程序,所以引导程序负责加载监控程序进内存并把控制权交给监控程序。监控程序负责在屏幕上打印菜单并接受用户输入,并根据用户输入所相应程序加载进内存并执行它,执行完后返回监控程序。所以把实验程序分成三大模块:引导程序,监控程序,各小程序。
- 攻难点:本实验要攻破的难点有:把三大模块数据准确放到软盘指定位置、准确地从软盘指定位置读数据到内存指定位置、运行内存中指定位置的程序。为了做到准确,每个程序占一个扇区(512字节),分别放在软盘中的第0面0磁道第1个扇区(引导程序),第2个扇区(监控程序),第3~n个扇区(各种小程序)。读到内存中的地址分别为07c00h(引导程序),07e00h(监控程序),08100h(各种小程序)
- 分步骤:用RadASM编写四个程序(引导程序,监控程序,程序1,程序2),并用NASM编译成二进制文件,用010Editor.exe新建一个空二进制文件,把之前编译好的四个二进制文件按顺序放进(插入)新建的二进制文件中的相应位置中(引导程序一定要在最前面),并保存(命名为LisaSystem)。用Vmware中虚拟机的软驱映射到这个二进制文件(LisaSystem)。启动Vmware中的虚拟机, 测试。
三数据结构与模块说明本实验分三大模块:引导程序,监控程序,其他小程序,它们的结构和关系如下图
 其中,最主要的是监控程序,监控程序也分几大模块。监控程序的模块结构如下图:
 四源程序(要有适当注释)1、LisaBoot.asmorg 07c00h mov ax,cs mov ds,ax mov es,ax call LoadData jmp 07e00h ;进入监控程序 ;******************利用BIOS中断int 13h来读软盘************************ LoadData: xor ah,ah ;复位软驱 xor dl,dl ; int 13h ; mov ch,0 ;要读的柱面(磁道)号:0 mov dh,0 ;要读的磁头号:0 mov al,1 ;要读的扇区数:1 mov cl,2 ;要读数据的起始扇区号:2 mov dl,0 ;要读的驱动器号:0(A盘即软盘) mov bx,07e00h ;把监控程序加载到内存07e00h位置 mov ah,02h ; int 13h ret ;******************LoadData结束************************ times 510-($-$$) db 0 dw 0xaa55 2、LisaTest.asmorg 07e00h mov ax,cs mov ds,ax mov es,ax call DispStr jmp $ DispStr: mov ax,BootMessage mov bp,ax mov cx,16 ;16个字符 mov ax,01301h mov bx,000ch mov dx,0 ;第一行打印字符串 int 10h ret BootMessage: db "Hello,OS World!" times 512-($-$$) db 0 ;填满整个扇区 3、MonitorMenuMode.asmorg 07e00h mov ax,cs mov ds,ax mov es,ax ;******************显示菜单************************ DisMenu: mov ah,06h xor al,al xor bh,bh int 10h ;清窗口 mov cx,18 ;18个字符 mov ax,p1 mov dx,0000h ;第0行打印字符串 call DispStr mov ax,p2 mov dx,0100h ;第1行打印字符串 call DispStr mov cx,7 mov ax,pexit mov dx,0200h ;第2行打印字符串 call DispStr mov cx,54 mov ax,inMsg mov dx,0300h ;第3行打印字符串 call DispStr ;******************接受用户输入************************ Selete: xor ah,ah int 16h sub al,30h cmp al,1 jz RightInput ;选择程序1 cmp al,2 jz RightInput ;选择程序2 cmp al,3 jnz DisMenu ;无效输入 ;退出系统 mov cx,19 mov ax,exitMsg mov dx,0500h ;第5行打印字符串 call DispStr SureExit: xor ah,ah int 16h cmp al,'n' jz DisMenu ;不退出 cmp al,'y' jnz SureExit ;无效输入 ;******************退出************************ mov ax,5300h xor bx,bx int 15h mov ax,5301h xor bx,bx int 15h mov ax,530eh xor bx,bx mov cx,101h int 15h mov ax,530fh mov bx,1 mov cx,bx int 15h
mov ax,5308h mov bx,1 mov cx,bx int 15h mov ax,5307h mov bx,1 mov cx,3 int 15h ;******************加载程序并运行************************ RightInput: add al,2 call LoadingPro ;加载程序进内存 ;mov ah,06h ;xor al,al ;xor bh,bh ;int 10h ;清窗口 jmp 08100h ;运行程序 jmp DisMenu ;******************加载程序进内存************************ ;入口参数:al要读的起始扇区号 ;出口参数:无 LoadingPro: xor ah,ah ; xor dl,dl ;复位软驱 int 13h ; mov cl,al ;要读数据的起始扇区号 mov bx,08100h ;把监控程序加载到内存08100h位置 mov ch,0 ;要读的柱面(磁道)号:0 mov al,1 ;要读的扇区数:1 mov dl,0 ;要读的驱动器号:0(A盘即软盘) mov dh,0 ;要读的磁头号:0 mov ah,02h ; int 13h ret ;******************显示字符串************************ ;入口参数:es:ax字符串地址,cx字符串长度(字符数),dx显示位置(dh行dl列) ;出口参数:无 DispStr: mov bp,ax mov ax,01301h mov bx,000ch int 10h ret ;**数据区** p1: db "(1)Run Program One" p2: db "(2)Run Program Two" pexit: db "(3)Exit" inMsg: db "Please enter the number of the program you want to run" exitMsg:db "Sure to exit? (y/n)" ;loadPro:db "Loading Program..." ;测试用的 ;runPro: db "Running Program..." ;测试用的 ;println:db "" ;测试用的 times 512-($-$$) db 0 ;填满整个扇区 4、p1.asmorg 08100h mov ax,cs mov ds,ax mov es,ax mov cx,70 mov ax,p1Message mov dx,0700h ;第7行打印字符串 call DispStr mov cx,33 mov ax,println mov dx,0900h ;第9行打印字符串 call DispStr xor ah,ah int 16h jmp 07e00h ;退出时返回监控程序 ;******************显示字符串************************ ;入口参数:es:ax字符串地址,cx字符串长度(字符数),dx显示位置(dh行dl列) ;出口参数:无 DispStr: mov bp,ax mov ax,01301h mov bx,000ch int 10h ret p1Message: db "Hello,Lisa,Welcom to OS World!",10,13,"Now you are running the first program." println: db "press any key to exit the program" times 512-($-$$) db 0 ;填满整个扇区 5、p2.asmorg 08100h mov ax,cs mov ds,ax mov es,ax mov cx,71 mov ax,p1Message mov dx,0700h ;第7行打印字符串 call DispStr mov cx,33 mov ax,println mov dx,0900h ;第9行打印字符串 call DispStr xor ah,ah int 16h jmp 07e00h ;退出时返回监控程序 ;******************显示字符串************************ ;入口参数:es:ax字符串地址,cx字符串长度(字符数),dx显示位置(dh行dl列) ;出口参数:无 DispStr: mov bp,ax mov ax,01301h mov bx,000ch int 10h ret p1Message: db "Hello,Lisa,Welcom to OS World!",10,13,"Now you are running the second program." println: db "press any key to exit the program" times 512-($-$$) db 0 ;填满整个扇区 6、MonitorCmdMode.asmorg 07e00h mov ax,cs mov ds,ax mov es,ax ;******************显示命令提示符************************ DisCmd: mov ax,0600h xor bh,bh int 10h ;清窗口 mov cx,80 mov ax,inCmd xor dx,dx clearing: push cx mov cx,1 call DispStr inc dl pop cx loop clearing ;清命令行 pop dx mov cx,5 ;18个字符 mov ax,inCmd mov dx,0000h ;第0行打印字符串 call DispStr ;******************接受用户输入************************ Selete: mov si,0 input: mov ah,00h int 16h cmp al,0dh ;输入回车结束 jz endinput cmp al,08h jnz notbackSpace ;撤消输入 cmp si,0 jz input dec si mov al,' ' mov [cmd+si],al mov cx,si inc cx mov ax,cmd mov dx,0005h call DispStr ;显示用户的输入 jmp input notbackSpace: mov [cmd+si],al inc si mov cx,si mov ax,cmd mov dx,0005h call DispStr ;显示用户的输入 jmp input endinput: ;输入结束 mov cx,si ;比较字符长度 cmp si,4 jz cmpexit cmp si,5 jz cmpp1 cmp si,6 jz cmpp2 jmp DisCmd cmpexit: mov si,cmd mov di,pexit rep cmpsb jnz DisCmd jmp Exit cmpp1: mov si,cmd mov di,p1 rep cmpsb jnz DisCmd mov al,1 jmp RightInput cmpp2: mov si,cmd mov di,p2 rep cmpsb jnz DisCmd mov al,2 jmp RightInput ;退出系统 Exit: mov cx,19 mov ax,exitMsg mov dx,0500h ;第5行打印字符串 call DispStr SureExit: xor ah,ah int 16h cmp al,'n' jz DisCmd ;不退出 cmp al,'y' jnz SureExit ;无效输入 ;******************退出************************ mov ax,5300h xor bx,bx int 15h mov ax,5301h xor bx,bx int 15h mov ax,530eh xor bx,bx mov cx,101h int 15h mov ax,530fh mov bx,1 mov cx,bx int 15h
mov ax,5308h mov bx,1 mov cx,bx int 15h mov ax,5307h mov bx,1 mov cx,3 int 15h ;******************加载程序并运行************************ RightInput: add al,2 call LoadingPro ;加载程序进内存 ;mov ah,06h ;xor al,al ;xor bh,bh ;int 10h ;清窗口 jmp 08100h ;运行程序 jmp DisCmd ;******************加载程序进内存************************ ;入口参数:al要读的起始扇区号 ;出口参数:无 LoadingPro: xor ah,ah ; xor dl,dl ;复位软驱 int 13h ; mov cl,al ;要读数据的起始扇区号 mov bx,08100h ;把监控程序加载到内存08100h位置 mov ch,0 ;要读的柱面(磁道)号:0 mov al,1 ;要读的扇区数:1 mov dl,0 ;要读的驱动器号:0(A盘即软盘) mov dh,0 ;要读的磁头号:0 mov ah,02h ; int 13h ret ;******************显示字符串************************ ;入口参数:es:ax字符串地址,cx字符串长度(字符数),dx显示位置(dh行dl列) ;出口参数:无 DispStr: mov bp,ax mov ax,01301h mov bx,000ch int 10h ret ;**数据区** blank: db " " p1: db "first" p2: db "second" pexit: db "exit" inCmd: db "Lisa>" exitMsg:db "Sure to exit? (y/n)" cmd: db ' ' times 512-($-$$) db 0;填满整个扇区 五运行结果与运行情况1、攻破难关一,加载程序入内存,然后运行。把显示"Hello,OS World!"的代码变成一个独立的程序(LisaTest.asm)编译后(LisaTest.bin)放在软盘的第2个扇区,引导程序(LisaBoot.asm)加载它到内存07e00h的位置,然后用jmp 07e00h跳过去,从下面的运行结果可知,跳转成功,但显示的是乱码。
 这是怎么回事?查看了一下LisaTest.asm,开头处没有org 07e00h 这一句,这句和乱码有什么关系?加进去试了一下,一句漂亮的” Hello,OS World!”显示了出来,这就怪了。用010Editor.exe查看了一个LisaTest.bin,发现第14个字节由原来的00h变成后来的7eh,这就是问题所在了,原来org 07e00h这句代码是告诉编译器这段代码将要被加载到内存偏移地址07e00h处的。成功的运行结果如下:
 2、攻破难关二,实现并运行监控程序。难关一通过,只要把LisaTest.asm改成监控程序(MonitorMenuMode.asm)就没问题了。 运行结果如下:
 3、攻破难关三,加载并运行小程序进入监控程序后,提示说输入你想要运行的程序号。 输入1,结果如下。再按一下键盘,又回到了上面那个画面,说明监控程序正确加载了程序1,退出程序1时又成功返回了监控程序。以下是运行了p1.asm的结果
 输入2,结果如下。再按一下键盘,又回到了上面那个画面,说明监控程序正确加载了程序2,退出程序2时又成功返回了监控程序。以下是运行了p2.asm的结果
 4、攻破难关四,退出(关机)其实关掉电源就好了,但心理不爽,明明有个“Exit”选项却不用,这不正常。但汇编没有关机指令,所以要实现这一点还真是煞费苦心,具体方法见(MonitorMenuMode.asm中退出部分)。下面是输入3后的运行结果:
 输入y当然就关机了,输入n又回到监控程序最开始的页面,输入其它无效果。到此,这个最简单的监控程序告一段落了。 六自我评析与总结1、自我打分80分 2、为你哪些地方做得比较好或比较出色思路、模块、结构很清晰; 目标明确、重点突出、难点攻破; 3、为你哪些地方做得不够好、哪些地方可以做得更好、进一步的工作做得不够好: - 规定每个程序占一个扇区,这样做灵活性极差。因为有的程序可能一个扇区装不下,安全性极差。
- 内存管理粗糙,所有小程序都放在08100h处,每运行一次程序都要重新加载一次,并覆盖掉原来的内存,这样使得内存使用效率不高,且浪费时间。
- 一次只能运行一个程序,万一程序运行一半死掉了,系统也就崩溃了。
可以的做得更好和进一步工作: - 可以尝试内存分段:划出一块内存存放分段信息(大小与具体情况有关),监控程序主要从这一块内存获得内存的分配情况。段信息长度固定(与具体情况有关),主要信息包括:段起始地址、段长度(段界限)。这样,内存的使用会更有效率。
- 为软盘引入文件系统:划出软盘的一块存储区域存放文件的索引,采用链似结构,方便文件的读取和修改(类似FAT文件系统),以一个扇区为最小单位,这样就可以放入大于一个扇区的程序。
- 引入进程的概念。
4、实验得到的收获- 对软盘的结构有所了解,知道了软盘有一个盘片,两面,每面80磁道, 每磁道18扇区^_^
- 对BIOS的各中断有所了解,并灵活能应用^_^
- 对系统的自启过程有了深入的认识^_^
- 初尝了亲手制作一个能运行程序的监控程序的快乐,对以后的学习充满信心^_^
- 收集了很不错的工具,像010Editor,RadASM等,为以后的实验准备条件^_^
- 尝试着了解文件系统、保护模式的概念,认识到引入这些概念的重要性。如果像我本次实验这样来管理存储和运行程序,还不累死人,气死人?^_^
5、本题的其他方法把监控程序的初始菜单改成模式选择:菜单模式、命令行模式。菜单模式如以上所做的,命令行模式则如进一步(可选)要求。还可加入滚屏效果。 6、验题的评价和改进意见暂时没有想到。 进一步(可选):要求: 实现一个命令解释器,代替上述的菜单选择方式。即自启程序启动后,不是显示上述菜单,而是显示命令提示符(如DOS中的 > ),等待用户键入命令,用户敲入相应命令后则加载、启动相应的命令程序,程序执行结束后,再显示命令行提示符,等待用户输入下一个命令,如此重复…… 功能结构类似菜单模式。很粗糙,有很多不足之处,只是一个尝试。 监控程序(MonitorCmdMode.asm)运行结果:
 运行了p1.asm的结果
 运行了p2.asm的结果

|