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