Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

TRAPS.ASM

Traps


; =============================================================================
;
;                                  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

Back to source browser