summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kexec.c
blob: 406e8e7423a6cd29d5e2b2955429a179403f4c2e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "tasking.h"
#include "memory.h"
#include "string.h"
#include "arch/cpu.h"

#define UMODE_STACK_TOP (USERLAND_MEMORY_LIMIT)
#define UMODE_STACKW PAGE_SIZE

static void*
s_umode_stack(void)
{
    uintptr_t top = UMODE_STACK_TOP;
    uintptr_t bottom = top - (UMODE_STACKW - 1);

    vm_ensure(bottom, top, (page_flags_t) {
        .present = true,
        .writeable = true,
        .useraccess = true,
        .executable = false
            });
    return (void*)top;
}

static inline void*
s_stack_push(void *sp, void *data, size_t len)
{
    sp = (void*)((uintptr_t)sp - len);
    memcpy(sp, data, len);
    return sp;
}

void
kexec(void *ip, int kargc, char **kargv, int kenvc, char **kenvp)
{
    /* Allocate a page for the user stack. */
    void *sp = s_umode_stack();
    
    intmax_t argc = kargc;
    sp = s_stack_push(sp, &argc, sizeof(intmax_t));

    /* TODO: Proper argv, envp*/
    sp = s_stack_push(sp, &kargv, sizeof(char**));
    
    intmax_t envc = kenvc;
    sp = s_stack_push(sp, &envc, sizeof(intmax_t));

    sp = s_stack_push(sp, &kenvp, sizeof(char**));

    umode_enter(ip, sp);
}