Merge tag 'pull-riscv-to-apply-20240806-2' of https://github.com/alistair23/qemu...
[qemu/kevin.git] / bsd-user / freebsd / target_os_stack.h
blobac0ef22cd7abb2b7eb19a76b42d63999a570efaa
1 /*
2 * FreeBSD setup_initial_stack() implementation.
4 * Copyright (c) 2013-14 Stacey D. Son
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #ifndef TARGET_OS_STACK_H
21 #define TARGET_OS_STACK_H
23 #include <sys/param.h>
24 #include "target_arch_sigtramp.h"
25 #include "qemu/guest-random.h"
26 #include "user/tswap-target.h"
29 * The initial FreeBSD stack is as follows:
30 * (see kern/kern_exec.c exec_copyout_strings() )
32 * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.)
33 * unsigned ps_nargvstr
34 * char **ps_envstr
35 * PS_STRINGS -> unsigned ps_nenvstr
37 * machine dependent sigcode (sv_sigcode of size
38 * sv_szsigcode)
40 * execpath (absolute image path for rtld)
42 * SSP Canary (sizeof(long) * 8)
44 * page sizes array (usually sizeof(u_long) )
46 * "destp" -> argv, env strings (up to 262144 bytes)
48 static inline int setup_initial_stack(struct bsd_binprm *bprm,
49 abi_ulong *ret_addr, abi_ulong *stringp)
51 int i;
52 abi_ulong stack_hi_addr;
53 size_t execpath_len, stringspace;
54 abi_ulong destp, argvp, envp, p;
55 struct target_ps_strings ps_strs;
56 char canary[sizeof(abi_long) * 8];
58 stack_hi_addr = p = target_stkbas + target_stksiz;
60 /* Save some space for ps_strings. */
61 p -= sizeof(struct target_ps_strings);
63 /* Add machine dependent sigcode. */
64 p -= TARGET_SZSIGCODE;
65 if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
66 TARGET_FREEBSD_NR_sigreturn)) {
67 errno = EFAULT;
68 return -1;
70 if (bprm->fullpath) {
71 execpath_len = strlen(bprm->fullpath) + 1;
72 p -= roundup(execpath_len, sizeof(abi_ulong));
73 if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
74 errno = EFAULT;
75 return -1;
78 /* Add canary for SSP. */
79 qemu_guest_getrandom_nofail(canary, sizeof(canary));
80 p -= roundup(sizeof(canary), sizeof(abi_ulong));
81 if (memcpy_to_target(p, canary, sizeof(canary))) {
82 errno = EFAULT;
83 return -1;
85 /* Add page sizes array. */
86 p -= sizeof(abi_ulong);
87 if (put_user_ual(TARGET_PAGE_SIZE, p)) {
88 errno = EFAULT;
89 return -1;
92 * Deviate from FreeBSD stack layout: force stack to new page here
93 * so that signal trampoline is not sharing the page with user stack
94 * frames. This is actively harmful in qemu as it marks pages with
95 * code it translated as read-only, which is somewhat problematic
96 * for user trying to use the stack as intended.
98 p = rounddown(p, TARGET_PAGE_SIZE);
100 /* Calculate the string space needed */
101 stringspace = 0;
102 for (i = 0; i < bprm->argc; ++i) {
103 stringspace += strlen(bprm->argv[i]) + 1;
105 for (i = 0; i < bprm->envc; ++i) {
106 stringspace += strlen(bprm->envp[i]) + 1;
108 if (stringspace > TARGET_ARG_MAX) {
109 errno = ENOMEM;
110 return -1;
112 /* Make room for the argv and envp strings */
113 destp = rounddown(p - stringspace, sizeof(abi_ulong));
114 p = argvp = destp - (bprm->argc + bprm->envc + 2) * sizeof(abi_ulong);
115 /* Remember the strings pointer */
116 if (stringp) {
117 *stringp = destp;
120 * Add argv strings. Note that the argv[] vectors are added by
121 * loader_build_argptr()
123 /* XXX need to make room for auxargs */
124 ps_strs.ps_argvstr = tswapl(argvp);
125 ps_strs.ps_nargvstr = tswap32(bprm->argc);
126 for (i = 0; i < bprm->argc; ++i) {
127 size_t len = strlen(bprm->argv[i]) + 1;
129 if (memcpy_to_target(destp, bprm->argv[i], len)) {
130 errno = EFAULT;
131 return -1;
133 if (put_user_ual(destp, argvp)) {
134 errno = EFAULT;
135 return -1;
137 argvp += sizeof(abi_ulong);
138 destp += len;
140 if (put_user_ual(0, argvp)) {
141 errno = EFAULT;
142 return -1;
145 * Add env strings. Note that the envp[] vectors are added by
146 * loader_build_argptr().
148 envp = argvp + sizeof(abi_ulong);
149 ps_strs.ps_envstr = tswapl(envp);
150 ps_strs.ps_nenvstr = tswap32(bprm->envc);
151 for (i = 0; i < bprm->envc; ++i) {
152 size_t len = strlen(bprm->envp[i]) + 1;
154 if (memcpy_to_target(destp, bprm->envp[i], len)) {
155 errno = EFAULT;
156 return -1;
158 if (put_user_ual(destp, envp)) {
159 errno = EFAULT;
160 return -1;
162 envp += sizeof(abi_ulong);
163 destp += len;
165 if (put_user_ual(0, envp)) {
166 errno = EFAULT;
167 return -1;
169 if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
170 sizeof(ps_strs))) {
171 errno = EFAULT;
172 return -1;
175 if (ret_addr) {
176 *ret_addr = p;
179 return 0;
182 #endif /* TARGET_OS_STACK_H */