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