aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--src/common/include/proc.h18
-rw-r--r--src/common/include/syscallproto.h18
-rw-r--r--src/kernel/include/process.h31
-rw-r--r--src/kernel/include/thread.h5
-rw-r--r--src/kernel/user/process.c39
-rw-r--r--src/kernel/user/syscall.c5
-rw-r--r--src/lib/include/syscall.h3
-rw-r--r--src/lib/libkogata/syscall.c7
9 files changed, 99 insertions, 40 deletions
diff --git a/README.md b/README.md
index 0b460bc..4ae6939 100644
--- a/README.md
+++ b/README.md
@@ -104,8 +104,13 @@ running the tests):
### Plans for soon
+* Complete process management (implement process exiting, process deletion, waiting, ...)
* Implement missing syscalls
-* Write device drivers : VGA, keyboard, ATA, FAT, VESA
+* Write device drivers : VGA, keyboard, FAT (or EXT2 ?), VESA
+* Work on userland
+* Define a format for "packages", ie readonly filesystem images used for adding system
+ components or apps to the OS ; make sure to implement it in a way that does not waste
+ memory
### Things to design
@@ -121,7 +126,6 @@ running the tests):
we can always reload them from the disk.
- An on-disk file with a page cache must be aware of all the places where the page is mapped,
so that it can unmap it when reclaiming pages.
- - Simpler model : cached pages cannot be freed while the file is open with `FM_MMAP`
* Reclaiming physical memory :
- Freeing some cached stuff, ie swapping pages from mmap regions
- Swapping pages from processes non-mmap regions (ie real data regions)
@@ -132,6 +136,8 @@ running the tests):
have the possibility of crashing the system
* How does a process transmit information (such as environment, arguments, file
descriptors) to its children ?
+* How do we do stream-like IO on files ? (ie how do we implement the append acces mode
+ and non-position-dependant read/write calls & seek call)
### Things not sure
@@ -147,5 +153,6 @@ running the tests):
None of the source files have a licence header because it's cumbersome. All the
code and associated documentation found in this repository is released under
-the ISC licence as detailed in the `COPYING` file.
+the ISC licence as detailed in the `COPYING` file. Some parts of the code are very
+directly inspired from examples found on the OSDev wiki, thank you all!
diff --git a/src/common/include/proc.h b/src/common/include/proc.h
new file mode 100644
index 0000000..01a6722
--- /dev/null
+++ b/src/common/include/proc.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define PS_LOADING 1
+#define PS_RUNNING 2
+#define PS_DONE 3
+#define PS_FAILURE 4 // exception or segfault or stuff
+#define PS_KILLED 5
+
+typedef struct {
+ int pid;
+ int state; // one of PS_*
+ int return_code; // an error code if state == PS_FAILURE
+} proc_status_t;
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/common/include/syscallproto.h b/src/common/include/syscallproto.h
index 7b85a49..518cdb4 100644
--- a/src/common/include/syscallproto.h
+++ b/src/common/include/syscallproto.h
@@ -1,5 +1,6 @@
#pragma once
+#include <proc.h>
#define SC_MAX 128 // maximum number of syscalls
@@ -40,8 +41,9 @@
#define SC_PROC_EXEC 55 // args: pid, exec_name, exec_name_strlen -- execute binary in process
#define SC_PROC_STATUS 56 // args: pid, proc_status_t*
#define SC_PROC_KILL 57 // args: pid, proc_status_t* -- inconditionnally kill child process
-#define SC_PROC_WAIT 58 // args: pid, proc_status_t*
-#define SC_PROC_WAIT_ANY 59 // args: proc_status_t*
+#define SC_PROC_WAIT 58 // args: pid?, block?, proc_status_t*
+
+#define INVALID_PID 0 // do a wait with this PID to wayt for any child
typedef struct {
const char* driver;
@@ -71,16 +73,4 @@ typedef struct {
int bind_to_pid; // used only for SC_BIND_SUBFS
} sc_subfs_args_t;
-#define PS_LOADING 1
-#define PS_RUNNING 2
-#define PS_DONE 3
-#define PS_FAILURE 4 // exception or segfault or stuff
-#define PS_KILLED 5
-typedef struct {
- int pid;
- int state; // one of PS_*
- int return_code; // an error code if state == PS_FAILURE
-} proc_status_t;
-
-
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h
index 6e287e1..82f1b4d 100644
--- a/src/kernel/include/process.h
+++ b/src/kernel/include/process.h
@@ -18,8 +18,10 @@
#include <mmap.h>
+#include <proc.h> // common header defining process statuses
+
#define USERSTACK_ADDR 0xB8000000
-#define USERSTACK_SIZE 0x00020000 // 32 KB
+#define USERSTACK_SIZE 0x00020000 // 32 KB - it is allocated on demand so no worries
typedef struct process process_t;
@@ -46,21 +48,40 @@ typedef struct process {
hashtbl_t *files;
int next_fd;
- thread_t *thread;
+ thread_t *threads;
uint64_t last_ran;
int pid;
struct process *parent;
+ struct process *next_child;
+ struct process *children;
} process_t;
typedef void* proc_entry_t;
+// ---- Process creation, deletion, waiting, etc.
+// Simple semantics : when a process exits, all its ressources are freed immediately
+// except for the process_t that remains attached to the parent process until it does
+// a wait() and acknowleges the process' ending
+// When a process exits, all the children are orphaned and nobody can wait on them anymore,
+// which is a bad thing : a user process must always wait for all its children !
+
process_t *current_process();
process_t *new_process(process_t *parent);
-// void delete_process(process_t *p); // TODO define semantics for freeing stuff
bool start_process(process_t *p, proc_entry_t entry); // maps a region for user stack
+void process_exit(process_t *p, int status, int exit_code); // exit current process
+
+bool process_new_thread(process_t *p, proc_entry_t entry, void* sp);
+void process_thread_exited(thread_t *t); // called by threading code when a thread exits
+
+process_t *process_find_child(process_t *p, int pid);
+void process_get_status(process_t *p, proc_status_t *st);
+void process_wait(process_t *p, proc_status_t *st, bool block); // waits for exit and frees process_t structure
+void process_wait_any_child(process_t *p, bool block);
+
+// ---- Process FS namespace & FD set
bool proc_add_fs(process_t *p, fs_t *fs, const char* name);
fs_t *proc_find_fs(process_t *p, const char* name);
@@ -69,12 +90,14 @@ int proc_add_fd(process_t *p, fs_handle_t *f); // on error returns 0, nonzero o
fs_handle_t *proc_read_fd(process_t *p, int fd);
void proc_close_fd(process_t *p, int fd);
+// ---- Process virtual memory space
+
bool mmap(process_t *proc, void* addr, size_t size, int mode); // create empty zone
bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_t size, int mode);
bool mchmap(process_t *proc, void* addr, int mode);
bool munmap(process_t *proc, void* addr);
-// for syscalls : check that process is authorized to do that
+// for syscalls : check that process is authorized to read/write given addresses
// (if not, process exits with a segfault)
void probe_for_read(const void* addr, size_t len);
void probe_for_write(const void* addr, size_t len);
diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h
index 127b0d7..163045d 100644
--- a/src/kernel/include/thread.h
+++ b/src/kernel/include/thread.h
@@ -30,9 +30,10 @@ typedef struct thread {
region_info_t *stack_region;
process_t *proc;
- isr_handler_t user_ex_handler; // page fault in kernel memory accessed by user code (violation)
+ isr_handler_t user_ex_handler; // exception in user code
struct thread *next_in_queue;
+ struct thread *next_in_proc;
} thread_t;
typedef void (*entry_t)(void*);
@@ -48,7 +49,7 @@ void exit();
void usleep(int usecs);
bool resume_thread(thread_t *thread);
-void kill_thread(thread_t *thread);
+void kill_thread(thread_t *thread); // cannot be called for current thread
// Kernel critical sections
#define CL_EXCL 3 // No interruptions accepted, context switching not allowed
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c
index 3f8da08..649c801 100644
--- a/src/kernel/user/process.c
+++ b/src/kernel/user/process.c
@@ -17,6 +17,11 @@ process_t *current_process() {
return 0;
}
+typedef struct {
+ proc_entry_t entry;
+ void *sp;
+} setup_data_t;
+
// ============================== //
// CREATING AND RUNNING PROCESSES //
// ============================== //
@@ -39,7 +44,7 @@ process_t *new_process(process_t *parent) {
proc->last_ran = 0;
proc->regions = 0;
- proc->thread = 0;
+ proc->threads = 0;
proc->pid = (next_pid++);
proc->parent = parent;
proc->next_fd = 1;
@@ -54,13 +59,17 @@ error:
return 0;
}
-static void run_user_code(void* entry) {
+static void run_user_code(void* param) {
+ setup_data_t *d = (setup_data_t*)param;
+
process_t *proc = current_thread->proc;
ASSERT(proc != 0);
switch_pagedir(proc->pd);
- void* esp = (void*)USERSTACK_ADDR + USERSTACK_SIZE;
+ void* esp = d->sp;
+ proc_entry_t entry = d->entry;
+ free(d);
asm volatile(" \
cli; \
@@ -86,14 +95,34 @@ bool start_process(process_t *p, void* entry) {
bool stack_ok = mmap(p, (void*)USERSTACK_ADDR, USERSTACK_SIZE, MM_READ | MM_WRITE);
if (!stack_ok) return false;
- thread_t *th = new_thread(run_user_code, entry);
- if (th == 0) {
+ bool ok = process_new_thread(p, entry, (void*)USERSTACK_ADDR + USERSTACK_SIZE);
+ if (!ok) {
munmap(p, (void*)USERSTACK_ADDR);
return false;
}
+ return true;
+}
+
+bool process_new_thread(process_t *p, proc_entry_t entry, void* sp) {
+ setup_data_t *d = (setup_data_t*)malloc(sizeof(setup_data_t));
+ d->entry = entry;
+ d->sp = sp;
+
+ thread_t *th = new_thread(run_user_code, d);
+ if (th == 0) {
+ return false;
+ }
+
th->proc = p;
th->user_ex_handler = proc_user_exception;
+
+ { int st = enter_critical(CL_NOINT); // it's a bit complicated to use mutexes on process_t (TODO: think)
+
+ th->next_in_proc = p->threads;
+ p->threads = th;
+
+ exit_critical(st); }
resume_thread(th);
diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c
index 3041c6d..009903c 100644
--- a/src/kernel/user/syscall.c
+++ b/src/kernel/user/syscall.c
@@ -319,10 +319,6 @@ static uint32_t proc_wait_sc(sc_args_t args) {
return -1; //TODO
}
-static uint32_t proc_wait_any_sc(sc_args_t args) {
- return -1; //TODO
-}
-
// ====================== //
// SYSCALLS SETUP ROUTINE //
// ====================== //
@@ -365,7 +361,6 @@ void setup_syscall_table() {
sc_handlers[SC_PROC_STATUS] = proc_status_sc;
sc_handlers[SC_PROC_KILL] = proc_kill_sc;
sc_handlers[SC_PROC_WAIT] = proc_wait_sc;
- sc_handlers[SC_PROC_WAIT_ANY] = proc_wait_any_sc;
}
void syscall_handler(registers_t *regs) {
diff --git a/src/lib/include/syscall.h b/src/lib/include/syscall.h
index c26a805..ddc0e18 100644
--- a/src/lib/include/syscall.h
+++ b/src/lib/include/syscall.h
@@ -49,7 +49,6 @@ bool bind_fd(pid_t pid, fd_t new_fd, fd_t fd);
bool proc_exec(pid_t pid, const char* file);
bool proc_status(pid_t pid, proc_status_t *s);
bool proc_kill(pid_t pid, proc_status_t *s);
-void proc_wait(pid_t pid, proc_status_t *s);
-void proc_wait_any(proc_status_t *s);
+void proc_wait(pid_t pid, bool wait, proc_status_t *s);
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/lib/libkogata/syscall.c b/src/lib/libkogata/syscall.c
index 6f37c47..4b31ab3 100644
--- a/src/lib/libkogata/syscall.c
+++ b/src/lib/libkogata/syscall.c
@@ -153,11 +153,8 @@ bool proc_status(pid_t pid, proc_status_t *s) {
bool proc_kill(pid_t pid, proc_status_t *s) {
return call(SC_PROC_KILL, pid, (uint32_t)s, 0, 0, 0);
}
-void proc_wait(pid_t pid, proc_status_t *s) {
- call(SC_PROC_WAIT, pid, (uint32_t)s, 0, 0, 0);
-}
-void proc_wait_any(proc_status_t *s) {
- call(SC_PROC_WAIT_ANY, (uint32_t)s, 0, 0, 0, 0);
+void proc_wait(pid_t pid, bool block, proc_status_t *s) {
+ call(SC_PROC_WAIT, pid, block, (uint32_t)s, 0, 0);
}