execregs.c revision 1.1 1 /* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 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.1 2025/02/27 00:55:32 riastradh Exp $");
31
32 #include "execregs.h"
33
34 #include <errno.h>
35 #include <spawn.h>
36 #include <stddef.h>
37 #include <unistd.h>
38
39 extern char **environ;
40
41 static unsigned long
42 nonnull(unsigned long x)
43 {
44
45 x |= x << 8;
46 x |= x << 16;
47 return x;
48 }
49
50 int
51 execregschild(char *path)
52 {
53 register long t1 __asm("r22") = nonnull(22);
54 register long t2 __asm("r21") = nonnull(21);
55 /* r30/sp: stack pointer */
56 register long t3 __asm("r20") = nonnull(20);
57 /* cr17/iisq_head: privileged */
58 /* cr17/iisq_tail: privileged */
59 /* cr18/iioq_head: privileged */
60 /* cr18/iioq_tail: privileged */
61 /* cr15/eiem: privileged */
62 /* cr22/ipsw: privileged */
63 /* sr3: privileged(?) */
64 /* cr8/pidr1: privileged */
65 /* cr20/isr: privileged */
66 /* cr21/ior: privileged */
67 /* cr19/iir: privileged */
68 /* flags: N/A(?) */
69 long sar = nonnull(0x8a); /* cr11 */
70 /* r1: ADDIL (add immediate left) result, nonnull anyway */
71 /* r2/rp: return pointer, nonnull anyway */
72 /* r3: frame pointer, nonnull anyway */
73 register long r4 __asm("r4") = nonnull(4);
74 register long r5 __asm("r5") = nonnull(5);
75 register long r6 __asm("r6") = nonnull(6);
76 register long r7 __asm("r7") = nonnull(7);
77 register long r8 __asm("r8") = nonnull(8);
78 register long r9 __asm("r9") = nonnull(9);
79 register long r10 __asm("r10") = nonnull(10);
80 register long r11 __asm("r11") = nonnull(11);
81 register long r12 __asm("r12") = nonnull(12);
82 register long r13 __asm("r13") = nonnull(13);
83 register long r14 __asm("r14") = nonnull(14);
84 register long r15 __asm("r15") = nonnull(15);
85 register long r16 __asm("r16") = nonnull(16);
86 register long r17 __asm("r17") = nonnull(17);
87 register long r18 __asm("r18") = nonnull(18);
88 register long t4 __asm("r19") = nonnull(19);
89 register long arg3 __asm("r23") = nonnull(23);
90 /* r24/arg2: envp, nonnull anyway */
91 /* r25/arg1: argv, nonnull anyway */
92 /* r26/arg0: path, nonnull anyway */
93 /* r27/dp: data pointer, nonnull anyway */
94 register long ret0 __asm("r28") = nonnull(28);
95 register long ret1 __asm("r29") = nonnull(29);
96 register long r31 __asm("r31") = nonnull(31);
97 /* sr0-sr7: space registers initialized by kernel */
98 /* cr9/pidr2: privileged */
99 /* cr12/pidr3: privileged */
100 /* cr13/pidr4: privileged */
101 /* cr0/rctr: privileged */
102 /* cr10/ccr: privileged */
103 /* cr23/eirr: privileged */
104 /* cr24: privileged */
105 /* cr25/vtop: privileged */
106 /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */
107 /* cr28: privileged */
108 /* cr30/fpregs: privileged */
109 /* cr31: privileged */
110
111 char *argv[] = {path, NULL};
112 char **envp = environ;
113
114 /*
115 * Not perfect -- compiler might use some registers for
116 * stack/argument transfers, but all the arguments are nonnull
117 * so this is probably a good test anyway.
118 */
119 __asm volatile("mtctl %[sar], %%sar" /* cr11 */
120 : /* outputs */
121 : [sar] "r"(sar)
122 : "memory");
123 __asm volatile("" :
124 "+r"(t1),
125 "+r"(t2),
126 "+r"(t3),
127 "+r"(r4),
128 "+r"(r5),
129 "+r"(r6),
130 "+r"(r7),
131 "+r"(r8),
132 "+r"(r9),
133 "+r"(r10),
134 "+r"(r11),
135 "+r"(r12)
136 :: "memory");
137 /* pacify gcc error: more than 30 operands in 'asm' */
138 __asm volatile("" :
139 "+r"(r13),
140 "+r"(r14),
141 "+r"(r15),
142 "+r"(r16),
143 "+r"(r17),
144 "+r"(r18),
145 "+r"(t4),
146 "+r"(arg3),
147 "+r"(ret0),
148 "+r"(ret1),
149 "+r"(r31)
150 :: "memory");
151
152 return execve(path, argv, envp);
153 }
154
155 pid_t
156 spawnregschild(char *path, int fd)
157 {
158 register long t1 __asm("r22") = nonnull(22);
159 register long t2 __asm("r21") = nonnull(21);
160 /* r30/sp: stack pointer */
161 register long t3 __asm("r20") = nonnull(20);
162 /* cr17/iisq_head: privileged */
163 /* cr17/iisq_tail: privileged */
164 /* cr18/iioq_head: privileged */
165 /* cr18/iioq_tail: privileged */
166 /* cr15/eiem: privileged */
167 /* cr22/ipsw: privileged */
168 /* sr3: privileged(?) */
169 /* cr8/pidr1: privileged */
170 /* cr20/isr: privileged */
171 /* cr21/ior: privileged */
172 /* cr19/iir: privileged */
173 /* flags: N/A(?) */
174 long sar = nonnull(0x8a); /* cr11 */
175 /* r1: ADDIL (add immediate left) result, nonnull anyway */
176 /* r2/rp: return pointer, nonnull anyway */
177 /* r3: frame pointer, nonnull anyway */
178 register long r4 __asm("r4") = nonnull(4);
179 register long r5 __asm("r5") = nonnull(5);
180 register long r6 __asm("r6") = nonnull(6);
181 register long r7 __asm("r7") = nonnull(7);
182 register long r8 __asm("r8") = nonnull(8);
183 register long r9 __asm("r9") = nonnull(9);
184 register long r10 __asm("r10") = nonnull(10);
185 register long r11 __asm("r11") = nonnull(11);
186 register long r12 __asm("r12") = nonnull(12);
187 register long r13 __asm("r13") = nonnull(13);
188 register long r14 __asm("r14") = nonnull(14);
189 register long r15 __asm("r15") = nonnull(15);
190 register long r16 __asm("r16") = nonnull(16);
191 register long r17 __asm("r17") = nonnull(17);
192 register long r18 __asm("r18") = nonnull(18);
193 register long t4 __asm("r19") = nonnull(19);
194 /* r23/arg3: attrp, nonnull anyway */
195 /* r24/arg2: fileactsp, nonnull anyway */
196 /* r25/arg1: path, nonnull anyway */
197 /* r26/arg0: pidp, nonnull anyway */
198 /* r27/dp: data pointer, nonnull anyway */
199 register long ret0 __asm("r28") = nonnull(28);
200 register long ret1 __asm("r29") = nonnull(29);
201 register long r31 __asm("r31") = nonnull(31);
202 /* sr0-sr7: space registers initialized by kernel */
203 /* cr9/pidr2: privileged */
204 /* cr12/pidr3: privileged */
205 /* cr13/pidr4: privileged */
206 /* cr0/rctr: privileged */
207 /* cr10/ccr: privileged */
208 /* cr23/eirr: privileged */
209 /* cr24: privileged */
210 /* cr25/vtop: privileged */
211 /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */
212 /* cr28: privileged */
213 /* cr30/fpregs: privileged */
214 /* cr31: privileged */
215
216 char *argv[] = {path, NULL};
217 char **envp = environ;
218 posix_spawn_file_actions_t fileacts;
219 posix_spawnattr_t attr;
220 pid_t pid;
221 int error;
222
223 error = posix_spawn_file_actions_init(&fileacts);
224 if (error)
225 goto out;
226 error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO);
227 if (error)
228 goto out;
229 error = posix_spawnattr_init(&attr);
230 if (error)
231 goto out;
232
233 /*
234 * Not perfect -- compiler might use some registers for
235 * stack/argument transfers, but all the arguments are nonnull
236 * so this is probably a good test anyway.
237 */
238 __asm volatile("mtctl %[sar], %%sar" /* cr11 */
239 : /* outputs */
240 : [sar] "r"(sar)
241 : "memory");
242 __asm volatile("" :
243 "+r"(t1),
244 "+r"(t2),
245 "+r"(t3),
246 "+r"(r4),
247 "+r"(r5),
248 "+r"(r6),
249 "+r"(r7),
250 "+r"(r8),
251 "+r"(r9),
252 "+r"(r10),
253 "+r"(r11),
254 "+r"(r12)
255 :: "memory");
256 /* pacify gcc error: more than 30 operands in 'asm' */
257 __asm volatile("" :
258 "+r"(r13),
259 "+r"(r14),
260 "+r"(r15),
261 "+r"(r16),
262 "+r"(r17),
263 "+r"(r18),
264 "+r"(t4),
265 "+r"(ret0),
266 "+r"(ret1),
267 "+r"(r31)
268 :: "memory");
269
270 error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp);
271 if (error)
272 goto out;
273
274 out: posix_spawnattr_destroy(&attr);
275 posix_spawn_file_actions_destroy(&fileacts);
276 if (error) {
277 errno = error;
278 return -1;
279 }
280 return 0;
281 }
282