|
MenuetOS 系统调用分析
作者: Star
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SYSTEM CALL ENTRY ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;函数名: i40
;类 型: 40号中断调用
;功 能: 陷阱门程序入口,即系统调用代码
;描 述: 注意参数传递方式
; 1)从程序->i40中断任务:寄存器传递eax <- ebx, ebx <- ecx, ecx <- edx, edx <- esi, esi <- edi
; 2)从调用函数->i40中断任务:栈传递:[esp+12]->edi,[esp+16]->esi,[esp+20]->ebp,[esp+24]->ebx,
; [esp+28]->edx,[esp+32]->ecx,[esp+36]->eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
i40:
cli
;1)清除进程任务的忙标志,以便调度时运行
; clear the busy flags in GDT for
; caller to be used again with jmp
mov edi,[0x3000]
imul edi,8
mov [edi+gdts+ tss0 +5], word 01010000b *256 +11101001b
;2)标记被调用的系统调用任务忙
; mark this system call handler busy
mov eax,[schd]
mov [usedi40+eax],byte 1
push eax
;3)影射系统调用到调用的进程任务中的[n*256+0x80000+0xB0]
; map this particular system call to the calling task
mov edi,[0x3000]
imul edi,256
mov [edi+0x80000+0xB0],eax
;4) 在usedi40中为下一次i40系统调用找一个空闲的句柄保存到[schd]
; search a free system call handler for the next interrupt 0x40 call
mov eax,0
search_free_i40:
cmp [usedi40+eax],byte 0
je found_free_i40
inc eax
cmp eax,110
jbe search_free_i40 ;if(eax<=110){search_free_i40}
jmp $
found_free_i40:
mov [schd],eax
; 5) 改变i40中断门的全局描述符表的选择子,指向下个空闲的陷阱任务状态段
; change the entry in the general desc. table ( at 0x40 ) to point to the next free handler
mov edx,8
imul edx,[schd]
add edx,tss0sys
mov edi,8*0x40
mov [edi+idts+ 8 +0], word 0
mov [edi+idts+ 8 +2], dx
mov [edi+idts+ 8 +4], word 11100101b*256
mov [edi+idts+ 8 +6], word 0
; 6)保存当前任务现场
;得到当前进程任务的全局描述符 = ebx
mov ebx,[0x3000]
shl ebx,3
add ebx,tss0_l
;保存当前进程任务号n到 [tasknum + 4*n]
mov ecx,[0x3000]
shl ecx,2
mov eax,[0x3000]
mov [tasknum+ecx],eax
;保存当前进程任务的段界限到 [reg1 + 4*n]
mov eax,[ebx]
mov [reg1+ecx],eax
;保存当前进程任务的段基址(BIT16-23)到 [reg2 + 4*n]
mov eax,[ebx+4]
mov [reg2+ecx],eax
;保存寄存器的值
mov ecx,8
imul ecx,[esp]
mov eax,[tss0sys_l+ecx]
mov [ebx],eax
mov eax,[tss0sys_l+ecx+4]
mov [ebx+4],eax
call save_registers
;7) 得到当前进程任务状态段的基地址
mov esi,[0x3000]
imul esi,128
add esi,0x40000
; 为返回挂起的当前进程作准备
; to be returned to the application
mov eax,[esi+l.eax-tss_sceleton]
mov ebx,[esi+l.ebx-tss_sceleton]
mov ecx,[esi+l.ecx-tss_sceleton]
pusha
;9) 得到系统调用函数用的参数,这些参数是从调用进程任务传递来的
;for system function use
mov edi,[esi+l.eax-tss_sceleton] ;得到系统调用号(eax->edi)
mov eax,[esi+l.ebx-tss_sceleton] ;ebx->eax
mov ebx,[esi+l.ecx-tss_sceleton] ;ecx->edx
mov ecx,[esi+l.edx-tss_sceleton] ;edx->ecx
mov edx,[esi+l.esi-tss_sceleton] ;esi->edx
mov esi,[esi+l.edi-tss_sceleton] ;edi->esi
;10) 执行系统调用
; and we are ready to call the appropriate system function
sti
push eax
and edi,0xff
call dword [servetable+edi*4]
pop eax
cli
popa
;11) 保存返回的值到程序进程任务状态段
;得到当前进程任务状态段的基地址
; system call returns the parameters to stack
mov esi,[0x3000]
imul esi,128
add esi,0x40000
; 保存返回的值到程序进程任务状态段
; save the returned registers to applications TSS
mov [esi+l.eax-tss_sceleton],eax
mov [esi+l.ebx-tss_sceleton],ebx
mov [esi+l.ecx-tss_sceleton],ecx
;12)恢复当前任务现场
;得到当前进程任务的状态段选择子
mov ebx,[0x3000]
shl ebx,3
add ebx,tss0_l
mov ecx,[0x3000]
shl ecx,2
;恢复当前进程任务的段界限
mov eax,[reg1+ecx]
mov [ebx],eax
;恢复前进程任务的段基址(BIT16-23)
mov eax,[reg2+ecx]
mov [ebx+4],eax
;恢复 [tasknum + 4*n] =0
mov [tasknum+ecx],dword 0
;13)清除系统调用句柄
mov edi,8
pop eax ; this handler ; clear this handlers gdt
mov [usedi40+eax],byte 0
imul edi,eax
mov [edi+tss0sys_l +5], word 01010000b *256 +11101001b
;14)激活当前任务
; jmp -> TSS of application
mov ebx,[0x3000]
shl bx,3
add bx,tss0t
mov [tss_s3],bx
db 0xea
tss_t3 dd 0
tss_s3 dw tss0t
jmp i40
tasknum: times 256 dd 0x0
reg1: times 256 dd 0x0
reg2: times 256 dd 0x0
usedi40: times 256 db 0x0
schd dd 0x0 |
|