sched: implement passing arguments to user-mode threads
This commit is contained in:
@@ -1,6 +1,14 @@
|
|||||||
#include <kernel/machine/cpu.h>
|
#include <kernel/machine/cpu.h>
|
||||||
#include <kernel/machine/thread.h>
|
#include <kernel/machine/thread.h>
|
||||||
|
|
||||||
|
#define MAX_REG_ARGS 6
|
||||||
|
#define REG_ARG_0 rdi
|
||||||
|
#define REG_ARG_1 rsi
|
||||||
|
#define REG_ARG_2 rdx
|
||||||
|
#define REG_ARG_3 rcx
|
||||||
|
#define REG_ARG_4 r8
|
||||||
|
#define REG_ARG_5 r9
|
||||||
|
|
||||||
/* this is the context information restored by ml_thread_switch.
|
/* this is the context information restored by ml_thread_switch.
|
||||||
* since ml_thread_switch only jumps to kernel-mode, IRETQ isn't used,
|
* since ml_thread_switch only jumps to kernel-mode, IRETQ isn't used,
|
||||||
* and the extra register values needed by IRETQ aren't present. */
|
* and the extra register values needed by IRETQ aren't present. */
|
||||||
@@ -23,10 +31,12 @@ void ml_thread_prepare_kernel_context(uintptr_t ip, uintptr_t *sp)
|
|||||||
ctx->rfl = 0x202;
|
ctx->rfl = 0x202;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void ml_thread_prepare_user_context(
|
extern kern_status_t ml_thread_prepare_user_context(
|
||||||
virt_addr_t ip,
|
virt_addr_t ip,
|
||||||
virt_addr_t user_sp,
|
virt_addr_t user_sp,
|
||||||
virt_addr_t *kernel_sp)
|
virt_addr_t *kernel_sp,
|
||||||
|
const uintptr_t *args,
|
||||||
|
size_t nr_args)
|
||||||
{
|
{
|
||||||
(*kernel_sp) -= sizeof(struct ml_cpu_context);
|
(*kernel_sp) -= sizeof(struct ml_cpu_context);
|
||||||
|
|
||||||
@@ -39,4 +49,31 @@ extern void ml_thread_prepare_user_context(
|
|||||||
ctx->rflags = 0x202;
|
ctx->rflags = 0x202;
|
||||||
ctx->rdi = 0; // arg 0
|
ctx->rdi = 0; // arg 0
|
||||||
ctx->rsi = 0; // arg 1
|
ctx->rsi = 0; // arg 1
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nr_args; i++) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
ctx->REG_ARG_0 = args[i];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ctx->REG_ARG_1 = args[i];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ctx->REG_ARG_2 = args[i];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ctx->REG_ARG_3 = args[i];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
ctx->REG_ARG_4 = args[i];
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
ctx->REG_ARG_5 = args[i];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return KERN_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
41
kernel/bsp.c
41
kernel/bsp.c
@@ -179,15 +179,52 @@ kern_status_t bsp_launch_async(struct bsp *bsp, struct task *task)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = vm_region_map_object(
|
||||||
|
task->t_address_space,
|
||||||
|
VM_REGION_ANY_OFFSET,
|
||||||
|
bsp->bsp_vmo,
|
||||||
|
0,
|
||||||
|
bsp->bsp_trailer.bsp_exec_offset,
|
||||||
|
VM_PROT_READ | VM_PROT_USER,
|
||||||
|
&bsp_data_base);
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = map_executable(bsp, task, &entry);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
vm_region_dump(task->t_address_space, 0);
|
vm_region_dump(task->t_address_space);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sp = stack_buffer + BOOTSTRAP_STACK_SIZE;
|
sp = stack_buffer + BOOTSTRAP_STACK_SIZE;
|
||||||
tracek("bootstrap: entry=%llx, sp=%llx", entry, sp);
|
tracek("bootstrap: entry=%llx, sp=%llx", entry, sp);
|
||||||
|
|
||||||
|
kern_handle_t self, self_address_space;
|
||||||
|
task_open_handle(task, &task->t_base, 0, &self);
|
||||||
|
task_open_handle(
|
||||||
|
task,
|
||||||
|
&task->t_address_space->vr_base,
|
||||||
|
0,
|
||||||
|
&self_address_space);
|
||||||
|
|
||||||
|
const uintptr_t args[] = {
|
||||||
|
0, // int argc
|
||||||
|
0, // const char ** argv
|
||||||
|
self, // kern_handle_t task
|
||||||
|
self_address_space, // kern_handle_t address_space
|
||||||
|
|
||||||
|
/* this parameter is specific to the bsp bootstrap program, so
|
||||||
|
* that it can access the rest of the bsp image. */
|
||||||
|
bsp_data_base,
|
||||||
|
};
|
||||||
|
const size_t nr_args = sizeof args / sizeof args[0];
|
||||||
|
|
||||||
struct thread *init_thread = task_create_thread(task);
|
struct thread *init_thread = task_create_thread(task);
|
||||||
thread_init_user(init_thread, entry, sp);
|
thread_init_user(init_thread, entry, sp, args, nr_args);
|
||||||
schedule_thread_on_cpu(init_thread);
|
schedule_thread_on_cpu(init_thread);
|
||||||
|
|
||||||
return KERN_OK;
|
return KERN_OK;
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ kern_status_t thread_init_kernel(struct thread *thr, virt_addr_t ip)
|
|||||||
kern_status_t thread_init_user(
|
kern_status_t thread_init_user(
|
||||||
struct thread *thr,
|
struct thread *thr,
|
||||||
virt_addr_t ip,
|
virt_addr_t ip,
|
||||||
virt_addr_t sp)
|
virt_addr_t sp,
|
||||||
|
const uintptr_t *args,
|
||||||
|
size_t nr_args)
|
||||||
{
|
{
|
||||||
thr->tr_id = thr->tr_parent->t_next_thread_id++;
|
thr->tr_id = thr->tr_parent->t_next_thread_id++;
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ kern_status_t thread_init_user(
|
|||||||
|
|
||||||
/* this context will be used by ml_user_return to jump to userspace
|
/* this context will be used by ml_user_return to jump to userspace
|
||||||
* with the specified instruction pointer and user stack */
|
* with the specified instruction pointer and user stack */
|
||||||
ml_thread_prepare_user_context(ip, sp, &thr->tr_sp);
|
ml_thread_prepare_user_context(ip, sp, &thr->tr_sp, args, nr_args);
|
||||||
/* this context will be used by the scheduler and ml_thread_switch to
|
/* this context will be used by the scheduler and ml_thread_switch to
|
||||||
* jump to ml_user_return in kernel mode with the thread's kernel stack.
|
* jump to ml_user_return in kernel mode with the thread's kernel stack.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user