+++ /dev/null
-/* Copyright (c) 2008, Sandia National Laboratories */
-
-#include <lwk/liblwk.h>
-#include <lwk/ctype.h>
-
-/**
- * Verifies that an ELF header is sane.
- * Returns 0 if header is sane and random non-zero values if header is insane.
- */
-int
-elf_check_hdr(const struct elfhdr *hdr)
-{
- if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) {
- print(TYPE_ERR "bad e_ident %#x\n",
- *((unsigned int *)hdr->e_ident));
- return -1;
- }
- if (hdr->e_ident[EI_CLASS] != ELF_CLASS) {
- print(TYPE_ERR "bad e_ident[EI_CLASS] %#x\n",
- (unsigned int)hdr->e_ident[EI_CLASS]);
- return -1;
- }
- if (hdr->e_ident[EI_DATA] != ELF_DATA) {
- print(TYPE_ERR "bad e_ident[EI_DATA] %#x\n",
- (unsigned int)hdr->e_ident[EI_DATA]);
- return -1;
- }
- if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
- print(TYPE_ERR "bad e_ident[EI_VERSION] %#x\n",
- (unsigned int)hdr->e_ident[EI_VERSION]);
- return -1;
- }
- if (hdr->e_ident[EI_OSABI] != ELF_OSABI) {
- print(TYPE_ERR "bad e_dent[EI_OSABI] %#x\n",
- (unsigned int)hdr->e_ident[EI_OSABI]);
- return -1;
- }
- if (hdr->e_type != ET_EXEC) {
- print(TYPE_ERR "bad e_type %#x\n",
- (unsigned int)hdr->e_type);
- return -1;
- }
- if (hdr->e_machine != ELF_ARCH) {
- print(TYPE_ERR "bad e_machine %#x\n",
- (unsigned int)hdr->e_machine);
- return -1;
- }
- if (hdr->e_version != EV_CURRENT) {
- print(TYPE_ERR "bad e_version %#x\n",
- (unsigned int)hdr->e_version);
- return -1;
- }
- if (hdr->e_flags != 0) {
- print(TYPE_ERR "bad e_flags %#x\n",
- (unsigned int)hdr->e_flags);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * Prints the contents of an ELF file header to the console.
- */
-void
-elf_print_elfhdr(const struct elfhdr *hdr)
-{
- print(TYPE_NORM "ELF File Header:\n");
- print(TYPE_NORM " type %0#10x\n", (unsigned int) hdr->e_type );
- print(TYPE_NORM " machine %0#10x\n", (unsigned int) hdr->e_machine );
- print(TYPE_NORM " version %0#10x\n", (unsigned int) hdr->e_version );
- print(TYPE_NORM " entry %0#18lx\n", (unsigned long) hdr->e_entry );
- print(TYPE_NORM " phoff %0#18lx\n", (unsigned long) hdr->e_phoff );
- print(TYPE_NORM " shoff %0#18lx\n", (unsigned long) hdr->e_shoff );
- print(TYPE_NORM " flags %0#10x\n", (unsigned int) hdr->e_flags );
- print(TYPE_NORM " ehsize %0#10x\n", (unsigned int) hdr->e_ehsize );
- print(TYPE_NORM " phentsize %0#10x\n", (unsigned int) hdr->e_phentsize );
- print(TYPE_NORM " phnum %0#10x\n", (unsigned int) hdr->e_phnum );
- print(TYPE_NORM " shentsize %0#10x\n", (unsigned int) hdr->e_shentsize );
- print(TYPE_NORM " shnum %0#10x\n", (unsigned int) hdr->e_shnum );
- print(TYPE_NORM " shstrndx %0#10x\n", (unsigned int) hdr->e_shstrndx );
-}
-
-/**
- * Prints the contents of an ELF program header to the console.
- */
-void
-elf_print_phdr(const struct elf_phdr *hdr)
-{
- char *name;
-
- switch (hdr->p_type) {
- case PT_NULL: name = "NULL"; break;
- case PT_LOAD: name = "LOAD"; break;
- case PT_DYNAMIC: name = "DYNAMIC"; break;
- case PT_INTERP: name = "INTERP"; break;
- case PT_NOTE: name = "NOTE"; break;
- case PT_SHLIB: name = "SHLIB"; break;
- case PT_PHDR: name = "PHDR"; break;
- case PT_LOPROC: name = "LOPROC"; break;
- case PT_HIPROC: name = "HIPROC"; break;
- default: name = "UNDEFINED TYPE";
- }
-
- print(TYPE_NORM "ELF Program Segment Header:\n");
- print(TYPE_NORM " type %s\n", name);
- print(TYPE_NORM " flags %0#10x\n", (unsigned int) hdr->p_flags );
- print(TYPE_NORM " offset %0#18lx\n", (unsigned long) hdr->p_offset );
- print(TYPE_NORM " vaddr %0#18lx\n", (unsigned long) hdr->p_vaddr );
- print(TYPE_NORM " paddr %0#18lx\n", (unsigned long) hdr->p_paddr );
- print(TYPE_NORM " filesz %0#18lx\n", (unsigned long) hdr->p_filesz );
- print(TYPE_NORM " memsz %0#18lx\n", (unsigned long) hdr->p_memsz );
- print(TYPE_NORM " align %0#18lx\n", (unsigned long) hdr->p_align );
-}
-
-/**
- * Converts ELF flags to the corresponding kernel memory subsystem flags.
- */
-vmflags_t
-elf_pflags_to_vmflags(unsigned int elf_pflags)
-{
- vmflags_t vmflags = VM_USER;
- if ( elf_pflags & PF_R ) vmflags |= VM_READ;
- if ( elf_pflags & PF_W ) vmflags |= VM_WRITE;
- if ( elf_pflags & PF_X ) vmflags |= VM_EXEC;
- return vmflags;
-}
-
-/**
- * Determines an ELF executable's entry point... where to start executing.
- * Note: The address returned is in the context of the executing ELF
- * image, not an address within the passed in elf_image.
- */
-vaddr_t
-elf_entry_point(const void *elf_image)
-{
- const struct elfhdr *ehdr = elf_image;
- return ehdr->e_entry;
-}
-
-/**
- * Determines the address of an ELF executable's program header table.
- * Note: The address returned is in the context of the executing ELF
- * image, not an address within the passed in elf_image.
- */
-vaddr_t
-elf_phdr_table_addr(const void *elf_image)
-{
- const struct elfhdr *ehdr = elf_image;
- struct elf_phdr *phdr_array, *phdr;
- unsigned int i;
-
- phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
-
- for (i = 0; i < ehdr->e_phnum; i++) {
- phdr = &phdr_array[i];
- if (phdr->p_type == PT_LOAD)
- return phdr->p_vaddr - phdr->p_offset + ehdr->e_phoff;
- }
- return 0;
-}
-
-/**
- * Returns the number of entries in an ELF executable's program header table.
- */
-unsigned int
-elf_num_phdrs(const void *elf_image)
-{
- const struct elfhdr *ehdr = elf_image;
- return ehdr->e_phnum;
-}
-
-/**
- * Determines where the UNIX heap should start for a given ELF executable.
- * Note: The address returned is in the context of the executing ELF
- * image, not an address relative to the passed in elf_image.
- */
-vaddr_t
-elf_heap_start(const void *elf_image)
-{
- const struct elfhdr *ehdr;
- const struct elf_phdr *phdr_array;
- const struct elf_phdr *phdr;
- vaddr_t end, heap_start=0;
- size_t i;
-
- /* Locate the program header array (in this context) */
- ehdr = elf_image;
- phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
-
- for (i = 0; i < ehdr->e_phnum; i++) {
- phdr = &phdr_array[i];
- if (phdr->p_type != PT_LOAD)
- continue;
-
- /* Calculate the end of the LOAD segment in memory */
- end = phdr->p_vaddr + phdr->p_memsz;
-
- if (end > heap_start)
- heap_start = end;
- }
-
- return heap_start;
-}
-
-/**
- * Given an argument string like "arg1=foo arg2=bar", parses it into
- * an argv[] or envp[] style array of string pointers. Useful for
- * constructing the argv and envp arguments to elf_init_stack().
- */
-int
-elf_init_str_array(
- size_t size,
- char * ptrs[],
- char * str
-)
-{
- size_t pos = 0;
- char *tmp;
-
- while (strlen(str)) {
- /* move past white space */
- while (*str && isspace(*str))
- ++str;
-
- tmp = str;
-
- /* find the end of the string */
- while (*str && !isspace(*str))
- ++str;
-
- *str++ = 0;
-
- if (strlen(tmp)) {
- if (pos == size - 1)
- return -1;
- ptrs[pos++] = tmp;
- }
-
- }
- ptrs[pos] = "";
- return 0;
-}
-
-/**
- * Writes an auxiliary info table entry.
- */
-static void
-write_aux(
- struct aux_ent * table,
- int index,
- unsigned long id,
- unsigned long val
-)
-{
- table[index].id = id;
- table[index].val = val;
-}
-
-/**
- * Determines the value of the current stack pointer in the target
- * address space. The sp argument is the stack pointer in this context
- * (i.e., the context this code is executing in), stack_mapping is the
- * address of the stack in this context, stack_start is the address
- * of the stack in the target address space, and extent is the size
- * of the stack.
- */
-static vaddr_t
-sp_in_aspace(void *sp,
- void *stack_mapping, vaddr_t stack_start, size_t extent)
-{
- vaddr_t stack_end = (vaddr_t)stack_mapping + extent;
- vaddr_t stack_vend = stack_start + extent;
- size_t stack_offset = stack_end - (vaddr_t)sp;
-
- return stack_vend - stack_offset;
-}
-
-/**
- * Sets up the initial stack for a new task. This includes storing the
- * argv[] argument array, envp[] environment array, and auxiliary info table
- * to the top of the user stack in the format that the C library expects them.
- * Eventually the arguments get passed to the application's
- * main(argc, argv, envp) function.
- *
- * If successful, the initial stack pointer value that should be used when
- * starting the new task is returned in >stack_ptr.
- *
- * This function sets up the initial stack as follows (stack grows down):
- *
- * Environment Strings
- * Argument Strings
- * Platform String
- * Auxiliary Info Table
- * envp[]
- * argv[]
- * argc
- *
- * Arguments:
- * [IN] elf_image The ELF executable, needed to setup aux info.
- * [IN] stack_mapping Where the stack is mapped in this context.
- * [IN] stack_start Where the stack is located in the target aspace.
- * [IN] stack_extent Size of the stack.
- * [IN] argv[] Array of pointers to argument strings.
- * [IN] envp[] Array of pointers to environment strings.
- * [IN] uid User ID of the task
- * [IN] gid Group ID of the task
- * [IN] hwcap Hardware capability bitfield
- * (used for AT_HWCAP entry in aux info table)
- * [OUT] stack_ptr The initial stack pointer value for the new task.
- * (note this is an address in the target aspace)
- *
- * Returns:
- * Success: 0
- * Failure: Error Code, stack may have been partially initialized
- */
-int
-elf_init_stack(
- void * elf_image,
- void * stack_mapping,
- vaddr_t stack_start,
- size_t stack_extent,
- char * argv[],
- char * envp[],
- uid_t uid,
- gid_t gid,
- uint32_t hwcap,
- vaddr_t * stack_ptr
-)
-{
- size_t i, len;
- uintptr_t sp;
- const char *platform_str = ELF_PLATFORM;
- struct aux_ent auxv[AT_ENTRIES];
- size_t argc=0, envc=0, auxc=0;
- size_t arg_len=0, env_len=0, auxv_len=0;
- size_t platform_str_len=0;
-
- char *strings_sp;
- char *platform_str_sp;
- unsigned long *auxv_sp;
- unsigned long *envp_sp;
- unsigned long *argv_sp;
- unsigned long *argc_sp;
-
- /* Count # of arguments and their total string length */
- while ((len = strlen(argv[argc])) != 0) {
- arg_len += (len + 1);
- ++argc;
- }
-
- /* Count # of environment variables and their total string length */
- while ((len = strlen(envp[envc])) != 0) {
- env_len += (len + 1);
- ++envc;
- }
-
- /* Calculate length of the arch's platform string, if there is one */
- if (platform_str)
- platform_str_len = strlen(platform_str) + 1;
-
- /* Make room on stack for arg, env, and platform strings */
- sp = (uintptr_t)((vaddr_t)stack_mapping + stack_extent);
- sp -= (arg_len + env_len + platform_str_len);
- strings_sp = (void *) sp;
-
- /* Build the auxilliary information table */
- write_aux(auxv, auxc++, AT_HWCAP, hwcap);
- write_aux(auxv, auxc++, AT_PAGESZ, ELF_EXEC_PAGESIZE);
- write_aux(auxv, auxc++, AT_CLKTCK, 1000000l);
- write_aux(auxv, auxc++, AT_PHDR, elf_phdr_table_addr(elf_image));
- write_aux(auxv, auxc++, AT_PHENT, sizeof(struct elf_phdr));
- write_aux(auxv, auxc++, AT_PHNUM, elf_num_phdrs(elf_image));
- write_aux(auxv, auxc++, AT_BASE, 0);
- write_aux(auxv, auxc++, AT_FLAGS, 0);
- write_aux(auxv, auxc++, AT_ENTRY, elf_entry_point(elf_image));
- write_aux(auxv, auxc++, AT_UID, uid);
- write_aux(auxv, auxc++, AT_EUID, uid);
- write_aux(auxv, auxc++, AT_GID, gid);
- write_aux(auxv, auxc++, AT_EGID, gid);
- write_aux(auxv, auxc++, AT_SECURE, 0);
- if (platform_str) {
- platform_str_sp = strings_sp;
- write_aux(
- auxv, auxc++, AT_PLATFORM,
- sp_in_aspace(platform_str_sp,
- stack_mapping, stack_start,
- stack_extent)
- );
- }
- write_aux(auxv, auxc++, AT_NULL, 0);
-
- /* Make room on stack for aux info table */
- auxv_len = auxc * sizeof(struct aux_ent);
- sp -= auxv_len;
-
- /* Make room on stack for argc, argv[], envp[] */
- sp -= ((1 + (argc + 1) + (envc + 1)) * sizeof(unsigned long));
-
- /* Align stack to 16-byte boundary */
- sp = round_down(sp, 16);
-
- /* Calculate stack address to store argc, argv[], envp[], and auxv[] */
- argc_sp = (unsigned long *) sp;
- argv_sp = argc_sp + 1;
- envp_sp = argv_sp + argc + 1;
- auxv_sp = envp_sp + envc + 1;
-
- /* Store arch's platform string, if there is one */
- if (platform_str) {
- memcpy(strings_sp, platform_str, platform_str_len);
- strings_sp += platform_str_len;
- }
-
- /* Store the auxiliary information array */
- memcpy(auxv_sp, auxv, auxv_len);
-
- /* Store argv[] */
- for (i = 0; i < argc; i++) {
- len = strlen(argv[i]) + 1;
- memcpy(strings_sp, argv[i], len);
- argv_sp[i] = sp_in_aspace(strings_sp,
- stack_mapping, stack_start,
- stack_extent),
- strings_sp += len;
- }
- argv_sp[i] = 0; /* NULL terminate argv[] */
-
- /* Store envp[] */
- for (i = 0; i < envc; i++) {
- len = strlen(envp[i]) + 1;
- memcpy(strings_sp, envp[i], len);
- envp_sp[i] = sp_in_aspace(strings_sp,
- stack_mapping, stack_start,
- stack_extent),
- strings_sp += len;
- }
- envp_sp[i] = 0; /* NULL terminate argv[] */
-
- /* Store argc */
- *argc_sp = argc;
-
- if (stack_ptr) {
- *stack_ptr = sp_in_aspace((void *)sp,
- stack_mapping, stack_start,
- stack_extent);
- }
- return 0;
-}
-
-/**
- * A "default" alloc_pmem() function for use with elf_load_executable().
- * A user may wish to define a custom replacement alloc_pmem() function
- * to, for example, keep track of the physical memory that is allocated.
- */
-paddr_t
-elf_dflt_alloc_pmem(size_t size, size_t alignment, uintptr_t arg)
-{
- struct pmem_region result;
-
- if (pmem_alloc_umem(size, alignment, &result))
- return 0;
-
- /* Mark the memory as being used by the init task */
- result.type = PMEM_TYPE_INIT_TASK;
- BUG_ON(pmem_update(&result));
-
- return result.start;
-}
-
-static int
-load_writable_segment(
- void * elf_image,
- struct elf_phdr * phdr,
- id_t aspace_id,
- vaddr_t start,
- size_t extent,
- vmpagesize_t pagesz,
- uintptr_t alloc_pmem_arg,
- paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
-)
-{
- int status;
- paddr_t pmem;
- vaddr_t local_start;
- vaddr_t src, dst;
- id_t my_aspace_id;
-
- /* Figure out my address space ID */
- if ((status = aspace_get_myid(&my_aspace_id)))
- return status;
-
- /* Allocate physical memory for the segment */
- if (!(pmem = alloc_pmem(extent, pagesz, alloc_pmem_arg)))
- return -ENOMEM;
-
- /* Map the segment into the target address space */
- status =
- aspace_map_region(
- aspace_id,
- start,
- extent,
- elf_pflags_to_vmflags(phdr->p_flags),
- pagesz,
- "ELF",
- pmem
- );
- if (status)
- return status;
-
- /* Map the segment into this address space */
- status =
- aspace_map_region_anywhere(
- my_aspace_id,
- &local_start,
- extent,
- (VM_USER|VM_READ|VM_WRITE),
- pagesz,
- "temporary",
- pmem
- );
- if (status)
- return status;
-
- /* Copy segment data from ELF image into the target address space
- * (via its temporary mapping in our address space) */
- dst = local_start + (phdr->p_vaddr - start);
- src = (vaddr_t)elf_image + phdr->p_offset;
- memcpy((void *)dst, (void *)src, phdr->p_filesz);
-
- /* Unmap the segment from this address space */
- status = aspace_del_region(my_aspace_id, local_start, extent);
- if (status)
- return status;
-
- return 0;
-}
-
-static int
-load_readonly_segment(
- paddr_t elf_image_paddr,
- struct elf_phdr * phdr,
- id_t aspace_id,
- vaddr_t start,
- size_t extent,
- vmpagesize_t pagesz
-)
-{
- return aspace_map_region(
- aspace_id,
- start,
- extent,
- elf_pflags_to_vmflags(phdr->p_flags),
- pagesz,
- "ELF (mapped)",
- elf_image_paddr +
- round_down(phdr->p_offset, pagesz)
- );
-}
-
-/**
- * Loads an ELF executable image into the specified address space.
- *
- * Arguments:
- * [IN] elf_image: Location of ELF image in this address space.
- * [IN] elf_image_paddr: Location of ELF image in physical memory.
- * [IN] aspace_id: Address space to load ELF image into.
- * [IN] pagesz: Page size to use when mapping ELF image.
- * [IN] alloc_pmem_arg: Argument to pass to alloc_pmem().
- * [IN] alloc_pmem: Function pointer to use to allocate physical
- * memory for the region. alloc_mem() returns
- * the physical address of the memory allocated.
- *
- * Returns:
- * Success: 0
- * Failure: Error Code, the target address space is left in an
- * undefined state and should be destroyed.
- */
-int
-elf_load_executable(
- void * elf_image,
- paddr_t elf_image_paddr,
- id_t aspace_id,
- vmpagesize_t pagesz,
- uintptr_t alloc_pmem_arg,
- paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
-)
-{
- struct elfhdr * ehdr;
- struct elf_phdr * phdr_array;
- struct elf_phdr * phdr;
- size_t i;
- vaddr_t start, end;
- size_t extent;
- size_t num_load_segments=0;
- int status;
-
- /* Locate the program header array (in this context) */
- ehdr = elf_image;
- phdr_array = (struct elf_phdr *)(elf_image + ehdr->e_phoff);
-
- /* Set up a region for each program segment */
- for (i = 0; i < ehdr->e_phnum; i++) {
- phdr = &phdr_array[i];
- if (phdr->p_type != PT_LOAD)
- continue;
-
- /* Calculate the segment's bounds */
- start = round_down(phdr->p_vaddr, pagesz);
- end = round_up(phdr->p_vaddr + phdr->p_memsz, pagesz);
- extent = end - start;
-
- if (phdr->p_flags & PF_W) {
- /* Writable segments must be copied into the
- * target address space */
- status =
- load_writable_segment(
- elf_image,
- phdr,
- aspace_id,
- start,
- extent,
- pagesz,
- alloc_pmem_arg,
- alloc_pmem
- );
- if (status)
- return status;
- } else {
- /* Read-only segments are mapped directly
- * from the ELF image */
- status =
- load_readonly_segment(
- elf_image_paddr,
- phdr,
- aspace_id,
- start,
- extent,
- pagesz
- );
- if (status)
- return status;
- }
-
- ++num_load_segments;
- }
-
- return (num_load_segments) ? 0 : -ENOENT;
-}
-
-static int
-make_region(
- id_t aspace_id,
- vaddr_t start,
- size_t extent,
- vmflags_t flags,
- vmpagesize_t pagesz,
- const char * name,
- uintptr_t alloc_pmem_arg,
- paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg),
- paddr_t * pmem
-)
-{
- int status;
-
- *pmem = alloc_pmem(extent, pagesz, alloc_pmem_arg);
- if (*pmem == 0) {
- print("Failed to allocate physical memory for %s.", name);
- return -ENOMEM;
- }
-
- status = aspace_map_region(aspace_id, start, extent,
- flags, pagesz,
- name, *pmem);
- if (status) {
- print("Failed to map physical memory for %s (status=%d).",
- name, status);
- return status;
- }
-
- return 0;
-}
-
-/**
- * Maximum number of arguments and environment variables that may
- * be passed to the new task created by elf_load().
- */
-#define MAX_ARGC 32
-#define MAX_ENVC 32
-
-/**
- * Kitchen-sink ELF image load function.
- * If something more custom is desired, this function can be used as a guide
- * for what needs to be done to load an ELF executable and setup the
- * accompanying address space.
- */
-int
-elf_load(
- void * elf_image,
- paddr_t elf_image_paddr,
- const char * name,
- id_t desired_aspace_id,
- vmpagesize_t pagesz,
- size_t heap_size,
- size_t stack_size,
- char * argv_str,
- char * envp_str,
- start_state_t * start_state,
- uintptr_t alloc_pmem_arg,
- paddr_t (*alloc_pmem)(size_t size, size_t alignment, uintptr_t arg)
-)
-{
- int status;
- char *argv[MAX_ARGC] = { (char *)name };
- char *envp[MAX_ENVC];
- id_t my_aspace_id, aspace_id;
- vaddr_t heap_start, stack_start, stack_end, stack_ptr;
- vaddr_t local_stack_start;
- size_t heap_extent, stack_extent;
- paddr_t heap_pmem, stack_pmem;
- uint32_t hwcap;
-
- if (!elf_image || !start_state || !alloc_pmem)
- return -EINVAL;
-
- if (elf_init_str_array(MAX_ARGC-1, argv+1, argv_str)) {
- print("Too many ARGV strings.");
- return -EINVAL;
- }
-
- if (elf_init_str_array(MAX_ENVC, envp, envp_str)) {
- print("Too many ENVP strings.");
- return -EINVAL;
- }
-
- if ((status = aspace_create(desired_aspace_id, "init_task", &aspace_id))) {
- print("Failed to create aspace (status=%d).", status);
- return status;
- }
-
- /* Load the ELF executable's LOAD segments */
- status =
- elf_load_executable(
- elf_image, /* where I can access the ELF image */
- elf_image_paddr, /* where it is in physical memory */
- aspace_id, /* the address space to map it into */
- pagesz, /* page size to map it with */
- 0, /* arg to pass to alloc_pmem */
- alloc_pmem /* func to use to allocate phys mem */
- );
- if (status) {
- print("Failed to load ELF image (status=%d).", status);
- return status;
- }
-
- /* Create the UNIX heap */
- heap_start = round_up(elf_heap_start(elf_image), pagesz);
- heap_extent = round_up(heap_size, pagesz);
- status =
- make_region(
- aspace_id,
- heap_start,
- heap_extent,
- (VM_USER|VM_READ|VM_WRITE|VM_EXEC|VM_HEAP),
- pagesz,
- "heap",
- alloc_pmem_arg,
- alloc_pmem,
- &heap_pmem
- );
- if (status) {
- print("Failed to create heap (status=%d).", status);
- return status;
- }
-
- /* Create the stack region */
- stack_end = SMARTMAP_ALIGN;
- stack_start = round_down(stack_end - stack_size, pagesz);
- stack_extent = stack_end - stack_start;
- status =
- make_region(
- aspace_id,
- stack_start,
- stack_extent,
- (VM_USER|VM_READ|VM_WRITE|VM_EXEC),
- pagesz,
- "stack",
- alloc_pmem_arg,
- alloc_pmem,
- &stack_pmem
- );
- if (status) {
- print("Failed to create stack (status=%d).", status);
- return status;
- }
-
- /* Map the stack region into this address space */
- if ((status = aspace_get_myid(&my_aspace_id)))
- return status;
- status =
- aspace_map_region_anywhere(
- my_aspace_id,
- &local_stack_start,
- stack_extent,
- (VM_USER|VM_READ|VM_WRITE),
- pagesz,
- "temporary",
- stack_pmem
- );
- if (status) {
- print("Failed to map stack locally (status=%d).", status);
- return status;
- }
-
- /* Initialize the stack */
- status = elf_hwcap(start_state->cpu_id, &hwcap);
- if (status) {
- print("Failed to get hw capabilities (status=%d).", status);
- return status;
- }
- status =
- elf_init_stack(
- elf_image,
- (void *)local_stack_start, /* Where I can access it */
- stack_start, /* Where it is in target aspace */
- stack_extent,
- argv, envp,
- start_state->uid, start_state->gid,
- hwcap,
- &stack_ptr
- );
- if (status) {
- print("Failed to initialize stack (status=%d).", status);
- return status;
- }
-
- start_state->aspace_id = aspace_id;
- start_state->entry_point = elf_entry_point(elf_image);
- start_state->stack_ptr = stack_ptr;
-
- return 0;
-}