celtic / akari

My attempt at bringing light to operating system development.

This URL has Read+Write access

akari / Syscall.cpp
100644 94 lines (77 sloc) 2.927 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <Syscall.hpp>
#include <Akari.hpp>
#include <UserCalls.hpp>
#include <UserIPC.hpp>
#include <Descriptor.hpp>
 
Syscall::Syscall(): _syscalls_assigned(0) {
Akari->descriptor->idt->installHandler(0x80, &Syscall::_handler);
 
addSyscall(0, (void *)&User::putc);
addSyscall(1, (void *)&User::puts);
addSyscall(2, (void *)&User::putl);
addSyscall(3, (void *)&User::getProcessId);
addSyscall(4, (void *)&User::irqWait);
addSyscall(5, (void *)&User::irqListen);
addSyscall(6, (void *)&User::panic);
addSyscall(7, (void *)&User::exit);
addSyscall(8, (void *)&User::defer);
addSyscall(9, (void *)&User::malloc);
addSyscall(10, (void *)&User::free);
addSyscall(11, (void *)&User::memcpy);
 
addSyscall(12, (void *)&User::IPC::registerName);
 
addSyscall(13, (void *)&User::IPC::registerStream);
addSyscall(14, (void *)&User::IPC::obtainStreamWriter);
addSyscall(15, (void *)&User::IPC::obtainStreamListener);
addSyscall(16, (void *)&User::IPC::readStream);
addSyscall(17, (void *)&User::IPC::readStreamUnblock);
addSyscall(18, (void *)&User::IPC::writeStream);
 
addSyscall(19, (void *)&User::IPC::registerQueue);
}
 
u8 Syscall::versionMajor() const { return 0; }
u8 Syscall::versionMinor() const { return 1; }
const char *Syscall::versionManufacturer() const { return "Akari"; }
const char *Syscall::versionProduct() const { return "Akari Syscall"; }
 
void Syscall::addSyscall(u16 num, void *fn) {
_syscalls[num] = fn;
}
 
void Syscall::returnToTask(Tasks::Task *task) {
_returnTask = task;
}
 
void Syscall::returnToNextTask() {
Tasks::Task *nextTask = Akari->tasks->getNextTask();
if (nextTask == Akari->tasks->current) {
AkariPanic("TODO: let no 'active' processes being running. i.e. have the ukernel HLT or similar.");
}
 
returnToTask(nextTask);
}
 
void *Syscall::_handler(struct modeswitch_registers *regs) {
if (regs->callback.eax >= AKARI_SYSCALL_MAXCALLS)
AkariPanic("System call greater than maximum requested. TODO: kill requesting process.");
if (!Akari->syscall->_syscalls[regs->callback.eax])
AkariPanic("Non-existing system call requested.");
 
Akari->syscall->_returnTask = 0;
 
void *call = Akari->syscall->_syscalls[regs->callback.eax];
    int ret;
    asm volatile(" \
push %1; \
push %2; \
push %3; \
push %4; \
push %5; \
call *%6; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
"
            : "=a" (ret)
            : "r" (regs->callback.edi), "r" (regs->callback.esi), "r" (regs->callback.edx), "r" (regs->callback.ecx), "r" (regs->callback.ebx), "r" (call)
            : "%ebx");
 
    regs->callback.eax = ret;
 
if (Akari->syscall->_returnTask) {
Akari->tasks->saveRegisterToTask(Akari->tasks->current, regs);
Akari->tasks->current = Akari->syscall->_returnTask;
return Akari->tasks->assignInternalTask(Akari->tasks->current);
}
 
return regs;
}