1 /* Copyright (c) 2008, Sandia National Laboratories */
3 #include <lwk/liblwk.h>
7 * Verifies that an ELF header is sane.
8 * Returns 0 if header is sane and random non-zero values if header is insane.
11 elf_check_hdr(const struct elfhdr *hdr)
13 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) {
14 print(TYPE_ERR "bad e_ident %#x\n",
15 *((unsigned int *)hdr->e_ident));
18 if (hdr->e_ident[EI_CLASS] != ELF_CLASS) {
19 print(TYPE_ERR "bad e_ident[EI_CLASS] %#x\n",
20 (unsigned int)hdr->e_ident[EI_CLASS]);
23 if (hdr->e_ident[EI_DATA] != ELF_DATA) {
24 print(TYPE_ERR "bad e_ident[EI_DATA] %#x\n",
25 (unsigned int)hdr->e_ident[EI_DATA]);
28 if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
29 print(TYPE_ERR "bad e_ident[EI_VERSION] %#x\n",
30 (unsigned int)hdr->e_ident[EI_VERSION]);
33 if (hdr->e_ident[EI_OSABI] != ELF_OSABI) {
34 print(TYPE_ERR "bad e_dent[EI_OSABI] %#x\n",
35 (unsigned int)hdr->e_ident[EI_OSABI]);
38 if (hdr->e_type != ET_EXEC) {
39 print(TYPE_ERR "bad e_type %#x\n",
40 (unsigned int)hdr->e_type);
43 if (hdr->e_machine != ELF_ARCH) {
44 print(TYPE_ERR "bad e_machine %#x\n",
45 (unsigned int)hdr->e_machine);
48 if (hdr->e_version != EV_CURRENT) {
49 print(TYPE_ERR "bad e_version %#x\n",
50 (unsigned int)hdr->e_version);
53 if (hdr->e_flags != 0) {
54 print(TYPE_ERR "bad e_flags %#x\n",
55 (unsigned int)hdr->e_flags);
63 * Prints the contents of an ELF file header to the console.
66 elf_print_elfhdr(const struct elfhdr *hdr)
68 print(TYPE_NORM "ELF File Header:\n");
69 print(TYPE_NORM " type %0#10x\n", (unsigned int) hdr->e_type );
70 print(TYPE_NORM " machine %0#10x\n", (unsigned int) hdr->e_machine );
71 print(TYPE_NORM " version %0#10x\n", (unsigned int) hdr->e_version );
72 print(TYPE_NORM " entry %0#18lx\n", (unsigned long) hdr->e_entry );
73 print(TYPE_NORM " phoff %0#18lx\n", (unsigned long) hdr->e_phoff );
74 print(TYPE_NORM " shoff %0#18lx\n", (unsigned long) hdr->e_shoff );
75 print(TYPE_NORM " flags %0#10x\n", (unsigned int) hdr->e_flags );
76 print(TYPE_NORM " ehsize %0#10x\n", (unsigned int) hdr->e_ehsize );
77 print(TYPE_NORM " phentsize %0#10x\n", (unsigned int) hdr->e_phentsize );
78 print(TYPE_NORM " phnum %0#10x\n", (unsigned int) hdr->e_phnum );
79 print(TYPE_NORM " shentsize %0#10x\n", (unsigned int) hdr->e_shentsize );
80 print(TYPE_NORM " shnum %0#10x\n", (unsigned int) hdr->e_shnum );
81 print(TYPE_NORM " shstrndx %0#10x\n", (unsigned int) hdr->e_shstrndx );
85 * Prints the contents of an ELF program header to the console.
88 elf_print_phdr(const struct elf_phdr *hdr)
92 switch (hdr->p_type) {
93 case PT_NULL: name = "NULL"; break;
94 case PT_LOAD: name = "LOAD"; break;
95 case PT_DYNAMIC: name = "DYNAMIC"; break;
96 case PT_INTERP: name = "INTERP"; break;
97 case PT_NOTE: name = "NOTE"; break;
98 case PT_SHLIB: name = "SHLIB"; break;
99 case PT_PHDR: name = "PHDR"; break;
100 case PT_LOPROC: name = "LOPROC"; break;
101 case PT_HIPROC: name = "HIPROC"; break;
102 default: name = "UNDEFINED TYPE";
105 print(TYPE_NORM "ELF Program Segment Header:\n");
106 print(TYPE_NORM " type %s\n", name);
107 print(TYPE_NORM " flags %0#10x\n", (unsigned int) hdr->p_flags );
108 print(TYPE_NORM " offset %0#18lx\n", (unsigned long) hdr->p_offset );
109 print(TYPE_NORM " vaddr %0#18lx\n", (unsigned long) hdr->p_vaddr );
110 print(TYPE_NORM " paddr %0#18lx\n", (unsigned long) hdr->p_paddr );
111 print(TYPE_NORM " filesz %0#18lx\n", (unsigned long) hdr->p_filesz );
112 print(TYPE_NORM " memsz %0#18lx\n", (unsigned long) hdr->p_memsz );
113 print(TYPE_NORM " align %0#18lx\n", (unsigned long) hdr->p_align );
117 * Converts ELF flags to the corresponding kernel memory subsystem flags.
120 elf_pflags_to_vmflags(unsigned int elf_pflags)
122 vmflags_t vmflags = VM_USER;
123 if ( elf_pflags & PF_R ) vmflags |= VM_READ;
124 if ( elf_pflags & PF_W ) vmflags |= VM_WRITE;
125 if ( elf_pflags & PF_X ) vmflags |= VM_EXEC;
130 * Determines an ELF executable's entry point... where to start executing.
131 * Note: The address returned is in the context of the executing ELF
132 * image, not an address within the passed in elf_image.
135 elf_entry_point(const void *elf_image)
137 const struct elfhdr *ehdr = elf_image;
138 return ehdr->e_entry;
142 * Determines the address of an ELF executable's program header table.
143 * Note: The address returned is in the context of the executing ELF
144 * image, not an address within the passed in elf_image.
147 elf_phdr_table_addr(const void *elf_image)
149 const struct elfhdr *ehdr = elf_image;
150 struct elf_phdr *phdr_array, *phdr;
153 phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
155 for (i = 0; i < ehdr->e_phnum; i++) {
156 phdr = &phdr_array[i];
157 if (phdr->p_type == PT_LOAD)
158 return phdr->p_vaddr - phdr->p_offset + ehdr->e_phoff;
164 * Returns the number of entries in an ELF executable's program header table.
167 elf_num_phdrs(const void *elf_image)
169 const struct elfhdr *ehdr = elf_image;
170 return ehdr->e_phnum;
174 * Determines where the UNIX heap should start for a given ELF executable.
175 * Note: The address returned is in the context of the executing ELF
176 * image, not an address relative to the passed in elf_image.
179 elf_heap_start(const void *elf_image)
181 const struct elfhdr *ehdr;
182 const struct elf_phdr *phdr_array;
183 const struct elf_phdr *phdr;
184 vaddr_t end, heap_start=0;
187 /* Locate the program header array (in this context) */
189 phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
191 for (i = 0; i < ehdr->e_phnum; i++) {
192 phdr = &phdr_array[i];
193 if (phdr->p_type != PT_LOAD)
196 /* Calculate the end of the LOAD segment in memory */
197 end = phdr->p_vaddr + phdr->p_memsz;
199 if (end > heap_start)
207 * Given an argument string like "arg1=foo arg2=bar", parses it into
208 * an argv[] or envp[] style array of string pointers. Useful for
209 * constructing the argv and envp arguments to elf_init_stack().
221 while (strlen(str)) {
222 /* move past white space */
223 while (*str && isspace(*str))
228 /* find the end of the string */
229 while (*str && !isspace(*str))
246 * Writes an auxiliary info table entry.
250 struct aux_ent * table,
256 table[index].id = id;
257 table[index].val = val;
261 * Determines the value of the current stack pointer in the target
262 * address space. The sp argument is the stack pointer in this context
263 * (i.e., the context this code is executing in), stack_mapping is the
264 * address of the stack in this context, stack_start is the address
265 * of the stack in the target address space, and extent is the size
269 sp_in_aspace(void *sp,
270 void *stack_mapping, vaddr_t stack_start, size_t extent)
272 vaddr_t stack_end = (vaddr_t)stack_mapping + extent;
273 vaddr_t stack_vend = stack_start + extent;
274 size_t stack_offset = stack_end - (vaddr_t)sp;
276 return stack_vend - stack_offset;
280 * Sets up the initial stack for a new task. This includes storing the
281 * argv[] argument array, envp[] environment array, and auxiliary info table
282 * to the top of the user stack in the format that the C library expects them.
283 * Eventually the arguments get passed to the application's
284 * main(argc, argv, envp) function.
286 * If successful, the initial stack pointer value that should be used when
287 * starting the new task is returned in >stack_ptr.
289 * This function sets up the initial stack as follows (stack grows down):
291 * Environment Strings
294 * Auxiliary Info Table
300 * [IN] elf_image The ELF executable, needed to setup aux info.
301 * [IN] stack_mapping Where the stack is mapped in this context.
302 * [IN] stack_start Where the stack is located in the target aspace.
303 * [IN] stack_extent Size of the stack.
304 * [IN] argv[] Array of pointers to argument strings.
305 * [IN] envp[] Array of pointers to environment strings.
306 * [IN] uid User ID of the task
307 * [IN] gid Group ID of the task
308 * [IN] hwcap Hardware capability bitfield
309 * (used for AT_HWCAP entry in aux info table)
310 * [OUT] stack_ptr The initial stack pointer value for the new task.
311 * (note this is an address in the target aspace)
315 * Failure: Error Code, stack may have been partially initialized
320 void * stack_mapping,
333 const char *platform_str = ELF_PLATFORM;
334 struct aux_ent auxv[AT_ENTRIES];
335 size_t argc=0, envc=0, auxc=0;
336 size_t arg_len=0, env_len=0, auxv_len=0;
337 size_t platform_str_len=0;
340 char *platform_str_sp;
341 unsigned long *auxv_sp;
342 unsigned long *envp_sp;
343 unsigned long *argv_sp;
344 unsigned long *argc_sp;
346 /* Count # of arguments and their total string length */
347 while ((len = strlen(argv[argc])) != 0) {
348 arg_len += (len + 1);
352 /* Count # of environment variables and their total string length */
353 while ((len = strlen(envp[envc])) != 0) {
354 env_len += (len + 1);
358 /* Calculate length of the arch's platform string, if there is one */
360 platform_str_len = strlen(platform_str) + 1;
362 /* Make room on stack for arg, env, and platform strings */
363 sp = (uintptr_t)((vaddr_t)stack_mapping + stack_extent);
364 sp -= (arg_len + env_len + platform_str_len);
365 strings_sp = (void *) sp;
367 /* Build the auxilliary information table */
368 write_aux(auxv, auxc++, AT_HWCAP, hwcap);
369 write_aux(auxv, auxc++, AT_PAGESZ, ELF_EXEC_PAGESIZE);
370 write_aux(auxv, auxc++, AT_CLKTCK, 1000000l);
371 write_aux(auxv, auxc++, AT_PHDR, elf_phdr_table_addr(elf_image));
372 write_aux(auxv, auxc++, AT_PHENT, sizeof(struct elf_phdr));
373 write_aux(auxv, auxc++, AT_PHNUM, elf_num_phdrs(elf_image));
374 write_aux(auxv, auxc++, AT_BASE, 0);
375 write_aux(auxv, auxc++, AT_FLAGS, 0);
376 write_aux(auxv, auxc++, AT_ENTRY, elf_entry_point(elf_image));
377 write_aux(auxv, auxc++, AT_UID, uid);
378 write_aux(auxv, auxc++, AT_EUID, uid);
379 write_aux(auxv, auxc++, AT_GID, gid);
380 write_aux(auxv, auxc++, AT_EGID, gid);
381 write_aux(auxv, auxc++, AT_SECURE, 0);
383 platform_str_sp = strings_sp;
385 auxv, auxc++, AT_PLATFORM,
386 sp_in_aspace(platform_str_sp,
387 stack_mapping, stack_start,
391 write_aux(auxv, auxc++, AT_NULL, 0);
393 /* Make room on stack for aux info table */
394 auxv_len = auxc * sizeof(struct aux_ent);
397 /* Make room on stack for argc, argv[], envp[] */
398 sp -= ((1 + (argc + 1) + (envc + 1)) * sizeof(unsigned long));
400 /* Align stack to 16-byte boundary */
401 sp = round_down(sp, 16);
403 /* Calculate stack address to store argc, argv[], envp[], and auxv[] */
404 argc_sp = (unsigned long *) sp;
405 argv_sp = argc_sp + 1;
406 envp_sp = argv_sp + argc + 1;
407 auxv_sp = envp_sp + envc + 1;
409 /* Store arch's platform string, if there is one */
411 memcpy(strings_sp, platform_str, platform_str_len);
412 strings_sp += platform_str_len;
415 /* Store the auxiliary information array */
416 memcpy(auxv_sp, auxv, auxv_len);
419 for (i = 0; i < argc; i++) {
420 len = strlen(argv[i]) + 1;
421 memcpy(strings_sp, argv[i], len);
422 argv_sp[i] = sp_in_aspace(strings_sp,
423 stack_mapping, stack_start,
427 argv_sp[i] = 0; /* NULL terminate argv[] */
430 for (i = 0; i < envc; i++) {
431 len = strlen(envp[i]) + 1;
432 memcpy(strings_sp, envp[i], len);
433 envp_sp[i] = sp_in_aspace(strings_sp,
434 stack_mapping, stack_start,
438 envp_sp[i] = 0; /* NULL terminate argv[] */
444 *stack_ptr = sp_in_aspace((void *)sp,
445 stack_mapping, stack_start,
452 * A "default" alloc_pmem() function for use with elf_load_executable().
453 * A user may wish to define a custom replacement alloc_pmem() function
454 * to, for example, keep track of the physical memory that is allocated.
457 elf_dflt_alloc_pmem(size_t size, size_t alignment, uintptr_t arg)
459 struct pmem_region result;
461 if (pmem_alloc_umem(size, alignment, &result))
464 /* Mark the memory as being used by the init task */
465 result.type = PMEM_TYPE_INIT_TASK;
466 BUG_ON(pmem_update(&result));
472 load_writable_segment(
474 struct elf_phdr * phdr,
479 uintptr_t alloc_pmem_arg,
480 paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
489 /* Figure out my address space ID */
490 if ((status = aspace_get_myid(&my_aspace_id)))
493 /* Allocate physical memory for the segment */
494 if (!(pmem = alloc_pmem(extent, pagesz, alloc_pmem_arg)))
497 /* Map the segment into the target address space */
503 elf_pflags_to_vmflags(phdr->p_flags),
511 /* Map the segment into this address space */
513 aspace_map_region_anywhere(
517 (VM_USER|VM_READ|VM_WRITE),
525 /* Copy segment data from ELF image into the target address space
526 * (via its temporary mapping in our address space) */
527 dst = local_start + (phdr->p_vaddr - start);
528 src = (vaddr_t)elf_image + phdr->p_offset;
529 memcpy((void *)dst, (void *)src, phdr->p_filesz);
531 /* Unmap the segment from this address space */
532 status = aspace_del_region(my_aspace_id, local_start, extent);
540 load_readonly_segment(
541 paddr_t elf_image_paddr,
542 struct elf_phdr * phdr,
549 return aspace_map_region(
553 elf_pflags_to_vmflags(phdr->p_flags),
557 round_down(phdr->p_offset, pagesz)
562 * Loads an ELF executable image into the specified address space.
565 * [IN] elf_image: Location of ELF image in this address space.
566 * [IN] elf_image_paddr: Location of ELF image in physical memory.
567 * [IN] aspace_id: Address space to load ELF image into.
568 * [IN] pagesz: Page size to use when mapping ELF image.
569 * [IN] alloc_pmem_arg: Argument to pass to alloc_pmem().
570 * [IN] alloc_pmem: Function pointer to use to allocate physical
571 * memory for the region. alloc_mem() returns
572 * the physical address of the memory allocated.
576 * Failure: Error Code, the target address space is left in an
577 * undefined state and should be destroyed.
582 paddr_t elf_image_paddr,
585 uintptr_t alloc_pmem_arg,
586 paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
589 struct elfhdr * ehdr;
590 struct elf_phdr * phdr_array;
591 struct elf_phdr * phdr;
595 size_t num_load_segments=0;
598 /* Locate the program header array (in this context) */
600 phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
602 /* Set up a region for each program segment */
603 for (i = 0; i < ehdr->e_phnum; i++) {
604 phdr = &phdr_array[i];
605 if (phdr->p_type != PT_LOAD)
608 /* Calculate the segment's bounds */
609 start = round_down(phdr->p_vaddr, pagesz);
610 end = round_up(phdr->p_vaddr + phdr->p_memsz, pagesz);
611 extent = end - start;
613 if (phdr->p_flags & PF_W) {
614 /* Writable segments must be copied into the
615 * target address space */
617 load_writable_segment(
630 /* Read-only segments are mapped directly
631 * from the ELF image */
633 load_readonly_segment(
648 return (num_load_segments) ? 0 : -ENOENT;
659 uintptr_t alloc_pmem_arg,
660 paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg),
666 *pmem = alloc_pmem(extent, pagesz, alloc_pmem_arg);
668 print("Failed to allocate physical memory for %s.", name);
672 status = aspace_map_region(aspace_id, start, extent,
676 print("Failed to map physical memory for %s (status=%d).",
685 * Maximum number of arguments and environment variables that may
686 * be passed to the new task created by elf_load().
692 * Kitchen-sink ELF image load function.
693 * If something more custom is desired, this function can be used as a guide
694 * for what needs to be done to load an ELF executable and setup the
695 * accompanying address space.
700 paddr_t elf_image_paddr,
702 id_t desired_aspace_id,
708 start_state_t * start_state,
709 uintptr_t alloc_pmem_arg,
710 paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
714 char *argv[MAX_ARGC] = { (char *)name };
715 char *envp[MAX_ENVC];
716 id_t my_aspace_id, aspace_id;
717 vaddr_t heap_start, stack_start, stack_end, stack_ptr;
718 vaddr_t local_stack_start;
719 size_t heap_extent, stack_extent;
720 paddr_t heap_pmem, stack_pmem;
723 if (!elf_image || !start_state || !alloc_pmem)
726 if (elf_init_str_array(MAX_ARGC-1, argv+1, argv_str)) {
727 print("Too many ARGV strings.");
731 if (elf_init_str_array(MAX_ENVC, envp, envp_str)) {
732 print("Too many ENVP strings.");
736 if ((status = aspace_create(desired_aspace_id, "init_task", &aspace_id))) {
737 print("Failed to create aspace (status=%d).", status);
741 /* Load the ELF executable's LOAD segments */
744 elf_image, /* where I can access the ELF image */
745 elf_image_paddr, /* where it is in physical memory */
746 aspace_id, /* the address space to map it into */
747 pagesz, /* page size to map it with */
748 0, /* arg to pass to alloc_pmem */
749 alloc_pmem /* func to use to allocate phys mem */
752 print("Failed to load ELF image (status=%d).", status);
756 /* Create the UNIX heap */
757 heap_start = round_up(elf_heap_start(elf_image), pagesz);
758 heap_extent = round_up(heap_size, pagesz);
764 (VM_USER|VM_READ|VM_WRITE|VM_EXEC|VM_HEAP),
772 print("Failed to create heap (status=%d).", status);
776 /* Create the stack region */
777 stack_end = SMARTMAP_ALIGN;
778 stack_start = round_down(stack_end - stack_size, pagesz);
779 stack_extent = stack_end - stack_start;
785 (VM_USER|VM_READ|VM_WRITE|VM_EXEC),
793 print("Failed to create stack (status=%d).", status);
797 /* Map the stack region into this address space */
798 if ((status = aspace_get_myid(&my_aspace_id)))
801 aspace_map_region_anywhere(
805 (VM_USER|VM_READ|VM_WRITE),
811 print("Failed to map stack locally (status=%d).", status);
815 /* Initialize the stack */
816 status = elf_hwcap(start_state->cpu_id, &hwcap);
818 print("Failed to get hw capabilities (status=%d).", status);
824 (void *)local_stack_start, /* Where I can access it */
825 stack_start, /* Where it is in target aspace */
828 start_state->uid, start_state->gid,
833 print("Failed to initialize stack (status=%d).", status);
837 start_state->aspace_id = aspace_id;
838 start_state->entry_point = elf_entry_point(elf_image);
839 start_state->stack_ptr = stack_ptr;