singrdk/base/Kernel/Singularity/Isal/ix/interrupt.asm

263 lines
11 KiB
NASM
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Microsoft Research Singularity
;;;
;;; Copyright (c) Microsoft Corporation. All rights reserved.
;;;
;;; This file contains x86-specific assembly code handling dispatching of interrupts.
include hal.inc
;;; IdtDispatchers are the dispatch functions used for populating the Idt. Each one
;;; pushes its interrupt id, along with a dummy error code if necessary to normalize
;;; the stack, and jumps to the central dispatch routine
DISPATCH_CLEAN MACRO num
align SIZEOF Struct_Microsoft_Singularity_Isal_IX_InterruptTable_Dispatcher
push 0 ; No error
push num
jmp SYMFIX(?g_DispatchVector@Class_Microsoft_Singularity_Isal_Isa@@SIXXZ)
ENDM
DISPATCH_ERR MACRO num
align SIZEOF Struct_Microsoft_Singularity_Isal_IX_InterruptTable_Dispatcher
push num
jmp SYMFIX(?g_DispatchVector@Class_Microsoft_Singularity_Isal_Isa@@SIXXZ)
ENDM
_IdtDispatchers proc
DISPATCH_CLEAN 000h ; #DE Divide-by-Zero
DISPATCH_CLEAN 001h ; #DB Debug Exception
DISPATCH_CLEAN 002h ; NMI Non-Maskable-Interrupt
DISPATCH_CLEAN 003h ; #BP Breakpoint
DISPATCH_CLEAN 004h ; #OF OVerflow
DISPATCH_CLEAN 005h ; #BR Bound-Range
DISPATCH_CLEAN 006h ; #UD Invalid Opcode
DISPATCH_CLEAN 007h ; #NM Device Not Available
DISPATCH_ERR 008h ; #DF Double Fault
DISPATCH_CLEAN 009h ; Unused (was x87 segment except)
DISPATCH_ERR 00ah ; #TS Invalid TSS
DISPATCH_ERR 00bh ; #NP Sgement Not Present
DISPATCH_ERR 00ch ; #SS Stack Exception
DISPATCH_ERR 00dh ; #GP General Protection
DISPATCH_ERR 00eh ; #PF Page Fault
DISPATCH_CLEAN 00fh ; Reserved
DISPATCH_CLEAN 010h ; #MF x87 Math Error
DISPATCH_ERR 011h ; #AC Alignment Check
DISPATCH_CLEAN 012h ; #MC Machine Check
DISPATCH_CLEAN 013h ; #XF SIMD Exception
DISPATCH_CLEAN 014h ; 014h exception
DISPATCH_CLEAN 015h ; 015h exception
DISPATCH_CLEAN 016h ; 016h exception
DISPATCH_CLEAN 017h ; 017h exception
DISPATCH_CLEAN 018h ; 018h exception
DISPATCH_CLEAN 019h ; 019h exception
DISPATCH_CLEAN 01ah ; 01ah exception
DISPATCH_CLEAN 01bh ; 01bh exception
DISPATCH_CLEAN 01ch ; 01ch exception
DISPATCH_CLEAN 01dh ; 01dh exception
DISPATCH_CLEAN 01eh ; 01eh exception
DISPATCH_CLEAN 01fh ; 01fh exception
DISPATCH_CLEAN 020h ; 021h: first interrupt
_num = 021h ; 021h to 0ffh
WHILE _num LE 0ffh
DISPATCH_CLEAN _num
_num = _num + 1
ENDM
_IdtDispatchers endp
;;; GetDispatchers returns the address of the IdtDispatchers array. This
;;; is necessary since we can't directly take the address of a function in managed code.
SYMFIX(?g_GetDispatchers@Struct_Microsoft_Singularity_Isal_IX_InterruptTable@@SIPAUStruct_Microsoft_Singularity_Isal_IX_InterruptTable_Dispatcher@@XZ) proc
lea eax, _IdtDispatchers
ret
SYMFIX(?g_GetDispatchers@Struct_Microsoft_Singularity_Isal_IX_InterruptTable@@SIPAUStruct_Microsoft_Singularity_Isal_IX_InterruptTable_Dispatcher@@XZ) endp
;;; LoadDispatchTable should be called on each processor to initialize its idt register to the
;;; shared dispatch table.
SYMFIX(?g_LoadIdt@Class_Microsoft_Singularity_Isal_Isa@@SIXXZ) proc
lidt fword ptr _Idtr
ret
SYMFIX(?g_LoadIdt@Class_Microsoft_Singularity_Isal_Isa@@SIXXZ) endp
;;; DispatchVector implements the meat of the low level interrupt dispatching logic. Its goal
;;; is to implement the transition to high level code with minimal overhead.
;;;
;;; There are essentially two tasks: save the context (if appropriate), and switch to the
;;; interrupt processing stack.
;;;
;;; This function either returns via iretd, or else doesn't return at all (because the
;;; handler called RestoreContext.)
;;;
;;; On entry to DispatchVector, the stack looks like this:
;;;
;;; [TOP] (after pushing regs)
;;; interrupt vector [esp] [esp+3P]
;;; interrupt err (parameter) [esp+1P] [esp+4P]
;;; interrupted eip [esp+2P] [esp+5P]
;;; interrupted cs [esp+3P] [esp+6P]
;;; interrupted efl [esp+4P] [esp+7P]
;;; [PAGING/X64]
;;; interrupted esp [esp+5P] [esp+8P]
;;; interrupted ss [esp+6P] [esp+9P]
;;; [NON-PAGING]
;;; previous stack continues esp+5P esp+8P
;;;
SYMFIX(?g_DispatchVector@Class_Microsoft_Singularity_Isal_Isa@@SIXXZ) proc
ifdef PAGING
if ISA_IX86
;; Fix up segment ds, es to point to valid values
push ss
pop ds
push ss
pop es
endif
;; If we've arrived from ring 3 FS will be invalid.
push Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt._pp - Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt._nul
pop fs
endif
;; Save regs in InterruptContext
push PAX
push PCX
push PDX
ifdef ISA_IX64
push r8
push r9
push r10
push r11
endif
;; Decide if/where to stash the context. For now, we use hard-coded
;; constants based on the vector to make the decision. Eventually this could be
;; delegated to the HAL for more dynamic control of behaviors.
;; The lowest vectors are exceptions - context save into ProcessorRecord, where the
;; cpu state will be visible to the debugger infrastructure.
mov PDX, [PSP].Struct_Microsoft_Singularity_Isal_InterruptContext._vector
cmp PDX, Struct_Microsoft_Singularity_Isal_InterruptContext_VectorExceptionMax
jg not_exception
GET_PROCESSOR_CONTEXT PAX
lea PCX, [PAX].Struct_Microsoft_Singularity_Isal_CpuRecord._spill
jmp save_context
not_exception:
;; The middle vectors are fast interrupts - no context save. These interrupts may
;; be used for fast operations which do not interact with the scheduler; control will
;; always resume at the interrupted location.
cmp PDX, Struct_Microsoft_Singularity_Isal_InterruptContext_VectorSchedulerMin
jl skip_save
;; The highest vectors are normal interrupts - context save into ThreadRecord. Typically
;; control may be resumed on a different thread.
GET_THREAD_CONTEXT PAX
lea PCX, [PAX].Struct_Microsoft_Singularity_Isal_ThreadRecord._spill
save_context:
;; Note PCX has the context buffer from above
mov PDX, PSP
call SYMFIX(?m_Save@Struct_Microsoft_Singularity_Isal_SpillContext@@SI_NPAU1@PAUStruct_Microsoft_Singularity_Isal_InterruptContext@@@Z)
skip_save:
;; Save previous stack limit
GET_THREAD_RECORD_FIELD PCX, _activeStackLimit
push PCX
;; See if we are on the interrupt stack
GET_CPU_RECORD_FIELD PDX, _interruptStackLimit
cmp PDX, PCX
mov PCX, PSP ; stash old stack ptr; doesn't change flags
je no_switch
;; switch to interrupt stack
GET_CPU_RECORD_FIELD PAX, _interruptStackBegin
mov PSP, PAX
SET_THREAD_RECORD_FIELD _activeStackLimit, PDX
no_switch:
;; Save the old stack pointer
push PCX
;; InterruptContext is old PSP + 4
add PCX, SIZEOF PWORD
;; call the handler
call SYMFIX(?g_DispatchInterrupt@Class_Microsoft_Singularity_Isal_Isa@@SIXPAUStruct_Microsoft_Singularity_Isal_InterruptContext@@@Z)
;; Note that we may or may not get here, depending on whether the InterruptDispatch routine
;; returned or not (it may have restored a previous context.) If we did get here, return
;; back to the interrupted context.
;; Restore the old stack pointer and limit
pop PSP
pop PAX
SET_THREAD_RECORD_FIELD _activeStackLimit, PAX
;; Restore caller save regs, do normal interrupt resume
ifdef ISA_IX64
pop r11
pop r10
pop r9
pop r8
endif
pop PDX
pop PCX
pop PAX
;; Discard vector/err
add PSP, SIZEOF PWORD * 2
;; Return
jmp [SYMFIX(?c_returnFromInterrupt@Class_Microsoft_Singularity_Isal_Isa@@2PAUvoid@@A)]
SYMFIX(?g_DispatchVector@Class_Microsoft_Singularity_Isal_Isa@@SIXXZ) endp
.data
;;; We have to manually declare this variable to get it properly aligned. This seems to be a bartok bug.
align 16
?c_idt@Class_Microsoft_Singularity_Isal_Isa@@2?AUStruct_Microsoft_Singularity_Isal_IX_InterruptTable@@A Struct_Microsoft_Singularity_Isal_IX_InterruptTable { }
;;; _Idtr is a global structure which is suitable for passing to the lidt instruction.
IDTR struct 2
_limit UINT16 ?
_base PWORD ?
IDTR ends
align 16
;; We want to align the PWORD after the offset, so add padding here.
dw ?
ifdef ISA_IX64
dw ?
dw ?
endif
_Idtr IDTR { \
(SIZEOF Struct_Microsoft_Singularity_Isal_IX_InterruptTable) - 1, \
?c_idt@Class_Microsoft_Singularity_Isal_Isa@@2?AUStruct_Microsoft_Singularity_Isal_IX_InterruptTable@@A }
END