从图中当然是看不出什么,不过按下ESC会挂起任务0,按下FI会重新启动。
百度网盘下载地址:
https://pan.baidu.com/s/1_-IznMWL3z1CROziiD6mCw
_current: dd 5 * 8
tss_table:
dd tss0
dd tss1
dd tss2
tss_table_end:
dd 0
addr_t_t:
dd tss_table
myaddr:
dq 0
timer_int: ;这里时钟中断处理程序简陋的没法再……
pusha
push ds
push es
push fs
push gs
push ss
mov edx, 2 * 8
mov ds, edx
; mov ss, edx
mov al, 0x20 ;这里既是发送本次中断结束信号,
out 0x20, al ;之所以注释掉是当然是只让它发生一次
; push 0xc ;这样屏幕就不会被时钟中断弄得乱糟糟了。
; push timer_str
; call disp
; add esp, 2 * 4
;全局变量中存放的是tss_table的值,
;但tss_table是常量,所以这里设置了一个变量,增加4是指向下一个任务。
.2: add dword [addr_t_t], 4
;是否到达任务指针数组的尾部。
cmp dword [addr_t_t], tss_table_end
;到达则跳转到.1处。
jae .1
;把数组的地址,存入ebx中,从而取ebx中的内容,[ebx]为第一个任务状态段的地址
mov ebx, dword [addr_t_t]
mov esi, [ebx]
;看是否是空任务,是则忽略。
cmp esi, 0
je .2
;如果不是空任务,则取其LDT选择符,我自认为这里是唯一的标识,所以取这里的值。
mov eax, [esi + 24 * 4]
;这里是得到相对应得TSS选择符。(可以参照全局表,和tss任务状态段来理解)。
sub eax, 8
;将选择符存入符合处理器远跳转指令的规格的数据结构。
mov [myaddr + 4], eax
;这是模仿linux0.11的任务切换方式,可参考赵炯先生大作的switch_to的那个宏函数,
;这里与之完全相同。
;是否是当前进程,是则中断返回,不切换任务。
mov edx, [_current]
cmp eax, edx
je int_end
;不是的情况下,切换任务。
mov [_current], eax
jmp far [myaddr] ;一定要用这个远跳转指令否则不能实现。
jmp int_end
.1:
mov dword [addr_t_t], tss_table - 4
jmp .2
int_end:
;这里主要是用键盘使0号进程挂起,但我不清楚是否就是向进程发送的一个信号。
;但我企图实现之。
cmp dword [kill_key], 1
jne .3
mov dword [tss_table + 0 * 4] , 0
.3:
cmp dword [kill_key], 0
jne .4
mov dword [tss_table + 0 * 4] , tss0
.4:
pop ss
pop gs
pop fs
pop es
pop ds
popa
iret
timer_str: db " TIMER is happended! ", 0xa,0
kill_key: dd 3