加载用户程序的监控程序 LeeRinji

实验题目

加载用户程序的监控程序

实验目的

实验要求

实验方案

实验环境

软件

大部分开发环境安装在 WSL 上,较之于双系统、虚拟机等其他开发方案,更加方便,也方便直接使用 Linux 下的一些指令。

硬件

开发环境配置

所用机器型号为 VAIO Z Flip 2016

虚拟机配置

实验原理

与前一个实验(“裸机控制权与引导程序”)差不多。

  1. 虚拟软盘的第一个扇区用于存储主引导程序(即监控程序),需要保证最后两个字节为55aa。验证主引导程序有效后,跳转到7c00h开始执行。
  2. 引导程序接受键盘输入,选择程序,随后从软盘加载指定程序扇区的内容到内存并跳转执行。
  3. 中断标号0x000x13已经具有功能,0x140x1f为保留标号,0x200xff提供给用户自定义中断。因此定义0x20h号中断用于从用户程序返回监控程序。
  4. 在用户程序的循环中需要加入软件中断int 20h,用于监测是否有键盘返回,如果有则返回监控程序,否则继续执行。

实验过程

a.asm

本次实验要求写 4 个用户程序,分别是在屏幕的 4 个象限中弹来弹去。四个代码的程序几乎相同,只需要修改某些常量和变量的定义即可。这里只给出其中一个程序的代码。

另外,本想直接用前一个实验的c.asm,却发现老师只考虑了边反射的情况,没有考虑四个角反射的情况,这会导致显示的内容从角飞出,在屏幕中乱飞。于是再次重构这段代码,使得编译后大小仅 137bytes:

%macro print 4	; string, length, x, y
	mov ax, cs
	mov ds, ax
	mov bp, %1
	mov ax, ds
	mov es, ax
	mov cx, %2
	mov ah, 13h
	mov al, 00h
	mov bh, 00h
	mov bl, %3	; 根据行号自动变色
	mov dh, %3
	mov dl, %4
	int 10h
%endmacro

	N equ 12	;显示区域高度
	M equ 32	;显示区域宽度减去字符串长度
	TOP equ 2	;显示区域上端点
	LEFT equ 40	;显示区域左端点
	LENGTH equ 8	;字符串的长度
	DELAY equ 99999999
	org 0A100h
	mov ax,0B800h
	mov gs,ax	; GS = 0xB800h,文本窗口显存起始地址

myLoop:
	dec dword[count]	; 递减计数变量
	jnz myLoop	; >0:跳转
	mov dword[count], DELAY

	mov word ax, [t]	; ax = t
	mov word bx,2*N-2
	xor dx, dx	; clear dx and prepare for division
	div bx  ; dx = t mod (2N - 2)
	cmp dx, N ; compare dx and n
	jb xok  ; if (dx < n) jump xok
	sub bx, dx
	mov dx, bx ; dx = 2n - 2 - dx
xok:
	mov word[x], dx
	add word[x], TOP

	mov word ax, [t]
	mov word bx, 2*M-2
	xor dx, dx
	div bx
	cmp dx, M
	jb yok
	sub bx, dx
	mov dx, bx
yok:
	mov word [y],dx
	add word [y],LEFT

	inc word[t]
	print message, LENGTH, [x], [y]
	int 20h
	jmp myLoop
datadef:
	count dd 1
	t dw 0
	x dw 1
	y dw 0
	message db ' wu-kan '

wukos.asm

引导扇区的 bootloader,其功能有:

这里遇到一个问题,就是直接使用上面自动变色的程序时没有显示。因前两行的 x 坐标恰好对应了颜色中的黑底黑字。因此修改显示颜色mov bl, 07h(黑底白字)即可。

OffSetOfUserPrg equ 0A100h
org  7c00h
%macro print 4	; string, length, x, y
	mov ax, cs
	mov ds, ax
	mov bp, %1
	mov ax, ds
	mov es, ax
	mov cx, %2
	mov ah, 13h
	mov al, 00h
	mov bh, 00h
	mov bl, 07h	; 黑底白字
	mov dh, %3
	mov dl, %4
	int 10h
%endmacro

mov ax, 0000h
mov es, ax
mov ax, 20h
mov bx, 4
mul bx
mov si, ax
mov ax, _int20h
mov [es:si], ax
add si, 2
mov ax, cs
mov [es:si], ax
begin:
	call cls
	print msg, msglen, 0, 0
input:
	mov ah, 0
	int 16h
	cmp al, '1'
	jl input
	cmp al, '4'
	jg input
	mov [sectorNum], al
	call cls
	print msg1, msglen1, 0, 0
	print sectorNum, 1, 0, 16

	mov cl, [sectorNum]
	sub cl, '0'-1  ;从第二个扇区开始
	mov ax, cs
	mov es, ax
	mov ah, 2
	mov al, 1
	mov dl, 0
	mov dh, 0
	mov ch, 0
	mov bx, OffSetOfUserPrg
	int 13H
	jmp OffSetOfUserPrg
cls:
	mov ax, 0B800h
	mov es, ax
	mov si, 0
	mov cx, 80*25
	mov dx, 0
	clsLoop:
		mov [es:si], dx
		add si, 2
	loop clsLoop
	ret
int20h:
	mov ah, 01h
	int 16h
	jz noclick
	mov ah, 00h
	int 16h
	cmp ax, 2e03h	; 检测Ctrl + C
	jne noclick
	jmp begin
noclick:
	iret
datadef:
	msg db 'Welcome to WuKOS, press 1~4 to run a program.'
	msglen equ ($-msg)
	msg1 db 'This is program 0, press Ctrl + C to return.'
	msglen1 equ ($-msg1)
	sectorNum db '1'

编译烧盘

在 WSL 终端下按顺序执行下述指令。主引导程序存储在虚拟软盘的第一个扇区,第一个用户程序存储在第二个扇区,第二个用户程序存储在第三个扇区,以此类推。

nasm wukos.asm -o wukos.com
nasm a.asm -o a.com
nasm b.asm -o b.com
nasm c.asm -o c.com
nasm d.asm -o d.com
/sbin/mkfs.msdos -C wukos.img 1440
dd if=wukos.com of=wukos.img conv=notrunc
dd if=a.com of=wukos.img seek=1 conv=notrunc
dd if=b.com of=wukos.img seek=2 conv=notrunc
dd if=c.com of=wukos.img seek=3 conv=notrunc
dd if=d.com of=wukos.img seek=4 conv=notrunc

运行结果

引导界面

图片描述

程序 1

图片描述

显示姓名。

程序 2

图片描述

显示学号。

程序 3

图片描述 显示邮箱。

程序 4

图片描述 显示博客。

实验总结

重写了之前的代码,没有想到本来上次已经很小的 290bytes 还能压到更小的 137bytes…

还遇到了根据行号变色时第一行看不到输出的原因,仔细思考和查阅网上资料后发现 00h 用于表示不显示,在自动变色行号为 0 的时候就会导致看不到输出。

现在对org 7c00h等语句有了更深的理解了。