Re: How to implement a syscall in Haiku

Ingo Weinhold <[email protected]> Thu, 12 Jun 2008 00:24:37 +0200
Newsgroups gmane.os.openbeos.kernel.devel
Message-ID <[email protected]>
On 2008-06-11 at 23:19:06 [+0200], Salvatore Benedetto <[email protected]> wrote:
> 
> as the subject suggest, the question is very simple.
> What are the steps in order to implement a syscall in Haiku?
> 
> I had a look at the _user_realtime_sem_open for example and I found
> that they are declare in syscall_dispatcher.h and syscall_table.h, but
> both of them are found in the "generated" directory, which reminds me
> that there is something to do with the build system.
> 
> The only document I found on the website is from 2002 and I guess
> it's pretty outdated? Is it?
> http://www.haiku-os.org/documents/dev/hello_kernel_you_have_a_syscall_from_userland
> 
> Anyhow, the syscall_info structures, requires that the second field to
> be the amount
> of the parameter size. What if one of the parameter it's a union? Is
> it that allowed?

You don't have to do anything with the syscall_info structure. Unions (at least 
pointers to unions) should be fine as parameters. If not, this is an issue in 
gensyscalls (and helpers) and the build system will politely issue some error 
message.

The steps to add a syscall are:

* Add the syscall prototype to headers/private/system/syscalls.h. Name it 
_kern_<foo>(). Avoid adding unnecessary dependencies to the header. I.e. if your 
syscall has pointers to structs as arguments, there's no need to include the headers 
that define the structs.

* Add a function prototype _user_<foo>() with the same signature as your syscall to 
a fitting kernel header under headers/private/kernel/. Assuming that you want to add 
syscalls for XSI semaphores, add a new kernel header for them.

* Make sure the header with the _user_<foo>() prototype is included by 
src/system/kernel/syscalls.cpp.

* Implement _user_<foo>() in a fitting source file.

That's it. There are some general rules for the implementation of a syscall:

* If your syscall has a 64 bit return value (as opposed to the common 32 bit 
status_t/ssize_t/int etc.), call syscall_64_bit_return_value() at the very beginning.

* Never access user memory directly or IOW, if your syscall has a parameter that is 
a pointer to something, never dereference the pointer. Also don't dereference 
pointers in structures you get from userland. If you have to access user data, first 
check that the pointer actually points to user address space, using the 
IS_USER_ADDRESS() macro (if not, fail with B_BAD_ADDRESS). Allocate kernel memory 
large enough to hold the user data. If it's a small structure or short string, use 
the stack, otherwise allocate on the heap. For variable sized data enforce maximum 
limits. Then copy the user data to your kernel memory using user_memcpy(). 
Parameters are the same as for memcpy(), but the return value is a status_t. If it's 
not B_OK, fail with B_BAD_ADDRESS. If you want to return a data structure to 
userland, use the same strategy (just with swapped parameters for user_memcpy(), of 
course).

* If your syscall can block and can be interrupted, make it restartable (there are 
exceptions when that is not necessary/desired, but usually it is). Restartable means 
that if your syscall has be interrupted by a signal, the kernel can just invoke it 
again after the signal has been handled. It will get the exact same parameters, 
which in some cases requires some special handling. E.g. relative timeouts have to 
be converted to absolute ones and stored. There are inline functions in 
<syscall_restart.h> which help with that. If you don't have any problematic 
parameters, just invoke syscall_restart_handle_post() with B_INTERRUPTED before you 
return from the syscall, if the syscall has been interrupted. Most syscalls return 
error codes and the function returns the error code passed to it, so one can use it 
like "return syscall_restart_handle_post(error);". If you have to deal with relative 
timeouts, use the appropriate syscall_restart_handle_timeout_pre() function at the 
beginning and syscall_restart_handle_timeout_post() (instead of 
restart_handle_post()) at the end of the syscall. The latter stores the timeout for 
restart, the former converts the timeout to absolute, respectively restores the 
stored timeout on syscall restart.

CU, Ingo

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php