| ================================= | |
| INTERNAL KERNEL ABI FOR FR-V ARCH | |
| ================================= | |
| The internal FRV kernel ABI is not quite the same as the userspace ABI. A | |
| number of the registers are used for special purposed, and the ABI is not | |
| consistent between modules vs core, and MMU vs no-MMU. | |
| This partly stems from the fact that FRV CPUs do not have a separate | |
| supervisor stack pointer, and most of them do not have any scratch | |
| registers, thus requiring at least one general purpose register to be | |
| clobbered in such an event. Also, within the kernel core, it is possible to | |
| simply jump or call directly between functions using a relative offset. | |
| This cannot be extended to modules for the displacement is likely to be too | |
| far. Thus in modules the address of a function to call must be calculated | |
| in a register and then used, requiring two extra instructions. | |
| This document has the following sections: | |
| (*) System call register ABI | |
| (*) CPU operating modes | |
| (*) Internal kernel-mode register ABI | |
| (*) Internal debug-mode register ABI | |
| (*) Virtual interrupt handling | |
| ======================== | |
| SYSTEM CALL REGISTER ABI | |
| ======================== | |
| When a system call is made, the following registers are effective: | |
| REGISTERS CALL RETURN | |
| =============== ======================= ======================= | |
| GR7 System call number Preserved | |
| GR8 Syscall arg #1 Return value | |
| GR9-GR13 Syscall arg #2-6 Preserved | |
| =================== | |
| CPU OPERATING MODES | |
| =================== | |
| The FR-V CPU has three basic operating modes. In order of increasing | |
| capability: | |
| (1) User mode. | |
| Basic userspace running mode. | |
| (2) Kernel mode. | |
| Normal kernel mode. There are many additional control registers | |
| available that may be accessed in this mode, in addition to all the | |
| stuff available to user mode. This has two submodes: | |
| (a) Exceptions enabled (PSR.T == 1). | |
| Exceptions will invoke the appropriate normal kernel mode | |
| handler. On entry to the handler, the PSR.T bit will be cleared. | |
| (b) Exceptions disabled (PSR.T == 0). | |
| No exceptions or interrupts may happen. Any mandatory exceptions | |
| will cause the CPU to halt unless the CPU is told to jump into | |
| debug mode instead. | |
| (3) Debug mode. | |
| No exceptions may happen in this mode. Memory protection and | |
| management exceptions will be flagged for later consideration, but | |
| the exception handler won't be invoked. Debugging traps such as | |
| hardware breakpoints and watchpoints will be ignored. This mode is | |
| entered only by debugging events obtained from the other two modes. | |
| All kernel mode registers may be accessed, plus a few extra debugging | |
| specific registers. | |
| ================================= | |
| INTERNAL KERNEL-MODE REGISTER ABI | |
| ================================= | |
| There are a number of permanent register assignments that are set up by | |
| entry.S in the exception prologue. Note that there is a complete set of | |
| exception prologues for each of user->kernel transition and kernel->kernel | |
| transition. There are also user->debug and kernel->debug mode transition | |
| prologues. | |
| REGISTER FLAVOUR USE | |
| =============== ======= ============================================== | |
| GR1 Supervisor stack pointer | |
| GR15 Current thread info pointer | |
| GR16 GP-Rel base register for small data | |
| GR28 Current exception frame pointer (__frame) | |
| GR29 Current task pointer (current) | |
| GR30 Destroyed by kernel mode entry | |
| GR31 NOMMU Destroyed by debug mode entry | |
| GR31 MMU Destroyed by TLB miss kernel mode entry | |
| CCR.ICC2 Virtual interrupt disablement tracking | |
| CCCR.CC3 Cleared by exception prologue | |
| (atomic op emulation) | |
| SCR0 MMU See mmu-layout.txt. | |
| SCR1 MMU See mmu-layout.txt. | |
| SCR2 MMU Save for EAR0 (destroyed by icache insns | |
| in debug mode) | |
| SCR3 MMU Save for GR31 during debug exceptions | |
| DAMR/IAMR NOMMU Fixed memory protection layout. | |
| DAMR/IAMR MMU See mmu-layout.txt. | |
| Certain registers are also used or modified across function calls: | |
| REGISTER CALL RETURN | |
| =============== =============================== ====================== | |
| GR0 Fixed Zero - | |
| GR2 Function call frame pointer | |
| GR3 Special Preserved | |
| GR3-GR7 - Clobbered | |
| GR8 Function call arg #1 Return value | |
| (or clobbered) | |
| GR9 Function call arg #2 Return value MSW | |
| (or clobbered) | |
| GR10-GR13 Function call arg #3-#6 Clobbered | |
| GR14 - Clobbered | |
| GR15-GR16 Special Preserved | |
| GR17-GR27 - Preserved | |
| GR28-GR31 Special Only accessed | |
| explicitly | |
| LR Return address after CALL Clobbered | |
| CCR/CCCR - Mostly Clobbered | |
| ================================ | |
| INTERNAL DEBUG-MODE REGISTER ABI | |
| ================================ | |
| This is the same as the kernel-mode register ABI for functions calls. The | |
| difference is that in debug-mode there's a different stack and a different | |
| exception frame. Almost all the global registers from kernel-mode | |
| (including the stack pointer) may be changed. | |
| REGISTER FLAVOUR USE | |
| =============== ======= ============================================== | |
| GR1 Debug stack pointer | |
| GR16 GP-Rel base register for small data | |
| GR31 Current debug exception frame pointer | |
| (__debug_frame) | |
| SCR3 MMU Saved value of GR31 | |
| Note that debug mode is able to interfere with the kernel's emulated atomic | |
| ops, so it must be exceedingly careful not to do any that would interact | |
| with the main kernel in this regard. Hence the debug mode code (gdbstub) is | |
| almost completely self-contained. The only external code used is the | |
| sprintf family of functions. | |
| Furthermore, break.S is so complicated because single-step mode does not | |
| switch off on entry to an exception. That means unless manually disabled, | |
| single-stepping will blithely go on stepping into things like interrupts. | |
| See gdbstub.txt for more information. | |
| ========================== | |
| VIRTUAL INTERRUPT HANDLING | |
| ========================== | |
| Because accesses to the PSR is so slow, and to disable interrupts we have | |
| to access it twice (once to read and once to write), we don't actually | |
| disable interrupts at all if we don't have to. What we do instead is use | |
| the ICC2 condition code flags to note virtual disablement, such that if we | |
| then do take an interrupt, we note the flag, really disable interrupts, set | |
| another flag and resume execution at the point the interrupt happened. | |
| Setting condition flags as a side effect of an arithmetic or logical | |
| instruction is really fast. This use of the ICC2 only occurs within the | |
| kernel - it does not affect userspace. | |
| The flags we use are: | |
| (*) CCR.ICC2.Z [Zero flag] | |
| Set to virtually disable interrupts, clear when interrupts are | |
| virtually enabled. Can be modified by logical instructions without | |
| affecting the Carry flag. | |
| (*) CCR.ICC2.C [Carry flag] | |
| Clear to indicate hardware interrupts are really disabled, set otherwise. | |
| What happens is this: | |
| (1) Normal kernel-mode operation. | |
| ICC2.Z is 0, ICC2.C is 1. | |
| (2) An interrupt occurs. The exception prologue examines ICC2.Z and | |
| determines that nothing needs doing. This is done simply with an | |
| unlikely BEQ instruction. | |
| (3) The interrupts are disabled (local_irq_disable) | |
| ICC2.Z is set to 1. | |
| (4) If interrupts were then re-enabled (local_irq_enable): | |
| ICC2.Z would be set to 0. | |
| A TIHI #2 instruction (trap #2 if condition HI - Z==0 && C==0) would | |
| be used to trap if interrupts were now virtually enabled, but | |
| physically disabled - which they're not, so the trap isn't taken. The | |
| kernel would then be back to state (1). | |
| (5) An interrupt occurs. The exception prologue examines ICC2.Z and | |
| determines that the interrupt shouldn't actually have happened. It | |
| jumps aside, and there disabled interrupts by setting PSR.PIL to 14 | |
| and then it clears ICC2.C. | |
| (6) If interrupts were then saved and disabled again (local_irq_save): | |
| ICC2.Z would be shifted into the save variable and masked off | |
| (giving a 1). | |
| ICC2.Z would then be set to 1 (thus unchanged), and ICC2.C would be | |
| unaffected (ie: 0). | |
| (7) If interrupts were then restored from state (6) (local_irq_restore): | |
| ICC2.Z would be set to indicate the result of XOR'ing the saved | |
| value (ie: 1) with 1, which gives a result of 0 - thus leaving | |
| ICC2.Z set. | |
| ICC2.C would remain unaffected (ie: 0). | |
| A TIHI #2 instruction would be used to again assay the current state, | |
| but this would do nothing as Z==1. | |
| (8) If interrupts were then enabled (local_irq_enable): | |
| ICC2.Z would be cleared. ICC2.C would be left unaffected. Both | |
| flags would now be 0. | |
| A TIHI #2 instruction again issued to assay the current state would | |
| then trap as both Z==0 [interrupts virtually enabled] and C==0 | |
| [interrupts really disabled] would then be true. | |
| (9) The trap #2 handler would simply enable hardware interrupts | |
| (set PSR.PIL to 0), set ICC2.C to 1 and return. | |
| (10) Immediately upon returning, the pending interrupt would be taken. | |
| (11) The interrupt handler would take the path of actually processing the | |
| interrupt (ICC2.Z is clear, BEQ fails as per step (2)). | |
| (12) The interrupt handler would then set ICC2.C to 1 since hardware | |
| interrupts are definitely enabled - or else the kernel wouldn't be here. | |
| (13) On return from the interrupt handler, things would be back to state (1). | |
| This trap (#2) is only available in kernel mode. In user mode it will | |
| result in SIGILL. |