singrdk/base/Kernel/Native/halidt.asm

1320 lines
44 KiB
NASM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Microsoft Research Singularity
;;
;; Copyright (c) Microsoft Corporation. All rights reserved.
;;
;; File: halidt.asm
;;
;; Note:
;;
.686p
.mmx
.xmm
.model flat
.code
assume ds:flat
assume es:flat
assume ss:flat
assume fs:nothing
assume gs:nothing
include hal.inc
DEBUG_INTERRUPTS EQU 0
ifdef DEBUG
SPINLOCK_RELEASE_SANITY_CHECK EQU 1
else
SPINLOCK_RELEASE_SANITY_CHECK EQU 0
endif
ifdef PAGING
public _SysEnter
endif
externdef ?c_exceptionHandler@@3P6IXHPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@ZA:uintPtr
; static void __fastcall Class.Microsoft.SingularityIoSystem.DispatchException(
; int interrupt [ECX], ref ThreadContex [EDX]))
; __fastcall:
; Arg0 passed in ECX
; Arg1 passed in EDX
; Others passed right to left on stack.
; EBX, ESI, EDI, and EBP are callee saved.
; EAX receives return value if any.
public _EdtEnter0
public _EdtEnter1
public _EdtEnterBody
externdef ?c_interruptHandler@@3P6IXHPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@ZA:uintPtr
; static void __fastcall Class.Microsoft.SingularityIoSystem.DispatchInterrupt(
; int interrupt [ECX], ref ThreadContex [EDX]))
; __fastcall:
; Arg0 passed in ECX
; Arg1 passed in EDX
; Others passed right to left on stack.
; EBX, ESI, EDI, and EBP are callee saved.
; EAX receives return value if any.
public _IdtEnter20
public _IdtEnter21
public _IdtEnterBody
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; The IDT_ENTER building macros insure that each IDT target has
;;; an offset of form (_IdtEnter0 or _EdtEnter0) + 0x10 * interrupt_number.
;;;
IDT_ENTER_IN STRUCT 1
_esi UINT32 ?
_num UINT32 ?
_err UINT32 ?
_eip UINT32 ?
_cs0 UINT32 ?
_efl UINT32 ?
IDT_ENTER_IN ENDS
ifdef PAGING
IDT_ENTER_IN_LARGE STRUCT 1
_esi UINT32 ?
_num UINT32 ?
_err UINT32 ?
_eip UINT32 ?
_cs0 UINT32 ?
_efl UINT32 ?
_esp UINT32 ?
_ss UINT32 ?
IDT_ENTER_IN_LARGE ENDS
endif
IDT_ENTER_OUT STRUCT 1
_esi UINT32 ?
_eip UINT32 ?
_cs0 UINT32 ?
_efl UINT32 ?
IDT_ENTER_OUT ENDS
ifdef PAGING
IDT_ENTER_OUT_LARGE STRUCT 1
_esi UINT32 ?
_eip UINT32 ?
_cs0 UINT32 ?
_efl UINT32 ?
_esp UINT32 ?
_ss UINT32 ?
IDT_ENTER_OUT_LARGE ENDS
endif
EDT_ENTER_CLEAN MACRO num
push 0 ; No error
push num
jmp _EdtEnterBody
align 16
ENDM
EDT_ENTER_ERR MACRO num
push num
jmp _EdtEnterBody
align 16
ENDM
IDT_ENTER_CLEAN MACRO num
push 0 ; No error
push num
jmp _IdtEnterBody
align 16
ENDM
IDT_SAVE_CONTEXT MACRO fxregs, error, dregs
;; Save the processor's thread context.
;; Mark that the context contains caller-saved registers as well.
;; Input:
;; ESI = address of ThreadContext structure.
;; ESP = bottom of IDT_ENTER_IN context:
;; ESP[ 0] = esi
;; ESP[ 4] = num
;; ESP[ 8] = err
;; ESP[12] = eip
;; ESP[16] = cs
;; ESP[20] = efl
;; XXX - if we came from ring 3 then stack also has SS and ESP
;; ESP[24] = esp
;; ESP[28] = ss
;; This code needs to check cs&3 and if non-zero save ss:esp to thread context
;; Output:
;; ESI = address of ThreadContext structure.
;; ESP = stack w/o IDT_ENTER_IN context
;; ECX = num
;;
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eax, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebx, ebx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ecx, ecx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edx, edx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebp, ebp
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edi, edi
mov eax, cr3
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cr3, eax
mov eax, [esp].IDT_ENTER_IN._esi
mov ebx, [esp].IDT_ENTER_IN._eip
mov ecx, [esp].IDT_ENTER_IN._cs0
mov edx, [esp].IDT_ENTER_IN._efl
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esi, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eip, ebx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cs0, ecx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._efl, edx
if dregs
mov eax, dr0
mov ebx, dr1
mov ecx, dr2
mov edx, dr3
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr0, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr1, ebx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr2, ecx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr3, edx
mov eax, dr6
mov ebx, dr7
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr6, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr7, ebx
xor eax, eax
mov dr6, eax
endif
mov ecx, [esp].IDT_ENTER_IN._num ; this flows through
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._num, cx
if error
mov ebx, [esp].IDT_ENTER_IN._err
mov eax, cr2
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._err, ebx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cr2, eax
endif
if fxregs
if dregs
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 3
else
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 1
endif
fxsave [esi].Struct_Microsoft_Singularity_X86_ThreadContext._mmx
fninit
mov eax, 37eh
push eax
fldcw [esp]
pop eax
else
if dregs
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 2
else
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 0
endif
endif
ifdef PAGING
;; Is it a small or large frame?
mov eax, [esp].IDT_ENTER_IN._cs0
and eax, 3
jz s_case_0
;; Case ring-3: IDT_ENTER_IN_LARGE
mov eax, [esp].IDT_ENTER_IN_LARGE._esp
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esp, eax
add esp, SIZEOF IDT_ENTER_IN_LARGE
jmp s_case_0_3
s_case_0:
endif
;; Case ring-0: IDT_ENTER_IN
add esp, SIZEOF IDT_ENTER_IN
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esp, esp
ifdef PAGING
s_case_0_3:
endif
ENDM
IDT_LOAD_CONTEXT MACRO dregs
;; Create the outgoing stack frame.
ifdef PAGING
;; Is it a small or large frame?
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cs0
and eax, 3
jz l_case_0
;; Case ring-3: push an IDT_ENTER_OUT_LARGE
sub esp, SIZEOF IDT_ENTER_OUT_LARGE
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esp
mov [esp].IDT_ENTER_OUT_LARGE._esp, eax
mov eax, Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtUD - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull + 3
mov [esp].IDT_ENTER_OUT_LARGE._ss, eax
mov es, ax
;; For the moment, share UF and PF:
mov eax, Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtPF - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull + 3
mov fs, ax
jmp l_cases_0_3
l_case_0:
endif ;; PAGING
;; Case ring-0: push an IDT_ENTER_OUT
mov esp, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esp
sub esp, SIZEOF IDT_ENTER_OUT
ifdef PAGING
l_cases_0_3:
;; Code common to ring-0 and ring-3
endif ;; PAGING
;; Check if we need to restore the floating-point registers
test [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 1
jz skip_fxrstor
fxrstor [esi].Struct_Microsoft_Singularity_X86_ThreadContext._mmx
skip_fxrstor:
if dregs
;; Check if we need to restore the debug registers
test [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 2
jz skip_drstor
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr0
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr1
mov ecx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr2
mov edx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr3
mov dr0, eax
mov dr1, ebx
mov dr2, ecx
mov dr3, edx
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr6
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr7
mov dr6, eax
mov dr7, ebx
skip_drstor:
endif
ifdef PAGING
;; Zero for cr3 in the ThreadContext means "don't care" (no paging)
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cr3
cmp eax, 0
je skip_cr3
;; Avoid TLB flushes if possible
mov ebx, CR3
cmp eax, ebx
je skip_cr3
mov CR3, eax
skip_cr3:
endif ;; PAGING
;; Restore the registers
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esi
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eip
mov ecx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cs0
mov edx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._efl
mov [esp].IDT_ENTER_OUT._esi, eax
mov [esp].IDT_ENTER_OUT._eip, ebx
mov [esp].IDT_ENTER_OUT._cs0, ecx
mov [esp].IDT_ENTER_OUT._efl, edx
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eax
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebx
mov ecx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ecx
mov edx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edx
mov ebp, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebp
mov edi, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edi
pop esi
ifdef PAGING
push es
pop ds
endif
ENDM
DBG_EDX_FROM_EAX MACRO edxval, eaxval
if DEBUG_INTERRUPTS
mov edx, edxval
mov eax, eaxval
mov [edx], eax
endif
ENDM
DBG_SCREEN_AS_VALUE MACRO edxval, eaxval
if DEBUG_INTERRUPTS
push eax
push edx
DBG_EDX_FROM_EAX edxval, eaxval
pop edx
pop eax
endif
ENDM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
ifdef DEBUG
?g_TestSave@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z proc
pop eax
push eax
pushad
mov ebx, 0fffffeb0h
mov edx, 0fffffed0h
mov ebp, 0fffffeb1h
mov edi, 0fffffed1h
mov esi, 0fffffef1h
pushfd ; _efl
push cs ; _cs0
push eax ; _eip
push 0eeeh ; _err
push 0fffh ; _num
push esi ; _esi
mov esi, ecx
IDT_SAVE_CONTEXT 1,1,1
popad
ret
?g_TestSave@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z endp
?g_TestSaveLoad@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z proc
pop eax
pushfd ; _efl
push cs ; _cs0
push eax ; _eip
push 0eeeh ; _err
push 0fffh ; _num
push esi ; _esi
mov esi, ecx
IDT_SAVE_CONTEXT 1,1,1
IDT_LOAD_CONTEXT 0
iretd
?g_TestSaveLoad@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z endp
endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Exceptions.
;;;
align 16
_EdtEnter proc
_EdtEnter0::
EDT_ENTER_CLEAN 000h ; #DE Divide-by-Zero
_EdtEnter1::
EDT_ENTER_CLEAN 001h ; #DB Debug Exception
EDT_ENTER_CLEAN 002h ; NMI Non-Maskable-Interrupt
EDT_ENTER_CLEAN 003h ; #BP Breakpoint
EDT_ENTER_CLEAN 004h ; #OF OVerflow
EDT_ENTER_CLEAN 005h ; #BR Bound-Range
EDT_ENTER_CLEAN 006h ; #UD Invalid Opcode
EDT_ENTER_CLEAN 007h ; #NM Device Not Available
EDT_ENTER_ERR 008h ; #DF Double Fault
EDT_ENTER_CLEAN 009h ; Unused (was x87 segment except)
EDT_ENTER_ERR 00ah ; #TS Invalid TSS
EDT_ENTER_ERR 00bh ; #NP Sgement Not Present
EDT_ENTER_ERR 00ch ; #SS Stack Exception
EDT_ENTER_ERR 00dh ; #GP General Protection
EDT_ENTER_ERR 00eh ; #PF Page Fault
EDT_ENTER_CLEAN 00fh ; Reserved
EDT_ENTER_CLEAN 010h ; #MF x87 Math Error
EDT_ENTER_ERR 011h ; #AC Alignment Check
EDT_ENTER_CLEAN 012h ; #MC Machine Check
EDT_ENTER_CLEAN 013h ; #XF SIMD Exception
EDT_ENTER_CLEAN 014h ; 014h exception
EDT_ENTER_CLEAN 015h ; 015h exception
EDT_ENTER_CLEAN 016h ; 016h exception
EDT_ENTER_CLEAN 017h ; 017h exception
EDT_ENTER_CLEAN 018h ; 018h exception
EDT_ENTER_CLEAN 019h ; 019h exception
EDT_ENTER_CLEAN 01ah ; 01ah exception
EDT_ENTER_CLEAN 01bh ; 01bh exception
EDT_ENTER_CLEAN 01ch ; 01ch exception
EDT_ENTER_CLEAN 01dh ; 01dh exception
EDT_ENTER_CLEAN 01eh ; 01eh exception
EDT_ENTER_CLEAN 01fh ; 01fh exception
_EdtEnterBody::
push esi
ifdef PAGING
push ss
pop ds ; Copy stack segment selector to DS so we can access memory!
push ss
pop es ; Copy stack segment selector to ES so we can access memory!
endif
DBG_SCREEN_AS_VALUE 0b8020h, 01f301f40h ; @0
ifdef PAGING
; XXX if we've arrived from ring 3 FS will be invalid
push Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtPF - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull
pop fs
endif
;; Exceptions spill to the per-processor exceptionContext.
mov esi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._processorContext]
lea esi, [esi].Struct_Microsoft_Singularity_X86_ProcessorContext._exceptionContext
IDT_SAVE_CONTEXT 1,1,1 ; Save fxregs, error codes, and dregs.
;; Link the per-processor exception to the faulting thread
mov edi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
mov eax, [edi].Struct_Microsoft_Singularity_X86_ThreadContext.__thread
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext.__thread, eax
;; Link the per-processor thread context to the original thread context.
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._next, esi
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._prev, edi
DBG_EDX_FROM_EAX 0b8024h, 01f311f40h ; @1
;; Switch to the exception stack and adjust the stack limit values.
mov esp, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._exceptionStackBegin]
mov eax, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._exceptionStackLimit]
mov edx, [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit, eax
mov fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._exceptionStackPreLimit], edx
DBG_EDX_FROM_EAX 0b8028h, 01f321f40h ; @2
;; Call the exception handler.
mov edx, esi
mov eax, [?c_exceptionHandler@@3P6IXHPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@ZA]
call eax
DBG_EDX_FROM_EAX 0b802ch, 01f331f40h ; @3
;; mov esi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._processorContext]
;; lea esi, [esi].Struct_Microsoft_Singularity_X86_ProcessorContext._exceptionContext
;; Restore the stack limit (edi should still be good)
mov eax, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._exceptionStackPreLimit]
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit, eax
;; Unlink the per-processor context.
mov edi, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._prev
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._next, 0
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._prev, 0
IDT_LOAD_CONTEXT 1
iretd
_EdtEnter endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Interrupts.
;;;
align 16
_IdtEnter proc
_IdtEnter20::
IDT_ENTER_CLEAN 020h ; 021h: first interrupt
_IdtEnter21::
_num = 021h ; 021h to 0ffh
WHILE _num LE 0ffh
IDT_ENTER_CLEAN _num
_num = _num + 1
ENDM
_IdtEnterBody::
push esi
ifdef PAGING
push ss
pop ds ; Copy stack segment selector to DS so we can access memory!
push ss
pop es ; Copy stack segment selector to ES so we can access memory!
endif
DBG_SCREEN_AS_VALUE 0b8000h, 01f301f40h ; @0
ifdef PAGING
; XXX if we've arrived from ring 3 FS will be invalid
push Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtPF - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull
pop fs
endif
;; Interrupts spill to the thread's context.
mov esi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
IDT_SAVE_CONTEXT 1,0,0 ; Save fxregs, but not error codes or dregs.
DBG_EDX_FROM_EAX 0b8004h, 01f311f40h ; @1
;; Switch to the interrupt stack and adjust the stack limit values.
mov edi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
mov esp, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackBegin]
mov eax, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackLimit]
mov edx, [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit, eax
mov fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackPreLimit], edx
DBG_EDX_FROM_EAX 0b8008h, 01f321f40h ; @2
;; Call the interrupt handler.
mov edx, esi
mov eax, [?c_interruptHandler@@3P6IXHPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@ZA]
call eax
DBG_EDX_FROM_EAX 0b800ch, 01f331f40h ; @3
;; Restore the stack limit (edi should still be good)
mov eax, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackPreLimit]
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit, eax
;; Select the processor's thread context (may have been changed by scheduler).
mov esi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
IDT_LOAD_CONTEXT 0
iretd
_IdtEnter endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Syscall via SYSENTER
;;;
ifdef PAGING
SYSENTER_IN STRUCT 1
_esi UINT32 ?
_num UINT32 ?
SYSENTER_IN ENDS
SYSENTER_SAVE_CONTEXT MACRO fxregs, dregs
;; Save the processor's thread context.
;; Input:
;; ESI = address of ThreadContext structure.
;; EDX = orig ESP
;; ECX = orig EIP
;; Output:
;; ESI = address of ThreadContext structure.
;; ESP = stack w/o IDT_ENTER_IN context
;; ECX = num
;;
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eip, ecx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esp, edx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._cs0, Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtUD - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull + 3
;mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ss, 05bh ; XXX no room at the inn
pushfd
pop edx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._efl, edx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eax, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebx, ebx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ecx, ecx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edx, edx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebp, ebp
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edi, edi
mov eax, [esp].SYSENTER_IN._esi
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esi, eax
mov ecx, [esp].SYSENTER_IN._num ; this flows through
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._num, cx
;; XXX Need to save segment registers!!
if dregs
mov eax, dr0
mov ebx, dr1
mov ecx, dr2
mov edx, dr3
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr0, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr1, ebx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr2, ecx
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr3, edx
mov eax, dr6
mov ebx, dr7
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr6, eax
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr7, ebx
xor eax, eax
mov dr6, eax
endif
if fxregs
if dregs
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 3
else
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 1
endif
fxsave [esi].Struct_Microsoft_Singularity_X86_ThreadContext._mmx
fninit
mov eax, 37eh
push eax
fldcw [esp]
pop eax
else
if dregs
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 2
else
mov [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 0
endif
endif
;; XXX this is wrong for the ring 3 case...
add esp, SIZEOF SYSENTER_IN
ENDM
SYSENTER_LOAD_CONTEXT MACRO dregs
;; Check if we need to restore the floating-point registers
test [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 1
jz skip_fxrstor
fxrstor [esi].Struct_Microsoft_Singularity_X86_ThreadContext._mmx
skip_fxrstor:
if dregs
;; Check if we need to restore the debug registers
test [esi].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 2
jz skip_drstor
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr0
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr1
mov ecx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr2
mov edx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr3
mov dr0, eax
mov dr1, ebx
mov dr2, ecx
mov dr3, edx
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr6
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._dr7
mov dr6, eax
mov dr7, ebx
skip_drstor:
endif
;; Restore the registers
mov eax, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eax
mov ebx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebx
mov ecx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ecx ; pointless
mov edx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edx ; pointless
mov ebp, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._ebp
mov edi, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._edi
;; We restore EIP into edx and ESP into ECX
mov ecx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esp
mov edx, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._eip
;; Need to restore segment registers
; Restore flags - is this necessary?
push [esi].Struct_Microsoft_Singularity_X86_ThreadContext._efl
mov esi, [esi].Struct_Microsoft_Singularity_X86_ThreadContext._esi
popfd
ENDM
align 16
_SysEnter proc
; SYSENTER doesn't put *anything* on the stack - the only way
; we can know the return EIP/ESP is if they are passed in registers.
; On Windows there is only one SYSENTER instruction in ntdll, so sysexit
; knows where to return to, and the ring 3 stack pointer is passed in edx.
;
; Entry state: ss:esp0, cs:eip loaded from processor MSRs
;
push 0
push 02Fh
push esi ; This is to make the stack frame look like IDT_ENTER_ expects
push ss
pop ds ; Copy stack segment selector to DS so we can access memory!
DBG_SCREEN_AS_VALUE 0b8000h, 01f301f40h ; @0
; XXX if we've arrived from ring 3 FS will be invalid
push Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtPF - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull
pop fs
push ss
pop es ; Copy stack segment selector to ES so we can access memory!
;; Interrupts spill to the thread's context.
mov esi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
;; XXX - Can save some time by not saving caller-save regs
SYSENTER_SAVE_CONTEXT 1,0 ; Save fxregs, but not error codes or dregs.
DBG_EDX_FROM_EAX 0b8004h, 01f311f40h ; @1
;; Switch to the interrupt stack and adjust the stack limit values.
mov edi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
mov esp, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackBegin]
mov eax, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackLimit]
mov edx, [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit, eax
mov fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackPreLimit], edx
DBG_EDX_FROM_EAX 0b8008h, 01f321f40h ; @2
;; Call the interrupt handler.
mov edx, esi
mov eax, [?c_interruptHandler@@3P6IXHPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@ZA]
call eax
DBG_EDX_FROM_EAX 0b800ch, 01f331f40h ; @3
;; Restore the stack limit (edi should still be good)
mov eax, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._interruptStackPreLimit]
mov [edi].Struct_Microsoft_Singularity_X86_ThreadContext._stackLimit, eax
;; Select the processor's thread context (may have been changed by scheduler).
mov esi, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
;
SYSENTER_LOAD_CONTEXT 0
; SYSEXIT does the following
; EIP <-- EDX
; ESP <-- ECX
; CS <-- MSR[IA32_CS_SYSENTER] + 0x18
sysexit
_SysEnter endp
endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; void Processor.SwitchToThreadContext(ref X86_ThreadContext newContext);
; Saves the current context and load the new context from
; newContext(ecx), effectively switching contexts between threads.
; Always returns executing in the new context.
; The code after _SwitchedInContextSwitch will only run if the context was
; switch out using this routine.
;
; precondition: Scheduler.dispatchLock held
;
align 16
?g_SwitchToThreadContextNoGC@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z proc
;; Save the old processor context.
pushfd
;; From here on we need interrupts disabled.
cli
mov edx, fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext]
;; On clean switch, no need to save caller-saved registers (eax,ecx,edx,fxsave)
ifdef PAGING
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._cs0, Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtPC - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull
endif
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._ebx, ebx
pop eax ; pop flags from stack.
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._efl, eax
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._esp, esp
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._ebp, ebp
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._esi, esi
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._edi, edi
ifdef PAGING
mov eax, CR3
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._cr3, eax
endif
lea eax, _SwitchedInContextSwitch
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._eip, eax
ifdef THREAD_TIME_ACCOUNTING
;; thread execution time accouting
;; Get and save current timestamp
mov ebx, edx ; save edx
rdtsc ; -> edx:eax
push eax ; save timestamp for later use
push edx
;; now - old.lastExecutionTimeUpdate
sub eax, dword ptr [ebx ].Struct_Microsoft_Singularity_X86_ThreadContext._lastExecutionTimeUpdate
sbb edx, dword ptr [ebx + 4].Struct_Microsoft_Singularity_X86_ThreadContext._lastExecutionTimeUpdate
;; old.executionTime += now - old.lastExecutionTimeUpdate
add dword ptr [ebx ].Struct_Microsoft_Singularity_X86_ThreadContext._executionTime, eax
adc dword ptr [ebx + 4].Struct_Microsoft_Singularity_X86_ThreadContext._executionTime, edx
pop edx ; restore timestamp
pop eax
;; new.lastExecutionTimeUpdate = now
mov dword ptr [ecx ].Struct_Microsoft_Singularity_X86_ThreadContext._lastExecutionTimeUpdate, eax
mov dword ptr [ecx + 4].Struct_Microsoft_Singularity_X86_ThreadContext._lastExecutionTimeUpdate, edx
mov edx, ebx ; restore edx
;; End thread execution time accouting
endif
;; On clean switch, no need to save caller-saved registers
; fxsave [edx].Struct_Microsoft_Singularity_X86_ThreadContext._mmx
mov [edx].Struct_Microsoft_Singularity_X86_ThreadContext._regs, 0
;; The old context has been saved, so we can now release the dispatch
;; lock and let other processors load the old context.
;; (We've released the old stack pointer and haven't yet
;; set up a new stack pointer, so the following code
;; does not touch the stack.)
;; This code duplicates code from SpinLock.Release.
if SPINLOCK_RELEASE_SANITY_CHECK
; if (this.lockWord != 1 || this.lockingThreadIndexPlusOne-1 != currentThreadId) throw ...
cmp ?c_dispatchLock@Class_Microsoft_Singularity_Scheduling_Scheduler@@2?AUStruct_System_Threading_SpinLock@@A.Struct_System_Threading_SpinLock._lockWord, 1
je spinLockOk1
int 3
spinLockOk1:
mov eax, ?c_dispatchLock@Class_Microsoft_Singularity_Scheduling_Scheduler@@2?AUStruct_System_Threading_SpinLock@@A.Struct_System_Threading_SpinLock._lockingThreadIndexPlusOne
sub eax, 1
cmp [edx].Struct_Microsoft_Singularity_X86_ThreadContext._threadIndex, ax
je spinLockOk2
int 3
spinLockOk2:
endif ; SPINLOCK_RELEASE_SANITY_CHECK
; this.lockingThreadIndexPlusOne = 0;
; this.lockWord = 0;
mov ?c_dispatchLock@Class_Microsoft_Singularity_Scheduling_Scheduler@@2?AUStruct_System_Threading_SpinLock@@A.Struct_System_Threading_SpinLock._lockingThreadIndexPlusOne, 0
mov ?c_dispatchLock@Class_Microsoft_Singularity_Scheduling_Scheduler@@2?AUStruct_System_Threading_SpinLock@@A.Struct_System_Threading_SpinLock._lockWord, 0
;; Load the new processor context.
mov fs:[Struct_Microsoft_Singularity_X86_ProcessorContext._threadContext], ecx
mov esi, ecx
IDT_LOAD_CONTEXT 0
iretd
_SwitchedInContextSwitch:
ret
?g_SwitchToThreadContextNoGC@Class_Microsoft_Singularity_Processor@@SIXPAUStruct_Microsoft_Singularity_X86_ThreadContext@@@Z endp
ifdef DOUBLE_FAULT_HANDLER
align 16
?CallTaskGate@@YIXGI@Z proc
;
; FAR JMP to double-fault task gate. This is hand-coded, because I can't figure out
; how to make MASM do this for me.
;
db 09Ah ; CALL FAR PTR
dd 0
dw Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtDFG - Struct_Microsoft_Singularity_BootInfo._Cpu0._GdtNull
ret
?CallTaskGate@@YIXGI@Z endp
PRINTAL MACRO
mov ah, 0ah;0ah
mov [edx], ax
add edx, 2
ENDM
PRINTC MACRO num
mov al, num
mov ah, 02h;0ah
mov [edx], ax
add edx, 2
ENDM
; DoubleFault
; Entered in 32-bit protected mode.
PUBLIC ?DoubleFault@@YIXXZ
?DoubleFault@@YIXXZ PROC NEAR
mov edx, 0b8000h
PRINTC '*'
PRINTC '*'
PRINTC '2'
PRINTC '*'
PRINTC '*'
PRINTC ' '
PRINTC 'e'
PRINTC 'b'
PRINTC 'p'
mov ecx, ebp
call printdw
PRINTC 'e'
PRINTC 'f'
PRINTC 'l'
pushfd
pop ecx
call printdw
PRINTC 'e'
PRINTC 'f'
PRINTC 'l'
pushfd
pop ecx
; or ecx, 04000h
; push ecx
; popfd
call printdw
mov edx, 0b8000h + 160
PRINTC 'c'
PRINTC 's'
push cs
pop cx
call printw
PRINTC 's'
PRINTC 's'
mov cx, ss
call printw
PRINTC 'd'
PRINTC 's'
mov cx, ds
call printw
PRINTC 'e'
PRINTC 's'
mov cx, es
call printw
PRINTC 'f'
PRINTC 's'
mov cx, fs
call printw
PRINTC 'g'
PRINTC 's'
mov cx, gs
call printw
PRINTC 't'
PRINTC 'r'
str cx
call printw
mov edx, 0b8000h + 160 * 2
PRINTC 'e'
PRINTC 's'
PRINTC 'p'
mov ecx, esp
call printdw
PRINTC '+'
PRINTC '0'
mov ecx, [esp]
call printdw
PRINTC '+'
PRINTC '4'
mov ecx, [esp+4]
call printdw
PRINTC '+'
PRINTC '8'
mov ecx, [esp+8]
call printdw
PRINTC '+'
PRINTC '1'
PRINTC '2'
mov ecx, [esp+12]
call printdw
PRINTC '+'
PRINTC '1'
PRINTC '6'
mov ecx, [esp+16]
call printdw
mov edx, 0b8000h + 160 * 3
PRINTC 'e'
PRINTC 's'
PRINTC 'i'
mov ecx, esi
call printdw
PRINTC 'p'
PRINTC 't'
mov cx, [esi].Struct_Microsoft_Singularity_X86_TSS._previous_tss
call printw
PRINTC 'e'
PRINTC 's'
PRINTC 'p'
mov ecx, [esi].Struct_Microsoft_Singularity_X86_TSS._esp
call printdw
PRINTC 'e'
PRINTC 'i'
PRINTC 'p'
mov ecx, [esi].Struct_Microsoft_Singularity_X86_TSS._eip
call printdw
PRINTC 'e'
PRINTC 'f'
PRINTC 'l'
mov ecx, [esi].Struct_Microsoft_Singularity_X86_TSS._eflags
call printdw
PRINTC 'c'
PRINTC 'r'
PRINTC '3'
mov ecx, [esi].Struct_Microsoft_Singularity_X86_TSS._cr3
call printdw
PRINTC 'u'
mov cx, [esi].Struct_Microsoft_Singularity_X86_TSS._trap_bit
call printw
mov edx, 0b8000h + 160 * 4
PRINTC 'e'
PRINTC 'd'
PRINTC 'i'
mov ecx, edi
call printdw
PRINTC 'p'
PRINTC 't'
mov cx, [edi].Struct_Microsoft_Singularity_X86_TSS._previous_tss
call printw
PRINTC 'e'
PRINTC 's'
PRINTC 'p'
mov ecx, [edi].Struct_Microsoft_Singularity_X86_TSS._esp
call printdw
PRINTC 'e'
PRINTC 'i'
PRINTC 'p'
mov ecx, [edi].Struct_Microsoft_Singularity_X86_TSS._eip
call printdw
PRINTC 'e'
PRINTC 'f'
PRINTC 'l'
mov ecx, [edi].Struct_Microsoft_Singularity_X86_TSS._eflags
call printdw
PRINTC 'c'
PRINTC 'r'
PRINTC '3'
mov ecx, [edi].Struct_Microsoft_Singularity_X86_TSS._cr3
call printdw
PRINTC 'u'
mov cx, [edi].Struct_Microsoft_Singularity_X86_TSS._trap_bit
call printw
mov edx, 0b8000h + 160 * 5
mov ebp, [esi].Struct_Microsoft_Singularity_X86_TSS._esp
PRINTC 'e'
PRINTC 's'
PRINTC 'p'
mov ecx, ebp
call printdw
PRINTC '+'
PRINTC '0'
mov ecx, [ebp]
call printdw
PRINTC '+'
PRINTC '4'
mov ecx, [ebp+4]
call printdw
PRINTC '+'
PRINTC '8'
mov ecx, [ebp+8]
call printdw
PRINTC '+'
PRINTC '1'
PRINTC '2'
mov ecx, [ebp+12]
call printdw
PRINTC '+'
PRINTC '1'
PRINTC '6'
mov ecx, [ebp+16]
call printdw
iretd ; // note, should clear CR0.TS
again:
jmp again
?DoubleFault@@YIXXZ ENDP
; Print a DWORD to the screen
; [in] ecx = dword to print
; [in] edx = address of screen
; [use] eax = trashed for temporary
;
printdw PROC NEAR
PRINTC ':'
mov eax, ecx
shr eax, 28
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print28
add eax, 7h
print28:
PRINTAL
mov eax, ecx
shr eax, 24
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print24
add eax, 7h
print24:
PRINTAL
mov eax, ecx
shr eax, 20
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print20
add eax, 7h
print20:
PRINTAL
mov eax, ecx
shr eax, 16
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print16
add eax, 7h
print16:
PRINTAL
mov eax, ecx
shr eax, 12
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print12
add eax, 7h
print12:
PRINTAL
mov eax, ecx
shr eax, 08
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print08
add eax, 7h
print08:
PRINTAL
mov eax, ecx
shr eax, 04
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print04
add eax, 7h
print04:
PRINTAL
mov eax, ecx
shr eax, 00
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print00
add eax, 7h
print00:
PRINTAL
PRINTC ' '
ret
printdw ENDP
; Print a WORD to the screen
; [in] ecx = word to print (in low 16-bits, high 16-bits ignored)
; [in] edx = address of screen
; [use] eax = trashed for temporary
;
printw PROC NEAR
PRINTC ':'
mov eax, ecx
shr eax, 12
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print12
add eax, 7h
print12:
PRINTAL
mov eax, ecx
shr eax, 08
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print08
add eax, 7h
print08:
PRINTAL
mov eax, ecx
shr eax, 04
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print04
add eax, 7h
print04:
PRINTAL
mov eax, ecx
shr eax, 00
and eax, 0fh
add eax, 030h
cmp eax, 03ah
jl print00
add eax, 7h
print00:
PRINTAL
PRINTC ' '
ret
printw ENDP
endif ;; DOUBLE_FAULT_HANDLER
END