1/*
2 * Copyright 2017, 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 <autoconf.h>
13#include <sel4utils/gen_config.h>
14#include <sel4/types.h>
15#include <sel4utils/thread.h>
16#include <sel4utils/helpers.h>
17#include <utils/zf_log.h>
18#include <utils/stack.h>
19#include <stdbool.h>
20
21int sel4utils_arch_init_context(void *entry_point, void *stack_top, seL4_UserContext *context)
22{
23    context->esp = (seL4_Word) stack_top;
24    /* set edx to zero in case we are setting this when spawning a process as
25     * edx is the atexit parameter, which we currently do not use */
26    context->edx = 0;
27    context->eip = (seL4_Word) entry_point;
28
29    return 0;
30}
31
32int sel4utils_arch_init_context_with_args(sel4utils_thread_entry_fn entry_point, void *arg0, void *arg1, void *arg2,
33                                          bool local_stack, void *stack_top, seL4_UserContext *context,
34                                          vka_t *vka, vspace_t *local_vspace, vspace_t *remote_vspace)
35{
36
37    if (!IS_ALIGNED((uintptr_t)stack_top, STACK_CALL_ALIGNMENT_BITS)) {
38        ZF_LOGE("Initial stack pointer must be %d byte aligned", STACK_CALL_ALIGNMENT);
39        return -1;
40    }
41
42    /* arguments as they should appear on the stack */
43    seL4_Word stack_args[] = {(seL4_Word) arg0, (seL4_Word) arg1, (seL4_Word) arg2};
44    if (stack_top) {
45        /* if we were to increase the stack pointer such that after the arguments are
46         * pushed, the stack pointer would be correctly aligned, we would add this
47         * value */
48        size_t up_padding = sizeof(stack_args) % STACK_CALL_ALIGNMENT;
49
50        /* but we can't add to the stack pointer as we might run off the end of our stack,
51         * so we'll decrease it by this value */
52        size_t down_padding = (STACK_CALL_ALIGNMENT - up_padding) % STACK_CALL_ALIGNMENT;
53
54        stack_top = (void *)((uintptr_t) stack_top - down_padding);
55    }
56
57    if (local_stack && stack_top) {
58        seL4_Word *stack_ptr = (seL4_Word *) stack_top;
59        stack_ptr[-3] = (seL4_Word) arg0;
60        stack_ptr[-2] = (seL4_Word) arg1;
61        stack_ptr[-1] = (seL4_Word) arg2;
62        stack_top = (void *)((uintptr_t) stack_top - sizeof(stack_args));
63    } else if (local_vspace && remote_vspace && vka) {
64        int error = sel4utils_stack_write(local_vspace, remote_vspace, vka, stack_args, sizeof(stack_args),
65                                          (uintptr_t *) &stack_top);
66        if (error) {
67            ZF_LOGE("Failed to copy arguments");
68            return -1;
69        }
70    }
71
72    /* we've pushed the arguments, so at this point our stack should be aligned
73     * thanks to our padding */
74    assert(IS_ALIGNED((uintptr_t)stack_top, STACK_CALL_ALIGNMENT_BITS));
75
76    /* the entry point function was compiled under the assumption that it will
77     * be called, and thus expects a return address to follow the arguments */
78    stack_top = (void *)((uintptr_t) stack_top - sizeof(uintptr_t));
79
80    return sel4utils_arch_init_context(entry_point, stack_top, context);
81}
82