Home | History | Annotate | Line # | Download | only in hppa
      1 /*	$NetBSD: execregs.c,v 1.2 2025/02/28 16:08:19 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2025 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __RCSID("$NetBSD: execregs.c,v 1.2 2025/02/28 16:08:19 riastradh Exp $");
     31 
     32 #include "execregs.h"
     33 
     34 #include <errno.h>
     35 #include <spawn.h>
     36 #include <stddef.h>
     37 #include <stdint.h>
     38 #include <unistd.h>
     39 
     40 extern char **environ;
     41 
     42 static unsigned long
     43 nonnull(unsigned long x)
     44 {
     45 
     46 	x |= x << 8;
     47 	x |= x << 16;
     48 	return x;
     49 }
     50 
     51 /*
     52  * setfpregs()
     53  *
     54  *	Set up all the floating-point registers with something nonzero
     55  *	in each one.  We initialize the floating-point status register
     56  *	to set various bits so it's not all zero, but nothing that
     57  *	would trigger traps.
     58  */
     59 static void
     60 setfpregs(void)
     61 {
     62 	static const uint64_t fpe[] = {
     63 		(__BITS(63,59)		/* all exception flags (VZOUI) set */
     64 		    | __BIT(58)		/* C bit (comparison) set */
     65 		    | __BITS(54,43)	/* CQ (comparison queue) all set */
     66 		    | __SHIFTIN(1, __BITS(42,41))	/* round toward zero */
     67 		    | __SHIFTIN(0, __BIT(38))	/* no delayed trap */
     68 		    | __SHIFTIN(1, __BIT(37))	/* Denormalized As Zero */
     69 		    | __SHIFTIN(0, __BITS(36,32))	/* exceptions masked */
     70 		    | 0x10101010),
     71 		0x9191919111111111,
     72 		0x9292929212121212,
     73 		0x9393939313131313,
     74 	};
     75 	const uint64_t *fpep = fpe;
     76 
     77 	static const double fr[28] = {
     78 		0x1.04p0, 0x1.05p0, 0x1.06p0, 0x1.07p0,
     79 		0x1.08p0, 0x1.09p0, 0x1.0ap0, 0x1.0bp0,
     80 		0x1.0cp0, 0x1.0dp0, 0x1.0ep0, 0x1.0fp0,
     81 		0x1.10p0, 0x1.11p0, 0x1.12p0, 0x1.13p0,
     82 		0x1.14p0, 0x1.15p0, 0x1.16p0, 0x1.17p0,
     83 		0x1.18p0, 0x1.19p0, 0x1.1ap0, 0x1.1bp0,
     84 		0x1.1cp0, 0x1.1dp0, 0x1.1ep0, 0x1.1fp0,
     85 	};
     86 	const double *frp = fr;
     87 
     88 	__asm volatile(
     89 		"fldds,ma	8(%0), %%fr0\n\t"
     90 		"fldds,ma	8(%0), %%fr1\n\t"
     91 		"fldds,ma	8(%0), %%fr2\n\t"
     92 		"fldds		0(%0), %%fr3"
     93 	    : "+r"(fpep)
     94 	    : "m"(fpe));
     95 
     96 	__asm volatile(
     97 		"fldds,ma	8(%0), %%fr4\n\t"
     98 		"fldds,ma	8(%0), %%fr5\n\t"
     99 		"fldds,ma	8(%0), %%fr6\n\t"
    100 		"fldds,ma	8(%0), %%fr7\n\t"
    101 		"fldds,ma	8(%0), %%fr8\n\t"
    102 		"fldds,ma	8(%0), %%fr9\n\t"
    103 		"fldds,ma	8(%0), %%fr10\n\t"
    104 		"fldds,ma	8(%0), %%fr11\n\t"
    105 		"fldds,ma	8(%0), %%fr12\n\t"
    106 		"fldds,ma	8(%0), %%fr13\n\t"
    107 		"fldds,ma	8(%0), %%fr14\n\t"
    108 		"fldds,ma	8(%0), %%fr15\n\t"
    109 		"fldds,ma	8(%0), %%fr16\n\t"
    110 		"fldds,ma	8(%0), %%fr17\n\t"
    111 		"fldds,ma	8(%0), %%fr18\n\t"
    112 		"fldds,ma	8(%0), %%fr19\n\t"
    113 		"fldds,ma	8(%0), %%fr20\n\t"
    114 		"fldds,ma	8(%0), %%fr21\n\t"
    115 		"fldds,ma	8(%0), %%fr22\n\t"
    116 		"fldds,ma	8(%0), %%fr23\n\t"
    117 		"fldds,ma	8(%0), %%fr24\n\t"
    118 		"fldds,ma	8(%0), %%fr25\n\t"
    119 		"fldds,ma	8(%0), %%fr26\n\t"
    120 		"fldds,ma	8(%0), %%fr27\n\t"
    121 		"fldds,ma	8(%0), %%fr28\n\t"
    122 		"fldds,ma	8(%0), %%fr29\n\t"
    123 		"fldds,ma	8(%0), %%fr30\n\t"
    124 		"fldds		0(%0), %%fr31"
    125 	    : "+r"(frp)
    126 	    : "m"(fr));
    127 }
    128 
    129 /*
    130  * setpsw()
    131  *
    132  *	Set some bits in PSW, the processor status word.
    133  */
    134 static void
    135 setpsw(void)
    136 {
    137 	uint32_t x = 0xe0000000, y = 0xffffffff, sum;
    138 
    139 	/*
    140 	 * Trigger some arithmetic that causes the carry/borrow
    141 	 * (PSW[C/B]) bits to be set.
    142 	 *
    143 	 * XXX Also set PSW[V].
    144 	 */
    145 	__asm volatile("sh3add %[sum], %[x], %[y]"
    146 	    : /* outputs */ [sum] "=r"(sum)
    147 	    : /* inputs */ [x] "r"(x), [y] "r"(y));
    148 }
    149 
    150 int
    151 execregschild(char *path)
    152 {
    153 	register long t1 __asm("r22") = nonnull(22);
    154 	register long t2 __asm("r21") = nonnull(21);
    155 	/* r30/sp: stack pointer */
    156 	register long t3 __asm("r20") = nonnull(20);
    157 	/* cr17/iisq_head: privileged */
    158 	/* cr17/iisq_tail: privileged */
    159 	/* cr18/iioq_head: privileged */
    160 	/* cr18/iioq_tail: privileged */
    161 	/* cr15/eiem: privileged */
    162 	/* cr22/ipsw: privileged */
    163 	/* sr3: privileged(?) */
    164 	/* cr8/pidr1: privileged */
    165 	/* cr20/isr: privileged */
    166 	/* cr21/ior: privileged */
    167 	/* cr19/iir: privileged */
    168 	/* flags: N/A(?) */
    169 	long sar = nonnull(0x8a);	/* cr11 */
    170 	/* r1: ADDIL (add immediate left) result, nonnull anyway */
    171 	/* r2/rp: return pointer, nonnull anyway */
    172 	/* r3: frame pointer, nonnull anyway */
    173 	register long r4 __asm("r4") = nonnull(4);
    174 	register long r5 __asm("r5") = nonnull(5);
    175 	register long r6 __asm("r6") = nonnull(6);
    176 	register long r7 __asm("r7") = nonnull(7);
    177 	register long r8 __asm("r8") = nonnull(8);
    178 	register long r9 __asm("r9") = nonnull(9);
    179 	register long r10 __asm("r10") = nonnull(10);
    180 	register long r11 __asm("r11") = nonnull(11);
    181 	register long r12 __asm("r12") = nonnull(12);
    182 	register long r13 __asm("r13") = nonnull(13);
    183 	register long r14 __asm("r14") = nonnull(14);
    184 	register long r15 __asm("r15") = nonnull(15);
    185 	register long r16 __asm("r16") = nonnull(16);
    186 	register long r17 __asm("r17") = nonnull(17);
    187 	register long r18 __asm("r18") = nonnull(18);
    188 	register long t4 __asm("r19") = nonnull(19);
    189 	register long arg3 __asm("r23") = nonnull(23);
    190 	/* r24/arg2: envp, nonnull anyway */
    191 	/* r25/arg1: argv, nonnull anyway */
    192 	/* r26/arg0: path, nonnull anyway */
    193 	/* r27/dp: data pointer, nonnull anyway */
    194 	register long ret0 __asm("r28") = nonnull(28);
    195 	register long ret1 __asm("r29") = nonnull(29);
    196 	register long r31 __asm("r31") = nonnull(31);
    197 	/* sr0-sr7: space registers initialized by kernel */
    198 	/* cr9/pidr2: privileged */
    199 	/* cr12/pidr3: privileged */
    200 	/* cr13/pidr4: privileged */
    201 	/* cr0/rctr: privileged */
    202 	/* cr10/ccr: privileged */
    203 	/* cr23/eirr: privileged */
    204 	/* cr24: privileged */
    205 	/* cr25/vtop: privileged */
    206 	/* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */
    207 	/* cr28: privileged */
    208 	/* cr30/fpregs: privileged */
    209 	/* cr31: privileged */
    210 
    211 	char *argv[] = {path, NULL};
    212 	char **envp = environ;
    213 
    214 	setfpregs();
    215 	setpsw();
    216 
    217 	/*
    218 	 * Not perfect -- compiler might use some registers for
    219 	 * stack/argument transfers, but all the arguments are nonnull
    220 	 * so this is probably a good test anyway.
    221 	 */
    222 	__asm volatile("mtctl %[sar], %%sar"	/* cr11 */
    223 	    : /* outputs */
    224 	    : [sar] "r"(sar)
    225 	    : "memory");
    226 	__asm volatile("" :
    227 	    "+r"(t1),
    228 	    "+r"(t2),
    229 	    "+r"(t3),
    230 	    "+r"(r4),
    231 	    "+r"(r5),
    232 	    "+r"(r6),
    233 	    "+r"(r7),
    234 	    "+r"(r8),
    235 	    "+r"(r9),
    236 	    "+r"(r10),
    237 	    "+r"(r11),
    238 	    "+r"(r12)
    239 	    :: "memory");
    240 	/* pacify gcc error: more than 30 operands in 'asm' */
    241 	__asm volatile("" :
    242 	    "+r"(r13),
    243 	    "+r"(r14),
    244 	    "+r"(r15),
    245 	    "+r"(r16),
    246 	    "+r"(r17),
    247 	    "+r"(r18),
    248 	    "+r"(t4),
    249 	    "+r"(arg3),
    250 	    "+r"(ret0),
    251 	    "+r"(ret1),
    252 	    "+r"(r31)
    253 	    :: "memory");
    254 
    255 	return execve(path, argv, envp);
    256 }
    257 
    258 pid_t
    259 spawnregschild(char *path, int fd)
    260 {
    261 	register long t1 __asm("r22") = nonnull(22);
    262 	register long t2 __asm("r21") = nonnull(21);
    263 	/* r30/sp: stack pointer */
    264 	register long t3 __asm("r20") = nonnull(20);
    265 	/* cr17/iisq_head: privileged */
    266 	/* cr17/iisq_tail: privileged */
    267 	/* cr18/iioq_head: privileged */
    268 	/* cr18/iioq_tail: privileged */
    269 	/* cr15/eiem: privileged */
    270 	/* cr22/ipsw: privileged */
    271 	/* sr3: privileged(?) */
    272 	/* cr8/pidr1: privileged */
    273 	/* cr20/isr: privileged */
    274 	/* cr21/ior: privileged */
    275 	/* cr19/iir: privileged */
    276 	/* flags: N/A(?) */
    277 	long sar = nonnull(0x8a);	/* cr11 */
    278 	/* r1: ADDIL (add immediate left) result, nonnull anyway */
    279 	/* r2/rp: return pointer, nonnull anyway */
    280 	/* r3: frame pointer, nonnull anyway */
    281 	register long r4 __asm("r4") = nonnull(4);
    282 	register long r5 __asm("r5") = nonnull(5);
    283 	register long r6 __asm("r6") = nonnull(6);
    284 	register long r7 __asm("r7") = nonnull(7);
    285 	register long r8 __asm("r8") = nonnull(8);
    286 	register long r9 __asm("r9") = nonnull(9);
    287 	register long r10 __asm("r10") = nonnull(10);
    288 	register long r11 __asm("r11") = nonnull(11);
    289 	register long r12 __asm("r12") = nonnull(12);
    290 	register long r13 __asm("r13") = nonnull(13);
    291 	register long r14 __asm("r14") = nonnull(14);
    292 	register long r15 __asm("r15") = nonnull(15);
    293 	register long r16 __asm("r16") = nonnull(16);
    294 	register long r17 __asm("r17") = nonnull(17);
    295 	register long r18 __asm("r18") = nonnull(18);
    296 	register long t4 __asm("r19") = nonnull(19);
    297 	/* r23/arg3: attrp, nonnull anyway */
    298 	/* r24/arg2: fileactsp, nonnull anyway */
    299 	/* r25/arg1: path, nonnull anyway */
    300 	/* r26/arg0: pidp, nonnull anyway */
    301 	/* r27/dp: data pointer, nonnull anyway */
    302 	register long ret0 __asm("r28") = nonnull(28);
    303 	register long ret1 __asm("r29") = nonnull(29);
    304 	register long r31 __asm("r31") = nonnull(31);
    305 	/* sr0-sr7: space registers initialized by kernel */
    306 	/* cr9/pidr2: privileged */
    307 	/* cr12/pidr3: privileged */
    308 	/* cr13/pidr4: privileged */
    309 	/* cr0/rctr: privileged */
    310 	/* cr10/ccr: privileged */
    311 	/* cr23/eirr: privileged */
    312 	/* cr24: privileged */
    313 	/* cr25/vtop: privileged */
    314 	/* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */
    315 	/* cr28: privileged */
    316 	/* cr30/fpregs: privileged */
    317 	/* cr31: privileged */
    318 
    319 	char *argv[] = {path, NULL};
    320 	char **envp = environ;
    321 	posix_spawn_file_actions_t fileacts;
    322 	posix_spawnattr_t attr;
    323 	pid_t pid;
    324 	int error;
    325 
    326 	error = posix_spawn_file_actions_init(&fileacts);
    327 	if (error)
    328 		goto out;
    329 	error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO);
    330 	if (error)
    331 		goto out;
    332 	error = posix_spawnattr_init(&attr);
    333 	if (error)
    334 		goto out;
    335 
    336 	setfpregs();
    337 	setpsw();
    338 
    339 	/*
    340 	 * Not perfect -- compiler might use some registers for
    341 	 * stack/argument transfers, but all the arguments are nonnull
    342 	 * so this is probably a good test anyway.
    343 	 */
    344 	__asm volatile("mtctl %[sar], %%sar"	/* cr11 */
    345 	    : /* outputs */
    346 	    : [sar] "r"(sar)
    347 	    : "memory");
    348 	__asm volatile("" :
    349 	    "+r"(t1),
    350 	    "+r"(t2),
    351 	    "+r"(t3),
    352 	    "+r"(r4),
    353 	    "+r"(r5),
    354 	    "+r"(r6),
    355 	    "+r"(r7),
    356 	    "+r"(r8),
    357 	    "+r"(r9),
    358 	    "+r"(r10),
    359 	    "+r"(r11),
    360 	    "+r"(r12)
    361 	    :: "memory");
    362 	/* pacify gcc error: more than 30 operands in 'asm' */
    363 	__asm volatile("" :
    364 	    "+r"(r13),
    365 	    "+r"(r14),
    366 	    "+r"(r15),
    367 	    "+r"(r16),
    368 	    "+r"(r17),
    369 	    "+r"(r18),
    370 	    "+r"(t4),
    371 	    "+r"(ret0),
    372 	    "+r"(ret1),
    373 	    "+r"(r31)
    374 	    :: "memory");
    375 
    376 	error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp);
    377 	if (error)
    378 		goto out;
    379 
    380 out:	posix_spawnattr_destroy(&attr);
    381 	posix_spawn_file_actions_destroy(&fileacts);
    382 	if (error) {
    383 		errno = error;
    384 		return -1;
    385 	}
    386 	return 0;
    387 }
    388