1*56726c7eSRobert Mustacchi#!/usr/bin/ksh
2*56726c7eSRobert Mustacchi#
3*56726c7eSRobert Mustacchi#
4*56726c7eSRobert Mustacchi# This file and its contents are supplied under the terms of the
5*56726c7eSRobert Mustacchi# Common Development and Distribution License ("CDDL"), version 1.0.
6*56726c7eSRobert Mustacchi# You may only use this file in accordance with the terms of version
7*56726c7eSRobert Mustacchi# 1.0 of the CDDL.
8*56726c7eSRobert Mustacchi#
9*56726c7eSRobert Mustacchi# A full copy of the text of the CDDL should have accompanied this
10*56726c7eSRobert Mustacchi# souroc.  A copy of the CDDL is also available via the Internet at
11*56726c7eSRobert Mustacchi# http://www.illumos.org/liocnse/CDDL.
12*56726c7eSRobert Mustacchi#
13*56726c7eSRobert Mustacchi
14*56726c7eSRobert Mustacchi#
15*56726c7eSRobert Mustacchi# Copyright 2022 Oxide Computer Company
16*56726c7eSRobert Mustacchi#
17*56726c7eSRobert Mustacchi
18*56726c7eSRobert Mustacchi#
19*56726c7eSRobert Mustacchi# This test generates a binary with a lot of different symbol capabilities and
20*56726c7eSRobert Mustacchi# then selects different capability environments to try and ensure that the
21*56726c7eSRobert Mustacchi# rules for what we pick are honored.
22*56726c7eSRobert Mustacchi#
23*56726c7eSRobert Mustacchi
24*56726c7eSRobert Mustacchiexport LC_ALL=C.UTF-8
25*56726c7eSRobert Mustacchiunalias -a
26*56726c7eSRobert Mustacchiset -o pipefail
27*56726c7eSRobert Mustacchi
28*56726c7eSRobert Mustacchisc_arg0=$(basename $0)
29*56726c7eSRobert Mustacchisc_err=0
30*56726c7eSRobert Mustacchisc_tmpdir=/tmp/symcap.$$
31*56726c7eSRobert Mustacchisc_prog="$sc_tmpdir/symcap"
32*56726c7eSRobert Mustacchi
33*56726c7eSRobert Mustacchi#
34*56726c7eSRobert Mustacchi# To build symbol caps, we need to annotate a .o file with object caps and then
35*56726c7eSRobert Mustacchi# turn that into a symbol cap with ld. The following arrays are used to create
36*56726c7eSRobert Mustacchi# this for us. sc_obj_hw1, sc_obj_hw2, and sc_obj_hw3 are the set of object
37*56726c7eSRobert Mustacchi# capabilities that we want to use and then eventually turn into symbol
38*56726c7eSRobert Mustacchi# capabilities. Each symbol capability prints out its own index when executed.
39*56726c7eSRobert Mustacchi# This means we can see which thing ld resolved to run based on the output.
40*56726c7eSRobert Mustacchi# The following summarizes our goals with each case:
41*56726c7eSRobert Mustacchi#
42*56726c7eSRobert Mustacchi# 0: none
43*56726c7eSRobert Mustacchi# 1: only hwcap 1
44*56726c7eSRobert Mustacchi# 2: only hwcap 1, but greater than (1)
45*56726c7eSRobert Mustacchi# 3: only hwcap 2
46*56726c7eSRobert Mustacchi# 4: only hwcap 2, but greater than (3)
47*56726c7eSRobert Mustacchi# 5: only hwcap 3
48*56726c7eSRobert Mustacchi# 6: only hwcap 3, but greater than (5)
49*56726c7eSRobert Mustacchi# 7: uses all 3
50*56726c7eSRobert Mustacchi# 8: differs from (7) in hwcap1
51*56726c7eSRobert Mustacchi#
52*56726c7eSRobert Mustacchisc_obj_hw1=( "0x0" "0x5" "0x42" "0x0"  "0x0"    "0x0"     "0x0"
53*56726c7eSRobert Mustacchi     "0x3"       "0x8" )
54*56726c7eSRobert Mustacchisc_obj_hw2=( "0x0" "0x0" "0x0"  "0x23" "0xff00" "0x0"     "0x0"
55*56726c7eSRobert Mustacchi    "0xff7ff6"   "0xff7ff6" )
56*56726c7eSRobert Mustacchisc_obj_hw3=( "0x0" "0x0" "0x0"  "0x0"  "0x0"    "0x12345" "0x7000000"
57*56726c7eSRobert Mustacchi    "0x87654321" "0x87654321" )
58*56726c7eSRobert Mustacchi
59*56726c7eSRobert Mustacchipass()
60*56726c7eSRobert Mustacchi{
61*56726c7eSRobert Mustacchi        typeset msg="$*"
62*56726c7eSRobert Mustacchi	echo "TEST PASSED: $msg"
63*56726c7eSRobert Mustacchi}
64*56726c7eSRobert Mustacchi
65*56726c7eSRobert Mustacchiwarn()
66*56726c7eSRobert Mustacchi{
67*56726c7eSRobert Mustacchi        typeset msg="$*"
68*56726c7eSRobert Mustacchi        [[ -z "$msg" ]] && msg="failed"
69*56726c7eSRobert Mustacchi        echo "TEST FAILED: $msg" >&2
70*56726c7eSRobert Mustacchi	sc_err=1
71*56726c7eSRobert Mustacchi}
72*56726c7eSRobert Mustacchi
73*56726c7eSRobert Mustacchifatal()
74*56726c7eSRobert Mustacchi{
75*56726c7eSRobert Mustacchi        typeset msg="$*"
76*56726c7eSRobert Mustacchi        [[ -z "$msg" ]] && msg="failed"
77*56726c7eSRobert Mustacchi        echo "$sc_arg0: $msg" >&2
78*56726c7eSRobert Mustacchi        exit 1
79*56726c7eSRobert Mustacchi}
80*56726c7eSRobert Mustacchi
81*56726c7eSRobert Mustacchicleanup()
82*56726c7eSRobert Mustacchi{
83*56726c7eSRobert Mustacchi	rm -rf "$sc_tmpdir"
84*56726c7eSRobert Mustacchi}
85*56726c7eSRobert Mustacchi
86*56726c7eSRobert Mustacchisanity_check()
87*56726c7eSRobert Mustacchi{
88*56726c7eSRobert Mustacchi	if  (( ${#sc_obj_hw1[@]} != ${#sc_obj_hw2[@]} )); then
89*56726c7eSRobert Mustacchi		fatal "sc_obj_hw1 does not match length of sc_obj_hw2"
90*56726c7eSRobert Mustacchi	fi
91*56726c7eSRobert Mustacchi
92*56726c7eSRobert Mustacchi	if  (( ${#sc_obj_hw2[@]} != ${#sc_obj_hw3[@]} )); then
93*56726c7eSRobert Mustacchi		fatal "sc_obj_hw1 does not match length of sc_obj_hw2"
94*56726c7eSRobert Mustacchi	fi
95*56726c7eSRobert Mustacchi}
96*56726c7eSRobert Mustacchi
97*56726c7eSRobert Mustacchisetup()
98*56726c7eSRobert Mustacchi{
99*56726c7eSRobert Mustacchi	typeset tolink=
100*56726c7eSRobert Mustacchi
101*56726c7eSRobert Mustacchi	if ! mkdir "$sc_tmpdir"; then
102*56726c7eSRobert Mustacchi		fatal "failed to make directory $sc_tmpdir"
103*56726c7eSRobert Mustacchi	fi
104*56726c7eSRobert Mustacchi
105*56726c7eSRobert Mustacchi	trap 'cleanup' EXIT
106*56726c7eSRobert Mustacchi
107*56726c7eSRobert Mustacchi	cat > $sc_tmpdir/main.c <<EOF
108*56726c7eSRobert Mustacchiextern void symcap_print(void);
109*56726c7eSRobert Mustacchi
110*56726c7eSRobert Mustacchiint
111*56726c7eSRobert Mustacchimain(void)
112*56726c7eSRobert Mustacchi{
113*56726c7eSRobert Mustacchi	symcap_print();
114*56726c7eSRobert Mustacchi	return (0);
115*56726c7eSRobert Mustacchi}
116*56726c7eSRobert MustacchiEOF
117*56726c7eSRobert Mustacchi	if (( $? != 0 )); then
118*56726c7eSRobert Mustacchi		fatal "failed to write main.c"
119*56726c7eSRobert Mustacchi	fi
120*56726c7eSRobert Mustacchi
121*56726c7eSRobert Mustacchi	tolink="$sc_tmpdir/main.c"
122*56726c7eSRobert Mustacchi
123*56726c7eSRobert Mustacchi	for (( i = 0; i < ${#sc_obj_hw1[@]}; i++)); do
124*56726c7eSRobert Mustacchi		typeset in="$sc_tmpdir/$i.c"
125*56726c7eSRobert Mustacchi		typeset map="$sc_tmpdir/$i.map"
126*56726c7eSRobert Mustacchi		typeset ofile="$sc_tmpdir/$i.o"
127*56726c7eSRobert Mustacchi		typeset obj="$sc_tmpdir/$i.o.obj"
128*56726c7eSRobert Mustacchi		typeset sym="$sc_tmpdir/$i.o.sym"
129*56726c7eSRobert Mustacchi
130*56726c7eSRobert Mustacchi		cat > $in <<EOF
131*56726c7eSRobert Mustacchi#include <stdio.h>
132*56726c7eSRobert Mustacchi
133*56726c7eSRobert Mustacchivoid
134*56726c7eSRobert Mustacchisymcap_print(void)
135*56726c7eSRobert Mustacchi{
136*56726c7eSRobert Mustacchi	printf("%u\n", $i);
137*56726c7eSRobert Mustacchi}
138*56726c7eSRobert MustacchiEOF
139*56726c7eSRobert Mustacchi		if (( $? != 0 )); then
140*56726c7eSRobert Mustacchi			fatal "failed to write $in"
141*56726c7eSRobert Mustacchi		fi
142*56726c7eSRobert Mustacchi
143*56726c7eSRobert Mustacchi		cat > $map <<EOF
144*56726c7eSRobert Mustacchi\$mapfile_version 2
145*56726c7eSRobert MustacchiCAPABILITY {
146*56726c7eSRobert Mustacchi	HW_1 += ${sc_obj_hw1[$i]};
147*56726c7eSRobert Mustacchi	HW_2 += ${sc_obj_hw2[$i]};
148*56726c7eSRobert Mustacchi	HW_3 += ${sc_obj_hw3[$i]};
149*56726c7eSRobert Mustacchi};
150*56726c7eSRobert MustacchiEOF
151*56726c7eSRobert Mustacchi		if (( $? != 0 )); then
152*56726c7eSRobert Mustacchi			fatal "failed to write $map"
153*56726c7eSRobert Mustacchi		fi
154*56726c7eSRobert Mustacchi
155*56726c7eSRobert Mustacchi		#
156*56726c7eSRobert Mustacchi		# There are three steps to creating a symbol capability due to
157*56726c7eSRobert Mustacchi		# the world we're in. First we need to make the normal .o. Then
158*56726c7eSRobert Mustacchi		# we use a mapfile to add the object caps, while reducing
159*56726c7eSRobert Mustacchi		# visibility. Then we turn the object cap into a symbol cap.
160*56726c7eSRobert Mustacchi		#
161*56726c7eSRobert Mustacchi		if ! gcc -m64 -o $ofile -c $in; then
162*56726c7eSRobert Mustacchi			fatal "failed to create object file $ofile"
163*56726c7eSRobert Mustacchi		fi
164*56726c7eSRobert Mustacchi
165*56726c7eSRobert Mustacchi		#
166*56726c7eSRobert Mustacchi		# If the entry has a zero for all cases (e.g. our default case),
167*56726c7eSRobert Mustacchi		# then skip the rest of this processing and append the .o.
168*56726c7eSRobert Mustacchi		#
169*56726c7eSRobert Mustacchi		if (( sc_obj_hw1[i] == 0 && sc_obj_hw2[i] == 0 &&
170*56726c7eSRobert Mustacchi		    sc_obj_hw3[i] == 0 )); then
171*56726c7eSRobert Mustacchi			tolink="$tolink $ofile"
172*56726c7eSRobert Mustacchi			continue
173*56726c7eSRobert Mustacchi		fi
174*56726c7eSRobert Mustacchi
175*56726c7eSRobert Mustacchi		if ! ld -r -o $obj $ofile -M$map -Breduce; then
176*56726c7eSRobert Mustacchi			fatal "failed to create object cap file $obj"
177*56726c7eSRobert Mustacchi		fi
178*56726c7eSRobert Mustacchi
179*56726c7eSRobert Mustacchi		if ! ld -r -o $sym -z symbolcap $obj; then
180*56726c7eSRobert Mustacchi			fatal "failed to create symbol cap file $sym"
181*56726c7eSRobert Mustacchi		fi
182*56726c7eSRobert Mustacchi
183*56726c7eSRobert Mustacchi		tolink="$tolink $sym"
184*56726c7eSRobert Mustacchi	done
185*56726c7eSRobert Mustacchi
186*56726c7eSRobert Mustacchi	if ! gcc -m64 -o $sc_prog $tolink; then
187*56726c7eSRobert Mustacchi		fatal "failed to create $sc_prog"
188*56726c7eSRobert Mustacchi	fi
189*56726c7eSRobert Mustacchi}
190*56726c7eSRobert Mustacchi
191*56726c7eSRobert Mustacchi#
192*56726c7eSRobert Mustacchi# Given a set of caps, indicate which index we expect to be printed out and
193*56726c7eSRobert Mustacchi# check for that.
194*56726c7eSRobert Mustacchi#
195*56726c7eSRobert Mustacchirun_one()
196*56726c7eSRobert Mustacchi{
197*56726c7eSRobert Mustacchi	typeset index="$1"
198*56726c7eSRobert Mustacchi	typeset caps="$2"
199*56726c7eSRobert Mustacchi	typeset out=
200*56726c7eSRobert Mustacchi
201*56726c7eSRobert Mustacchi	out=$(LD_CAP_FILES=$sc_prog LD_HWCAP="$caps" $sc_prog)
202*56726c7eSRobert Mustacchi	if (( $? != 0 )); then
203*56726c7eSRobert Mustacchi		warn "failed to execute $sc_prog with cap $caps"
204*56726c7eSRobert Mustacchi		return
205*56726c7eSRobert Mustacchi	fi
206*56726c7eSRobert Mustacchi
207*56726c7eSRobert Mustacchi	if [[ "$out" != "$index" ]]; then
208*56726c7eSRobert Mustacchi		warn "$caps had wrong output, found $out, expected $index"
209*56726c7eSRobert Mustacchi	else
210*56726c7eSRobert Mustacchi		pass "LD_HWCAP=$caps"
211*56726c7eSRobert Mustacchi	fi
212*56726c7eSRobert Mustacchi}
213*56726c7eSRobert Mustacchi
214*56726c7eSRobert Mustacchisanity_check
215*56726c7eSRobert Mustacchisetup
216*56726c7eSRobert Mustacchi
217*56726c7eSRobert Mustacchi#
218*56726c7eSRobert Mustacchi# First, go through and verify that if we match the caps exactly for this, we'll
219*56726c7eSRobert Mustacchi# choose this symbol.
220*56726c7eSRobert Mustacchi#
221*56726c7eSRobert Mustacchirun_one 0 "[1]0x0,[2]0x0,[3]0x0"
222*56726c7eSRobert Mustacchirun_one 1 "[1]0x5,[2]0x0,[3]0x0"
223*56726c7eSRobert Mustacchirun_one 2 "[1]0x42,[2]0x0,[3]0x0"
224*56726c7eSRobert Mustacchirun_one 3 "[1]0x0,[2]0x23,[3]0x0"
225*56726c7eSRobert Mustacchirun_one 4 "[1]0x0,[2]0xff00,[3]0x0"
226*56726c7eSRobert Mustacchirun_one 5 "[1]0x0,[2]0x0,[3]0x12345"
227*56726c7eSRobert Mustacchirun_one 6 "[1]0x0,[2]0x0,[3]0x7000000"
228*56726c7eSRobert Mustacchirun_one 7 "[1]0x3,[2]0xff7ff6,[3]0x87654321"
229*56726c7eSRobert Mustacchirun_one 8 "[1]0x8,[2]0xff7ff6,[3]0x87654321"
230*56726c7eSRobert Mustacchi
231*56726c7eSRobert Mustacchi#
232*56726c7eSRobert Mustacchi# For cases where we have multiple symbol caps at a given level, show that we
233*56726c7eSRobert Mustacchi# pick a sub one when we're between the two.
234*56726c7eSRobert Mustacchi#
235*56726c7eSRobert Mustacchirun_one 0 "[1]0x40,[2]0x0,[3]0x0"
236*56726c7eSRobert Mustacchirun_one 1 "[1]0x45,[2]0x0,[3]0x0"
237*56726c7eSRobert Mustacchirun_one 1 "[1]0x45,[2]0x10,[3]0x0"
238*56726c7eSRobert Mustacchirun_one 2 "[1]0x142,[2]0x10,[3]0x0"
239*56726c7eSRobert Mustacchirun_one 3 "[1]0x1,[2]0x137,[3]0x0"
240*56726c7eSRobert Mustacchi
241*56726c7eSRobert Mustacchi#
242*56726c7eSRobert Mustacchi# We expect the system to pick the "best" aka highest capability. So for the
243*56726c7eSRobert Mustacchi# next round we attempt to combine multiple values and see which we pick. In
244*56726c7eSRobert Mustacchi# particular here we're trying to pick between things at the same level and also
245*56726c7eSRobert Mustacchi# ensure we pick the one that is higher (e.g. hw3 > hw2 > hw1)
246*56726c7eSRobert Mustacchi#
247*56726c7eSRobert Mustacchirun_one 6 "[1]0x47,[2]0xff23,[3]0x7012345"
248*56726c7eSRobert Mustacchirun_one 5 "[1]0x47,[2]0xff23,[3]0x6012345"
249*56726c7eSRobert Mustacchirun_one 5 "[1]0x47,[2]0xff23,[3]0x1012345"
250*56726c7eSRobert Mustacchirun_one 4 "[1]0x47,[2]0xff23,[3]0x1002345"
251*56726c7eSRobert Mustacchirun_one 3 "[1]0x47,[2]0x7723,[3]0x1002345"
252*56726c7eSRobert Mustacchirun_one 3 "[1]0x47,[2]0x0f23,[3]0x1002345"
253*56726c7eSRobert Mustacchirun_one 3 "[1]0x47,[2]0x0023,[3]0x1002345"
254*56726c7eSRobert Mustacchirun_one 2 "[1]0x47,[2]0x0003,[3]0x1002345"
255*56726c7eSRobert Mustacchirun_one 2 "[1]0x46,[2]0x0003,[3]0x1002345"
256*56726c7eSRobert Mustacchirun_one 1 "[1]0x35,[2]0x0003,[3]0x1002345"
257*56726c7eSRobert Mustacchirun_one 1 "[1]0x15,[2]0x0003,[3]0x1002345"
258*56726c7eSRobert Mustacchirun_one 0 "[1]0x10,[2]0x0003,[3]0x1002345"
259*56726c7eSRobert Mustacchi
260*56726c7eSRobert Mustacchi#
261*56726c7eSRobert Mustacchi# Finally we want a few tests that verify that when things match, the lowest bit
262*56726c7eSRobert Mustacchi# of it decides.
263*56726c7eSRobert Mustacchi#
264*56726c7eSRobert Mustacchirun_one 8 "[1]0xb,[2]0xff7ff6,[3]0x87654321"
265*56726c7eSRobert Mustacchirun_one 8 "[1]0x3b,[2]0xff7ff6,[3]0x87654321"
266*56726c7eSRobert Mustacchirun_one 8 "[1]0xffffffff,[2]0xffffffff,[3]0xffffffff"
267*56726c7eSRobert Mustacchirun_one 7 "[1]0xfffffff7,[2]0xffffffff,[3]0xffffffff"
268*56726c7eSRobert Mustacchi
269*56726c7eSRobert Mustacchiexit $sc_err
270