post on 18 Mar 2019 about 4351words require 15min
CC BY 4.0 (除特别声明或转载文章外)
如果这篇博客帮助到你,可以请我喝一杯咖啡~
加载用户程序的监控程序
sudo apt install nasm
安装在 WSL 上。大部分开发环境安装在 WSL 上,较之于双系统、虚拟机等其他开发方案,更加方便,也方便直接使用 Linux 下的一些指令。
所用机器型号为 VAIO Z Flip 2016
与前一个实验(「裸机控制权与引导程序」)差不多。
55aa
。验证主引导程序有效后,跳转到7c00h
开始执行。0x00
到0x13
已经具有功能,0x14
到0x1f
为保留标号,0x20
到0xff
提供给用户自定义中断。因此定义0x20h
号中断用于从用户程序返回监控程序。int 20h
,用于监测是否有键盘返回,如果有则返回监控程序,否则继续执行。本次实验要求写 4 个用户程序,分别是在屏幕的 4 个象限中弹来弹去。四个代码的程序几乎相同,只需要修改某些常量和变量的定义即可。这里只给出其中一个程序的代码。
另外,本想直接用前一个实验的c.asm
,却发现老师只考虑了边反射的情况,没有考虑四个角反射的情况,这会导致显示的内容从角飞出,在屏幕中乱飞。于是再次重构这段代码,使得编译后大小仅 137bytes:
org 0A100h
,表明用户程序读入内存应从内存物理地址 0A100h 开始。int 10h
实现,并写了一个%macro print
来简化这一过程(造轮子),仍然支持根据行号自动变色。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
%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 '
引导扇区的 bootloader,其功能有:
int 13h
读取扇区,并把它放到内存合适的位置上。int 16h
读取键盘输入,用于选择程序。这里遇到一个问题,就是直接使用上面自动变色的程序时没有显示。因前两行的 x 坐标恰好对应了颜色中的黑底黑字。因此修改显示颜色mov bl, 07h
(黑底白字)即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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 终端下按顺序执行下述指令。主引导程序存储在虚拟软盘的第一个扇区,第一个用户程序存储在第二个扇区,第二个用户程序存储在第三个扇区,以此类推。
1
2
3
4
5
6
7
8
9
10
11
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
显示姓名。
显示学号。
显示邮箱。
显示博客。
重写了之前的代码,没有想到本来上次已经很小的 290bytes 还能压到更小的 137bytes…
还遇到了根据行号变色时第一行看不到输出的原因,仔细思考和查阅网上资料后发现 00h 用于表示不显示,在自动变色行号为 0 的时候就会导致看不到输出。
现在对org 7c00h
等语句有了更深的理解了。
Related posts