Gauntlet/docs/Exception_EntryExit 
Created by Adam Wiggins: 11/09/1999
Last Modified by Adam Wiggins: 02/10/1999
Exception Entry/Exit Psudo Assembly for Development

/********************************
* SWI + Register Syscall Method *
********************************/

/*******************************************
*          Exception Stack Frames          *
********************************************
* Other User  * Other Kernel *   Syscall   *
********************************************<-- Top of TCB, start of Kernel
*  p_lr -> pc *  p_lr -> pc  * sv_lr -> pc *    Stack of this thread. Kernel
*    usr_lr   *      r12     *    usr_sp   *    Stack is full descending.
*    usr_sp   *      r11     *     SPSR    *
*     r12     *      ...     *   p_lr / ~  *
*     r11     *       r0     *      ~      *
*     ...     *      SPSR    *      ~      *
*      r0     *    p_lr / ~  *     ...     *
*     SPSR    *       ~      *      ~      *
*   p_lr / ~  *       ~      *      ~      *
*******************************************/

p_lr is on the top of the stack (after the last stack from) for preempted and
sleeping threads

/* Reset Entry point 0x0
************************/

	Currently not relavent but later it could be used to recover from sleep on the SA1100 with help from the boot monitor.

/* Undefined Entry Point 0x4
****************************/

	Undefined Instruction Dispatcher should first assertain wether the user or kernel raised the exception. If it was the kernel we panic otherwise we should stack an exception frame of the users register set and generate an exception IPC to the thread's exception handler.

/* SWI Entry point 0x8
**********************/

	Syscalls should first dispatch to the relavent handler and then stack a syscall frame of the user state (this sets up the kernel stack pointer for that thread so kernel pre-emption allows has the kernel stack pointer already set). Once the user state is stacked the syscall can proceed.
	Invalid syscall numbers result in a exception IPC to the threads exception handler.

/* Prefetch Abort Entry point 0xC
*********************************/

	As with all exceptions the prefetch about must check if the kernel or user generated the abort. If it was the kernel then we either panic. If the user generates this exception a page fault IPC is generated to the threads pager thread OR we have a FASS situation and must take the relavent action.
	In addition at the start we have to work out the reason for the abort since the FSR/FAR arn't updated.

/* Data Abort Entry Point at 0xC
********************************/

	The Data abort is the same as the prefetch about with the addition that
rather then just panic on a kernel generated exception we must check if the exception was on a dynamic kernel data structure and take messures to add a kernel
mapping for it.

/* Unused Entry Point at 0x14
*****************************/

	Not relavent since it should never be generated.

/* IRQ Entry Point at 0x18
**************************/

Non-Preemptable Kernel:
	work out interrupts reason. Either a kernel timer or user interrupt. If kernel timer take relavent action (most likely some form of context switch) else generate interrupt IPC to registered handler thread for that interrupt.

Preemptable Kernel:
	Once again IRQ like most exceptions needs to check wether the exception was raised in the kernel or user mode. For user mode we have to stack an exception frame of the user state and then load up the kernel invarient registers. For the kernel we only have to stack an exception frame of the non invarient kernel state (ie registers). Once we've saved the state we send of an IPC to the registered handler thread for that interrupt (If non is registered the interrupt should be masked, if the interrupt controler supports this which it should).
	Some CPUs might not have routale interrupts so we have to check if the IRQ was from a 'kernel' interrupt like a timer one.

Fully Preemptable Kernel: 
	In the case where we can't route interrupts to the IRQ or FIQ the IRQ dispatcher looks very similar to the FIQ dispatcher but we have less banked registers and also we have to unmask the IRQ on entry to any exception (a bit of a pain)

/* FIQ Entry Point at 0x1C
**************************/

Non-Preemptable Kernel: 
	Only the periodic timer updated is routed to the FIQ and this makes use of just the banked registers.

Preemptable Kernel:
	FIQ must yet again first check if the user or kernel was interrupted. If the user we just do the same stacking as with the IRQ and then handle the interrupt which most likely is a timeout invoking a thread switch. If it was in the kernel we must first check if the kernel is in a preemptable state, if not we have to mask FIQ's and return to the interrupted kernel state. 
	As above if the CPU can't route interrupts then we have the same checking code as the IRQ once we've handled the non-preemptable check.

Fully Preemptable Kernel:
	A nice solution for full preemption is to route all interrupts to the FIQ signal and when we have a FIQ we stack the unbanked registers, go about handling the interrupt until (if at all) we hit a thread switch. At this stage the FIQ either saves the user bank of registers (if the user was interrupted) or switches to the interrupted mode and saves that modes bank and then switches to the relavent thread. At this stage since we are leaving the FIQ mode we can assume the FIQ registers are scratch and we can unmask the FIQ bit, this way it will appear that the same mode has been interrupted. We must be careful though to insure the initially interrupted kernel state is preserved on the stack to be restored.
