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