execregs.c revision 1.2 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