; =============================================================================
;
; Litos - Traps
;
; -----------------------------------------------------------------------------
; Interrupts:
; Maskable interrupts
; All Interrupt Requests (IRQs) issued by I/O devices give rise
; to maskable interrupts. A maskable interrupt can be in two
; states: masked or unmasked; a masked interrupt is ignored by
; the control unit as long as it remains masked.
; Nonmaskable interrupts
; Only a few critical events (such as hardware failures) give
; rise to nonmaskable interrupts. Nonmaskable interrupts are
; always recognized by the CPU.
; Exceptions:
; Processor-detected exceptions
; Generated when the CPU detects an anomalous condition while
; executing an instruction. These are further divided into three
; groups, depending on the value of the eip register that is
; saved on the Kernel Mode stack when the CPU control unit raises
; the exception.
; - Faults
; Can generally be corrected; once corrected, the program is
; allowed to restart with no loss of continuity. The saved value
; of eip is the address of the instruction that caused the fault,
; and hence that instruction can be resumed when the exception
; handler terminates. Resuming the same instruction is necessary
; whenever the handler is able to correct the anomalous condition
; that caused the exception.
; - Traps
; Reported immediately following the execution of the trapping
; instruction; after the kernel returns control to the program,
; it is allowed to continue its execution with no loss of
; continuity. The saved value of eip is the address of the
; instruction that should be executed after the one that caused
; the trap. A trap is triggered only when there is no need to
; reexecute the instruction that terminated. The main use of
; traps is for debugging purposes. The role of the interrupt
; signal in this case is to notify the debugger that a specific
; instruction has been executed (for instance, a breakpoint has
; been reached within a program). Once the user has examined the
; data provided by the debugger, she may ask that execution of
; the debugged program resume, starting from the next
; instruction.
; - Aborts
; A serious error occurred; the control unit is in trouble, and
; it may be unable to store in the eip register the precise
; location of the instruction causing the exception. Aborts are
; used to report severe errors, such as hardware failures and
; invalid or inconsistent values in system tables. The interrupt
; signal sent by the control unit is an emergency signal used to
; switch control to the corresponding abort exception handler.
; This handler has no choice but to force the affected process
; to terminate.
; Programmed exceptions
; Occur at the request of the programmer. They are triggered by
; int or int3 instructions; the into (check for overflow) and
; bound (check on address bound) instructions also give rise to
; a programmed exception when the condition they are checking is
; not true. Programmed exceptions are handled by the control unit
; as traps; they are often called software interrupts. Such
; exceptions have two common uses: to implement system calls and
; to notify a debugger of a specific event.
; -----------------------------------------------------------------------------
; System uses this classification:
; Interrupt gate
; An Intel interrupt gate that cannot be accessed by a User Mode
; process (the gate's DPL field is equal to 0). All system
; interrupt handlers are activated by means of interrupt gates,
; and all are restricted to Kernel Mode.
; System gate
; An Intel trap gate that can be accessed by a User Mode process
; (the gate's DPL field is equal to 3). The fifth system
; exception handlers associated with the vectors 3, 4, 5, 80h and
; 90h are activated by means of system gates, so the fifth
; assembly language instructions int3, into, bound, int 0x80
; and int 0x90 can be issued in User Mode.
; Trap gate
; An Intel trap gate that cannot be accessed by a User Mode
; process (the gate's DPL field is equal to 0). Most system
; exception handlers are activated by means of trap gates.
; =============================================================================
CODE_SECTION 32
; -----------------------------------------------------------------------------
; Initialize system interrupt table
; -----------------------------------------------------------------------------
; ------------- Prepare registers to default interrupt handler
InitIDT: mov edx,DefInt ; EDX <- default interrupt handler
mov eax,(SYSTEM_CS << 16) ; EAX <- code selector
xchg ax,dx ; AX <- handler LOW, DL <- 0
mov dh,B7+14 ; EDX <- present, 386 interrupt gate
mov edi,SystemIDTTab; EDI <- system int. descr. table
mov ecx,256 ; ECX <- 256 (number of IDT items)
; ------------- Initialize system interrupt table to default handler
InitIDT2: stosd ; store IDT entry LOW
xchg eax,edx ; EAX <-> EDX
stosd ; store IDT entry HIGH
xchg eax,edx ; EAX <-> EDX
loop InitIDT2 ; next IDT entry
; ------------- Load new interrupt table
lidt [SystemIDT] ; load system interrupt descr. table
ret
; -----------------------------------------------------------------------------
; Exceptions and interrupts
; -----------------------------------------------------------------------------
; If CS of handler has the same privilege level as the currently task,
; CPU uses current task, and:
; - pushes EFLAGS, CS and EIP on the stack
; - pushes error code on the stack (if appropriate)
; - loads new CS:EIP
; - clears IF (only for interrupt gate)
; - begins execution
;
; On return from the same privilege level (IRET instruction), CPU:
; - restores CS:EIP
; - restores EFLAGS
; - increments stack pointer
; - resumes execution
;
; If CS of handler has more privilege level as the currently task,
; CPU switches to the task for the handler's privilege level, and:
; - temporarily saves (internaly) SS, ESP, EFLAGS, CS and EIP
; - loads SS:ESP from TSS
; - pushes SS, ESP, EFLAGS, CS and EIP onto the new stack
; - pushes error code on the stack (if appropriate)
; - loads new CS:EIP
; - clears IF (only for interrupt gate)
; - begins execution at the new privilege level
;
; On return from the higher privilege level (IRET instruction), CPU:
; - restores CS:EIP
; - restores EFLAGS
; - restores SS:ESP
; - resumes execution
; -----------------------------------------------------------------------------
; ------------- Int 0: #DE Divide Error Exception (division by zero)
; Fault, raised when a program issues an integer division by 0 (DIV and IDIV
; instructions). CS:EIP = address of the instruction that caused the fault.
DivideError: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGFPE+SIR_TRAP*256+(FPE_IDIV<<16)+(SIT_TRAP<<24)
mov cl,0+B7 ; CL <- 0, trap number + VM86 flag
jmp short TrapError ; trap service
; ------------- Int 1: #DB Debug Exception (tracing one instruction)
; Trap or fault, raised when the T flag (RF bit) of eflags is set (quite useful
; to implement step-by-step execution of a debugged program) or when
; the address of an instruction or operand falls within the range
; of an active debug register. CS:EIP = address of the next instruction (trap)
; or address of the instruction that generated the exception (fault).
; The exception handler can distinguish between traps or faults by examining
; the contents of DR6 and the other debug registers.
; - Instruction fetch breakpoint: fault
; - Data read or write breakpoint: trap
; - I/O read or write breakpoint: trap
; - General detect condition: fault
; - Single-step: trap
; - Task-switch: trap
; - Int 1 instruction: trap
Debug: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGTRAP+SIR_TRAP*256+(TRAP_TRACE<<16)+(SIT_TRAP<<24)
mov cl,1+B7 ; CL <- 1, signal number + VM86 flag
jmp short TrapError ; trap service
; ------------- Int 3: #BP Breakpoint (INT 3 instructions, called by software)
; Trap, caused by an "int3" (breakpoint) instruction (usually inserted by
; a debugger). EIP = address of the next instruction.
Break: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGTRAP+SIR_TRAP*256+(TRAP_BREAK<<16)+(SIT_TRAP<<24)
mov cl,3+B7 ; CL <- 3, signal number + VM86 flag
jmp short TrapError ; trap service
; ------------- Int 4: #OF Overflow (INTO instruction, called by software)
; Trap, an "into" (check for overflow) instruction has been executed when
; the OF (overflow) flag of eflags is set. EIP = next instruction.
Overflow: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGSEGV+SIR_TRAP*256+(SEGV_OVER<<16)+(SIT_TRAP<<24)
mov cl,4+B7 ; CL <- 4, signal number + VM86 flag
jmp short TrapError ; trap service
; ------------- Int 5: #BR Bound range exceeded (BOUND, called by software)
; Fault, a "bound" (check on address bound) instruction is executed with
; the operand outside of the valid address bounds.
; EIP = address of the instruction that caused the fault.
Bounds: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGSEGV+SIR_TRAP*256+(SEGV_BOUND<<16)+(SIT_TRAP<<24)
mov cl,5+B7 ; CL <- 5, signal number + VM86 flag
jmp short TrapError ; trap service
; ------------- Int 6: #UD Invalid Operation code (UD2 or reserved opcode)
; Fault, the CPU execution unit has detected an invalid opcode.
; The UD2 instruction was introduced in the Pentium Pro processor.
; EIP = address of the instruction that caused the fault.
InvalidOp: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGILL+SIR_TRAP*256+(ILL_CODE<<16)+(SIT_TRAP<<24)
mov cl,6 ; CL <- 6, signal number
jmp short TrapError ; trap service
; ------------- Int 7: #NM Device not available (no math coprocessor)
; Fault, an FPU instruction has been executed while the EM flag (emulator)
; of register CR0 was set; an FPU, MMX, or SIMD instruction has been executed
; with the TS flag (task switch) of cr0 is set; WAIT or FWAT instruction has
; been executed while the MP and TS flags of CR0 were set.
; EIP = address of the instruction (or WAIT/FWAIT) that caused the fault.
; Notes: FPU emulator currently not supported.
DevNotAvail: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGFPE+SIR_TRAP*256+(FPE_NO<<16)+(SIT_TRAP<<24)
mov cl,7 ; CL <- 7, signal number
jmp short TrapError ; trap service
; ------------- Int 8: #DF Double fault
; Abort. Normally, when the CPU detects an exception while trying to call
; the handler for a prior exception, the two exceptions can be handled
; serially. In a few cases, however, the processor cannot handle them
; serially, so it raises this exception. A program-state following
; a double-fault exception is undefined. The program or task cannot be resumed
; or restarted. The only available action of the double-fault exception handler
; is to collect all possible context information for use in diagnostics and
; then close the application and/or shut down or reset the processor.
DoubleFault: ; inserts error code (always 0)
pusha ; push all registers
;!!!!!!
mov cl,8 ; CL <- 8, signal number
jmp short TrapError ; trap service
; ------------- Int 9: Coprocessor segment overrun
; Abort. Problems with the external mathematical coprocessor.
; Only 386, later processors do not generate this exception.
; EIP = address of the instruction that caused the fault.
; A program-state following a coprocessor segment-overrun exception is
; undefined. The program or task cannot be resumed or restarted. The only
; available action of the exception handler is to save the instruction pointer
; and reinitialize the FPU using the FNINIT instruction.
FPUOverrun: push byte 0 ; no error code
pusha ; push all registers
mov eax,SIGFPE+SIR_TRAP*256+(FPE_SEGM<<16)+(SIT_TRAP<<24)
mov cl,9 ; CL <- 9, signal number
jmp short TrapError ; trap service
; ------------- Int 10: #TS Invalid TSS Exception
; Fault, the CPU has attempted a context switch to a process having an invalid
; Task State Segment. EIP = address of the instruction that caused the fault
; (before task switch) or address of the first instruction of the new task.
InvalidTSS: ; inserts error code containing the
; segment selector index that caused
; the violation (see IDT.INC)
pusha ; push all registers
mov eax,SIGSEGV+SIR_TRAP*256+(SEGV_TSS<<16)+(SIT_TRAP<<24)
mov cl,10 ; CL <- 10, signal number
jmp short TrapError ; trap service
; ------------- Int 11: #NP Segment not present
; Fault, a reference was made to a segment not present in memory (one in which
; the Segment-Present flag of the Segment Descriptor was cleared).
; EIP = address of the instruction that caused the fault.
SegmNotPres: ; inserts error code containing the
; segment selector index that caused
; the violation (see IDT.INC)
pusha ; push all registers
mov eax,SIGBUS+SIR_TRAP*256+(BUS_SEGM<<16)+(SIT_TRAP<<24)
mov cl,11 ; CL <- 11, signal number
jmp short TrapError ; trap service
; ------------- Int 12: #SS Stack segment fault
; Fault, the instruction attempted to exceed the stack segment limit, or
; the segment identified by SS is not present in memory.
; EIP = address of the instruction that caused the fault.
StackSegment: ; inserts error code
pusha ; push all registers
mov eax,SIGBUS+SIR_TRAP*256+(BUS_STACK<<16)+(SIT_TRAP<<24)
mov cl,12 ; CL <- 12, signal number
; ------------- Push other registers
; Here is: EAX = signal number and signal byte parameters
; (entries SI_SIGNAL .. SI_TYPE)
; CL = trap number
; B7 = VM86 mode enabled
TrapError: push ds ; push DS
push es ; push ES
cld ; direction up
; ------------- Initialize kernel segments
mov ebx,SYSTEM_DS ; EBX <- system DS
mov ds,ebx ; DS <- system DS
mov es,ebx ; ES <- system DS
; ------------- Get error code
mov ebp,esp ; EBP <- trap stack frame TRAPSTACK
xor esi,esi ; ESI <- 0
dec esi ; ESI <- -1, trap flag
xchg esi,[ebp+TRAP_Code] ; ESI <- error code
; ------------- Call trap service
call DoTrap ; call trap service
; !!!!! TODO: handle signal to not return to user code
; !!!!! TODO: skip bad instruction if ignore error
; ------------- Pop registers
pop es ; pop ES
pop ds ; pop DS
popa ; pop all registers
add esp,byte 4 ; skip error code
iret
; ------------- Int 13: #GP General Protection
; Fault, one of the protection rules in the protected mode of the 80x86 has
; been violated. EIP = address of the instruction that caused the fault.
GenProtect: ; inserts error code
pusha ; push all registers
;!!!!!!
mov cl,13 ; CL <- 13, signal number
jmp short TrapError ; trap service
; ------------- Int 14: #PF Page fault
; Fault, the addressed page is not present in memory, the corresponding Page
; Table entry is null, or a violation of the paging protection mechanism has
; occurred. EIP = address of the instruction that caused the fault.
; PageFault: see KERNEL\PAGE.ASM
; ------------- Int 15: Unknown interrupt (Spurious interrupt bug)
SpurIntBug: push byte 0 ; no error code
pusha ; push all registers
;!!!!!!
mov cl,15 ; CL <- 15, signal number
jmp short TrapError ; trap service
; ------------- Int 16: #MF Floating-point error (math fault)
; Fault, the floating-point unit integrated into the CPU chip has signaled
; an error condition, such as numeric overflow or division by 0. Processor
; also generate this exception when performing a signed division whose result
; cannot be stored as a signed integer (for instance -2147483648/-1).
; EIP = address of the instruction that caused the fault.
FPUError: push byte 0 ; no error code
pusha ; push all registers
;!!!!!!
mov cl,16 ; CL <- 16, signal number
jmp short TrapError ; trap service
; ------------- Int 17: #AC Alignment check
; Fault, the address of an operand is not correctly aligned (for instance,
; the address of a long integer is not a multiple of 4).
; This exception was introduced in the 486 processor.
; EIP = address of the instruction that caused the fault.
AlignCheck: ; inserts error code (always 0)
pusha ; push all registers
mov eax,SIGBUS+SIR_TRAP*256+(BUS_ALIGN<<16)+(SIT_TRAP<<24)
mov cl,17 ; CL <- 17, signal number
jmp short TrapError ; trap service
; ------------- Int 18: #MC Machine check (Pentium Pro and later)
; Abort, a machine-check mechanism has detected a CPU or bus error.
; This exception was introduced in the Pentium processor.
MachCheck: push byte 0 ; no error code
pusha ; push all registers
;!!!!!!
mov cl,18 ; CL <- 18, signal number
jmp short TrapError ; trap service
; ------------- Int 19: #XF SIMD Coprocessor error
; Fault, the SSE or SSE2 unit integrated in the CPU chip has signaled an error
; condition on a floating-point operation.
; This exception was introduced in the Pentium III processor.
; EIP = address of the instruction that caused the fault.
SIMDError: push byte 0 ; no error code
pusha ; push all registers
;!!!!!!
mov cl,19 ; CL <- 19, signal number
jmp short TrapError ; trap service
; ------------- Int 32: IRET exception
;IRETError: push byte 0 ; no error code
; pusha ; push all registers
; mov eax,SIGSEGV+SIR_TRAP*256+(SEGV_IRET<<16)+(SIT_TRAP<<24)
; mov cl,32 ; CL <- 32, signal number
; jmp short TrapError ; trap service
; -----------------------------------------------------------------------------
; Handle system exception
; -----------------------------------------------------------------------------
; INPUT: EBP = trap stack frame
; -----------------------------------------------------------------------------
; ------------- Push registers
DoException: push eax ; push EAX
push ecx ; push ECX
push esi ; push ESI
push edi ; push EDI
; ------------- Search exception table
mov edi,ExcStart ; EDI <- exception table
mov ecx,ExcEnd ; ECX <- exception table end
sub ecx,edi ; ECX <- size of exception table
shr ecx,2+2 ; ECX <- number of entries / 4
mov eax,[ebp+TRAP_Int+REGI_EIP] ; EAX <- EIP
repne scasd ; find exception address
jne DoException6 ; address not found, error
; ------------- Jump to exception fixup
sub edi,ExcStart ; EDI <- offset in table+4
mov eax,[edi+Exc2Start-4] ; EAX <- exception fixup
mov [ebp+TRAP_Int+REGI_EIP],eax ; fixup address
jmp short DoException8
; ------------- System error - unhandled exception
DoException6: call Die ; system error
; ------------- Pop registers
DoException8: pop edi ; pop EDI
pop esi ; pop ESI
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Trap service
; -----------------------------------------------------------------------------
; INPUT: EAX = signal number and signal byte parameters
; (entries SI_SIGNAL .. SI_TYPE)
; CL = trap number
; B7 = VM86 mode enabled
; ESI = error code
; EBP = trap stack frame
; -----------------------------------------------------------------------------
; ------------- Push registers
DoTrap: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
push edi ; push EDI
; ------------- Save last error code and last trap number
CURRENT edx ; EDX <- current task
mov ch,cl ; CH <- push VM86 mode enabled flag
and cl,7fh ; clear VM86 mode enabled flag
movzx edi,cl ; EDI <- trap number
mov [edx+TASK_TrapNum],edi ; last trap number
mov [edx+TASK_TrapErr],esi ; last error code
; ------------- Check if VM86 mode is used and enabled
test byte [ebp+TRAP_Int+REGI_Flags+2],(EFLAGS_VM>>16); VM86?
jz DoTrap2 ; no VM86 mode
or ch,ch ; VM86 mode enabled?
jns DoTrap3 ; VM86 not enabled
; ------------- Handle VM86 trap
call DoVM86Trap ; handle VM86 trap
jc DoTrap3 ; trap signal
jmp short DoTrap9
; ------------- Check if it is kernel trap
DoTrap2: test byte [ebp+TRAP_Int+REGI_CS],3 ; privilege level?
jz DoTrap4 ; kernel trap
; ------------- Send signal to current task
DoTrap3: sub esp,byte SIGINFO_size; create buffer (must be aligned!)
mov ecx,esp ; ECX <- info structure
mov [ecx+SI_SignalDW],eax ; signal byte parameters
mov [ecx+SI_Sender],edx ; sender
mov eax,[ebp+TRAP_Int+REGI_EIP] ; instruction address
mov [ecx+SI_TrapAddr],eax ; instruction address
mov [ecx+SI_TrapNum],edi ; trap number
mov [ecx+SI_TrapErr],esi ; trap error code
and dword [ecx+SI_Param4],byte 0 ; parameter 4
call SignalSendInfo ; send signal
add esp,byte SIGINFO_size ; return stack pointer
jmp short DoTrap9
; ------------- Handle system exception
DoTrap4: call DoException ; handle system exception
; ------------- Pop registers
DoTrap9: pop edi ; pop EDI
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Handle VM86 trap
; -----------------------------------------------------------------------------
; INPUT: CL = trap number
; ESI = error code
; EBP = trap stack frame
; OUTPUT: CY = no VM86 trap
; -----------------------------------------------------------------------------
DoVM86Trap:
stc
ret
; -----------------------------------------------------------------------------
; System error
; -----------------------------------------------------------------------------
; INPUT: EAX = signal number and signal byte parameters
; (entries SI_SIGNAL .. SI_TYPE)
; CL = trap number
; ESI = error code
; EBP = trap stack frame
; -----------------------------------------------------------------------------
Die:
ret
; -----------------------------------------------------------------------------
; NMI (non maskable interrupt, int 2) service
; -----------------------------------------------------------------------------
; It is recomended that the NMI interrupt handler be accessed through an
; interrupt gate to disable maskable hardware interrupts.
; ------------- Push registers
NMI: push eax ; push EAX
push ebx ; push EBX
push ds ; push DS
; ------------- Initialize kernel segments
mov eax,SYSTEM_DS ; EAX <- system DS
mov ds,eax ; DS <- system DS
; ------------- Get current run-queue (-> EBX)
CURRENT ebx ; EBX <- get current task
movzx ebx,byte [ebx+TASK_CPU] ; EBX <- old CPU
mov ebx,[RunQueueAddr+ebx*4] ; EBX <- run-queue of old CPU
; ------------- Get NMI reason (-> AL)
in al,61h ; AL <- NMI reason
; ------------- Watchdog or unsupported NMI reason
test al,B6+B7 ; unknown NMI reason?
jnz NMI2 ; known NMI reason
bts dword [ebx+RUNQ_Flags],4 ; watchdog disabled?
jc NMI8 ; watchdog is currently disabled
or byte [ebx+RUNQ_Flags],B2 ; signal watchdog
mov dword [byte ebx+RUNQ_CountDog],NMI_DELAYDOG*TIME_1MS*1000
jmp short NMI8
; ------------- Check if memory or I/O error is already disabled
NMI2: bts dword [ebx+RUNQ_Flags],3 ; memory,I/O check disabled?
jc NMI8 ; memory,I/O check currently disabled
; ------------- Memory parity error
test al,B7 ; memory parity error?
jz NMI4 ; no memory parity error
or byte [ebx+RUNQ_Flags],B0 ; signal memory error
; ------------- I/O channel parity error
NMI4: test al,B6 ; I/O channel error?
jz NMI6 ; no I/O channel error
or byte [ebx+RUNQ_Flags],B1 ; signal I/O error
; ------------- Disable memory or I/O check and set delay for new check
NMI6: and al,B0+B1+B2+B3 ; clear reserved bits
or al,B2+B3 ; disable memory and I/O check
out 61h,al ; disable memory and I/O check
mov dword [byte ebx+RUNQ_CountMem],NMI_DELAYMEM*TIME_1MS*1000
; ------------- Reset NMI request
NMI8: mov al,B7+13 ; AL <- NMI disabled + R/O CMOS entry
out 70h,al ; disable NMI
in al,71h ; short delay
mov al,[CMOSNMIFlag]; AL <- current state of NMI (enabled)
out 70h,al ; enable NMI
in al,71h ; short delay
; ------------- Pop registers
pop ds ; pop DS
pop ebx ; pop EBX
pop eax ; pop EAX
iret ; it enables next NMI
; -----------------------------------------------------------------------------
; Set task gate
; -----------------------------------------------------------------------------
; INPUT: AX = GDT entry (selector, not index), offset = 0
; EBX = index of IDT entry (0 to 255)
; OUTPUT: EBX = index of next IDT entry
; -----------------------------------------------------------------------------
; ------------- Push registers
SetTaskGate: push eax ; push EAX
push ebx ; push EBX
; ------------- Set task gate
lea ebx,[SystemIDTTab+IDT_size*ebx] ; EBX <- address of IDT
shl eax,16 ; EAX <- rotate GDT selector
mov [ebx],eax ; store IDT entry LOW
mov dword [ebx+4],(B7+5)*256 ; flags - task gate, present
; ------------- Pop registers
pop ebx ; pop EBX
pop eax ; pop EAX
inc ebx ; index of next IDT entry
ret
; -----------------------------------------------------------------------------
; Set gate
; -----------------------------------------------------------------------------
; INPUT: AL = flags
; B0-B3: entry type
; 5 = task gate (uses TSS)
; 12 = call gate
; 14 = 386 interrupt gate (uses GDT)
; 15 = 386 trap gate (uses LDT)
; B5-B6: interrupt privileg level
; 0 = exceptions and hardware interrupts
; 3 = software (user) interrupts
; EBX = address of IDT entry
; EDX = offset of handler
; -----------------------------------------------------------------------------
; ------------- Push registers
SetGate: push eax ; push EAX
push edx ; push EDX
; ------------- Set interrupt gate
and eax,byte B0+B1+B2+B3+B5+B6 ; EAX <- mask flags
or eax,(SYSTEM_CS << 16) + B7 ; EAX <- code selector
xchg al,ah ; AH <- flags, AL <- 0
xchg ax,dx ; AX <- handler LOW,DH <- flags,DL <- 0
mov [ebx],eax ; store IDT entry LOW
mov [ebx+4],edx ; store IDT entry HIGH
; ------------- Pop registers
pop edx ; pop EDX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Set call gate
; -----------------------------------------------------------------------------
; INPUT: EBX = address of IDT entry
; EDX = target address
; NOTES: Call gate is software gate called by user with CALL FAR.
; -----------------------------------------------------------------------------
SetCallGate: push eax ; push EAX
mov al,12+B5+B6 ; AL <- flags
call SetGate ; set gate
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Set system trap gate
; -----------------------------------------------------------------------------
; INPUT: EBX = index of IDT entry (0 to 255)
; EDX = target address
; OUTPUT: EBX = index of next IDT entry
; NOTES: System trap gate is software exception accessible by user.
; System trap gate doesn't disable interrupts.
; -----------------------------------------------------------------------------
SetSysTrapGate: push eax ; push EAX
mov al,15+B5+B6 ; AL <- flags
jmp short SetIntGate2 ; set gate
; -----------------------------------------------------------------------------
; Set trap gate
; -----------------------------------------------------------------------------
; INPUT: EBX = index of IDT entry (0 to 255)
; EDX = target address
; OUTPUT: EBX = index of next IDT entry
; NOTES: Trap gate is hardware exception not accessible by user.
; Trap gate doesn't disable interrupts.
; -----------------------------------------------------------------------------
SetTrapGate: push eax ; push EAX
mov al,15 ; AL <- flags
jmp short SetIntGate2 ; set gate
; -----------------------------------------------------------------------------
; Set system interrupt gate (software interrupt; it disables interrupts)
; -----------------------------------------------------------------------------
; INPUT: EBX = index of IDT entry (0 to 255)
; EDX = target address
; OUTPUT: EBX = index of next IDT entry
; NOTES: System interrupt gate is software interrupt accessible by user.
; System interrupt gate disables interrupts.
; -----------------------------------------------------------------------------
SetSysIntGate: push eax ; push EAX
mov al,14+B5+B6 ; AL <- flags
jmp short SetIntGate2 ; set gate
; -----------------------------------------------------------------------------
; Set interrupt gate
; -----------------------------------------------------------------------------
; INPUT: EBX = index of IDT entry (0 to 255)
; EDX = target address
; OUTPUT: EBX = index of next IDT entry
; NOTES: Interrupt gate is hardware interrupt not accessible by user.
; Interrupt gate disables interrupts.
; -----------------------------------------------------------------------------
SetIntGate: push eax ; push EAX
mov al,14 ; AL <- flags
SetIntGate2: push ebx ; push EBX
lea ebx,[SystemIDTTab+IDT_size*ebx] ; EBX <- address of IDT
call SetGate ; set gate
pop ebx ; pop EBX
pop eax ; pop EAX
inc ebx ; index of next IDT entry
ret
; -----------------------------------------------------------------------------
; Initialize traps
; -----------------------------------------------------------------------------
; ------------- Int 0: Divide error
TrapInit: xor ebx,ebx ; EBX <- 0, index of IDT entry
mov edx,DivideError ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 1: Debug
mov edx,Debug ; EDX <- target address
call SetIntGate ; set interrupt gate
; ------------- Int 2: NMI
mov edx,NMI ; EDX <- target address
call SetIntGate ; set interrupt gate
; ------------- Int 3: Break
mov edx,Break ; EDX <- target address
call SetSysIntGate ; set system interrupt gate
; ------------- Int 4: Overflow
mov edx,Overflow ; EDX <- target address
call SetSysTrapGate ; set system trap gate
; ------------- Int 5: Bounds
mov edx,Bounds ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 6: Ivalid Operation
mov edx,InvalidOp ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 7: Device not available
mov edx,DevNotAvail ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 8: Double fault
mov edx,DoubleFault ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 9: Coprocessor segment overrun
mov edx,FPUOverrun ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 10: Invalid TSS
mov edx,InvalidTSS ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 11: Segment not present
mov edx,SegmNotPres ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 12: Stack segment
mov edx,StackSegment; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 13: General Protection
mov edx,GenProtect ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 14: Page fault
mov edx,PageFault ; EDX <- target address
call SetIntGate ; set interrupt gate
; ------------- Int 15: Spurious interrupt bug
mov edx,SpurIntBug ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 16: Coprocessor error
mov edx,FPUError ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 17: Alignment check
mov edx,AlignCheck ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 18: Machine check
mov edx,MachCheck ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Int 19: SIMD Coprocessor error
mov edx,SIMDError ; EDX <- target address
call SetTrapGate ; set trap gate
; ------------- Linux call gate
; mov ebx,LINUX_INT ; EBX <- Linux system call vector
; mov edx,LinuxCall ; EDX <- target address
; call SetSysTrapGate ; set system trap gate
; ------------- System call gate
; mov ebx,SYSTEM_INT ; EBX <- system call vector
; mov edx,SystemCall ; EDX <- target address
; call SetSysTrapGate ; set system trap gate
; ------------- Initialize unused interrupts
mov bl,20 ; EBX <- 20, first unused interrupt
mov edx,DefInt ; EDX <- default handler
TrapInit2: call SetIntGate ; set interrupt gate
or bl,bl ; all interrupts?
jnz TrapInit2 ; init next interrupt
ret
; -----------------------------------------------------------------------------
; Default interrupt handler
; -----------------------------------------------------------------------------
; ------------- Push registers
DefInt: pusha ; push all registers
push ds ; push DS
push es ; push ES
; ------------- Display error message
%ifdef DEBUG
cld
mov eax,SYSTEM_DS
mov ds,eax
mov es,eax
mov esi,IntError
call DebOutText
%endif
; ------------- Pop registers
pop es ; pop ES
pop ds ; pop DS
popa ; pop all registers
iret
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
; align 4, db 0
;DefaultLDT: dd 0 ; default IDT entry
; ------------- NMI flags
align 4, db 0
NMIWatchdog: dd 0 ; NMI flag: B0=use watchdog
; ------------- System interrupt descriptor table
align 4, db 0
dw 0
SystemIDT: dw IDT_size*256-1 ; IDT size limit
dd SystemIDTTab ; IDT base address
; ------------- Interrupt error message
%ifdef DEBUG
IntError: db 'Unknown interrupt!',10,0
%endif
; -----------------------------------------------------------------------------
; Uninitialized data
; -----------------------------------------------------------------------------
BSS_SECTION
|