| /* Low-level libffi support for Altera Nios II. | |
| Copyright (c) 2013 Mentor Graphics. | |
| Permission is hereby granted, free of charge, to any person obtaining | |
| a copy of this software and associated documentation files (the | |
| ``Software''), to deal in the Software without restriction, including | |
| without limitation the rights to use, copy, modify, merge, publish, | |
| distribute, sublicense, and/or sell copies of the Software, and to | |
| permit persons to whom the Software is furnished to do so, subject to | |
| the following conditions: | |
| The above copyright notice and this permission notice shall be | |
| included in all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, | |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ | |
| /* This function is declared on the C side as | |
| extern UINT64 ffi_call_sysv (void (*arghook) (char *, extended_cif *), | |
| extended_cif *ecif, | |
| unsigned nbytes, | |
| void (*fn) (void)); | |
| On input, the arguments appear as | |
| r4 = arghook | |
| r5 = ecif | |
| r6 = nbytes | |
| r7 = fn | |
| */ | |
| .section .text | |
| .align 2 | |
| .global ffi_call_sysv | |
| .type ffi_call_sysv, @function | |
| ffi_call_sysv: | |
| .cfi_startproc | |
| /* Create the stack frame, saving r16 so we can use it locally. */ | |
| addi sp, sp, -12 | |
| .cfi_def_cfa_offset 12 | |
| stw ra, 8(sp) | |
| stw fp, 4(sp) | |
| stw r16, 0(sp) | |
| .cfi_offset 31, -4 | |
| .cfi_offset 28, -8 | |
| .cfi_offset 16, -12 | |
| mov fp, sp | |
| .cfi_def_cfa_register 28 | |
| mov r16, r7 | |
| /* Adjust the stack pointer to create the argument buffer | |
| nbytes long. */ | |
| sub sp, sp, r6 | |
| /* Call the arghook function. */ | |
| mov r2, r4 /* fn */ | |
| mov r4, sp /* argbuffer */ | |
| callr r2 /* r5 already contains ecif */ | |
| /* Pop off the first 16 bytes of the argument buffer on the stack, | |
| transferring the contents to the argument registers. */ | |
| ldw r4, 0(sp) | |
| ldw r5, 4(sp) | |
| ldw r6, 8(sp) | |
| ldw r7, 12(sp) | |
| addi sp, sp, 16 | |
| /* Call the user function, which leaves its result in r2 and r3. */ | |
| callr r16 | |
| /* Pop off the stack frame. */ | |
| mov sp, fp | |
| ldw ra, 8(sp) | |
| ldw fp, 4(sp) | |
| ldw r16, 0(sp) | |
| addi sp, sp, 12 | |
| ret | |
| .cfi_endproc | |
| .size ffi_call_sysv, .-ffi_call_sysv | |
| /* Closure trampolines jump here after putting the C helper address | |
| in r9 and the closure pointer in r10. The user-supplied arguments | |
| to the closure are in the normal places, in r4-r7 and on the | |
| stack. Push the register arguments on the stack too and then call the | |
| C helper function to deal with them. */ | |
| .section .text | |
| .align 2 | |
| .global ffi_closure_sysv | |
| .type ffi_closure_sysv, @function | |
| ffi_closure_sysv: | |
| .cfi_startproc | |
| /* Create the stack frame, pushing the register args on the stack | |
| just below the stack args. This is the same trick illustrated | |
| in Figure 7-3 in the Nios II Processor Reference Handbook, used | |
| for variable arguments and structures passed by value. */ | |
| addi sp, sp, -20 | |
| .cfi_def_cfa_offset 20 | |
| stw ra, 0(sp) | |
| .cfi_offset 31, -20 | |
| stw r4, 4(sp) | |
| .cfi_offset 4, -16 | |
| stw r5, 8(sp) | |
| .cfi_offset 5, -12 | |
| stw r6, 12(sp) | |
| .cfi_offset 6, -8 | |
| stw r7, 16(sp) | |
| .cfi_offset 7, -4 | |
| /* Call the helper. | |
| r4 = pointer to arguments on stack | |
| r5 = closure pointer (loaded in r10 by the trampoline) | |
| r9 = address of helper function (loaded by trampoline) */ | |
| addi r4, sp, 4 | |
| mov r5, r10 | |
| callr r9 | |
| /* Pop the stack and return. */ | |
| ldw ra, 0(sp) | |
| addi sp, sp, 20 | |
| .cfi_def_cfa_offset -20 | |
| ret | |
| .cfi_endproc | |
| .size ffi_closure_sysv, .-ffi_closure_sysv | |