Tobias Thierer | 43be7d2 | 2020-03-02 19:23:34 +0000 | [diff] [blame] | 1 | #!/usr/bin/env perl |
| 2 | # Copyright (c) 2019, Google Inc. |
| 3 | # |
| 4 | # Permission to use, copy, modify, and/or distribute this software for any |
| 5 | # purpose with or without fee is hereby granted, provided that the above |
| 6 | # copyright notice and this permission notice appear in all copies. |
| 7 | # |
| 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 11 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 13 | # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 14 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | |
| 16 | # This file defines helper functions for crypto/test/abi_test.h on ppc64le. See |
| 17 | # that header for details on how to use this. |
| 18 | # |
| 19 | # For convenience, this file is linked into libcrypto, where consuming builds |
| 20 | # already support architecture-specific sources. The static linker should drop |
| 21 | # this code in non-test binaries. This includes a shared library build of |
| 22 | # libcrypto, provided --gc-sections or equivalent is used. |
| 23 | # |
| 24 | # References: |
| 25 | # |
| 26 | # ELFv2: http://openpowerfoundation.org/wp-content/uploads/resources/leabi/leabi-20170510.pdf |
| 27 | |
| 28 | use strict; |
| 29 | |
| 30 | my $flavour = shift; |
| 31 | my $output = shift; |
| 32 | if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } |
| 33 | |
| 34 | $0 =~ m/(.*[\/\\])[^\/\\]+$/; |
| 35 | my $dir = $1; |
| 36 | my $xlate; |
| 37 | ( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or |
| 38 | ( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or |
| 39 | die "can't locate ppc-xlate.pl"; |
| 40 | |
| 41 | open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\""; |
| 42 | *STDOUT = *OUT; |
| 43 | |
| 44 | unless ($flavour =~ /linux.*64le/) { |
| 45 | die "This file only supports the ELFv2 ABI, used by ppc64le"; |
| 46 | } |
| 47 | |
| 48 | my $code = ""; |
| 49 | |
| 50 | sub load_or_store_regs { |
| 51 | # $op is "l" or "st". |
| 52 | my ($op, $base_reg, $base_offset) = @_; |
| 53 | # Vector registers. |
| 54 | foreach (20..31) { |
| 55 | my $offset = $base_offset + ($_ - 20) * 16; |
| 56 | # Vector registers only support indexed register addressing. |
| 57 | $code .= "\tli\tr11, $offset\n"; |
| 58 | $code .= "\t${op}vx\tv$_, r11, $base_reg\n"; |
| 59 | } |
| 60 | # Save general registers. |
| 61 | foreach (14..31) { |
| 62 | my $offset = $base_offset + 192 + ($_ - 14) * 8; |
| 63 | $code .= "\t${op}d\tr$_, $offset($base_reg)\n"; |
| 64 | } |
| 65 | # Save floating point registers. |
| 66 | foreach (14..31) { |
| 67 | my $offset = $base_offset + 336 + ($_ - 14) * 8; |
| 68 | $code .= "\t${op}fd\tf$_, $offset($base_reg)\n"; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | sub load_regs { |
| 73 | my ($base_reg, $base_offset) = @_; |
| 74 | load_or_store_regs("l", $base_reg, $base_offset); |
| 75 | } |
| 76 | |
| 77 | sub store_regs { |
| 78 | my ($base_reg, $base_offset) = @_; |
| 79 | load_or_store_regs("st", $base_reg, $base_offset); |
| 80 | } |
| 81 | |
| 82 | my ($func, $state, $argv, $argc) = ("r3", "r4", "r5", "r6"); |
| 83 | $code .= <<____; |
| 84 | .machine "any" |
| 85 | .text |
| 86 | |
| 87 | # abi_test_trampoline loads callee-saved registers from |state|, calls |func| |
| 88 | # with |argv|, then saves the callee-saved registers into |state|. It returns |
| 89 | # the result of |func|. The |unwind| argument is unused. |
| 90 | # uint64_t abi_test_trampoline(void (*func)(...), CallerState *state, |
| 91 | # const uint64_t *argv, size_t argc, |
| 92 | # uint64_t unwind); |
| 93 | .globl abi_test_trampoline |
| 94 | .align 5 |
| 95 | abi_test_trampoline: |
| 96 | # LR is saved into the caller's stack frame. |
| 97 | mflr r0 |
| 98 | std r0, 16(r1) |
| 99 | |
| 100 | # Allocate 66*8 = 528 bytes of stack frame. From the top of the stack |
| 101 | # to the bottom, the stack frame is: |
| 102 | # |
| 103 | # 0(r1) - Back chain pointer |
| 104 | # 8(r1) - CR save area |
| 105 | # 16(r1) - LR save area (for |func|) |
| 106 | # 24(r1) - TOC pointer save area |
| 107 | # 32(r1) - Saved copy of |state| |
| 108 | # 40(r1) - Padding |
| 109 | # 48(r1) - Vector register save area (v20-v31, 12 registers) |
| 110 | # 240(r1) - General register save area (r14-r31, 18 registers) |
| 111 | # 384(r1) - Floating point register save area (f14-f31, 18 registers) |
| 112 | # |
| 113 | # Note the layouts of the register save areas and CallerState match. |
| 114 | # |
| 115 | # In the ELFv2 ABI, the parameter save area is optional if the function |
| 116 | # is non-variadic and all parameters fit in registers. We only support |
| 117 | # such functions, so we omit it to test that |func| does not rely on it. |
| 118 | stdu r1, -528(r1) |
| 119 | |
| 120 | mfcr r0 |
| 121 | std r0, 8(r1) # Save CR |
| 122 | std r2, 24(r1) # Save TOC |
| 123 | std $state, 32(r1) # Save |state| |
| 124 | ____ |
| 125 | # Save registers to the stack. |
| 126 | store_regs("r1", 48); |
| 127 | # Load registers from the caller. |
| 128 | load_regs($state, 0); |
| 129 | $code .= <<____; |
| 130 | # Load CR from |state|. |
| 131 | ld r0, 480($state) |
| 132 | mtcr r0 |
| 133 | |
| 134 | # Move parameters into temporary registers so they are not clobbered. |
| 135 | addi r11, $argv, -8 # Adjust for ldu below |
| 136 | mr r12, $func |
| 137 | |
| 138 | # Load parameters into registers. |
| 139 | cmpdi $argc, 0 |
| 140 | beq .Largs_done |
| 141 | mtctr $argc |
| 142 | ldu r3, 8(r11) |
| 143 | bdz .Largs_done |
| 144 | ldu r4, 8(r11) |
| 145 | bdz .Largs_done |
| 146 | ldu r5, 8(r11) |
| 147 | bdz .Largs_done |
| 148 | ldu r6, 8(r11) |
| 149 | bdz .Largs_done |
| 150 | ldu r7, 8(r11) |
| 151 | bdz .Largs_done |
| 152 | ldu r8, 8(r11) |
| 153 | bdz .Largs_done |
| 154 | ldu r9, 8(r11) |
| 155 | bdz .Largs_done |
| 156 | ldu r10, 8(r11) |
| 157 | |
| 158 | .Largs_done: |
| 159 | li r2, 0 # Clear TOC to test |func|'s global entry point |
| 160 | mtctr r12 |
| 161 | bctrl |
| 162 | ld r2, 24(r1) # Restore TOC |
| 163 | |
| 164 | ld $state, 32(r1) # Reload |state| |
| 165 | ____ |
| 166 | # Output resulting registers to the caller. |
| 167 | store_regs($state, 0); |
| 168 | # Restore registers from the stack. |
| 169 | load_regs("r1", 48); |
| 170 | $code .= <<____; |
| 171 | mfcr r0 |
| 172 | std r0, 480($state) # Output CR to caller |
| 173 | ld r0, 8(r1) |
| 174 | mtcrf 0b00111000, r0 # Restore CR2-CR4 |
| 175 | addi r1, r1, 528 |
| 176 | ld r0, 16(r1) # Restore LR |
| 177 | mtlr r0 |
| 178 | blr |
| 179 | .size abi_test_trampoline,.-abi_test_trampoline |
| 180 | ____ |
| 181 | |
| 182 | # abi_test_clobber_* clobbers the corresponding register. These are used to test |
| 183 | # the ABI-testing framework. |
| 184 | foreach (0..31) { |
| 185 | # r1 is the stack pointer. r13 is the thread pointer. |
| 186 | next if ($_ == 1 || $_ == 13); |
| 187 | $code .= <<____; |
| 188 | .globl abi_test_clobber_r$_ |
| 189 | .align 5 |
| 190 | abi_test_clobber_r$_: |
| 191 | li r$_, 0 |
| 192 | blr |
| 193 | .size abi_test_clobber_r$_,.-abi_test_clobber_r$_ |
| 194 | ____ |
| 195 | } |
| 196 | |
| 197 | foreach (0..31) { |
| 198 | $code .= <<____; |
| 199 | .globl abi_test_clobber_f$_ |
| 200 | .align 4 |
| 201 | abi_test_clobber_f$_: |
| 202 | li r0, 0 |
| 203 | # Use the red zone. |
| 204 | std r0, -8(r1) |
| 205 | lfd f$_, -8(r1) |
| 206 | blr |
| 207 | .size abi_test_clobber_f$_,.-abi_test_clobber_f$_ |
| 208 | ____ |
| 209 | } |
| 210 | |
| 211 | foreach (0..31) { |
| 212 | $code .= <<____; |
| 213 | .globl abi_test_clobber_v$_ |
| 214 | .align 4 |
| 215 | abi_test_clobber_v$_: |
| 216 | vxor v$_, v$_, v$_ |
| 217 | blr |
| 218 | .size abi_test_clobber_v$_,.-abi_test_clobber_v$_ |
| 219 | ____ |
| 220 | } |
| 221 | |
| 222 | foreach (0..7) { |
| 223 | # PPC orders CR fields in big-endian, so the mask is reversed from what one |
| 224 | # would expect. |
| 225 | my $mask = 1 << (7 - $_); |
| 226 | $code .= <<____; |
| 227 | .globl abi_test_clobber_cr$_ |
| 228 | .align 4 |
| 229 | abi_test_clobber_cr$_: |
| 230 | # Flip the bits on cr$_ rather than setting to zero. With a four-bit |
| 231 | # register, zeroing it will do nothing 1 in 16 times. |
| 232 | mfcr r0 |
| 233 | not r0, r0 |
| 234 | mtcrf $mask, r0 |
| 235 | blr |
| 236 | .size abi_test_clobber_cr$_,.-abi_test_clobber_cr$_ |
| 237 | ____ |
| 238 | } |
| 239 | |
| 240 | $code .= <<____; |
| 241 | .globl abi_test_clobber_ctr |
| 242 | .align 4 |
| 243 | abi_test_clobber_ctr: |
| 244 | li r0, 0 |
| 245 | mtctr r0 |
| 246 | blr |
| 247 | .size abi_test_clobber_ctr,.-abi_test_clobber_ctr |
| 248 | |
| 249 | .globl abi_test_clobber_lr |
| 250 | .align 4 |
| 251 | abi_test_clobber_lr: |
| 252 | mflr r0 |
| 253 | mtctr r0 |
| 254 | li r0, 0 |
| 255 | mtlr r0 |
| 256 | bctr |
| 257 | .size abi_test_clobber_lr,.-abi_test_clobber_lr |
| 258 | |
| 259 | ____ |
| 260 | |
| 261 | print $code; |
Pete Bentley | 2f26c21 | 2021-10-01 11:32:03 +0000 | [diff] [blame] | 262 | close STDOUT or die "error closing STDOUT: $!"; |