summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/tce/syscalls.h3
-rw-r--r--src/kernel/linker/elf.cpp2
-rw-r--r--src/kernel/task/syscall.cpp9
-rw-r--r--src/kernel/task/task.cpp129
-rw-r--r--src/kernel/task/task.h9
-rw-r--r--src/kernel/ui/vt.cpp1
-rw-r--r--src/kernel/vfs/node.cpp5
-rw-r--r--src/user/lib/include/tce/syscall.h3
-rw-r--r--src/user/lib/tce/syscall.c10
-rw-r--r--src/user/test/main.c44
10 files changed, 162 insertions, 53 deletions
diff --git a/src/include/tce/syscalls.h b/src/include/tce/syscalls.h
index e14768f..26021a0 100644
--- a/src/include/tce/syscalls.h
+++ b/src/include/tce/syscalls.h
@@ -16,6 +16,9 @@
#define SC_MMAP 12
#define SC_MUNMAP 13
+#define SC_RUN 14
+#define SC_WAITPID 15
+
#define SC_OPEN 20
#define SC_OPEN_RELATIVE 21
#define SC_STAT 22
diff --git a/src/kernel/linker/elf.cpp b/src/kernel/linker/elf.cpp
index 8fc2e0c..6c45f10 100644
--- a/src/kernel/linker/elf.cpp
+++ b/src/kernel/linker/elf.cpp
@@ -45,7 +45,7 @@ thread_entry elf_load(uint8_t *data, process* process) {
}
process* elf_exec(uint8_t *data, int privilege, char** args) {
- if (elf_check(data)) return 0;
+ if (elf_check(data) != 0) return 0;
process* p = new process(0, 0, privilege);
diff --git a/src/kernel/task/syscall.cpp b/src/kernel/task/syscall.cpp
index e9f9d3a..4eddb61 100644
--- a/src/kernel/task/syscall.cpp
+++ b/src/kernel/task/syscall.cpp
@@ -28,6 +28,7 @@ CALL1V(idt_waitIrq, irq_wait_sc);
CALL0(proc_priv, proc_priv_sc);
CALL1(process_sbrk, proc_sbrk_sc);
CALL1V(process_brk, proc_brk_sc);
+CALL1(process_waitpid, waitpid_sc);
CALL1V(close, close_sc);
@@ -41,6 +42,10 @@ static void thread_new_sc(registers* r) {
sti();
}
+static void run_sc(registers *r) {
+ r->eax = process_run((char*)r->ebx, (char**)r->ecx);
+}
+
static void open_sc(registers *r) {
r->eax = open((char*)r->ebx, r->ecx);
}
@@ -89,8 +94,8 @@ int_callback syscalls[NUMBER_OF_SYSCALLS] = { // This must correspond to common
proc_brk_sc,
0,
0,
- 0,
- 0, //15
+ run_sc,
+ waitpid_sc, //15
0,
0,
0,
diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp
index 1a5d535..02294bd 100644
--- a/src/kernel/task/task.cpp
+++ b/src/kernel/task/task.cpp
@@ -6,6 +6,10 @@
#include <mem/gdt.h>
#include "timer.h"
+#include <linker/elf.h>
+
+#include <vfs/node.h>
+#include <lib/earray.h>
#include <ui/vt.h>
#define KSTACKSIZE 0x8000
@@ -14,29 +18,37 @@
static void thread_exit_stackJmp(uint32_t reason);
static void thread_exit2(uint32_t reason);
static void thread_delete(thread *th);
-static void process_delete(process *pr);
+static void process_finish(process *pr, int retval);
//From task_.asm
extern "C" uint32_t read_eip();
extern "C" void task_idle(void*);
-static uint32_t nextpid = 1;
-process *processes = 0, *kernel_process = 0, *current_process = 0;
+earray<process> *proc_by_pid;
+earray<void> *proc_retval;
+
+process *kernel_process = 0, *current_process = 0;
thread *current_thread = 0, *idle_thread = 0;
+int proc_count = 0;
+
uint32_t tasking_tmpStack[KSTACKSIZE];
/* Sets up tasking. Called by kmain on startup.
Creates a kernel process and an IDLE thread in it. */
void tasking_init() {
+ proc_by_pid = new earray<process>(12, 32);
+ proc_retval = new earray<void>(12, 32);
+
cli();
- kernel_process = new process(); //This process must be hidden to users
- kernel_process->pid = kernel_process->uid = kernel_process->thread_count = 0;
+ kernel_process = new process();
+ kernel_process->uid = kernel_process->thread_count = 0;
+ kernel_process->pid = proc_by_pid->add(kernel_process);
kernel_process->privilege = PL_KERNEL;
kernel_process->parent = kernel_process;
kernel_process->pagedir = kernel_pagedir;
- kernel_process->next = 0;
kernel_process->threads = 0;
+ kernel_process->threads_waiting = 0;
current_thread = 0;
idle_thread = new thread(kernel_process, task_idle, 0, 0);
sti();
@@ -46,17 +58,17 @@ void tasking_init() {
Updates the page directories of all the processes. */
void tasking_updateKernelPagetable(uint32_t idx, page_table *table, uint32_t tablephysical) {
if (idx < FIRST_KERNEL_PAGETABLE) return;
- process* it = processes;
- while (it != 0) {
+ for (int i = 0; i < proc_by_pid->count(); i++) {
+ process *it = proc_by_pid->at(i);
+ if (it == 0) continue;
it->pagedir->tables[idx] = table;
it->pagedir->tablesPhysical[idx] = tablephysical;
- it = it->next;
}
}
/* Called when a timer IRQ fires. Does a context switch. */
void schedule() {
- if (processes == 0) PANIC("No processes are running !");
+ //if (processes == 0) PANIC("No processes are running !");
asm volatile("cli");
uint32_t esp, ebp, eip;
@@ -97,7 +109,7 @@ void schedule() {
Ends the thread for most exceptions, ends the whole process for page faults. */
uint32_t tasking_handleException(registers *regs) {
if (current_thread == 0) return 0; //No tasking yet
- NL; WHERE; ke_vt->writeStr("exception:`");
+ NL; WHERE; ke_vt->writeStr("Exception: `");
char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint",
"Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault",
"Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault",
@@ -105,10 +117,9 @@ uint32_t tasking_handleException(registers *regs) {
*ke_vt << exception_messages[regs->int_no];
*ke_vt << "'\teip:" << regs->eip;
if (regs->eip >= K_HIGHHALF_ADDR) {
- *ke_vt << "\n Exception stack trace :\n";
+ *ke_vt << "\nException in kernel. Stack trace:\n";
stack_trace(regs->ebp);
- PANIC("Kernel error'd.");
- }
+ }
if (regs->int_no == 14) {
*ke_vt << "\n>>> Process exiting.\n";
thread_exit_stackJmp(EX_PR_EXCEPTION);
@@ -155,7 +166,7 @@ void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h
if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) {
thread_delete(th);
} else {
- process_delete(pr);
+ process_finish(pr, reason);
}
retrn:
sti();
@@ -274,14 +285,13 @@ thread::thread(class process *proc, thread_entry entry_point, void *data, void *
/* Creates a new process. Creates a struct process and fills it up. */
process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12, 64) {
- pid = (nextpid++);
uid = _uid;
thread_count = 0;
threads = 0;
+ threads_waiting = 0;
privilege = _privilege;
parent = _parent;
pagedir = pagedir_new();
- next = processes;
data = 0;
dataseg = 0;
@@ -294,7 +304,9 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12,
stack = stacksBottom + USER_STACK_SIZE - 4;
}
- processes = this;
+ pid = proc_by_pid->add(this);
+
+ proc_count++;
}
/* Deletes given thread, freeing the stack(s). */
@@ -318,26 +330,25 @@ static void thread_delete(thread *th) {
}
/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */
-static void process_delete(process *pr) {
+static void process_finish(process *pr, int retval) {
+ proc_retval->set(pr->pid, (void*)retval);
+
+
thread *it = pr->threads;
while (it != 0) {
thread_delete(it);
it = it->next;
}
- if (processes == pr) {
- processes = pr->next;
- } else {
- process *it = processes;
- while (it) {
- if (it->next == pr) {
- it->next = pr->next;
- break;
- }
- it = it->next;
- }
- }
pagedir_delete(pr->pagedir);
+ proc_by_pid->set(pr->pid, 0);
+ while (pr->threads_waiting != 0) {
+ pr->threads_waiting->wakeUp();
+ pr->threads_waiting = pr->threads_waiting->queue_next;
+ }
kfree(pr);
+
+ proc_count--;
+ if (proc_count == 0) PANIC("No more processes are running! This is bad! Or is it?");
}
size_t process::sbrk(size_t size) {
@@ -408,11 +419,65 @@ void* process::set_args(char** args) {
return p;
}
-// syscalls
+// ===================== SYSTEM CALLS
+
+
size_t process_sbrk(size_t size) {
return current_process->sbrk(size);
}
+
void process_brk(size_t ptr) {
ASSERT(ptr < K_HIGHHALF_ADDR);
current_process->sbrk(ptr - current_process->data);
}
+
+int process_run(char* file, char** args) {
+ node* bin = vfs_find(root, file);
+ if (bin == 0) return E_NOT_FOUND;
+ if ((bin->type & FT_FILE) == 0) return E_INVALID;
+
+ int len = bin->get_size();
+ void *v = kmalloc(len);
+ int r = bin->read(0, len, (char*)v);
+ if (r != len) {
+ kfree(v);
+ return E_NOT_IMPLEMENTED;
+ }
+ if (elf_check((uint8_t*)v) != 0) {
+ kfree(v);
+ return E_NOT_IMPLEMENTED;
+ }
+
+ // copy arguments to kernel
+ char **arg_data;
+ int argc = 0;
+ if (args != 0) {
+ for (char** a = args; *a != 0; a++) argc++;
+ arg_data = (char**)kmalloc(sizeof(char*) * (argc + 2));
+ for (int i = 0; i < argc; i++) arg_data[i+1] = strdup(args[i]);
+ } else {
+ arg_data = (char**)kmalloc(sizeof(char*)*2);
+ }
+ arg_data[0] = strdup(file);
+ arg_data[argc + 1] = 0;
+
+ // load
+ process *p = elf_exec((uint8_t*)v, PL_USER, arg_data);
+
+ kfree(v);
+ for (int i = 0; arg_data[i] != 0; i++) kfree(arg_data[i]);
+ kfree(arg_data);
+ return (p == 0 ? E_INVALID : p->pid);
+}
+
+int process_waitpid(int pid) {
+ if (pid <= 0) return E_INVALID_RANGE;
+
+ process *p = proc_by_pid->at(pid);
+ if (p != 0) {
+ current_thread->queue_next = p->threads_waiting;
+ p->threads_waiting = current_thread;
+ thread_goInactive();
+ }
+ return (int)proc_retval->at(pid);
+}
diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h
index 99738b9..2ebb66e 100644
--- a/src/kernel/task/task.h
+++ b/src/kernel/task/task.h
@@ -34,8 +34,8 @@ class process {
segment_map *dataseg;
- process *next; //Forms a linked list
thread *threads;
+ thread *threads_waiting; // threads waiting for this process to end
earray<node> fd; // file descriptors
@@ -77,9 +77,12 @@ uint32_t tasking_handleException(registers *regs);
void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event.
int proc_priv(); //Returns current privilege level
-void thread_exit(); //syscall
-void process_exit(size_t retval); //syscall
+// syscalls
+void thread_exit();
+void process_exit(size_t retval);
size_t process_sbrk(size_t size);
void process_brk(size_t ptr);
+int process_run(char* file, char** args);
+int process_waitpid(int pid);
#endif
diff --git a/src/kernel/ui/vt.cpp b/src/kernel/ui/vt.cpp
index 48a2da4..2869fec 100644
--- a/src/kernel/ui/vt.cpp
+++ b/src/kernel/ui/vt.cpp
@@ -215,6 +215,7 @@ int vt::read(size_t offset, size_t len, char* buffer) {
}
if (end || c == len) return c;
+ if (kbd_waiter != 0) return c;
kbd_waiter = current_thread;
thread_goInactive();
}
diff --git a/src/kernel/vfs/node.cpp b/src/kernel/vfs/node.cpp
index 08c7817..ea7b531 100644
--- a/src/kernel/vfs/node.cpp
+++ b/src/kernel/vfs/node.cpp
@@ -25,8 +25,10 @@ void vfs_setup() {
root->add_child(".ui", dot_ui);
}
-node* vfs_find(node* root, char* path) {
+node* vfs_find(node* root, char* fn) {
node* el = root;
+ char *path = strdup(fn);
+ char *s = path;
char *member = path;
while (*path != 0 && el != 0) {
@@ -47,6 +49,7 @@ node* vfs_find(node* root, char* path) {
if (el != 0 && member != path) {
el = el->get_child(member);
}
+ kfree(s);
return el;
}
diff --git a/src/user/lib/include/tce/syscall.h b/src/user/lib/include/tce/syscall.h
index 028b544..1811422 100644
--- a/src/user/lib/include/tce/syscall.h
+++ b/src/user/lib/include/tce/syscall.h
@@ -19,6 +19,9 @@ int proc_priv();
void* sbrk(size_t size);
void brk(void* ptr);
+int run(char* file, char** args);
+int waitpid(int pid);
+
FILE open(char* filename, int mode);
FILE open_relative(FILE root, char* filename, int mode);
int stat(char* filename, file_info *info);
diff --git a/src/user/lib/tce/syscall.c b/src/user/lib/tce/syscall.c
index 3e8d75e..bc8bfd8 100644
--- a/src/user/lib/tce/syscall.c
+++ b/src/user/lib/tce/syscall.c
@@ -73,6 +73,16 @@ void brk(void* ptr) {
return call (SC_BRK, ptr, 0, 0, 0, 0);
}
+// ********** proc
+
+int run(char* filename, char** args) {
+ return call(SC_RUN, (unsigned)filename, (unsigned)args, 0, 0, 0);
+}
+
+int waitpid(int p) {
+ return call(SC_WAITPID, p, 0, 0, 0, 0);
+}
+
// ********** file
FILE open(char* filename, int mode) {
diff --git a/src/user/test/main.c b/src/user/test/main.c
index 81753bd..eb289ca 100644
--- a/src/user/test/main.c
+++ b/src/user/test/main.c
@@ -74,6 +74,19 @@ void list_dir(FILE f, int lv) {
}
}
+void list_root() {
+ FILE f = open("/", 0);
+ if (f <= 0) {
+ printk(" -> Could not open '/', error #");
+ printk_int(f);
+ printk("...\n");
+ } else {
+ printk("Now enumerating '/' (fd "); printk_int(f); printk(") :\n");
+ list_dir(f, 1);
+ close(f);
+ }
+}
+
void fprint(FILE f, char *s) {
write(f, 0, strlen(s), s);
}
@@ -102,19 +115,9 @@ int main(char** args) {
if (threads == 0) break;
}
printk("\n -> Ok, let's try something else.\n");
+ list_root();
- FILE f = open("/", 0);
- if (f <= 0) {
- printk(" -> Could not open '/', error #");
- printk_int(f);
- printk("...\n");
- } else {
- printk("Now enumerating '/' (fd "); printk_int(f); printk(") :\n");
- list_dir(f, 1);
- close(f);
- }
-
- f = open("/.ui/klog", 0);
+ FILE f = open("/.ui/klog", 0);
if (f <= 0) {
printk(" -> Error #"); printk_int(f); printk(" - too bad. Exiting.\n");
} else {
@@ -133,13 +136,26 @@ int main(char** args) {
} else if (strcmp(buffer, "help") == 0) {
fprint(f, "Available commands: about, help, exit.\n");
} else if (strcmp(buffer, "exit") == 0) {
- fprint(f, "Exiting the shell. I think the system is pretty likely to panic.\n");
+ fprint(f, "Exiting the shell. See you later!\n");
break;
} else if (strcmp(buffer, "gotosleep") == 0) {
while (1) thread_sleep(1000);
+ } else if (strcmp(buffer, "spawn") == 0) {
+ char *args[] = {"hello", "world", 0};
+ int pid = run("/somewhere/bin/test", args);
+ if (pid < 0) {
+ printk("Error "); printk_int(pid); printk("\n");
+ } else {
+ printk("Launched, pid="); printk_int(pid); printk("\n");
+ int ret = waitpid(pid);
+ printk("Exited, ret="); printk_int(ret); printk("\n");
+ }
+ } else if (strcmp(buffer, "root") == 0) {
+ list_root();
} else {
- fprint(f, "Unknown command. ");
+ fprint(f, "Unknown command : ");
fprint(f, buffer);
+ fprint(f, "\n");
}
} else {
fprint(f, " - - - oops\n");