summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kexec.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kexec.c')
-rw-r--r--arch/x86_64/kexec.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/arch/x86_64/kexec.c b/arch/x86_64/kexec.c
new file mode 100644
index 0000000..406e8e7
--- /dev/null
+++ b/arch/x86_64/kexec.c
@@ -0,0 +1,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);
+}