Browse Source

exec

master
Mathieu Serandour 6 months ago
parent
commit
5a1cbcd8c3
  1. 179
      kernel/int/syscall.c
  2. 102
      kernel/int/syscall.h
  3. 119
      kernel/int/syscall_interface.h
  4. 119
      kernel/sched/process.c
  5. 21
      kernel/sched/process.h
  6. 8
      kernel/sched/restore_context.s
  7. 4
      kernel/sched/sched.c
  8. 5
      kernel/sched/sched.h
  9. 4
      kernel/sched/thread.c

179
kernel/int/syscall.c

@ -21,19 +21,14 @@ typedef uint64_t(*sc_fun_t)(process_t*, void*, size_t);
static sc_fun_t sc_funcs[SC_END];
static inline void sc_warn(const char* msg, void* args, size_t args_sz) {
log_warn("syscall process %u, thread %u: %s, \targs_sz=%u, args:",
/*
log_debug("syscall process %u, thread %u: %s",
sched_current_pid(),
sched_current_tid(),
msg,
args_sz
);
dump(
args,
args_sz,
16,
DUMP_HEX8
);
*/
}
@ -80,6 +75,26 @@ static int check_args(const process_t* proc, const void* args, size_t args_sz) {
}
static char* get_absolute_path(const char* cwd, const char* path) {
if(path[0] == '/') {
// absolute path
return strdup(path);
}
size_t cwd_sz = strlen(cwd);
size_t path_sz = strlen(path);
char* abs_path = malloc(cwd_sz + path_sz + 2);
memcpy(abs_path, cwd, cwd_sz);
abs_path[cwd_sz] = '/';
memcpy(abs_path + cwd_sz + 1, path, path_sz + 1);
return abs_path;
}
static uint64_t sc_unimplemented(process_t* proc, void* args, size_t args_sz) {
(void) proc;
@ -173,29 +188,59 @@ char* parse_cmdline(const char* cmdline, size_t cmdline_sz) {
}
*/
uint64_t sc_exec(process_t* proc, void* args, size_t args_sz) {
static uint64_t sc_exec(process_t* proc, void* args, size_t args_sz) {
if(args_sz != sizeof(struct sc_exec_args)) {
sc_warn("bad args_sz", args, args_sz);
return -1;
}
////////////////////////////////////////////
///// checking arguments /////
////////////////////////////////////////////
struct sc_exec_args* exec_args = (struct sc_exec_args*)args;
if(check_args(proc, exec_args->args, exec_args->args_sz)) {
sc_warn("bad cmdline", args, args_sz);
if(exec_args->args_sz < 1 ||
check_args(proc, exec_args->args, exec_args->args_sz))
{
log_warn("issou %u", exec_args->args_sz);
sc_warn("bad cmdline size", args, args_sz);
return -1;
}
// this unsures that strlen won't generate a page fault
if(exec_args->args[args_sz - 1] != '\0') {
if(exec_args->args[exec_args->args_sz - 1] != '\0'
) {
sc_warn("bad cmdline", args, args_sz);
return -1;
}
const char* path = exec_args->args;
if(exec_args->env_sz < 1 ||
check_args(proc, exec_args->env, exec_args->env_sz))
{
sc_warn("bad env vars", args, args_sz);
return -1;
}
// this unsures that strlen won't generate a page fault
if(exec_args->env[exec_args->env_sz - 1] != '\0'
) {
sc_warn("bad environment vars", args, args_sz);
return -1;
}
////////////////////////////////////////////
///// open executable file /////
////////////////////////////////////////////
// first element of args is the program name
char* path = get_absolute_path(proc->cwd, exec_args->args);
file_handle_t* elf_file = vfs_open_file(path);
free(path);
if(!elf_file) {
sc_warn("failed to open file", args, args_sz);
@ -212,25 +257,93 @@ uint64_t sc_exec(process_t* proc, void* args, size_t args_sz) {
size_t rd = vfs_read_file(elf_data, file_sz, 1, elf_file);
assert(rd != file_sz);
assert(rd == file_sz);
vfs_close_file(elf_file);
// as we might to map another process
// we won't be able to access args and env
// so we copy them in kernel heap
char* args_copy = (char*)malloc(exec_args->args_sz);
char* env_copy = (char*)malloc(exec_args->env_sz);
memcpy(args_copy, exec_args->args, exec_args->args_sz);
memcpy(env_copy, exec_args->env, exec_args->env_sz);
// very bad naming....
size_t cmd_args_sz = exec_args->args_sz;
size_t env_sz = exec_args->env_sz;
////////////////////////////////////////////
///// create process /////
////////////////////////////////////////////
// resulting process
// either the current process or a new one
process_t* new_proc;
if(!exec_args->new_process) {
assert(0);
// regular UNIX exec
replace_process(proc, elf_data, file_sz);
new_proc = proc;
}
else {
sched_create_process(proc->pid, elf_data, file_sz);
unmap_user();
// sched_create_process needs the user to be unmaped
pid_t p = sched_create_process(proc->pid, elf_data, file_sz);
if(p == -1) {
sc_warn("failed to create process", args, args_sz);
// even if the process creation failed, we
// still need to remap the process
set_user_page_map(proc->page_dir_paddr);
return -1;
}
new_proc = sched_get_process(p);
}
// here, new_proc is currently mapped in memory
assert(new_proc);
////////////////////////////////////////////
//// set process arguments and env vars ////
////////////////////////////////////////////
if(set_process_entry_arguments(new_proc,
args_copy, cmd_args_sz, env_copy, env_sz
)) {
sc_warn("failed to set process arguments", args, args_sz);
// even if the process creation failed, we
// still need to remap the process
set_user_page_map(proc->page_dir_paddr);
return -1;
}
// done :)
// now we must restore the current process
// memory map before returning
set_user_page_map(proc->page_dir_paddr);
return 0;
}
static fd_t find_free_fd(process_t* proc) {
static fd_t find_available_fd(process_t* proc) {
for(fd_t i = 0; i < MAX_FDS; i++) {
if(proc->fds[i].type == FD_NONE)
return i;
@ -270,26 +383,6 @@ static fd_t insert_process_dir(process_t* proc, struct DIR* dir) {
}
static char* get_absolute_path(const char* cwd, const char* path) {
if(path[0] == '/') {
// absolute path
return strdup(path);
}
size_t cwd_sz = strlen(cwd);
size_t path_sz = strlen(path);
char* abs_path = malloc(cwd_sz + path_sz + 2);
memcpy(abs_path, cwd, cwd_sz);
abs_path[cwd_sz] = '/';
memcpy(abs_path + cwd_sz + 1, path, path_sz + 1);
return abs_path;
}
static uint64_t sc_open(process_t* proc, void* args, size_t args_sz) {
if(args_sz != sizeof(struct sc_open_args)) {
sc_warn("bad args_sz", args, args_sz);
@ -313,7 +406,7 @@ static uint64_t sc_open(process_t* proc, void* args, size_t args_sz) {
}
fd_t fd = find_free_fd(proc);
fd_t fd = find_available_fd(proc);
if(fd == (fd_t)-1) {
@ -384,9 +477,7 @@ static uint64_t sc_close(process_t* proc, void* args, size_t args_sz) {
}
close_fd(&proc->fds[fd]);
return 0;
return close_fd(&proc->fds[fd]);
}
@ -590,6 +681,9 @@ static uint64_t sc_getcwd(process_t* proc, void* args, size_t args_sz) {
struct sc_getcwd_args* a = args;
if(a->buf_sz == 0 && a->buf == NULL)
return strlen(proc->cwd) + 1;
check_args(proc, a->buf, a->buf_sz);
if(a->buf_sz < strlen(proc->cwd) + 1) {
@ -659,7 +753,7 @@ static uint64_t sc_dup(process_t* proc, void* args, size_t args_sz) {
}
}
else {
fd2 = find_free_fd(proc);
fd2 = find_available_fd(proc);
if(fd2 == (fd_t)-1) {
sc_warn("too many fds", args, args_sz);
@ -673,7 +767,7 @@ static uint64_t sc_dup(process_t* proc, void* args, size_t args_sz) {
}
uint64_t sc_clock(process_t* proc, void* args, size_t args_sz) {
static uint64_t sc_clock(process_t* proc, void* args, size_t args_sz) {
if(args_sz != 0) {
sc_warn("bad args_sz", args, args_sz);
return -1;
@ -704,6 +798,7 @@ void syscall_init(void) {
sc_funcs[SC_SEEK] = sc_seek;
sc_funcs[SC_READ] = sc_read;
sc_funcs[SC_WRITE] = sc_write;
sc_funcs[SC_EXEC] = sc_exec;
sc_funcs[SC_CHDIR] = sc_chdir;
sc_funcs[SC_GETCWD] = sc_getcwd;
sc_funcs[SC_CLOCK] = sc_clock;

102
kernel/int/syscall.h

@ -1,8 +1,4 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef unsigned fd_t;
/**
@ -12,38 +8,6 @@ typedef unsigned fd_t;
*/
void syscall_init(void);
// bincows syscalls
#define SC_SLEEP 1
#define SC_CLOCK 2
#define SC_EXIT 3
#define SC_OPEN 4
#define SC_CLOSE 5
#define SC_READ 6
#define SC_WRITE 7
#define SC_SEEK 8
#define SC_DUP 9
#define SC_CREATE_THREAD 10
#define SC_JOIN_THREAD 11
#define SC_EXIT_THREAD 12
#define SC_SBRK 13
#define SC_FORK 14
#define SC_EXEC 15
#define SC_CHDIR 16
#define SC_GETCWD 17
#define SC_GETPID 18
#define SC_GETPPID 19
#define SC_END 20
typedef enum open_mode {
MODE_READ = 0,
MODE_WRITE = 1,
MODE_READ_WRITE = 2,
} open_mode_t;
typedef enum open_flags {
O_RDONLY = 0,
O_WRONLY = 1,
@ -61,69 +25,5 @@ typedef enum open_flags {
O_DIR = 4096,
} open_flags_t;
#include "syscall_interface.h"
struct sc_open_args {
const char* path;
size_t path_len;
open_flags_t flags;
open_mode_t mode;
char chs[3];
};
struct sc_seek_args {
fd_t fd;
int64_t offset;
int whence;
};
struct sc_read_args {
fd_t fd;
void* buf;
size_t count;
};
struct sc_write_args {
fd_t fd;
const void* buf;
size_t count;
};
struct sc_exec_args {
// args contains 0 terminated args
// total size: args_sz
const char* args;
size_t args_sz;
// args: argv[0]
// args+strlen(argv[0])+1: argv[1]
// ...
// if 0, the syscall will
// behave like the unix one
int new_process;
};
struct sc_chdir_args {
const char* path;
size_t path_len;
};
struct sc_getcwd_args {
char* buf;
size_t buf_sz;
};
struct sc_dup_args {
fd_t fd;
fd_t fd2;
// if new == -1, this operation
// performs dup(fd)
// else, it performs dup2(fd, fd2)
};

119
kernel/int/syscall_interface.h

@ -0,0 +1,119 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef unsigned fd_t;
// bincows syscalls
#define SC_SLEEP 1
#define SC_CLOCK 2
#define SC_EXIT 3
#define SC_OPEN 4
#define SC_CLOSE 5
#define SC_READ 6
#define SC_WRITE 7
#define SC_SEEK 8
#define SC_DUP 9
#define SC_CREATE_THREAD 10
#define SC_JOIN_THREAD 11
#define SC_EXIT_THREAD 12
#define SC_SBRK 13
#define SC_FORK 14
#define SC_EXEC 15
#define SC_CHDIR 16
#define SC_GETCWD 17
#define SC_GETPID 18
#define SC_GETPPID 19
#define SC_END 20
typedef enum open_mode {
MODE_READ = 0,
MODE_WRITE = 1,
MODE_READ_WRITE = 2,
} open_mode_t;
struct sc_open_args {
const char* path;
size_t path_len;
open_flags_t flags;
open_mode_t mode;
char chs[3];
};
struct sc_seek_args {
fd_t fd;
int64_t offset;
int whence;
};
struct sc_read_args {
fd_t fd;
void* buf;
size_t count;
};
struct sc_write_args {
fd_t fd;
const void* buf;
size_t count;
};
struct sc_exec_args {
// args contains 0 terminated args
// total size: args_sz
const char* args;
size_t args_sz;
// args: argv[0]
// args+strlen(argv[0])+1: argv[1]
// ...
// env contains 0 terminated env
// total size: env_sz
const char* env;
size_t env_sz;
// same as args
// if 0, the syscall will
// behave like the unix one
int new_process;
};
struct sc_chdir_args {
const char* path;
size_t path_len;
};
struct sc_getcwd_args {
char* buf;
size_t buf_sz;
};
struct sc_dup_args {
fd_t fd;
fd_t fd2;
// if new == -1, this operation
// performs dup(fd)
// else, it performs dup2(fd, fd2)
};

119
kernel/sched/process.c

@ -46,7 +46,11 @@ void dup_fd(file_descriptor_t* fd, file_descriptor_t* new_fd) {
}
void close_fd(file_descriptor_t* fd) {
int close_fd(file_descriptor_t* fd) {
if(fd->file == NULL) {
return -1;
}
switch(fd->type) {
case FD_FILE:
vfs_close_file(fd->file);
@ -59,11 +63,18 @@ void close_fd(file_descriptor_t* fd) {
}
fd->type = FD_NONE;
return 0;
}
int create_process(process_t* process, process_t* pparent, const void* elffile, size_t elffile_sz) {
int create_process(
process_t* process,
process_t* pparent,
const void* elffile,
size_t elffile_sz
) {
// assert that no userspace is mapped
assert(get_user_page_map() == 0);
@ -85,6 +96,8 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
fds = malloc(sizeof(file_descriptor_t*) * MAX_FDS);
char* cwd;
if(pparent) {
// inherit parent file handlers
ppid = pparent->pid;
@ -95,7 +108,7 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
}
// inherit parent directory
process->cwd = strdup(pparent->cwd);
cwd = strdup(pparent->cwd);
}
else {
// empty file handlers
@ -106,7 +119,7 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
//memset(fds, 0, sizeof(file_descriptor_t*) * MAX_FDS);
// root directory
process->cwd = strdup("/");
cwd = strdup("/");
}
@ -125,6 +138,7 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
FIRST_TID
);
// set PC
threads[0].rsp->rip = (uint64_t)program->entry;
@ -146,6 +160,7 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
.page_dir_paddr = user_page_map,
.pid = pid,
.ppid = ppid,
.cwd = cwd,
.program = program,
.clock_begin = clock_ns()
};
@ -155,7 +170,6 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
process->brk = process->unaligned_brk = process->heap_begin =
(void *)(((uint64_t)elf_end+0xfff) & ~0x0fffllu);
return 1;
}
@ -188,6 +202,9 @@ int replace_process(process_t* process, void* elffile, size_t elffile_sz) {
unmap_user();
free_user_page_map(process->page_dir_paddr);
// recreate page directory
process->page_dir_paddr = alloc_user_page_map();
set_user_page_map(process->page_dir_paddr);
// only one thread
@ -226,6 +243,98 @@ int replace_process(process_t* process, void* elffile, size_t elffile_sz) {
process->threads[0].rsp->rip = (uint64_t)program->entry;
return 0;
}
static size_t string_list_len(char* list) {
size_t len = 0;
while(*list) {
list += strlen(list) + 1;
len++;
}
return len;
}
int set_process_entry_arguments(process_t* process,
char* argv, size_t argv_sz, char* envp, size_t envp_sz
) {
assert(process);
//setup stack
uint64_t rsp = (uint64_t)process->threads[0].stack.base
+ process->threads[0].stack.size;
// align sizes to 16 bytes
// because we are copying it in
// a stack
argv_sz = (argv_sz + 15) & ~0x0f;
envp_sz = (envp_sz + 15) & ~0x0f;
// put the arguments and env vars in the stack
uint64_t user_argv = (rsp -= argv_sz);
uint64_t user_envp = (rsp -= envp_sz);
log_warn("user_argv=%lx, user_envp=%lx", user_argv, user_envp);
// frame begin
uint64_t* user_frame_begin = (uint64_t*)(rsp -= sizeof(uint64_t));
*user_frame_begin = 0;
process->threads[0].rsp = (uint64_t*)(rsp -= sizeof(gp_regs_t));
// stack.base < rsp < user_envp < user_argv
if(process->threads[0].rsp <= process->threads[0].stack.base) {
// not enough space
return -1;
}
// copy argv and envp
memcpy((void*)user_argv, argv, argv_sz);
memcpy((void*)user_envp, envp, envp_sz);
// compute argc and envc
int argc;
int envc;
if(argv)
argc = string_list_len(argv);
else
argc = 0;
if(envp)
envc = string_list_len(envp);
else
envc = 0;
// fill registers initial values
// entry arguments:
// _start(int argc, char* args, int envrionc, char* environ)
process->threads[0].rsp->rdi = argc;
process->threads[0].rsp->rsi = user_argv;
process->threads[0].rsp->rdx = envc;
process->threads[0].rsp->rcx = user_envp;
process->threads[0].rsp->rsp = rsp;
process->threads[0].rsp->rbp = user_frame_begin;
process->threads[0].rsp->rip = process->program->entry;
process->threads[0].rsp->cs = USER_CS;
process->threads[0].rsp->ss = USER_DS;
process->threads[0].rsp->rflags = USER_RF;
return 0;
}

21
kernel/sched/process.h

@ -95,6 +95,16 @@ typedef struct process {
int create_process(process_t* process, process_t* pparent, const void* elffile, size_t elffile_sz);
/**
* @brief Set the process entry arguments object
*
* argv and envp are null terminated strings with
* NULL last element
*
*/
int set_process_entry_arguments(process_t* process,
char* argv, size_t argv_sz, char* envp, size_t envp_sz);
/**
* @brief free an exited process
* (no remainng thread)
@ -103,7 +113,12 @@ int create_process(process_t* process, process_t* pparent, const void* elffile,
*/
void free_process(process_t* process);
/**
* In order to replace the process,
* the current process must already
* be mapped.
* The process stays mapped
*/
int replace_process(process_t* process, void* elffile, size_t elffile_sz);
@ -114,9 +129,9 @@ int replace_process(process_t* process, void* elffile, size_t elffile_sz);
* and calls the right close
* function
*
* @param fd
* @return int 0 if success, non-0 otherwise
*/
void close_fd(file_descriptor_t* fd);
int close_fd(file_descriptor_t* fd);
/**
* duplicates fd to new_fd

8
kernel/sched/restore_context.s

@ -25,14 +25,6 @@ _restore_context:
; set segments
mov rax, [rsp + 152] ; gp_regs_t.ss
; we set every segment but the stack one
; iretq will take care of it
mov ds, ax
mov fs, ax
mov gs, ax
mov es, ax
pop r15
pop r14
pop r13

4
kernel/sched/sched.c

@ -132,12 +132,12 @@ pid_t sched_create_process(pid_t ppid, const void* elffile, size_t elffile_sz) {
if(!parent) {
// no such ppid
return 0;
return -1;
}
}
if(!create_process(&new, parent, elffile, elffile_sz))
return 0;
return -1;
_cli();

5
kernel/sched/sched.h

@ -26,7 +26,10 @@ pid_t alloc_pid(void);
// create process and return its pid
// or 0 if unsuccessful
// or -1 if unsuccessful
// in order to create a process, no process should
// initially mapped in memory.
// the created process is mapped and is not unmapped
pid_t sched_create_process(pid_t ppid, const void* elffile, size_t elffile_sz);

4
kernel/sched/thread.c

@ -28,8 +28,8 @@ int create_thread(
thread->rsp->cs = USER_CS;
thread->rsp->ss = USER_DS;
thread->rsp->rflags = get_rflags();
thread->rsp->rflags = USER_RF;
thread->rsp->rbp = (uint64_t)(stack_base - 8);
thread->rsp->rsp = (uint64_t)stack_base + stack_size;

Loading…
Cancel
Save