Menu

系统调用

实验题目

系统调用

实验目的

  1. 理解系统调用的实现方法。
  2. 实现原型操作系统中一些基本的系统调用。
  3. 设计并实现一测试系统调用的用户程序,利用系统调用实现用户界面和内部功能。
  4. 在原型操作系统上建立一个初步 C 语言开发环境,理解操作系统与高级语言之间的关系。

实验方案

实验环境

软件

  • Windows 10, 64-bit (Build 17763) 10.0.17763
  • Windows Subsystem for Linux [Ubuntu 18.04.2 LTS]:WSL 是以软件的形式运行在 Windows 下的 Linux 子系统,是近些年微软推出来的新工具,可以在 Windows 系统上原生运行 Linux。
  • gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04):C 语言程序编译器,Ubuntu 自带。
  • NASM version 2.13.02:汇编程序编译器,通过sudo apt install nasm安装在 WSL 上。
  • Oracle VM VirtualBox 6.0.4 r128413 (Qt5.6.2):轻量开源的虚拟机软件。
  • VSCode - Insiders v1.33.0:好用的文本编辑器,有丰富的插件。
  • hexdump for VSCode 1.7.2: VSCode 中一个好用的十六进制显示插件。
  • GNU Make 4.1:安装在 Ubuntu 下,一键编译并连接代码,生成最终的文件。

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

硬件

开发环境配置

所用机器型号为 VAIO Z Flip 2016

  • Intel(R) Core(TM) i7-6567U CPU @3.30GHZ 3.31GHz
  • 8.00GB RAM
虚拟机配置
  • 处理器内核总数:1
  • RAM:4MB

实验过程

实验代码

bootloader.asm

上一个实验中的代码完全相同,不再放出。

kernel.asm

操作系统内核的汇编部分代码,提供int 33中断和 1~4 的四个 ah 功能号在屏幕的四个象限上显示自定义信息,检测到Ctrl + C时返回。

同时,提供了如下的全局函数供 C 语言部分调用。

  • _getch从屏幕上无回显地读入一个字符。
  • _getCursor返回屏幕光标的位置。
  • _setCursor设置屏幕光标的位置。
  • _putC向光标位置写入一个字符。
  • _pageUP屏幕内容向上滚动。
  • _loadProgram加载用户程序。

getch(),gets(),putch(),puts(),scanf()和 printf()函数的汇编部分代码均通过调用上述函数实现。

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
%macro print 5 ; string, length, x, y, color
	pusha
	push ax
	push bx
	push cx
	push dx
	push bp
	push ds
	push es
	mov ax, 0b800H
	mov gs, ax
	mov ax, cs
	mov ds, ax
	mov bp, %1
	mov ax, ds
	mov es, ax
	mov cx, %2
	mov ax, 1300H
	mov dh, %3
	mov dl, %4
	mov bx, %5
	int 10H
	pop es
	pop ds
	pop bp
	pop dx
	pop cx
	pop bx
	pop ax
	popa
%endmacro
%macro setIVT 2
	push es
	push ds
	push si
	pusha
	mov ax, 0000H
	mov es, ax
	mov ax, %1
	mov bx, 4
	mul bx
	mov si, ax
	mov ax, %2
	mov [es:si], ax
	add si, 2
	mov ax, cs
	mov [es:si], ax
	popa
	pop si
	pop ds
	pop es
%endmacro
	bits 16
	UserPrgOffset equ 0a100H
	PrgSectorOffset equ 0
	extern terminal
	global _start
	global _getch
	global _getCursor
	global _setCursor
	global _putC
	global _pageUP
	global _loadProgram
_start:
	setIVT 8, int8
	setIVT 33, int33
	call terminal
	ret
_getCursor:
	push ebp
	mov ebp, esp
	push ebx
	sub esp, 4
	mov eax, 768
	mov edx, 0
	mov ebx, edx
	int 0x10
	mov eax, edx
	mov dword [ebp-8], eax
	mov eax, dword [ebp-8]
	add esp, 4
	pop ebx
	pop ebp
	ret
_getch:
	mov ah, 01H
	int 16H
	jz _getch
	mov ah, 00H
	int 16H
	ret
_setCursor:
	push ebp
	mov ebp, esp
	push ebx
	mov eax, 512
	mov ecx, 0
	mov edx, dword [ebp+8]
	mov ebx, ecx
	int 0x10
	pop ebx
	pop ebp
	ret
_putC:
	push ebp
	mov ebp, esp
	push ebx
	mov eax, dword [ebp+8]
	or ah, 9
	mov edx, dword [ebp+12]
	mov ecx, 1
	mov ebx, edx
	int 0x10
	pop ebx
	pop ebp
	ret
