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 /* fp: frame pointer, nonnull */ 54 /* ap: argument pointer, on user stack, nonnull */ 55 /* sp: stack pointer, nonnull */ 56 register long r0 __asm("r0") = nonnull(0x10); 57 register long r1 __asm("r1") = nonnull(1); 58 register long r2 __asm("r2") = nonnull(2); 59 register long r3 __asm("r3") = nonnull(3); 60 register long r4 __asm("r4") = nonnull(4); 61 register long r5 __asm("r5") = nonnull(5); 62 register long r6 __asm("r6") = nonnull(6); 63 register long r7 __asm("r7") = nonnull(7); 64 register long r8 __asm("r8") = nonnull(8); 65 register long r9 __asm("r9") = nonnull(9); 66 register long r10 __asm("r10") = nonnull(10); 67 register long r11 __asm("r11") = nonnull(11); 68 /* pc: user PC, will be nonnull */ 69 /* psl: processor status longword, will be nonnull */ 70 71 char *argv[] = {path, NULL}; 72 char **envp = environ; 73 74 /* 75 * Not perfect -- compiler might use some registers for 76 * stack/argument transfers, but all the arguments are nonnull 77 * so this is probably a good test anyway. 78 */ 79 __asm volatile("" : 80 "+r"(r0), 81 "+r"(r1), 82 "+r"(r2), 83 "+r"(r3), 84 "+r"(r4), 85 "+r"(r5), 86 "+r"(r6), 87 "+r"(r7), 88 "+r"(r8), 89 "+r"(r9), 90 "+r"(r10), 91 "+r"(r11) 92 :: "memory"); 93 94 return execve(path, argv, envp); 95 } 96 97 pid_t 98 spawnregschild(char *path, int fd) 99 { 100 /* fp: frame pointer, nonnull */ 101 /* ap: argument pointer, on user stack, nonnull */ 102 /* sp: stack pointer, nonnull */ 103 register long r0 __asm("r0") = nonnull(0x10); 104 register long r1 __asm("r1") = nonnull(1); 105 register long r2 __asm("r2") = nonnull(2); 106 register long r3 __asm("r3") = nonnull(3); 107 register long r4 __asm("r4") = nonnull(4); 108 register long r5 __asm("r5") = nonnull(5); 109 register long r6 __asm("r6") = nonnull(6); 110 register long r7 __asm("r7") = nonnull(7); 111 register long r8 __asm("r8") = nonnull(8); 112 register long r9 __asm("r9") = nonnull(9); 113 register long r10 __asm("r10") = nonnull(10); 114 register long r11 __asm("r11") = nonnull(11); 115 /* pc: user PC, will be nonnull */ 116 /* psl: processor status longword, will be nonnull */ 117 118 char *argv[] = {path, NULL}; 119 char **envp = environ; 120 posix_spawn_file_actions_t fileacts; 121 posix_spawnattr_t attr; 122 pid_t pid; 123 int error; 124 125 error = posix_spawn_file_actions_init(&fileacts); 126 if (error) 127 goto out; 128 error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); 129 if (error) 130 goto out; 131 error = posix_spawnattr_init(&attr); 132 if (error) 133 goto out; 134 135 /* 136 * Not perfect -- compiler might use some registers for 137 * stack/argument transfers, but all the arguments are nonnull 138 * so this is probably a good test anyway. 139 */ 140 __asm volatile("" : 141 "+r"(r0), 142 "+r"(r1), 143 "+r"(r2), 144 "+r"(r3), 145 "+r"(r4), 146 "+r"(r5), 147 "+r"(r6), 148 "+r"(r7), 149 "+r"(r8), 150 "+r"(r9), 151 "+r"(r10), 152 "+r"(r11) 153 :: "memory"); 154 155 error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); 156 if (error) 157 goto out; 158 159 out: posix_spawnattr_destroy(&attr); 160 posix_spawn_file_actions_destroy(&fileacts); 161 if (error) { 162 errno = error; 163 return -1; 164 } 165 return 0; 166 } 167