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 28use strict; 29 30my $flavour = shift; 31my $output = shift; 32if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } 33 34$0 =~ m/(.*[\/\\])[^\/\\]+$/; 35my $dir = $1; 36my $xlate; 37( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or 38( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or 39die "can't locate ppc-xlate.pl"; 40 41open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\""; 42*STDOUT = *OUT; 43 44unless ($flavour =~ /linux.*64le/) { 45 die "This file only supports the ELFv2 ABI, used by ppc64le"; 46} 47 48my $code = ""; 49 50sub 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 72sub load_regs { 73 my ($base_reg, $base_offset) = @_; 74 load_or_store_regs("l", $base_reg, $base_offset); 75} 76 77sub store_regs { 78 my ($base_reg, $base_offset) = @_; 79 load_or_store_regs("st", $base_reg, $base_offset); 80} 81 82my ($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 95abi_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. 126store_regs("r1", 48); 127# Load registers from the caller. 128load_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. 167store_regs($state, 0); 168# Restore registers from the stack. 169load_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. 184foreach (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 190abi_test_clobber_r$_: 191 li r$_, 0 192 blr 193.size abi_test_clobber_r$_,.-abi_test_clobber_r$_ 194____ 195} 196 197foreach (0..31) { 198 $code .= <<____; 199.globl abi_test_clobber_f$_ 200.align 4 201abi_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 211foreach (0..31) { 212 $code .= <<____; 213.globl abi_test_clobber_v$_ 214.align 4 215abi_test_clobber_v$_: 216 vxor v$_, v$_, v$_ 217 blr 218.size abi_test_clobber_v$_,.-abi_test_clobber_v$_ 219____ 220} 221 222foreach (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 229abi_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 243abi_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 251abi_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 261print $code; 262close STDOUT or die "error closing STDOUT: $!"; 263