上一次完成了安装程序以及页面展示的代码编写,这次开始进行功能开发,本次开发前两个功能,分别是重新启动计算机以及引导现有的操作系统。
这次是在上次的代码基础上进行功能开发,不过,代码上有所调整,添加了引导程序,为什么会这么做?下面会进行说明。
首先给出调整后的代码,功能和(一)篇的内容一样,都是安装程序以及页面欢迎信息展示,不同的是添加了引导程序,以及将任务程序写入了 2 扇区。
boot segment ; 将软盘中0道0面2扇区的任务程序读入到0:7e00处,然后跳转到该地址执行程序 mov ax, 0 ; 7e00 = 7c00 + 200h,该偏移地址与7c00地址相差512字节,空出512字节空间, mov es, ax ; 其它功能开发将会用到这空出的512字节空间 mov bx, 7e00h mov al, 1 mov ch, 0 mov cl, 2 mov dl, 0 mov dh, 0 mov ah, 2 int 13h mov ax, 0 push ax mov ax, 7e00h push ax retf db 512 dup(0) boot ends code segment jmp short start ; 跳转到 start 执行程序 option1: db '1) reset pc', 0 option2: db '2) start system', 0 option3: db '3) clock', 0 option4: db '4) set clock', 0 start: mov bp, 0 mov bx, offset option1 call printf mov bp, 160 mov bx, offset option2 call printf mov bp, 320 mov bx, offset option3 call printf mov bp, 480 mov bx, offset option4 call printf stop: jmp short stop ; 死循环,暂停当前位置,不向下继续执行程序 printf: mov ax, 0b800h mov es, ax mov si, 0 mov ch, 0 va: mov cl, cs:[bx + 07e00h] ; 获取显示字符加上 7e00 jcxz ok mov es:[si + bp], cl add si, 2 inc bx jmp va ok: ret db 512 dup(0) ; 定义 512 字节 0 数据,因为写入软盘是一个扇区 512字节,程序不够 code ends ; 512 字节,其它补充 0 ; 写入软盘代码段 setup segment en: mov ax, code ; 写入代码的段地址,任务程序在 code 段中 mov es, ax mov bx, 0 ; 偏移地址,从第一个字节开始写入数据 mov al, 1 ; 写入的扇区数,这里写入 1 个扇区 mov ch, 0 ; 磁道号 mov cl, 2 ; 扇区号,写入 2 扇区 mov dl, 0 ; 驱动器号,软驱从 0 开始,0:软驱A mov dh, 0 ; 磁头号(面) mov ah, 3 ; int 13h 的功能号(3 表示写扇区) int 13h mov ax, boot ; 将引导程序 boot 写入 0道0面1扇区 mov es, ax mov bx, 0 mov al, 1 mov ch, 0 mov cl, 1 mov dl, 0 mov dh, 0 mov ah, 3 int 13h mov ax, 4c00h int 21h setup ends end en
从上面给出的代码可以看出,除了将任务程序写入了2扇区,在1扇区添加了将2扇区数据读入到0:7e00处,并跳转到此处执行程序外,其它和上次的代码并没有区别。那么问题就来了,上次将程序默认读入到0:7c00处执行,并没有问题,程序正常执行,欢迎页面展示信息正常展示,为什么这次要将代码做出改动,将任务程序加载到0:7e00处执行,空出512字节的空间。我这样做的原因将会在下述开发的功能中给出说明。
用户输入“1”、“2”、“3”、“4”对应不同功能,首先要处理的就是获取用户输入的信息,使用int 16h中断进行键盘缓冲区的读取。
; 获取键盘输入 input: mov ah, 0 int 16h cmp al, '1' ; 1:重新启动计算机,跳转到标号 reset 执行重新启动计算机程序 je reset cmp al, '2' ; 2:引导现有的操作系统,跳转到标号 system 执行引导现有操作系统程序 je system jmp short input
接下来就是开发重新启动计算机程序和引导现有操作系统程序功能了,首先来看重新启动计算机程序功能。
reset: mov ax, 0ffffh ; 重新启动计算机,就是让程序跳转到 FFFF:0 单元处执行,这样就会将开机后的操作 push ax ; 执行一遍,效果就是重新启动了计算机 mov ax, 0 push ax retf
重启计算机是比较简单的,只要将程序跳转到FFFF:0单元处执行就可以了,下面就是开发引导现有操作系统程序功能了,这里也是我花了好长时间才完成的功能。
; 将c盘0道0面1扇区读入到内存0:7c00处,然后跳转到0:7c00处执行程序 system: mov ax, 0 mov es, ax mov bx, 7c00h mov al, 1 mov ch, 0 mov cl, 1 mov dl, 80h ; 硬盘C:80h mov dh, 0 mov ah, 2 int 13h mov ax, 0 push ax mov ax, 7c00h push ax retf
从代码上,并不复杂,就是将c盘0道0面1扇区读入到了0:7c00处,然后跳转到该处执行程序罢了,代码结构和boot代码段的结构是一样的,只是读取的数据和读入到内存的地址不一样罢了。
我开始遇到的问题是,将c盘0道0面1扇区的数据读入到0:7e00处,然后跳转到该处执行程序,但是怎么也执行不成功,无法引导现有的操作系统,来回试了好多次都不行,所以就换了种方式,将任务程序读入到0:7e00处,将c盘0道0面1扇区读入到0:7c00处,此时就可以正常引导现有的操作系统了,这也是我为什么将代码做了调整,将任务程序写入到2扇区,再通过引导程序将2扇区的数据读入到0:7e00处执行的原因了,目的是空出7c00处的512字节给操作系统的引导程序使用。如果有哪位知道原因是什么,请不吝赐教。
最后贴上完整的代码,执行,看一下效果。按下“1”:重新启动计算机;按下“2”:引导现有的操作系统。
boot segment mov ax, 0 mov es, ax mov bx, 7e00h mov al, 1 mov ch, 0 mov cl, 2 mov dl, 0 mov dh, 0 mov ah, 2 int 13h mov ax, 0 push ax mov ax, 7e00h push ax retf db 512 dup(0) boot ends code segment jmp short start ; 跳转到 start 执行程序 option1: db '1) reset pc', 0 option2: db '2) start system', 0 option3: db '3) clock', 0 option4: db '4) set clock', 0 start: mov bp, 0 mov bx, offset option1 call printf mov bp, 160 mov bx, offset option2 call printf mov bp, 320 mov bx, offset option3 call printf mov bp, 480 mov bx, offset option4 call printf ; 获取键盘输入 input: mov ah, 0 int 16h cmp al, '1' je reset cmp al, '2' je system jmp short input stop: jmp short stop ; 死循环,暂停当前位置,不向下继续执行程序 printf: mov ax, 0b800h mov es, ax mov si, 0 mov ch, 0 va: mov cl, cs:[bx + 07e00h] ; 获取显示字符加上 7e00 jcxz ok mov es:[si + bp], cl add si, 2 inc bx jmp va ok: ret reset: mov ax, 0ffffh push ax mov ax, 0 push ax retf system: ; 将c盘0道0面1扇区读入到内存0:7c00处,然后跳转到0:7c00处执行程序 mov ax, 0 mov es, ax mov bx, 7c00h mov al, 1 mov ch, 0 mov cl, 1 mov dl, 80h ; 硬盘C:80h mov dh, 0 mov ah, 2 int 13h mov ax, 0 push ax mov ax, 7c00h push ax retf db 512 dup(0) ; 定义 512 字节 0 数据,因为写入软盘是一个扇区 512字节,程序不够 code ends ; 512 字节,其它补充 0 ; 写入软盘代码段 setup segment en: mov ax, code ; 写入代码的段地址,任务程序在 code 段中 mov es, ax mov bx, 0 ; 偏移地址,从第一个字节开始写入数据 mov al, 1 ; 写入的扇区数,这里写入 1 个扇区 mov ch, 0 ; 磁道号 mov cl, 2 ; 扇区号 mov dl, 0 ; 驱动器号,软驱从 0 开始,0:软驱A mov dh, 0 ; 磁头号(面) mov ah, 3 ; int 13h 的功能号(3 表示写扇区) int 13h mov ax, boot mov es, ax mov bx, 0 mov al, 1 mov ch, 0 mov cl, 1 mov dl, 0 mov dh, 0 mov ah, 3 int 13h mov ax, 4c00h int 21h setup ends end en
到此完成了功能1和功能2,下次再接着将功能3和功能4开发完。
新建了一个自己的个人网站,欢迎前来拍砖,地址:http://www.techxiaoz.xyz
公众号