x86_64: implement functions to jump to userspace
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user