| ========================== | |
| KERNEL ABIS FOR METAG ARCH | |
| ========================== | |
| This document describes the Linux ABIs for the metag architecture, and has the | |
| following sections: | |
| (*) Outline of registers | |
| (*) Userland registers | |
| (*) Kernel registers | |
| (*) System call ABI | |
| (*) Calling conventions | |
| ==================== | |
| OUTLINE OF REGISTERS | |
| ==================== | |
| The main Meta core registers are arranged in units: | |
| UNIT Type DESCRIPTION GP EXT PRIV GLOBAL | |
| ======= ======= =============== ======= ======= ======= ======= | |
| CT Special Control unit | |
| D0 General Data unit 0 0-7 8-15 16-31 16-31 | |
| D1 General Data unit 1 0-7 8-15 16-31 16-31 | |
| A0 General Address unit 0 0-3 4-7 8-15 8-15 | |
| A1 General Address unit 1 0-3 4-7 8-15 8-15 | |
| PC Special PC unit 0 1 | |
| PORT Special Ports | |
| TR Special Trigger unit 0-7 | |
| TT Special Trace unit 0-5 | |
| FX General FP unit 0-15 | |
| GP registers form part of the main context. | |
| Extended context registers (EXT) may not be present on all hardware threads and | |
| can be context switched if support is enabled and the appropriate bits are set | |
| in e.g. the D0.8 register to indicate what extended state to preserve. | |
| Global registers are shared between threads and are privilege protected. | |
| See arch/metag/include/asm/metag_regs.h for definitions relating to core | |
| registers and the fields and bits they contain. See the TRMs for further details | |
| about special registers. | |
| Several special registers are preserved in the main context, these are the | |
| interesting ones: | |
| REG (ALIAS) PURPOSE | |
| ======================= =============================================== | |
| CT.1 (TXMODE) Processor mode bits (particularly for DSP) | |
| CT.2 (TXSTATUS) Condition flags and LSM_STEP (MGET/MSET step) | |
| CT.3 (TXRPT) Branch repeat counter | |
| PC.0 (PC) Program counter | |
| Some of the general registers have special purposes in the ABI and therefore | |
| have aliases: | |
| D0 REG (ALIAS) PURPOSE D1 REG (ALIAS) PURPOSE | |
| =============== =============== =============== ======================= | |
| D0.0 (D0Re0) 32bit result D1.0 (D1Re0) Top half of 64bit result | |
| D0.1 (D0Ar6) Argument 6 D1.1 (D1Ar5) Argument 5 | |
| D0.2 (D0Ar4) Argument 4 D1.2 (D1Ar3) Argument 3 | |
| D0.3 (D0Ar2) Argument 2 D1.3 (D1Ar1) Argument 1 | |
| D0.4 (D0FrT) Frame temp D1.4 (D1RtP) Return pointer | |
| D0.5 Call preserved D1.5 Call preserved | |
| D0.6 Call preserved D1.6 Call preserved | |
| D0.7 Call preserved D1.7 Call preserved | |
| A0 REG (ALIAS) PURPOSE A1 REG (ALIAS) PURPOSE | |
| =============== =============== =============== ======================= | |
| A0.0 (A0StP) Stack pointer A1.0 (A1GbP) Global base pointer | |
| A0.1 (A0FrP) Frame pointer A1.1 (A1LbP) Local base pointer | |
| A0.2 A1.2 | |
| A0.3 A1.3 | |
| ================== | |
| USERLAND REGISTERS | |
| ================== | |
| All the general purpose D0, D1, A0, A1 registers are preserved when entering the | |
| kernel (including asynchronous events such as interrupts and timer ticks) except | |
| the following which have special purposes in the ABI: | |
| REGISTERS WHEN STATUS PURPOSE | |
| =============== ======= =============== =============================== | |
| D0.8 DSP Preserved ECH, determines what extended | |
| DSP state to preserve. | |
| A0.0 (A0StP) ALWAYS Preserved Stack >= A0StP may be clobbered | |
| at any time by the creation of a | |
| signal frame. | |
| A1.0 (A1GbP) SMP Clobbered Used as temporary for loading | |
| kernel stack pointer and saving | |
| core context. | |
| A0.15 !SMP Protected Stores kernel stack pointer. | |
| A1.15 ALWAYS Protected Stores kernel base pointer. | |
| On UP A0.15 is used to store the kernel stack pointer for storing the userland | |
| context. A0.15 is global between hardware threads though which means it cannot | |
| be used on SMP for this purpose. Since no protected local registers are | |
| available A1GbP is reserved for use as a temporary to allow a percpu stack | |
| pointer to be loaded for storing the rest of the context. | |
| ================ | |
| KERNEL REGISTERS | |
| ================ | |
| When in the kernel the following registers have special purposes in the ABI: | |
| REGISTERS WHEN STATUS PURPOSE | |
| =============== ======= =============== =============================== | |
| A0.0 (A0StP) ALWAYS Preserved Stack >= A0StP may be clobbered | |
| at any time by the creation of | |
| an irq signal frame. | |
| A1.0 (A1GbP) ALWAYS Preserved Reserved (kernel base pointer). | |
| =============== | |
| SYSTEM CALL ABI | |
| =============== | |
| When a system call is made, the following registers are effective: | |
| REGISTERS CALL RETURN | |
| =============== ======================= =============================== | |
| D0.0 (D0Re0) Return value (or -errno) | |
| D1.0 (D1Re0) System call number Clobbered | |
| D0.1 (D0Ar6) Syscall arg #6 Preserved | |
| D1.1 (D1Ar5) Syscall arg #5 Preserved | |
| D0.2 (D0Ar4) Syscall arg #4 Preserved | |
| D1.2 (D1Ar3) Syscall arg #3 Preserved | |
| D0.3 (D0Ar2) Syscall arg #2 Preserved | |
| D1.3 (D1Ar1) Syscall arg #1 Preserved | |
| Due to the limited number of argument registers and some system calls with badly | |
| aligned 64-bit arguments, 64-bit values are always packed in consecutive | |
| arguments, even if this is contrary to the normal calling conventions (where the | |
| two halves would go in a matching pair of data registers). | |
| For example fadvise64_64 usually has the signature: | |
| long sys_fadvise64_64(i32 fd, i64 offs, i64 len, i32 advice); | |
| But for metag fadvise64_64 is wrapped so that the 64-bit arguments are packed: | |
| long sys_fadvise64_64_metag(i32 fd, i32 offs_lo, | |
| i32 offs_hi, i32 len_lo, | |
| i32 len_hi, i32 advice) | |
| So the arguments are packed in the registers like this: | |
| D0 REG (ALIAS) VALUE D1 REG (ALIAS) VALUE | |
| =============== =============== =============== ======================= | |
| D0.1 (D0Ar6) advice D1.1 (D1Ar5) hi(len) | |
| D0.2 (D0Ar4) lo(len) D1.2 (D1Ar3) hi(offs) | |
| D0.3 (D0Ar2) lo(offs) D1.3 (D1Ar1) fd | |
| =================== | |
| CALLING CONVENTIONS | |
| =================== | |
| These calling conventions apply to both user and kernel code. The stack grows | |
| from low addresses to high addresses in the metag ABI. The stack pointer (A0StP) | |
| should always point to the next free address on the stack and should at all | |
| times be 64-bit aligned. The following registers are effective at the point of a | |
| call: | |
| REGISTERS CALL RETURN | |
| =============== ======================= =============================== | |
| D0.0 (D0Re0) 32bit return value | |
| D1.0 (D1Re0) Upper half of 64bit return value | |
| D0.1 (D0Ar6) 32bit argument #6 Clobbered | |
| D1.1 (D1Ar5) 32bit argument #5 Clobbered | |
| D0.2 (D0Ar4) 32bit argument #4 Clobbered | |
| D1.2 (D1Ar3) 32bit argument #3 Clobbered | |
| D0.3 (D0Ar2) 32bit argument #2 Clobbered | |
| D1.3 (D1Ar1) 32bit argument #1 Clobbered | |
| D0.4 (D0FrT) Clobbered | |
| D1.4 (D1RtP) Return pointer Clobbered | |
| D{0-1}.{5-7} Preserved | |
| A0.0 (A0StP) Stack pointer Preserved | |
| A1.0 (A0GbP) Preserved | |
| A0.1 (A0FrP) Frame pointer Preserved | |
| A1.1 (A0LbP) Preserved | |
| A{0-1},{2-3} Clobbered | |
| 64-bit arguments are placed in matching pairs of registers (i.e. the same | |
| register number in both D0 and D1 units), with the least significant half in D0 | |
| and the most significant half in D1, leaving a gap where necessary. Further | |
| arguments are stored on the stack in reverse order (earlier arguments at higher | |
| addresses): | |
| ADDRESS 0 1 2 3 4 5 6 7 | |
| =============== ===== ===== ===== ===== ===== ===== ===== ===== | |
| A0StP --> | |
| A0StP-0x08 32bit argument #8 32bit argument #7 | |
| A0StP-0x10 32bit argument #10 32bit argument #9 | |
| Function prologues tend to look a bit like this: | |
| /* If frame pointer in use, move it to frame temp register so it can be | |
| easily pushed onto stack */ | |
| MOV D0FrT,A0FrP | |
| /* If frame pointer in use, set it to stack pointer */ | |
| ADD A0FrP,A0StP,#0 | |
| /* Preserve D0FrT, D1RtP, D{0-1}.{5-7} on stack, incrementing A0StP */ | |
| MSETL [A0StP++],D0FrT,D0.5,D0.6,D0.7 | |
| /* Allocate some stack space for local variables */ | |
| ADD A0StP,A0StP,#0x10 | |
| At this point the stack would look like this: | |
| ADDRESS 0 1 2 3 4 5 6 7 | |
| =============== ===== ===== ===== ===== ===== ===== ===== ===== | |
| A0StP --> | |
| A0StP-0x08 | |
| A0StP-0x10 | |
| A0StP-0x18 Old D0.7 Old D1.7 | |
| A0StP-0x20 Old D0.6 Old D1.6 | |
| A0StP-0x28 Old D0.5 Old D1.5 | |
| A0FrP --> Old A0FrP (frame ptr) Old D1RtP (return ptr) | |
| A0FrP-0x08 32bit argument #8 32bit argument #7 | |
| A0FrP-0x10 32bit argument #10 32bit argument #9 | |
| Function epilogues tend to differ depending on the use of a frame pointer. An | |
| example of a frame pointer epilogue: | |
| /* Restore D0FrT, D1RtP, D{0-1}.{5-7} from stack, incrementing A0FrP */ | |
| MGETL D0FrT,D0.5,D0.6,D0.7,[A0FrP++] | |
| /* Restore stack pointer to where frame pointer was before increment */ | |
| SUB A0StP,A0FrP,#0x20 | |
| /* Restore frame pointer from frame temp */ | |
| MOV A0FrP,D0FrT | |
| /* Return to caller via restored return pointer */ | |
| MOV PC,D1RtP | |
| If the function hasn't touched the frame pointer, MGETL cannot be safely used | |
| with A0StP as it always increments and that would expose the stack to clobbering | |
| by interrupts (kernel) or signals (user). Therefore it's common to see the MGETL | |
| split into separate GETL instructions: | |
| /* Restore D0FrT, D1RtP, D{0-1}.{5-7} from stack */ | |
| GETL D0FrT,D1RtP,[A0StP+#-0x30] | |
| GETL D0.5,D1.5,[A0StP+#-0x28] | |
| GETL D0.6,D1.6,[A0StP+#-0x20] | |
| GETL D0.7,D1.7,[A0StP+#-0x18] | |
| /* Restore stack pointer */ | |
| SUB A0StP,A0StP,#0x30 | |
| /* Return to caller via restored return pointer */ | |
| MOV PC,D1RtP |