2.2.XP系统中系统调用的内核入口KiSystemService函数的实现
2.2.XP系统中系统调用的内核入口KiSystemService函数的实现
_KiSystemService
改代码是汇编,xp的核心代码C写的,部分汇编写的。
_KiSystemService proc
ENTER_SYSCALL kss_a, kss_t ; set up trap frame and save state
?FpoValue = 0
;
; (eax) = Service number
; (edx) = Callers stack pointer
; (esi) = Current thread address
;
; All other registers have been saved and are free.
;
; Check if the service number within valid range
;
_KiSystemServiceRepeat:
mov edi, eax ; copy system service number
shr edi, SERVICE_TABLE_SHIFT ; isolate service table number
and edi, SERVICE_TABLE_MASK ;
mov ecx, edi ; save service table number
add edi, [esi]+ThServiceTable ; compute service descriptor address
mov ebx, eax ; save system service number
and eax, SERVICE_NUMBER_MASK ; isolate service table offset
;
; If the specified system service number is not within range, then attempt
; to convert the thread to a GUI thread and retry the service dispatch.
;
cmp eax, [edi]+SdLimit ; check if valid service
jae Kss_ErrorHandler ; if ae, try to convert to GUI thread
;
; If the service is a GUI service and the GDI user batch queue is not empty,
; then call the appropriate service to flush the user batch.
;
cmp ecx, SERVICE_TABLE_TEST ; test if GUI service
jne short Kss40 ; if ne, not GUI service
mov ecx, PCR[PcTeb] ; get current thread TEB address
xor ebx, ebx ; get number of batched GDI calls
KiSystemServiceAccessTeb:
or ebx, [ecx]+TbGdiBatchCount ; may cause an inpage exception
jz short Kss40 ; if z, no batched calls
push edx ; save address of user arguments
push eax ; save service number
call [_KeGdiFlushUserBatch] ; flush GDI user batch
pop eax ; restore service number
pop edx ; restore address of user arguments
;
; The arguments are passed on the stack. Therefore they always need to get
; copied since additional space has been allocated on the stack for the
; machine state frame. Note that we don't check for the zero argument case -
; copy is always done regardless of the number of arguments because the
; zero argument case is very rare.
;
Kss40: inc dword ptr PCR[PcPrcbData+PbSystemCalls] ; system calls
if DBG
mov ecx, [edi]+SdCount ; get count table address
jecxz Kss45 ; if zero, table not specified
inc dword ptr [ecx+eax*4] ; increment service count
Kss45: push dword ptr [esi]+ThApcStateIndex ; (ebp-4)
push dword ptr [esi]+ThKernelApcDisable ; (ebp-8)
;
; work around errata 19 which can in some cases cause an
; extra dword to be moved in the rep movsd below. In the DBG
; build, this will usually case a bugcheck 1 where ebp-8 is no longer
; the kernel apc disable count
;
sub esp,4
?FpoValue = ?FpoValue+3
endif
FPOFRAME ?FpoValue, 0
mov esi, edx ; (esi)->User arguments
mov ebx, [edi]+SdNumber ; get argument table address
xor ecx, ecx
mov cl, byte ptr [ebx+eax] ; (ecx) = argument size
mov edi, [edi]+SdBase ; get service table address
mov ebx, [edi+eax*4] ; (ebx)-> service routine
sub esp, ecx ; allocate space for arguments
shr ecx, 2 ; (ecx) = number of argument DWORDs
mov edi, esp ; (es:edi)->location to receive 1st arg
cmp esi, _MmUserProbeAddress ; check if user address
jae kss80 ; if ae, then not user address
KiSystemServiceCopyArguments:
rep movsd ; copy the arguments to top of stack.
; Since we usually copy more than 3
; arguments. rep movsd is faster than
; mov instructions.
if DBG
;
; Check for user mode call into system at elevated IRQL.
;
test byte ptr [ebp]+TsSegCs,MODE_MASK
jz short kss50a ; kernel mode, skip test
stdCall _KeGetCurrentIrql
or al, al ; bogus irql, go bugcheck
jnz kss100
kss50a:
test _MmInjectUserInpageErrors, 2
jz short @f
stdCall _MmTrimProcessMemory, <0>
jmp short kssdoit
@@:
mov eax,PCR[PcPrcbData+PbCurrentThread]
mov eax,[eax]+ThApcState+AsProcess
test dword ptr [eax]+PrFlags,0100000h ; is this a inpage-err process?
je short @f
stdCall _MmTrimProcessMemory, <0>
@@:
endif
;
; Make actual call to system service
;
kssdoit:
CAPSTARTX <_KiSystemService,ebx>
call ebx ; call system service
CAPENDX <_KiSystemService>
kss60:
if DBG
mov ecx,PCR[PcPrcbData+PbCurrentThread] ; (ecx)-> Current Thread
;
; Check for return to user mode at elevated IRQL.
;
test byte ptr [ebp]+TsSegCs,MODE_MASK
jz short kss50b
mov esi, eax
stdCall _KeGetCurrentIrql
or al, al
jnz kss100 ; bogus irql, go bugcheck
mov eax, esi
kss50b:
;
; Check that APC state has not changed
;
mov edx, [ebp-4]
cmp dl, [ecx]+ThApcStateIndex
jne kss120
mov edx, [ebp-8]
cmp edx, [ecx]+ThKernelApcDisable
jne kss120
endif
kss61:
;
; Upon return, (eax)= status code
;
mov esp, ebp ; deallocate stack space for arguments
;
; Restore old trap frame address from the current trap frame.
;
kss70: mov ecx, PCR[PcPrcbData+PbCurrentThread] ; get current thread address
mov edx, [ebp].TsEdx ; restore previous trap frame address
mov [ecx].ThTrapFrame, edx ;
;
; System service's private version of KiExceptionExit
; (Also used by KiDebugService)
;
; Check for pending APC interrupts, if found, dispatch to them
; (saving eax in frame first).
;
public _KiServiceExit
_KiServiceExit:
cli ; disable interrupts
DISPATCH_USER_APC ebp, ReturnCurrentEax
;
; Exit from SystemService
;
EXIT_ALL NoRestoreSegs, NoRestoreVolatile
;
; The address of the argument list is not a user address. If the previous mode
; is user, then return an access violation as the status of the system service.
; Otherwise, copy the argument list and execute the system service.
;
kss80: test byte ptr [ebp].TsSegCs, MODE_MASK ; test previous mode
jz KiSystemServiceCopyArguments ; if z, previous mode kernel
mov eax, STATUS_ACCESS_VIOLATION ; set service status
jmp kss60 ;
;++
;
; _KiServiceExit2 - same as _KiServiceExit BUT the full trap_frame
; context is restored
;
;--
public _KiServiceExit2
_KiServiceExit2:
cli ; disable interrupts
DISPATCH_USER_APC ebp
;
; Exit from SystemService
;
EXIT_ALL ; RestoreAll
if DBG
kss100: push PCR[PcIrql] ; put bogus value on stack for dbg
?FpoValue = ?FpoValue + 1
FPOFRAME ?FpoValue, 0
mov byte ptr PCR[PcIrql],0 ; avoid recursive trap
cli
;
; IRQL_GT_ZERO_AT_SYSTEM_SERVICE Returning to usermode at elevated IRQL.
;
; KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
; System Call Handler (address of system routine),
; Irql,
; 0,
; 0,
; );
;
stdCall _KeBugCheckEx,<IRQL_GT_ZERO_AT_SYSTEM_SERVICE, ebx, eax, 0, 0>
;
; APC_INDEX_MISMATCH This is probably caused by the system call entering
; critical regions and not leaving them. This is fatal. Include as
; much information in the bugcheck as possible.
;
; KeBugCheckEx(APC_INDEX_MISMATCH,
; System Call Handler (address of system routine),
; Thread->ApcStateIndex << 8 | Saved ApcStateIndex,
; Thread->KernelApcDisable,
; Saved KernelApcDisable
; );
;
kss120: mov eax, [ebp]-4
mov ah, [ecx]+ThApcStateIndex
stdCall _KeBugCheckEx,<APC_INDEX_MISMATCH, ebx, eax, [ecx]+ThKernelApcDisable, dword ptr [ebp]-8>
endif
ret
;
; If the sysenter instruction was executed in 16 bit mode, generate
; an error rather than trying to process the system call. There is
; no way to return to the correct code in user mode.
;
Kfsc90:
push 0 ; save VX86 Es, Ds, Fs, Gs
push 0
push 0
push 0
push 01bh ; save transition CS
push 0 ; can't know user esp
push EFLAGS_INTERRUPT_MASK+EFLAGS_V86_MASK+2h; eflags with VX86 set
push 01bh ; CS
push 0 ; don't know original EIP
jmp _KiTrap06 ; turn exception into illegal op.
_KiSystemService endp