When code crashes the cpu normally generates an interrupt (see Intel programmers guides for details). The interrupts are handled by system services. Any system module or driver can try to allocate one or more CPU generated interrupts using system service 0xA7 (and system service 0xAF to de-allocate it). Any code that has allocated interrupts will be called if the interrupt occurs.
This is a breif list. For full details see Intel programmers guides.
00 Divide error
01 Debug exceptions
02 Nonmaskable interrupt
03 Breakpoint (one-byte INT 3 instruction)
04 Overflow (INTO instruction)
05 Bounds check (BOUND instruction)
06 Invalid opcode
07 Coprocessor not available
08 Double fault
09 (reserved by Intel)
0A Invalid TSS
0B Segment not present
0C Stack exception
0D General protection
0E Page fault
0F (reserved by Intel)
10 Coprecessor error
11-1F (reserved by Intel)
In general this is easy. For example:
;Coprocessor not available interrupt
mov cx,cs ;Code ID for driver or system module
mov edx,CPUint07 ;Offset to be called
callMemory 0xA7 ;Standard macro (mov eax,0xA7; call 0x18:0)
test al,al ;Was there an error?
jne error ; yes
After doing this system services will call your code when the chosen interrupt/s are triggered.
When a CPU generated interrupt occurs system services calls all code that's allocated that interrupt after doing some pre-processing. Before and after than call certain registers must contain certain information:
AL Interrupt status flags
Bit Meaning when 1
0 Interrupted task is restartable
1 Exception handler is task (interrupted task suspended)
7 Cause of interrupt repaired
AH Interrupt number
EBX Address of task page
CX Task ID
EDX Error code (or 0)
During the call the address space will be the same as the one in use when the interrupt occured. Routines called by system services in this manner must be re-entrant in case multiple interrupts occur.
When the called code returns it must leave all registers the same as they where when it called except AL. Setting bit 8 of AL will prevent any further exception handlers being called. Setting bit 0 of AL allows the task to be restarted (otherwise the task is terminated).
System services does some strange things that need explaining. A table of up to 16 different far calls to make is kept for when each interrupt occurs. The code indicated by these tables will be called one after the other until the cause is repaired or all code has been called. When system services calls interrupt receivers it should check that the code that caused the interrupt is not the same code it's about to call.
During boot system services starts before time services, so during boot it can't allocate any tasks to interrupts. To get around this the time services should call system service 0xEF when it starts (unless time services is being replaced). If system services is being replaced time services will be present so this isn't necessary an system services should go ahead and create tasks for the relevant IDT descriptors.