1/* 2 * Copyright 2019, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12#include <sel4runtime.h> 13#include <sel4runtime/auxv.h> 14#include <sel4runtime/mode/elf.h> 15#include <sel4runtime/start.h> 16#include <sel4/sel4.h> 17#include <sel4runtime/gen_config.h> 18#include <autoconf.h> 19 20#include "init.h" 21#include "util.h" 22 23// Minimum alignment across all platforms. 24#define MIN_ALIGN_BYTES 16 25#define MIN_ALIGNED __attribute__((aligned (MIN_ALIGN_BYTES))) 26 27// Static TLS for initial thread. 28static char static_tls[CONFIG_SEL4RUNTIME_STATIC_TLS] MIN_ALIGNED = {}; 29 30// Thread lookup pointers. 31typedef struct { 32 sel4runtime_uintptr_t tls_base; 33} thread_lookup_t; 34 35// The seL4 runtime environment. 36static struct { 37 char const *process_name; 38 39 // optional bootinfo pointer. 40 seL4_BootInfo *bootinfo; 41 42 /* 43 * The initial thread object is initially set to a static thread 44 * object. It is only used until a TLS is set up for the first 45 * thread. 46 * 47 * Once the TLS has been initialised for the first thread, this is 48 * then set to NULL and the thread local reference should be used. 49 */ 50 sel4runtime_uintptr_t initial_thread_tls_base; 51 seL4_CPtr initial_thread_tcb; 52 seL4_IPCBuffer *initial_thread_ipc_buffer; 53 54 // ELF Headers 55 struct { 56 sel4runtime_size_t count; 57 sel4runtime_size_t size; 58 Elf_Phdr *headers; 59 } program_header; 60 61 // TLS images 62 struct { 63 // The location of the initial image in memory. 64 void *image; 65 // The size of the initial image in memory. 66 sel4runtime_size_t image_size; 67 // The size needed to store the full TLS. 68 sel4runtime_size_t memory_size; 69 // The size needed to store the TLS and the thread structure. 70 sel4runtime_size_t region_size; 71 // Alignment needed for the TLS data. 72 sel4runtime_size_t align; 73 // Offset of the TLS data from the thread pointer. 74 sel4runtime_size_t offset; 75 } tls; 76 77 // Argument vector 78 char const *const *argv; 79 int argc; 80 81 // Auxiliary vector 82 auxv_t const *auxv; 83 84 // Environment vector 85 char const *const *envp; 86 87 // Exit callbacks 88 sel4runtime_exit_cb *exit_cb; 89 sel4runtime_pre_exit_cb *pre_exit_cb; 90} env = { 91 /* 92 * Initialise the initial thread as referring to the global thread 93 * object. 94 */ 95 .initial_thread_tls_base = (sel4runtime_uintptr_t)SEL4RUNTIME_NULL, 96}; 97 98static void name_process(char const *name); 99static void parse_auxv(auxv_t const auxv[]); 100static void parse_phdrs(void); 101static void load_tls_data(Elf_Phdr *header); 102static void try_init_static_tls(void); 103static void copy_tls_data(unsigned char *tls); 104static sel4runtime_uintptr_t tls_base_from_tls_region(unsigned char *tls_region); 105static unsigned char *tls_from_tls_base(sel4runtime_uintptr_t tls_base); 106static unsigned char *tls_from_tls_region(unsigned char *tls_region); 107static thread_lookup_t *thread_lookup_from_tls_region(unsigned char *tls_region); 108static const sel4runtime_size_t tls_region_size(sel4runtime_size_t mem_size, sel4runtime_size_t align); 109static void empty_tls(void); 110static int is_initial_thread(void); 111 112char const *sel4runtime_process_name(void) 113{ 114 return env.process_name; 115} 116 117char const *const *sel4runtime_argv(void) 118{ 119 return env.argv; 120} 121 122int sel4runtime_argc(void) 123{ 124 return env.argc; 125} 126 127char const *const *sel4runtime_envp(void) 128{ 129 return env.envp; 130} 131 132auxv_t const *sel4runtime_auxv(void) 133{ 134 return env.auxv; 135} 136 137seL4_BootInfo *sel4runtime_bootinfo(void) 138{ 139 return env.bootinfo; 140} 141 142sel4runtime_size_t sel4runtime_get_tls_size(void) 143{ 144 return env.tls.region_size; 145} 146 147int sel4runtime_initial_tls_enabled(void) 148{ 149 /* 150 * If the TLS for the initial process has been activated, the thread 151 * object in the TLS will be used rather than the static thread 152 * object. 153 */ 154 return env.initial_thread_tls_base != (sel4runtime_uintptr_t)SEL4RUNTIME_NULL; 155} 156 157sel4runtime_uintptr_t sel4runtime_write_tls_image(void *tls_memory) 158{ 159 if (tls_memory == SEL4RUNTIME_NULL) { 160 return (sel4runtime_uintptr_t)SEL4RUNTIME_NULL; 161 } 162 163 copy_tls_data(tls_memory); 164 165 return tls_base_from_tls_region(tls_memory); 166} 167 168sel4runtime_uintptr_t sel4runtime_move_initial_tls(void *tls_memory) 169{ 170 if (tls_memory == SEL4RUNTIME_NULL) { 171 return (sel4runtime_uintptr_t)SEL4RUNTIME_NULL; 172 } 173 174 sel4runtime_uintptr_t tls_base = sel4runtime_write_tls_image(tls_memory); 175 if (tls_base == (sel4runtime_uintptr_t)SEL4RUNTIME_NULL) { 176 return (sel4runtime_uintptr_t)SEL4RUNTIME_NULL; 177 } 178 179 sel4runtime_set_tls_base(tls_base); 180 181 if (env.initial_thread_ipc_buffer != SEL4RUNTIME_NULL) { 182 __sel4_ipc_buffer = env.initial_thread_ipc_buffer; 183 } 184 185 env.initial_thread_tls_base = tls_base; 186 187#if defined(CONFIG_DEBUG_BUILD) 188 if (env.initial_thread_tcb && env.initial_thread_ipc_buffer && env.process_name) { 189 // The thread can only be named after the TLS is initialised 190 // and if an IPC buffer is present. 191 seL4_DebugNameThread(env.initial_thread_tcb, env.process_name); 192 } 193#endif 194 195 return env.initial_thread_tls_base; 196} 197 198sel4runtime_exit_cb *sel4runtime_set_exit(sel4runtime_exit_cb *cb) 199{ 200 sel4runtime_exit_cb *old = env.exit_cb; 201 env.exit_cb = cb; 202 return old; 203} 204 205sel4runtime_pre_exit_cb *sel4runtime_set_pre_exit(sel4runtime_pre_exit_cb *cb) 206{ 207 sel4runtime_pre_exit_cb *old = env.pre_exit_cb; 208 env.pre_exit_cb = cb; 209 return old; 210} 211 212void sel4runtime_exit(int code) 213{ 214 if (env.pre_exit_cb != SEL4RUNTIME_NULL) { 215 code = env.pre_exit_cb(code); 216 } 217 218 __sel4runtime_run_destructors(); 219 220 /* If the exit is never set this will try and call a NULL function 221 * pointer which should result in a fault. This is as good a way as 222 * any to exit the process if we don't know anything better about 223 * the environment. */ 224 env.exit_cb(code); 225} 226 227int __sel4runtime_write_tls_variable( 228 sel4runtime_uintptr_t dest_tls_base, 229 unsigned char *local_tls_dest, 230 unsigned char *src, 231 sel4runtime_size_t bytes 232) 233{ 234 sel4runtime_uintptr_t local_tls_base = sel4runtime_get_tls_base(); 235 unsigned char *local_tls = tls_from_tls_base(local_tls_base); 236 sel4runtime_size_t offset = local_tls_dest - local_tls; 237 sel4runtime_size_t tls_size = env.tls.memory_size; 238 239 // Write must not go past end of TLS. 240 if (offset > tls_size || offset + bytes > tls_size) { 241 return -1; 242 } 243 244 unsigned char *dest_tls = tls_from_tls_base(dest_tls_base); 245 unsigned char *dest_addr = dest_tls + offset; 246 247 __sel4runtime_memcpy(dest_addr, src, bytes); 248 249 return 0; 250} 251 252void __sel4runtime_load_env( 253 int argc, 254 char const *const *argv, 255 char const *const *envp, 256 auxv_t const auxv[] 257) 258{ 259 empty_tls(); 260 parse_auxv(auxv); 261 parse_phdrs(); 262 if (argc > 0) { 263 name_process(argv[0]); 264 } 265 try_init_static_tls(); 266 267 env.argc = argc; 268 env.argv = argv; 269 env.auxv = auxv; 270 env.envp = envp; 271 272 __sel4runtime_run_constructors(); 273} 274 275static void name_process(char const *name) 276{ 277 env.process_name = name; 278 279 while (name && *name != '\0') { 280 if (*name == '/') { 281 env.process_name = name + 1; 282 } 283 284 name++; 285 } 286} 287 288static void parse_auxv(auxv_t const auxv[]) 289{ 290 for (int i = 0; auxv[i].a_type != AT_NULL; i++) { 291 switch (auxv[i].a_type) { 292 case AT_PHENT: { 293 env.program_header.size = auxv[i].a_un.a_val; 294 break; 295 } 296 case AT_PHNUM: { 297 env.program_header.count = auxv[i].a_un.a_val; 298 break; 299 } 300 case AT_PHDR: { 301 env.program_header.headers = auxv[i].a_un.a_ptr; 302 break; 303 } 304 case AT_SEL4_BOOT_INFO: { 305 seL4_BootInfo *bootinfo = auxv[i].a_un.a_ptr; 306 if (bootinfo == SEL4RUNTIME_NULL) { 307 break; 308 } 309 env.bootinfo = bootinfo; 310 env.initial_thread_ipc_buffer = bootinfo->ipcBuffer; 311 env.initial_thread_tcb = seL4_CapInitThreadTCB; 312 break; 313 } 314 case AT_SEL4_IPC_BUFFER_PTR: { 315 env.initial_thread_ipc_buffer = auxv[i].a_un.a_ptr; 316 break; 317 } 318 case AT_SEL4_TCB: { 319 env.initial_thread_tcb = auxv[i].a_un.a_val; 320 break; 321 } 322 default: 323 break; 324 } 325 } 326} 327 328static void parse_phdrs(void) 329{ 330 for (sel4runtime_size_t h = 0; h < env.program_header.count; h++) { 331 Elf_Phdr *header = &env.program_header.headers[h]; 332 switch (header->p_type) { 333 case PT_TLS: 334 load_tls_data(header); 335 break; 336 default: 337 break; 338 } 339 } 340} 341 342static void load_tls_data(Elf_Phdr *header) 343{ 344 env.tls.image = (void *) header->p_vaddr; 345 if (header->p_align > MIN_ALIGN_BYTES) { 346 env.tls.align = header->p_align; 347 } else { 348 env.tls.align = MIN_ALIGN_BYTES; 349 } 350 env.tls.image_size = header->p_filesz; 351 env.tls.memory_size = ROUND_UP(header->p_memsz, header->p_align); 352 env.tls.region_size = tls_region_size( 353 env.tls.memory_size, 354 env.tls.align 355 ); 356} 357 358static void try_init_static_tls(void) 359{ 360 if (env.tls.region_size <= sizeof(static_tls)) { 361 sel4runtime_move_initial_tls(static_tls); 362 } 363} 364 365static void copy_tls_data(unsigned char *tls_region) 366{ 367 unsigned char *tls = tls_from_tls_region(tls_region); 368 __sel4runtime_memcpy(tls, env.tls.image, env.tls.image_size); 369 unsigned char *tbss = &tls[env.tls.image_size]; 370 __sel4runtime_memset(tbss, 0, env.tls.memory_size - env.tls.image_size); 371 372 thread_lookup_t *lookup = thread_lookup_from_tls_region(tls_region); 373 if (lookup != SEL4RUNTIME_NULL) { 374 lookup->tls_base = tls_base_from_tls_region(tls_region); 375 } 376} 377 378static sel4runtime_uintptr_t tls_base_from_tls_region(unsigned char *tls_region) 379{ 380 sel4runtime_uintptr_t tls_base = (sel4runtime_uintptr_t)tls_region; 381#if !defined(TLS_ABOVE_TP) 382 tls_base += env.tls.memory_size; 383#endif 384 return ROUND_UP(tls_base, env.tls.align); 385} 386 387static unsigned char *tls_from_tls_base(sel4runtime_uintptr_t tls_base) 388{ 389 sel4runtime_uintptr_t tls_addr = tls_base; 390#if !defined(TLS_ABOVE_TP) 391 tls_addr -= env.tls.memory_size; 392#endif 393#if defined(GAP_ABOVE_TP) 394 tls_addr += GAP_ABOVE_TP; 395#endif 396 return (unsigned char *)tls_addr; 397} 398 399static unsigned char *tls_from_tls_region(unsigned char *tls_region) 400{ 401 return tls_from_tls_base(tls_base_from_tls_region(tls_region)); 402} 403 404static thread_lookup_t *thread_lookup_from_tls_region( 405 unsigned char *tls_region 406) 407{ 408#if !defined(TLS_ABOVE_TP) 409 return (thread_lookup_t *)tls_base_from_tls_region(tls_region); 410#else 411 return SEL4RUNTIME_NULL; 412#endif 413} 414 415static const sel4runtime_size_t tls_region_size(sel4runtime_size_t mem_size, sel4runtime_size_t align) 416{ 417 return align 418 + ROUND_UP(sizeof(thread_lookup_t), align) 419#if defined(GAP_ABOVE_TP) 420 + ROUND_UP(GAP_ABOVE_TP, align) 421#endif 422 + ROUND_UP(mem_size, align); 423} 424 425static void empty_tls(void) 426{ 427 env.tls.image = SEL4RUNTIME_NULL; 428 env.tls.align = MIN_ALIGN_BYTES; 429 env.tls.image_size = 0; 430 env.tls.memory_size = 0; 431 env.tls.region_size = tls_region_size( 432 env.tls.memory_size, 433 env.tls.align 434 ); 435} 436 437/* 438 * Check if the executing thread is the inital thread of the process. 439 * 440 * This will optimistically assume that the current thread is the 441 * initial thread of no thread ever had TLS configured. 442 */ 443static int is_initial_thread(void) 444{ 445 return env.initial_thread_tls_base == (sel4runtime_uintptr_t)SEL4RUNTIME_NULL 446 || sel4runtime_get_tls_base() == env.initial_thread_tls_base; 447} 448