Update markdown and tabs and stuff
This commit is contained in:
@@ -6,15 +6,15 @@ tags: [osdev]
|
||||
System calls is the way user processes communicate to the kernel. Look
|
||||
at the following program, for example.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("Hello, world!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
{: .lang-c}
|
||||
:::c
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("Hello, world!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
When you call the program, even before it is started, the shell makes a
|
||||
couple of system calls such as `fork()` and `exec()`. The program itself
|
||||
@@ -37,20 +37,21 @@ implemented it in my kernel yet, but here's how it would work.
|
||||
####User side
|
||||
First the definition in the c library:
|
||||
|
||||
int read(int file, char *ptr, int len)
|
||||
{
|
||||
return _syscall_read(file, ptr, len);
|
||||
}
|
||||
:::c
|
||||
int read(int file, char *ptr, int len)
|
||||
{
|
||||
return _syscall_read(file, ptr, len);
|
||||
}
|
||||
|
||||
Simply a wrapper for an assembly function:
|
||||
|
||||
[global _syscall_read]
|
||||
_syscall_read:
|
||||
mov eax, SYSCALL_READ
|
||||
int 0x80
|
||||
mov [syscall_error], edx
|
||||
ret
|
||||
{: .lang-nasm}
|
||||
:::nasm
|
||||
[global _syscall_read]
|
||||
_syscall_read:
|
||||
mov eax, SYSCALL_READ
|
||||
int 0x80
|
||||
mov [syscall_error], edx
|
||||
ret
|
||||
|
||||
This function puts an identifier for the system call in the `eax`
|
||||
register and then execute the system call interrupt.
|
||||
@@ -62,37 +63,39 @@ Conventions](http://wiki.osdev.org/Calling_Conventions) more carefully.
|
||||
|
||||
Of course, this can be simplified with a macro to
|
||||
|
||||
[global _syscall_read]
|
||||
DEF_SYSCALL(read, SYSCALL_READ)
|
||||
{: .lang-nasm}
|
||||
:::nasm
|
||||
[global _syscall_read]
|
||||
DEF_SYSCALL(read, SYSCALL_READ)
|
||||
|
||||
####Kernel side
|
||||
|
||||
In the kernel, the system call is caught by the following function:
|
||||
|
||||
registers_t *syscall_handler(registers_t *r)
|
||||
{
|
||||
if(syscall_handlers[r->eax])
|
||||
r = syscall_handlers[r->eax](r);
|
||||
else
|
||||
r->edx = ERR_NOSYSCALL;
|
||||
|
||||
return r;
|
||||
}
|
||||
:::c
|
||||
registers_t *syscall_handler(registers_t *r)
|
||||
{
|
||||
if(syscall_handlers[r->eax])
|
||||
r = syscall_handlers[r->eax](r);
|
||||
else
|
||||
r->edx = ERR_NOSYSCALL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
If the system call is registered correctly in the kernel (through the
|
||||
macro `KREG_SYSCALL(read, SYSCALL_READ)`), this will pass everything
|
||||
onto the following function:
|
||||
|
||||
KDEF_SYSCALL(read, r)
|
||||
{
|
||||
process_stack stack = init_pstack();
|
||||
|
||||
r->eax = read((int)stack[0], (char *)stack[1], (int)stack[2]);
|
||||
:::c
|
||||
KDEF_SYSCALL(read, r)
|
||||
{
|
||||
process_stack stack = init_pstack();
|
||||
|
||||
r->eax = read((int)stack[0], (char *)stack[1], (int)stack[2]);
|
||||
r->edx = errno;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
The `init_pstack()` macro expands to `(unitptr_t *)(r->useresp + 0x4)`
|
||||
and this lets us read the arguments passed to the system call from where
|
||||
@@ -100,10 +103,11 @@ they are pushed on call.
|
||||
|
||||
Then the `read()` function has the same definition as the library version.
|
||||
|
||||
int read(int file, char *ptr, int len)
|
||||
{
|
||||
...
|
||||
}
|
||||
:::c
|
||||
int read(int file, char *ptr, int len)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
_Spoiler alert:_ Keeping a version of `read()` (and in fact every
|
||||
syscall function) inside the kernel will turn out to have some really
|
||||
|
||||
Reference in New Issue
Block a user