| /* ----------------------------------------------------------------------- |
| sysv.S - Copyright (c) 1998 Geoffrey Keating |
| Copyright (C) 2007 Free Software Foundation, Inc |
| |
| PowerPC Assembly glue. |
| |
| 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. |
| ----------------------------------------------------------------------- */ |
| |
| #define LIBFFI_ASM |
| #include <fficonfig.h> |
| #include <ffi.h> |
| #include <powerpc/asm.h> |
| |
| #ifndef POWERPC64 |
| FFI_HIDDEN(ffi_call_SYSV) |
| ENTRY(ffi_call_SYSV) |
| .cfi_startproc |
| /* Save the old stack pointer as AP. */ |
| mr %r10,%r1 |
| .cfi_def_cfa_register 10 |
| |
| /* Allocate the stack space we need. */ |
| stwux %r1,%r1,%r8 |
| /* Save registers we use. */ |
| mflr %r9 |
| stw %r28,-16(%r10) |
| stw %r29,-12(%r10) |
| stw %r30, -8(%r10) |
| stw %r31, -4(%r10) |
| stw %r9, 4(%r10) |
| .cfi_offset 65, 4 |
| .cfi_offset 31, -4 |
| .cfi_offset 30, -8 |
| .cfi_offset 29, -12 |
| .cfi_offset 28, -16 |
| |
| /* Save arguments over call... */ |
| stw %r7, -20(%r10) /* closure, */ |
| mr %r31,%r6 /* flags, */ |
| mr %r30,%r5 /* rvalue, */ |
| mr %r29,%r4 /* function address, */ |
| mr %r28,%r10 /* our AP. */ |
| .cfi_def_cfa_register 28 |
| |
| /* Call ffi_prep_args_SYSV. */ |
| mr %r4,%r1 |
| bl ffi_prep_args_SYSV@local |
| |
| /* Now do the call. */ |
| /* Set up cr1 with bits 4-7 of the flags. */ |
| mtcrf 0x40,%r31 |
| /* Get the address to call into CTR. */ |
| mtctr %r29 |
| /* Load all those argument registers. */ |
| lwz %r3,-24-(8*4)(%r28) |
| lwz %r4,-24-(7*4)(%r28) |
| lwz %r5,-24-(6*4)(%r28) |
| lwz %r6,-24-(5*4)(%r28) |
| bf- 5,1f |
| nop |
| lwz %r7,-24-(4*4)(%r28) |
| lwz %r8,-24-(3*4)(%r28) |
| lwz %r9,-24-(2*4)(%r28) |
| lwz %r10,-24-(1*4)(%r28) |
| nop |
| 1: |
| |
| #ifndef __NO_FPRS__ |
| /* Load all the FP registers. */ |
| bf- 6,2f |
| lfd %f1,-24-(8*4)-(8*8)(%r28) |
| lfd %f2,-24-(8*4)-(7*8)(%r28) |
| lfd %f3,-24-(8*4)-(6*8)(%r28) |
| lfd %f4,-24-(8*4)-(5*8)(%r28) |
| nop |
| lfd %f5,-24-(8*4)-(4*8)(%r28) |
| lfd %f6,-24-(8*4)-(3*8)(%r28) |
| lfd %f7,-24-(8*4)-(2*8)(%r28) |
| lfd %f8,-24-(8*4)-(1*8)(%r28) |
| #endif |
| 2: |
| |
| /* Make the call. */ |
| lwz %r11, -20(%r28) |
| bctrl |
| |
| /* Now, deal with the return value. */ |
| mtcrf 0x03,%r31 /* cr6-cr7 */ |
| bt- 31,L(small_struct_return_value) |
| bt- 30,L(done_return_value) |
| #ifndef __NO_FPRS__ |
| bt- 29,L(fp_return_value) |
| #endif |
| stw %r3,0(%r30) |
| bf+ 27,L(done_return_value) |
| stw %r4,4(%r30) |
| bf 26,L(done_return_value) |
| stw %r5,8(%r30) |
| stw %r6,12(%r30) |
| /* Fall through... */ |
| |
| L(done_return_value): |
| /* Restore the registers we used and return. */ |
| lwz %r9, 4(%r28) |
| lwz %r31, -4(%r28) |
| mtlr %r9 |
| lwz %r30, -8(%r28) |
| lwz %r29,-12(%r28) |
| lwz %r28,-16(%r28) |
| .cfi_remember_state |
| /* At this point we don't have a cfa register. Say all our |
| saved regs have been restored. */ |
| .cfi_same_value 65 |
| .cfi_same_value 31 |
| .cfi_same_value 30 |
| .cfi_same_value 29 |
| .cfi_same_value 28 |
| /* Hopefully this works.. */ |
| .cfi_def_cfa_register 1 |
| .cfi_offset 1, 0 |
| lwz %r1,0(%r1) |
| .cfi_same_value 1 |
| blr |
| |
| #ifndef __NO_FPRS__ |
| L(fp_return_value): |
| .cfi_restore_state |
| bf 27,L(float_return_value) |
| stfd %f1,0(%r30) |
| bf 26,L(done_return_value) |
| stfd %f2,8(%r30) |
| b L(done_return_value) |
| L(float_return_value): |
| stfs %f1,0(%r30) |
| b L(done_return_value) |
| #endif |
| |
| L(small_struct_return_value): |
| /* |
| * The C code always allocates a properly-aligned 8-byte bounce |
| * buffer to make this assembly code very simple. Just write out |
| * r3 and r4 to the buffer to allow the C code to handle the rest. |
| */ |
| stw %r3, 0(%r30) |
| stw %r4, 4(%r30) |
| b L(done_return_value) |
| .cfi_endproc |
| |
| END(ffi_call_SYSV) |
| |
| #if defined __ELF__ && defined __linux__ |
| .section .note.GNU-stack,"",@progbits |
| #endif |
| #endif |