blob: e836ea9e35fbb324a200858640e5124ca7b29c2a [file] [log] [blame] [edit]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <autoconf.h>
#include <sel4utils/gen_config.h>
#include <vka/vka.h>
#include <vspace/vspace.h>
#include <sel4utils/thread.h>
#include <sel4utils/process_config.h>
#include <sel4utils/vspace.h>
#include <sel4utils/elf.h>
#include <sel4platsupport/timer.h>
#define WORD_STRING_SIZE ((CONFIG_WORD_SIZE / 3) + 1)
typedef struct object_node object_node_t;
struct object_node {
vka_object_t object;
object_node_t *next;
};
typedef struct {
vka_object_t pd;
vspace_t vspace;
sel4utils_alloc_data_t data;
vka_object_t cspace;
uint32_t cspace_size;
uint32_t cspace_next_free;
sel4utils_thread_t thread;
vka_object_t fault_endpoint;
void *entry_point;
uintptr_t sysinfo;
/* cptr (with respect to the process cnode) of the tcb of the first thread (0 means not supplied) */
seL4_CPtr dest_tcb_cptr;
seL4_Word pagesz;
object_node_t *allocated_object_list_head;
/* ELF headers that describe the sections of the loaded image (at least as they
* existed at load time). Is different to the elf_regions, which have reservations,
* these are the original headers from the elf and include nonloaded information regions */
int num_elf_phdrs;
Elf_Phdr *elf_phdrs;
/* if the elf wasn't loaded into the address space, this describes the regions.
* this permits lazy loading / copy on write / page sharing / whatever crazy thing
* you want to implement */
int num_elf_regions;
sel4utils_elf_region_t *elf_regions;
bool own_vspace;
bool own_cspace;
bool own_ep;
} sel4utils_process_t;
/* sel4utils processes start with some caps in their cspace.
* These are the caps
*/
enum sel4utils_cspace_layout {
/* no cap in NULL */
SEL4UTILS_NULL_SLOT = 0,
/*
* The root cnode (with appropriate guard)
*/
SEL4UTILS_CNODE_SLOT = 1,
/* The slot on the cspace that fault_endpoint is put if
* sel4utils_configure_process is used.
*/
SEL4UTILS_ENDPOINT_SLOT = 2,
/* The page directory slot */
SEL4UTILS_PD_SLOT = 3,
/* the slot for the asid pool that this thread is in and can create threads
* in. 0 if this kernel does not support asid pools */
SEL4UTILS_ASID_POOL_SLOT = 4,
/* the slot for this processes tcb */
SEL4UTILS_TCB_SLOT = 5,
/* the slot for this processes sc */
SEL4UTILS_SCHED_CONTEXT_SLOT = 6,
/* The slot for this processes reply object */
SEL4UTILS_REPLY_SLOT = 7,
/* First free slot in the cspace configured by sel4utils */
SEL4UTILS_FIRST_FREE = 8
};
/**
* Start a process, and copy arguments into the processes address space.
*
* This is intended to use when loading applications of the format:
*
* int main(int argc, char **argv) { };
*
* The third argument (in r2 for arm, on stack for ia32) will be the address of the ipc buffer.
* This is intended to be loaded by the crt into the data word of the ipc buffer,
* or you can just add it to your function prototype.
*
* Add the following to your crt to use it this way:
*
* arm: str r2, [r2, #484]
* ia32: popl %ebp
* movl %ebp, 484(%ebp)
*
* @param process initialised sel4utils process struct.
* @param vka vka interface to use for allocation of frames.
* @param vspace the current vspace.
* @param argc the number of arguments.
* @param argv a pointer to an array of strings in the current vspace.
* @param resume 1 to start the process, 0 to leave suspended.
*
* @return -1 on error, 0 on success.
*
*/
int sel4utils_spawn_process(sel4utils_process_t *process, vka_t *vka, vspace_t *vspace,
int argc, char *argv[], int resume);
/**
* Start a process, and copy arguments into the processes address space.
*
* This is intended for use when loading applications that have a System V ABI compliant
* entry point. This means that the entry point should *not* be a 'main' that is expecting
* argc and argv in the form as passed here, but should be an _start routine that will
* take a stack frame with the arguments on it and construct an appropriate invocation
* to a main function. The stack frame passed to the entry point will have an auxv, envp
* and argv
*
* @param process initialised sel4utils process struct.
* @param vka vka interface to use for allocation of frames.
* @param vspace the current vspace.
* @param argc the number of arguments.
* @param argv a pointer to an array of strings in the current vspace.
* @param resume 1 to start the process, 0 to leave suspended.
*
* @return -1 on error, 0 on success.
*
*/
int sel4utils_spawn_process_v(sel4utils_process_t *process, vka_t *vka, vspace_t *vspace,
int argc, char *argv[], int resume);
/**
* This is the function to use if you just want to set up a process as fast as possible.
* It creates a simple cspace and vspace for you, allocates a fault endpoint and puts
* it into the new cspace. The process will start at priority 0.
*
* If CONFIG_RT is enabled, it will not have a scheduling context.
*
* It loads the elf file into the new vspace, parses the elf file and stores the entry point
* into process->entry_point.
*
* It uses the same vka for both allocations - the new process will not have an allocator.
*
* The process will have just one thread.
*
* Otherwise, use it as a model for loading processes and use the elf_load.
*
* WARNING: when launching processes on ia32 please ensure your calling convention
* matches that documented in sel4utils_start_thread. Otherwise your arguments
* won't come through correctly.
*
* @param process uninitialised process struct.
* @param vka allocator to use to allocate objects.
* @param vspace vspace allocator for the current vspace.
* @param image_name name of the elf image to load from the cpio archive.
*
* @return 0 on success, -1 on error.
*/
int sel4utils_configure_process(sel4utils_process_t *process, vka_t *vka, vspace_t *vspace,
const char *image_name);
/**
* Configure a process with more customisations (Create your own vspace, customise cspace size).
*
* @param process uninitialised process struct
* @param vka allocator to use to allocate objects.
* @param spawner_vspace vspace to use to allocate virtual memory in the current address space.
* @param config process config.
*
* @return 0 on success, -1 on error.
*/
int sel4utils_configure_process_custom(sel4utils_process_t *process, vka_t *target_vka,
vspace_t *spawner_vspace, sel4utils_process_config_t config);
/**
* Copy a cap into a process' cspace.
*
* This will only work if you configured the process using one of the above functions, or
* have mimicked their functionality.
*
* @param process process to copy the cap to
* @param src path in the current cspace to copy the cap from
*
* @return 0 on failure, otherwise the slot in the processes cspace.
*/
seL4_CPtr sel4utils_copy_path_to_process(sel4utils_process_t *process, cspacepath_t src);
/**
* Copy a cap into a process' cspace.
*
* This will only work if you configured the process using one of the above functions, or
* have mimicked their functionality.
*
* @param process process to copy the cap to
* @param vka vka that can translate the cap into a cspacepath_t.
* @param cap cap location in your own cspace.
*
* @return 0 on failure, otherwise the slot in the processes cspace.
*/
seL4_CPtr sel4utils_copy_cap_to_process(sel4utils_process_t *process, vka_t *vka, seL4_CPtr cap);
/**
* Move a cap into a process' cspace.
*
* This will only work if you configured the process using one of the above functions, or
* have mimicked their functionality. Additionally the VKA that is passed in to have the
* slot freed can only do this if it is tracking that slot. IE when moving one of the initial
* caps provided by bootinfo such as the IRQ Control Cap the VKA may not be able to free the slot.
* Passing in NULL for the VKA will result in no slot being freed.
*
* @param process process to move the cap to
* @param src path in the current cspace to move the cap from
* @param vka the allocator that owns the cslot the cap is currently in, so it may be freed after the move.
* if NULL, then the original slot will not be freed.
*
* @return 0 on failure, otherwise the slot in the processes cspace.
*/
seL4_CPtr sel4utils_move_cap_to_process(sel4utils_process_t *process, cspacepath_t src, vka_t *from_vka);
/**
*
* Mint a cap into a process' cspace.
*
* As above, except mint the cap with rights and data.
*
* @return 0 on failure, otherwise the slot in the cspace where the new cap is.
*/
seL4_CPtr sel4utils_mint_cap_to_process(sel4utils_process_t *process, cspacepath_t src, seL4_CapRights_t rights,
seL4_Word data);
/**
* Destroy a process.
*
* This will free everything possible associated with a process and teardown the vspace.
*
* @param process process to destroy
* @param vka allocator used to allocate objects for this process
*/
void sel4utils_destroy_process(sel4utils_process_t *process, vka_t *vka);
/*
* sel4utils default allocated object function for vspaces.
*
* Stores a list of allocated objects in the process struct and frees them
* when sel4utils_destroy_process is called.
*/
void sel4utils_allocated_object(void *cookie, vka_object_t object);
/*
* Create c-formatted argument list to pass to a process from arbitrarily long amount of words.
*
* @param strings empty 2d array of chars to populate with word strings.
* @param argv empty 1d array of char pointers which will be set up with pointers to
* strings in strings.
* @param argc number of words
* @param ... list of words to create arguments from.
*
*/
void sel4utils_create_word_args(char strings[][WORD_STRING_SIZE], char *argv[], int argc, ...);
/*
* Get the initial cap equivalent for a sel4utils created process.
* This will only work if sel4utils created the processes cspace.
*
* @param cap initial cap index from sel4/bootinfo_types.h
* @return the corresponding cap in a sel4utils launched process.
*/
seL4_CPtr sel4utils_process_init_cap(void *data, seL4_CPtr cap);
/*
* Helper function for copying timer IRQs and Device untyped caps into another process.
*
* @param to struct to store new cap info
* @param from struct containing current cap info
* @param vka vka to create cnodes
* @param process target process to copy caps too
*
* @return 0 on success.
*/
int sel4utils_copy_timer_caps_to_process(timer_objects_t *to, timer_objects_t *from, vka_t *vka,
sel4utils_process_t *process);