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