paul@324 | 1 | /* |
paul@324 | 2 | * Stack support for new tasks and threads. |
paul@324 | 3 | * |
paul@324 | 4 | * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk> |
paul@324 | 5 | * |
paul@324 | 6 | * This program is free software; you can redistribute it and/or |
paul@324 | 7 | * modify it under the terms of the GNU General Public License as |
paul@324 | 8 | * published by the Free Software Foundation; either version 2 of |
paul@324 | 9 | * the License, or (at your option) any later version. |
paul@324 | 10 | * |
paul@324 | 11 | * This program is distributed in the hope that it will be useful, |
paul@324 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@324 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@324 | 14 | * GNU General Public License for more details. |
paul@324 | 15 | * |
paul@324 | 16 | * You should have received a copy of the GNU General Public License |
paul@324 | 17 | * along with this program; if not, write to the Free Software |
paul@324 | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@324 | 19 | * Boston, MA 02110-1301, USA |
paul@324 | 20 | */ |
paul@324 | 21 | |
paul@324 | 22 | #include <l4/util/elf.h> |
paul@324 | 23 | #include <l4/util/util.h> |
paul@324 | 24 | |
paul@324 | 25 | #include <l4/libloader/adjust_stack> |
paul@324 | 26 | |
paul@324 | 27 | #include <mem/memory_utils.h> |
paul@324 | 28 | |
paul@324 | 29 | #include <stdio.h> |
paul@324 | 30 | #include <string.h> |
paul@324 | 31 | |
paul@324 | 32 | #include "stack.h" |
paul@324 | 33 | |
paul@324 | 34 | |
paul@324 | 35 | |
paul@324 | 36 | /* Initialise a stack in a memory segment. */ |
paul@324 | 37 | |
paul@324 | 38 | Stack::Stack(Segment &segment) |
paul@324 | 39 | : _segment(segment) |
paul@324 | 40 | { |
paul@324 | 41 | _element = (l4_umword_t *) (segment.buf + segment.size); |
paul@324 | 42 | |
paul@324 | 43 | /* Add a terminator for any additional initial capabilities. */ |
paul@324 | 44 | |
paul@324 | 45 | l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; |
paul@324 | 46 | |
paul@324 | 47 | *(--entry) = l4re_env_cap_entry_t(); |
paul@324 | 48 | _element = (l4_umword_t *) entry; |
paul@324 | 49 | } |
paul@324 | 50 | |
paul@324 | 51 | /* Push any additional initial capabilities. */ |
paul@324 | 52 | |
paul@324 | 53 | void Stack::push_cap_entries(l4re_env_cap_entry_t *entries) |
paul@324 | 54 | { |
paul@324 | 55 | l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; |
paul@324 | 56 | |
paul@324 | 57 | while ((entries != NULL) && (entries->cap != L4_INVALID_CAP)) |
paul@324 | 58 | *(--entry) = *entries; |
paul@324 | 59 | |
paul@324 | 60 | _caps = (l4_addr_t) entry; |
paul@324 | 61 | _element = (l4_umword_t *) entry; |
paul@324 | 62 | } |
paul@324 | 63 | |
paul@324 | 64 | /* Push environment values in reverse order. */ |
paul@324 | 65 | |
paul@324 | 66 | void Stack::push_string(char *s) |
paul@324 | 67 | { |
paul@324 | 68 | char *arg = (char *) _element; |
paul@324 | 69 | char *arg_last = arg; |
paul@324 | 70 | |
paul@324 | 71 | arg -= round(strlen(s) + 1, sizeof(l4_umword_t)); |
paul@324 | 72 | |
paul@324 | 73 | memset(arg, 0, arg_last - arg); |
paul@324 | 74 | memcpy(arg, s, strlen(s)); |
paul@324 | 75 | |
paul@324 | 76 | _element = (l4_umword_t *) arg; |
paul@324 | 77 | } |
paul@324 | 78 | |
paul@324 | 79 | /* Push environment values in reverse order. */ |
paul@324 | 80 | |
paul@324 | 81 | void Stack::push_env(char *envp[]) |
paul@324 | 82 | { |
paul@324 | 83 | _env_top = (char *) _element; |
paul@324 | 84 | _env_entries = 0; |
paul@324 | 85 | |
paul@324 | 86 | for (; *envp != NULL; envp++, _env_entries++) |
paul@324 | 87 | push_string(*envp); |
paul@324 | 88 | } |
paul@324 | 89 | |
paul@324 | 90 | /* Push argument values in reverse order. */ |
paul@324 | 91 | |
paul@324 | 92 | void Stack::push_args(int argc, char *argv[]) |
paul@324 | 93 | { |
paul@324 | 94 | _arg_top = (char *) _element; |
paul@324 | 95 | |
paul@324 | 96 | for (int i = 0; i < argc; i++) |
paul@324 | 97 | push_string(argv[i]); |
paul@324 | 98 | } |
paul@324 | 99 | |
paul@324 | 100 | /* Loader flags, debugging flags, and the KIP capability index. |
paul@324 | 101 | See: generate_l4aux in Remote_app_model */ |
paul@324 | 102 | |
paul@324 | 103 | void Stack::push_l4re_aux() |
paul@324 | 104 | { |
paul@324 | 105 | _aux = (l4re_aux_t *) _element; |
paul@324 | 106 | _aux--; |
paul@324 | 107 | _element = (l4_umword_t *) _aux; |
paul@324 | 108 | } |
paul@324 | 109 | |
paul@324 | 110 | void Stack::push_l4re_env() |
paul@324 | 111 | { |
paul@324 | 112 | _env = (l4re_env_t *) _element; |
paul@324 | 113 | _env--; |
paul@324 | 114 | _element = (l4_umword_t *) _env; |
paul@324 | 115 | } |
paul@324 | 116 | |
paul@324 | 117 | /* Set the common auxiliary information. */ |
paul@324 | 118 | |
paul@324 | 119 | void Stack::set_l4re_aux(l4re_aux_t *aux) |
paul@324 | 120 | { |
paul@324 | 121 | memcpy(_aux, aux, sizeof(l4re_aux_t)); |
paul@324 | 122 | |
paul@324 | 123 | /* Take the binary name from the first program argument. */ |
paul@324 | 124 | |
paul@324 | 125 | _aux->binary = (char *) _argv[0]; |
paul@324 | 126 | } |
paul@324 | 127 | |
paul@324 | 128 | /* Set the common environment, introducing the reference to additional |
paul@324 | 129 | capabilities. */ |
paul@324 | 130 | |
paul@324 | 131 | void Stack::set_l4re_env(l4re_env_t *env) |
paul@324 | 132 | { |
paul@324 | 133 | memcpy(_env, env, sizeof(l4re_env_t)); |
paul@324 | 134 | _env->caps = (l4re_env_cap_entry_t *) (_segment.region_address(_caps)); |
paul@324 | 135 | } |
paul@324 | 136 | |
paul@324 | 137 | /* Push the auxiliary vector. */ |
paul@324 | 138 | |
paul@324 | 139 | void Stack::push_auxv() |
paul@324 | 140 | { |
paul@324 | 141 | _auxv_end = (char *) _element; |
paul@324 | 142 | |
paul@324 | 143 | struct auxv_entry *auxv_base = (struct auxv_entry *) _element; |
paul@324 | 144 | |
paul@324 | 145 | *(--auxv_base) = {AT_NULL, 0}; |
paul@324 | 146 | |
paul@324 | 147 | /* L4Re global environment pointer. */ |
paul@324 | 148 | |
paul@324 | 149 | *(--auxv_base) = {AT_L4_ENV, _segment.region_address((char *) _env)}; |
paul@324 | 150 | |
paul@324 | 151 | /* L4Re auxiliary structure pointer. */ |
paul@324 | 152 | |
paul@324 | 153 | *(--auxv_base) = {AT_L4_AUX, _segment.region_address((char *) _aux)}; |
paul@324 | 154 | |
paul@324 | 155 | /* Apparently required entries. |
paul@324 | 156 | NOTE: The user/group identifiers should be obtained from the broader |
paul@324 | 157 | environment. */ |
paul@324 | 158 | |
paul@324 | 159 | *(--auxv_base) = {AT_PAGESZ, L4_PAGESIZE}; |
paul@324 | 160 | *(--auxv_base) = {AT_UID, 0}; |
paul@324 | 161 | *(--auxv_base) = {AT_EUID, 0}; |
paul@324 | 162 | *(--auxv_base) = {AT_GID, 0}; |
paul@324 | 163 | *(--auxv_base) = {AT_EGID, 0}; |
paul@324 | 164 | |
paul@324 | 165 | _element = (l4_umword_t *) auxv_base; |
paul@324 | 166 | } |
paul@324 | 167 | |
paul@324 | 168 | /* Fill the stack in reverse with an address, returning the size of the |
paul@324 | 169 | value. */ |
paul@324 | 170 | |
paul@324 | 171 | offset_t Stack::write_address(char *arg, char **addr, char *s) |
paul@324 | 172 | { |
paul@324 | 173 | offset_t size = round(strlen(s) + 1, sizeof(l4_umword_t)); |
paul@324 | 174 | |
paul@324 | 175 | *addr = (char *) _segment.region_address(arg - size); |
paul@324 | 176 | return size; |
paul@324 | 177 | } |
paul@324 | 178 | |
paul@324 | 179 | /* Populate stack with environment pointers, employing a pointer ordering |
paul@324 | 180 | that is the reverse of the value ordering. */ |
paul@324 | 181 | |
paul@324 | 182 | void Stack::push_envp(char *envp[]) |
paul@324 | 183 | { |
paul@324 | 184 | /* Write the terminating element. */ |
paul@324 | 185 | |
paul@324 | 186 | *(--_element) = 0; |
paul@324 | 187 | |
paul@324 | 188 | /* Reserve space and fill the stack from the top inwards. */ |
paul@324 | 189 | |
paul@324 | 190 | char **ep = (char **) (_element - _env_entries); |
paul@324 | 191 | char *arg = _env_top; |
paul@324 | 192 | |
paul@324 | 193 | for (; *envp != NULL; envp++, ep++) |
paul@324 | 194 | arg -= write_address(arg, ep, *envp); |
paul@324 | 195 | |
paul@324 | 196 | _element -= _env_entries; |
paul@324 | 197 | } |
paul@324 | 198 | |
paul@324 | 199 | /* Populate stack with argument pointers and count, employing a pointer |
paul@324 | 200 | ordering that is the reverse of the value ordering. */ |
paul@324 | 201 | |
paul@324 | 202 | void Stack::push_argv(int argc, char *argv[]) |
paul@324 | 203 | { |
paul@324 | 204 | /* Write the terminating element. */ |
paul@324 | 205 | |
paul@324 | 206 | *(--_element) = 0; |
paul@324 | 207 | |
paul@324 | 208 | /* Reserve space and fill the stack from the top inwards. */ |
paul@324 | 209 | |
paul@324 | 210 | _argv = (char **) (_element - argc); |
paul@324 | 211 | char *arg = _arg_top; |
paul@324 | 212 | |
paul@324 | 213 | for (int i = 0; i < argc; i++) |
paul@324 | 214 | arg -= write_address(arg, &_argv[i], argv[i]); |
paul@324 | 215 | |
paul@324 | 216 | /* Write the count. */ |
paul@324 | 217 | |
paul@324 | 218 | _element -= argc; |
paul@324 | 219 | |
paul@324 | 220 | *(--_element) = argc; |
paul@324 | 221 | } |
paul@324 | 222 | |
paul@324 | 223 | /* Adjust the stack alignment and return the stack address. */ |
paul@324 | 224 | |
paul@324 | 225 | l4_addr_t Stack::align_stack() |
paul@324 | 226 | { |
paul@324 | 227 | char *current = (char *) _element; |
paul@324 | 228 | char *adjusted = Ldr::adjust_sp(current, NULL); |
paul@324 | 229 | |
paul@324 | 230 | if (adjusted != current) |
paul@324 | 231 | memmove(adjusted, (const void *) current, _auxv_end - current); |
paul@324 | 232 | |
paul@324 | 233 | _element = (l4_umword_t *) adjusted; |
paul@324 | 234 | |
paul@324 | 235 | return _segment.region_address(adjusted); |
paul@324 | 236 | } |
paul@324 | 237 | |
paul@324 | 238 | /* Populate the stack with arguments and initial environment. */ |
paul@324 | 239 | |
paul@324 | 240 | void Stack::populate(int argc, char *argv[], char *envp[]) |
paul@324 | 241 | { |
paul@324 | 242 | /* Populate stack with environment and argument values. */ |
paul@324 | 243 | |
paul@324 | 244 | push_env(envp); |
paul@324 | 245 | push_args(argc, argv); |
paul@324 | 246 | |
paul@324 | 247 | /* Push L4Re flags, environment and auxiliary vector. */ |
paul@324 | 248 | |
paul@324 | 249 | push_l4re_aux(); |
paul@324 | 250 | push_l4re_env(); |
paul@324 | 251 | push_auxv(); |
paul@324 | 252 | |
paul@324 | 253 | /* Push environment and argument pointers. */ |
paul@324 | 254 | |
paul@324 | 255 | push_envp(envp); |
paul@324 | 256 | push_argv(argc, argv); |
paul@324 | 257 | |
paul@324 | 258 | /* Adjust the stack alignment, setting the start address. */ |
paul@324 | 259 | |
paul@324 | 260 | _start = align_stack(); |
paul@324 | 261 | } |
paul@324 | 262 | |
paul@324 | 263 | /* Return the stack pointer start address in the mapped program segment. */ |
paul@324 | 264 | |
paul@324 | 265 | l4_addr_t Stack::start_address() |
paul@324 | 266 | { |
paul@324 | 267 | return _start; |
paul@324 | 268 | } |
paul@324 | 269 | |
paul@324 | 270 | /* vim: tabstop=2 expandtab shiftwidth=2 |
paul@324 | 271 | */ |