_pageUP:
	push ebp
	mov ebp, esp
	mov eax, dword [ebp+8]
	or ah, 6
	mov ecx, 0
	mov edx, 184fh
	int 0x10
	pop ebp
	ret
_loadProgram:
	push ebp
	mov ebp, esp
	push ax
	push bx
	push cx
	push dx
	push es
	mov ax, cs
	mov es, ax
	mov bx, UserPrgOffset
	mov ah, 2
	mov al, 2
	mov dl, 0
	mov dh, 1
	mov ch, 0
	mov cl, byte [ebp+8]
	add cl, PrgSectorOffset
	int 13H
	call UserPrgOffset
	pop es
	pop dx
	pop cx
	pop bx
	pop ax
	mov esp, ebp
	pop ebp
	ret
int8:
	cli
	pusha
	push eax
	call draw_slash
	mov al, 20H
	out 20H, al
	out 0a0H, al
	pop eax
	popa
	sti
	iret
int33:
	cmp ah,1
	jne prg2
	mov word[n], 12
	mov word[m], 30
	mov word[top], 2
	mov word[left], 40
	mov word[length], 8
	mov word[msg], msg1
	call show
	iret
prg2:
	cmp ah,2
	jne prg3
	mov word[n], 12
	mov word[m], 30
	mov word[top], 2
	mov word[left], 0
	mov word[length], 10
	mov word[msg], msg2
	call show
	iret
prg3:
	cmp ah,4
	jne prg4
	mov word[n], 12
	mov word[m], 20
	mov word[top], 13
	mov word[left], 0
	mov word[length], 20
	mov word[msg], msg3
	call show
	iret
prg4:
	mov word[n], 12
	mov word[m], 14
	mov word[top], 13
	mov word[left], 40
	mov word[length], 26
	mov word[msg], msg4
	call show
	iret
draw_slash:
	print bar,1,24,78,7
	cmp byte[bar],'|'
	jne rslash
	mov byte[bar],'/'
	ret
rslash:
	cmp byte[bar],'/'
	jne hslash
	mov byte[bar],'-'
	ret
hslash:
	cmp byte[bar],'-'
	jne lslash
	mov byte[bar],'\'
	ret
lslash:
	mov byte[bar],'|'
	ret
show:
	dec dword[cnt]
	jnz show
	mov dword[cnt],99999999
	mov word ax, [t]
	mov word bx, [n]
	add bx, bx
	sub bx, 2
	xor dx, dx
	div bx
	cmp dx, [n]
	jb xok
	sub bx, dx
	mov dx, bx
xok:
	add dx, [top]
	mov word[x], dx
	mov word ax, [t]
	mov word bx, [m]
	add bx,bx
	sub bx,2
	xor dx, dx
	div bx
	cmp dx, [m]
	jb yok
	sub bx, dx
	mov dx, bx
yok:
	add dx,[left]
	mov word [y],dx
	inc word[t]
	print [msg],[length],[x],[y],[x]
	mov ah, 01H
	int 16H
	jz show
	print msgouch,10,[x],[y],[x]
	mov ah, 00H
	int 16H
	cmp ax, 2e03H
	jne show
	ret
datadef:
	cnt dd 1
	t dw 0
	x dw 1
	y dw 0
	n dw 12
	m dw 32
	top dw 2
	left dw 40
	length dw 8
	msg dw 1
	msg1 db ' wu-kan '
	msg2 db ' 17341163 '
	msg3 db ' [email protected] '
	msg4 db ' https://wu-kan.github.io '
	msgouch db 'Ouch!Ouch!'
	bar db '|'

kerner.c

操作系统内核 C 语言部分的代码。和上一实验相比没有改变,这里不再放出。

link.ld

wukos.asmkernel.c两个文件编译出来的内容连接起来。和上一个实验中的完全相同,不再放出。

prg1.asm~prg4.asm

直接调用 int 33 中断和 ah 功能号实现。

1
2
3
4
5
6
org 0a100H
push ax
mov ah,1
int 33
pop ax
ret

上面是 prg1.asm 的内容,其余同理,不再放出。

Makefile

上一个实验完全相同,不再放出。

运行结果

1 如上图,进入操作系统后开始了「无敌风火轮」(右下角)。 2 如上图,使用exec指令轮流运行我的四个程序,分别调用中断int 33的四个功能号。按下 Ctrl+C 可以退出程序。程序检测到键盘输入,因此显示Ouch!Ouch!

风火轮仍然在转。 3 输入若干指令。

风火轮仍然在转。 4 继续输入若干指令,此时超出屏幕显示范围,自动滚屏。

风火轮仍然在转。

实验总结

得益于前两个实验,本次实验较为熟练地完成了任务。看着自己的操作系统不断地完善,心中还是很有成就感的。同时,由于踩过了许多寄存器保护的坑,这次在调用功能号前记得将其值压栈,于是很顺利没有出现问题。