• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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