7 changed files with 321 additions and 0 deletions
@ -0,0 +1,73 @@ |
|||
#include "../lib/assert.h" |
|||
#include "../memory/heap.h" |
|||
#include "../memory/vmap.h" |
|||
#include "../memory/paging.h" |
|||
|
|||
#include "sched.h" |
|||
|
|||
#define FIRST_TID 1 |
|||
#define STACK_SIZE 256*1024 |
|||
|
|||
// return stack base
|
|||
// we suppose that the process is already mapped
|
|||
// we find a stack address by polling user top memory
|
|||
static void* alloc_stack(process_t* process) { |
|||
// @todo this doesnt work with more than 1 thread
|
|||
void* base = (void*)USER_END + 1 - STACK_SIZE; |
|||
(void) process; |
|||
|
|||
alloc_pages( |
|||
base, |
|||
STACK_SIZE >> 12, |
|||
PRESENT_ENTRY | PL_XD |
|||
); |
|||
|
|||
return base; |
|||
} |
|||
|
|||
|
|||
int create_process(process_t* process, const void* elffile, size_t elffile_sz) { |
|||
|
|||
elf_program_t* program = elf_load(elffile, elffile_sz); |
|||
|
|||
if(!program) |
|||
return 0; |
|||
|
|||
thread_t* threads = malloc(sizeof(thread_t)); |
|||
|
|||
|
|||
pid_t pid = alloc_pid(); |
|||
|
|||
assert(process); |
|||
|
|||
create_thread( |
|||
&threads[0], |
|||
pid, |
|||
alloc_stack(process), |
|||
STACK_SIZE, |
|||
FIRST_TID |
|||
); |
|||
|
|||
threads[0].regs.rip = program->entry; |
|||
|
|||
|
|||
*process = (process_t) { |
|||
.files = NULL, |
|||
.n_files = 0, |
|||
.n_threads = 1, |
|||
.threads = threads, |
|||
.page_dir_paddr = 0, |
|||
.pid = pid, |
|||
.ppid = KERNEL_PID, |
|||
.program = program, |
|||
}; |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
|
|||
void free_process(process_t* process) { |
|||
assert(process); |
|||
|
|||
} |
|||
|
@ -0,0 +1,51 @@ |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "../lib/elf/elf.h" |
|||
|
|||
#include "../fs/vfs.h" |
|||
|
|||
// this file describes what are processes
|
|||
|
|||
typedef int pid_t; |
|||
|
|||
|
|||
typedef struct process { |
|||
pid_t pid; |
|||
|
|||
pid_t ppid; |
|||
|
|||
uint64_t page_dir_paddr; |
|||
|
|||
size_t n_threads; |
|||
struct thread* threads; |
|||
|
|||
|
|||
elf_program_t* program; |
|||
|
|||
|
|||
size_t n_files; |
|||
file_handle_t** files; |
|||
|
|||
} process_t; |
|||
|
|||
|
|||
/**
|
|||
* @brief create a process with a given elf file |
|||
* the elf file is not borrowed. The caller must |
|||
* free it afterwards. |
|||
* |
|||
* this functions initializes a process with: |
|||
* - no opened file |
|||
* - single thread executing the elf entry |
|||
* |
|||
* |
|||
* @param process output process structure |
|||
* @param elf_file input file |
|||
* @return int 0 if failure, non-0 otherwise |
|||
*/ |
|||
int create_process(process_t* process, const void* elffile, size_t elffile_sz); |
|||
|
|||
void free_process(process_t* process); |
@ -0,0 +1,45 @@ |
|||
|
|||
|
|||
[global _restore_context] |
|||
|
|||
; [[noreturn]] restore_context(struct gp_regs*) |
|||
;typedef struct gp_regs { |
|||
; uint64_t rip; |
|||
; uint64_t rbp; |
|||
; uint64_t rsp; |
|||
; uint64_t rax; |
|||
; uint64_t rcx; |
|||
; uint64_t rdx; |
|||
; uint64_t rbx; |
|||
; uint64_t rsi; |
|||
; uint64_t rdi; |
|||
; uint64_t rflags; |
|||
; |
|||
;// r8 -> r15 |
|||
; uint64_t ext[8]; |
|||
; |
|||
;} __attribute__((packed)) gp_regs_t; |
|||
_restore_context: |
|||
mov rsp, rdi |
|||
|
|||
|
|||
pop r15 |
|||
pop r14 |
|||
pop r13 |
|||
pop r12 |
|||
pop r11 |
|||
pop r10 |
|||
pop r9 |
|||
pop r8 |
|||
|
|||
pop rdi |
|||
pop rsi |
|||
pop rbx |
|||
pop rdx |
|||
pop rcx |
|||
pop rax |
|||
pop rbp |
|||
|
|||
|
|||
iretq |
|||
|
@ -0,0 +1,31 @@ |
|||
#include "sched.h" |
|||
#include "process.h" |
|||
|
|||
// pid
|
|||
|
|||
static pid_t current_pid = KERNEL_PID; |
|||
|
|||
|
|||
// alloc pids in a circular way
|
|||
static pid_t last_pid = KERNEL_PID; |
|||
|
|||
gp_regs_t saved; |
|||
|
|||
// defined in restore_context.s
|
|||
void __attribute__((noreturn)) _restore_context(struct gp_regs*); |
|||
|
|||
|
|||
void sched_save(gp_regs_t* context) { |
|||
saved = *context; |
|||
} |
|||
|
|||
|
|||
void schedule(void) { |
|||
//_restore_context(&saved);
|
|||
} |
|||
|
|||
|
|||
|
|||
pid_t alloc_pid(void) { |
|||
return ++last_pid; |
|||
} |
@ -0,0 +1,23 @@ |
|||
#pragma once |
|||
|
|||
#include "thread.h" |
|||
#include "process.h" |
|||
|
|||
#define KERNEL_PID ((pid_t)0) |
|||
|
|||
|
|||
void sched_save(gp_regs_t* context); |
|||
|
|||
|
|||
// if this function returns, then a fast context restore
|
|||
// can happen: no need to unmap/map user space memory
|
|||
void schedule(void); |
|||
|
|||
|
|||
/**
|
|||
* return a fresh new pid that |
|||
* doesn't overlap with an existing process |
|||
* or with a process that just exited |
|||
*/ |
|||
pid_t alloc_pid(void); |
|||
|
@ -0,0 +1,30 @@ |
|||
#include "thread.h" |
|||
#include "../lib/registers.h" |
|||
#include "../memory/vmap.h" |
|||
|
|||
int create_thread( |
|||
thread_t* thread, |
|||
pid_t pid, |
|||
void* stack_base, |
|||
size_t stack_size, |
|||
tid_t tid |
|||
) { |
|||
*thread = (thread_t) { |
|||
.pid = pid, |
|||
.stack = { |
|||
.base = stack_base, |
|||
.size = stack_size, |
|||
}, |
|||
.tid = tid, |
|||
}; |
|||
|
|||
thread->regs.cs = USER_CS; |
|||
thread->regs.ss = USER_DS; |
|||
|
|||
thread->regs.rflags = get_rflags(); |
|||
thread->regs.rbp = 0; |
|||
|
|||
thread[0].regs.rsp = stack_base + stack_size; |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,68 @@ |
|||
#pragma once |
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
|
|||
#include "../lib/assert.h" |
|||
|
|||
#include "process.h" |
|||
|
|||
// this file describes what a thread is
|
|||
|
|||
|
|||
typedef struct stack { |
|||
void* base; |
|||
size_t size; |
|||
} stack_t; |
|||
|
|||
|
|||
typedef int32_t tid_t; |
|||
|
|||
typedef struct gp_regs { |
|||
|
|||
// r15 -> r8
|
|||
uint64_t ext[8]; |
|||
|
|||
|
|||
uint64_t rdi; |
|||
uint64_t rsi; |
|||
uint64_t rbx; |
|||
uint64_t rdx; |
|||
uint64_t rcx; |
|||
uint64_t rbp; |
|||
uint64_t rax; |
|||
|
|||
|
|||
uint64_t rip; |
|||
uint64_t cs; |
|||
uint64_t rflags; |
|||
uint64_t rsp; |
|||
uint64_t ss; |
|||
|
|||
} __attribute__((packed)) gp_regs_t; |
|||
|
|||
|
|||
static_assert_equals(sizeof(gp_regs_t), 160); |
|||
|
|||
|
|||
struct kernel_task { |
|||
gp_regs_t* regs; |
|||
stack_t stack; |
|||
}; |
|||
|
|||
|
|||
typedef |
|||
struct thread { |
|||
pid_t pid; |
|||
|
|||
tid_t tid; |
|||
|
|||
stack_t stack; |
|||
gp_regs_t regs; |
|||
|
|||
} thread_t; |
|||
|
|||
|
|||
// 0 if the thread cannot be created
|
|||
int create_thread(thread_t* thread, pid_t pid, void* stack_base, size_t stacs_size, tid_t); |
|||
|
Loading…
Reference in new issue