x86_64: implement functions to jump to userspace

This commit is contained in:
2026-02-08 11:58:27 +00:00
parent da611ab070
commit 880930e917
3 changed files with 71 additions and 7 deletions

View File

@@ -3,8 +3,27 @@
#include <mango/sched.h>
extern void switch_to(struct thread *from, struct thread *to);
extern void prepare_stack(uintptr_t ip, uintptr_t *sp);
extern void user_jump(uintptr_t ip, uintptr_t sp);
struct ml_cpu_context;
/* switch from one thread to another. the stack of the `to` thread must have
* been prepared in one of two ways:
* 1) a previous call to ml_thread_switch where it was the `from` thread.
* 2) a call to ml_thread_prepare_kernel_context
* the switch occurs entirely with kernel mode. a further return from an
* interrupt context is then used to return to usermode if necessary.
*/
extern void ml_thread_switch(struct thread *from, struct thread *to);
/* perform the initial transition to userspace. the stack must be prepared using
* ml_thread_prepare_user_context before this function can be used */
extern void ml_thread_switch_user(void);
/* prepare the stack so that ml_thread_switch can jump to the specified IP/SP */
extern void ml_thread_prepare_kernel_context(uintptr_t ip, uintptr_t *sp);
/* prepare the stack so that ml_thread_switch_user can jump to usermode
* with the specified IP/user SP */
extern void ml_thread_prepare_user_context(
virt_addr_t ip,
virt_addr_t user_sp,
virt_addr_t *kernel_sp);
#endif

View File

@@ -1,12 +1,16 @@
#include <mango/machine/cpu.h>
#include <mango/machine/thread.h>
/* this is the context information restored by ml_thread_switch.
* since ml_thread_switch only jumps to kernel-mode, IRETQ isn't used,
* and the extra register values needed by IRETQ aren't present. */
struct thread_ctx {
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rdi, rsi, rbp, unused_rsp, rbx, rdx, rcx, rax;
uint64_t rfl;
} __packed;
void prepare_stack(uintptr_t ip, uintptr_t *sp)
void ml_thread_prepare_kernel_context(uintptr_t ip, uintptr_t *sp)
{
(*sp) -= sizeof(uintptr_t);
uintptr_t *dest_ip = (uintptr_t *)(*sp);
@@ -18,3 +22,20 @@ void prepare_stack(uintptr_t ip, uintptr_t *sp)
ctx->rfl = 0x202;
}
extern void ml_thread_prepare_user_context(
virt_addr_t ip,
virt_addr_t user_sp,
virt_addr_t *kernel_sp)
{
(*kernel_sp) -= sizeof(struct ml_cpu_context);
struct ml_cpu_context *ctx = (struct ml_cpu_context *)(*kernel_sp);
ctx->rip = ip;
ctx->rsp = user_sp;
ctx->ss = 0x23;
ctx->cs = 0x1B;
ctx->rflags = 0x202;
ctx->rdi = 0; // arg 0
ctx->rsi = 0; // arg 1
}

View File

@@ -2,12 +2,12 @@
.extern THREAD_sp
.global switch_to
.type switch_to, @function
.global ml_thread_switch
.type ml_thread_switch, @function
// %rdi = (struct thread *) current thread.
// %rsi = (struct thread *) next thread.
switch_to:
ml_thread_switch:
pushfq
push %rax
@@ -50,3 +50,27 @@ switch_to:
popfq
ret
.global ml_thread_switch_user
.type ml_thread_switch_user, @function
ml_thread_switch_user:
pop %r15
pop %r14
pop %r13
pop %r12
pop %r11
pop %r10
pop %r9
pop %r8
pop %rdi
pop %rsi
pop %rbp
add $8, %rsp
pop %rbx
pop %rdx
pop %rcx
pop %rax
add $16, %rsp
iretq