| /* |
| * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org> |
| * |
| * 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. |
| */ |
| |
| /* |
| * vax Foreign Function Interface |
| */ |
| |
| #define LIBFFI_ASM |
| #include <fficonfig.h> |
| #include <ffi.h> |
| |
| .text |
| |
| /* |
| * void * %r0 |
| * ffi_call_elfbsd(extended_cif *ecif, 4(%ap) |
| * unsigned bytes, 8(%ap) |
| * unsigned flags, 12(%ap) |
| * void *rvalue, 16(%ap) |
| * void (*fn)()); 20(%ap) |
| */ |
| .globl ffi_call_elfbsd |
| .type ffi_call_elfbsd,@function |
| .align 2 |
| ffi_call_elfbsd: |
| .word 0x00c # save R2 and R3 |
| |
| # Allocate stack space for the args |
| subl2 8(%ap), %sp |
| |
| # Call ffi_prep_args |
| pushl %sp |
| pushl 4(%ap) |
| calls $2, ffi_prep_args |
| |
| # Get function pointer |
| movl 20(%ap), %r1 |
| |
| # Build a CALLS frame |
| ashl $-2, 8(%ap), %r0 |
| pushl %r0 # argument stack usage |
| movl %sp, %r0 # future %ap |
| # saved registers |
| bbc $11, 0(%r1), 1f |
| pushl %r11 |
| 1: bbc $10, 0(%r1), 1f |
| pushl %r10 |
| 1: bbc $9, 0(%r1), 1f |
| pushl %r9 |
| 1: bbc $8, 0(%r1), 1f |
| pushl %r8 |
| 1: bbc $7, 0(%r1), 1f |
| pushl %r7 |
| 1: bbc $6, 0(%r1), 1f |
| pushl %r6 |
| 1: bbc $5, 0(%r1), 1f |
| pushl %r5 |
| 1: bbc $4, 0(%r1), 1f |
| pushl %r4 |
| 1: bbc $3, 0(%r1), 1f |
| pushl %r3 |
| 1: bbc $2, 0(%r1), 1f |
| pushl %r2 |
| 1: |
| pushal 9f |
| pushl %fp |
| pushl %ap |
| movl 16(%ap), %r3 # struct return address, if needed |
| movl %r0, %ap |
| movzwl 4(%fp), %r0 # previous PSW, without the saved registers mask |
| bisl2 $0x20000000, %r0 # calls frame |
| movzwl 0(%r1), %r2 |
| bicw2 $0xf003, %r2 # only keep R11-R2 |
| ashl $16, %r2, %r2 |
| bisl2 %r2, %r0 # saved register mask of the called function |
| pushl %r0 |
| pushl $0 |
| movl %sp, %fp |
| |
| # Invoke the function |
| pushal 2(%r1) # skip procedure entry mask |
| movl %r3, %r1 |
| bicpsw $0x000f |
| rsb |
| |
| 9: |
| # Copy return value if necessary |
| tstl 16(%ap) |
| jeql 9f |
| movl 16(%ap), %r2 |
| |
| bbc $0, 12(%ap), 1f # CIF_FLAGS_CHAR |
| movb %r0, 0(%r2) |
| brb 9f |
| 1: |
| bbc $1, 12(%ap), 1f # CIF_FLAGS_SHORT |
| movw %r0, 0(%r2) |
| brb 9f |
| 1: |
| bbc $2, 12(%ap), 1f # CIF_FLAGS_INT |
| movl %r0, 0(%r2) |
| brb 9f |
| 1: |
| bbc $3, 12(%ap), 1f # CIF_FLAGS_DINT |
| movq %r0, 0(%r2) |
| brb 9f |
| 1: |
| movl %r1, %r0 # might have been a struct |
| #brb 9f |
| |
| 9: |
| ret |
| |
| /* |
| * ffi_closure_elfbsd(void); |
| * invoked with %r0: ffi_closure *closure |
| */ |
| .globl ffi_closure_elfbsd |
| .type ffi_closure_elfbsd, @function |
| .align 2 |
| ffi_closure_elfbsd: |
| .word 0 |
| |
| # Allocate room on stack for return value |
| subl2 $8, %sp |
| |
| # Invoke the closure function |
| pushal 4(%ap) # calling stack |
| pushal 4(%sp) # return value |
| pushl %r0 # closure |
| calls $3, ffi_closure_elfbsd_inner |
| |
| # Copy return value if necessary |
| bitb $1, %r0 # CIF_FLAGS_CHAR |
| beql 1f |
| movb 0(%sp), %r0 |
| brb 9f |
| 1: |
| bitb $2, %r0 # CIF_FLAGS_SHORT |
| beql 1f |
| movw 0(%sp), %r0 |
| brb 9f |
| 1: |
| bitb $4, %r0 # CIF_FLAGS_INT |
| beql 1f |
| movl 0(%sp), %r0 |
| brb 9f |
| 1: |
| bitb $8, %r0 # CIF_FLAGS_DINT |
| beql 1f |
| movq 0(%sp), %r0 |
| #brb 9f |
| 1: |
| |
| 9: |
| ret |
| |
| /* |
| * ffi_closure_struct_elfbsd(void); |
| * invoked with %r0: ffi_closure *closure |
| * %r1: struct return address |
| */ |
| .globl ffi_closure_struct_elfbsd |
| .type ffi_closure_struct_elfbsd, @function |
| .align 2 |
| ffi_closure_struct_elfbsd: |
| .word 0 |
| |
| # Invoke the closure function |
| pushal 4(%ap) # calling stack |
| pushl %r1 # return value |
| pushl %r0 # closure |
| calls $3, ffi_closure_elfbsd_inner |
| |
| ret |