Syscall again
Syscall again
Hi everyone,
I've got a doubt, well maybe some of them ;D.
On a syscall, we dedicate a int XXh for them. Well, on University they show us threads, mutex, etc as system calls. But taking a look at Tim's Mobius source code, in shell.c he don't call any int.
My question is: if i have to dedicate an int to the syscalls, where should i call this int? ( ising C of course ). Shouls I create a funtions on the libs tha call this int..
Thanks for all.
I've got a doubt, well maybe some of them ;D.
On a syscall, we dedicate a int XXh for them. Well, on University they show us threads, mutex, etc as system calls. But taking a look at Tim's Mobius source code, in shell.c he don't call any int.
My question is: if i have to dedicate an int to the syscalls, where should i call this int? ( ising C of course ). Shouls I create a funtions on the libs tha call this int..
Thanks for all.
Re:Syscall again
System calls are there to handle user requests. As you already noticed, system calls are realized by calling a interrupt routine. So when you want to implement the system call READ for example, and you want to provide an API for this function, you could have something like this:
This is just an example, so basically the read() function you provide the users is just a frontend which initiates a system call.
Code: Select all
ssize_t read(int fd, void *buf, size_t count)
{
[move fd -> eax]
[move buf -> ebx]
[move count -> ecx]
asm __volatile__ ("int $0x80");
[return edx]
}
Re:Syscall again
Correct; Although, just for the sake of "completeness", it should be mentioned that a syscall doesn't "have to" be implemented in an interrupt...it could be an ordinary routine that's CALLed rather than INT'd...abless wrote: System calls are there to handle user requests. As you already noticed, system calls are realized by calling a interrupt routine. So when you want to implement the system call READ for example, and you want to provide an API for this function, you could have something like this:
This is just an example, so basically the read() function you provide the users is just a frontend which initiates a system call.Code: Select all
ssize_t read(int fd, void *buf, size_t count) { [move fd -> eax] [move buf -> ebx] [move count -> ecx] asm __volatile__ ("int $0x80"); [return edx] }
The benefit of the INT way, though, is that interrupts go via the IDT table so they automatically provide a very simple way to "relocate" syscalls that won't break earlier code...the syscall code could be moved elsewhere but as long as "int 0x80" is always pointing to the right place, then any code using "int 0x80" will work as expected...
The direct CALL way, though, has less run-time overhead (interrupts go through quite a bit of overhead that a direct CALL wouldn't have) but as addresses are stored in the actual CALL instructions themselves then some way of "patching" these addresses - probably as part of the OS loader code - would be needed...so, though less run-time overhead, it's going to be asking for more loader-overhead instead...
Which way to choose is up to you and what compromises you want to make in the design...the INT way is nice and simple but will be slightly slower than the direct CALL...the direct CALL way is quicker but requires extra work by the loader and that extra information is added to the executable to make the loader know what things need to be "patched"...depends what you prefer, really...slightly better performance (but not really all that much to be writing home about) or a much more complicated way of storing and loading executables...
Probably best to stick with the Linux-style INT way than to get into the complexity of the Windows-style CALL way...and what's been said about that is entirely correct...just chipping into the thread that "there's more than one way to skin a cat", as the saying goes...you don't "have to" do it like Linux does but, then again, Linux does do it in a sensible way so it's not a bad role model at all to be following...I'm not recommending either way, just informing people that there's more than one possibility here
Beth
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Syscall again
Beth, just one thing you should clarify (imho)
When you talk about a "call", are you refering to the ordinary CALL one does to reach a local function or a CALL through a call gate ?
using a call gate is very similar (in terms of execution time) to taking a trap interrupt, afaik.
And a legacy call would not allow your thread to enter kernel mode, so i hardly see how it could be used to make system calls...
When you talk about a "call", are you refering to the ordinary CALL one does to reach a local function or a CALL through a call gate ?
using a call gate is very similar (in terms of execution time) to taking a trap interrupt, afaik.
And a legacy call would not allow your thread to enter kernel mode, so i hardly see how it could be used to make system calls...
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Syscall again
hmm...
Shouldn't calls to kernel space functions be done via CALL GATES? It seems to me after having looked into the spec's that they are located in the IDT after all, aren't they?
But after all, I think, the int XX mechanism for system calls is something really safe and smooth. You have automatic context saving (when you have coded the functionality for it) and context switching - because system calls can lead to block the process issuing the call or sending him sleeping some time or else... gosh, arguing at THIS Time in the morning is something near impossible for me... So, by leading the system call throu this int xx mechanism, you in the meantime faciliate a smooth context switch. You already have the necessary nitty gritty at hands: ISR stubs and else.
@pype: One has to prepare an asm stub for the system call, right? something that takes the parameters from the stack, stuffs them in the according registers - as abless has shown - and then issues the int xx. The isr fetches the parameters from the registers. Is this right?
Shouldn't calls to kernel space functions be done via CALL GATES? It seems to me after having looked into the spec's that they are located in the IDT after all, aren't they?
But after all, I think, the int XX mechanism for system calls is something really safe and smooth. You have automatic context saving (when you have coded the functionality for it) and context switching - because system calls can lead to block the process issuing the call or sending him sleeping some time or else... gosh, arguing at THIS Time in the morning is something near impossible for me... So, by leading the system call throu this int xx mechanism, you in the meantime faciliate a smooth context switch. You already have the necessary nitty gritty at hands: ISR stubs and else.
@pype: One has to prepare an asm stub for the system call, right? something that takes the parameters from the stack, stuffs them in the according registers - as abless has shown - and then issues the int xx. The isr fetches the parameters from the registers. Is this right?
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
BlueillusionOS iso image
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Syscall again
@infinity: yep. Though it's not mandatory to make arguments go through the stack : if you make your syscall definition an inline function, you can have the compiler filling the registers appropriately.
Clicker has
which actually declares
Thus any system call that has 2 parameter can be quickly defined as
The asm stub is only for receiving the interrupt (and thus written only once). It just pushes every register on the stack (for saving them) and the C code will access these through macros:
thus the system service code just has to use KPARAM1(params) to access parameter #1 of the call
Clicker has
Code: Select all
#define __sc(rid,mid) "int $0x31":"=a"(ret):"0"(rid+((mid)<<16))
#define __scbegin(n,x...) static inline syscall##n(word rid,word mid , ## x) { dword ret;
#define __scend return ret;}
__scbegin(0)
asm volatile(__sc(rid,mid));
__scend
__scbegin(1,dword p1)
asm volatile(__sc(rid,mid),"b"(p1));
__scend
Code: Select all
static inline syscall2(word rid,word mid,dword p1, dword p2)
{
asm volatile("int $0x31":"=a"(ret):"0"(rid+((mid)<<16)),"b"(p1),"c"(p2));
return ret;
}
Code: Select all
#define newWindow(height, width) syscall2(GUI_RESOURCE,CREATE_WINDOW,height,width)
Code: Select all
//! structure for systemcalls parameters passing.
typedef struct kresParams {
dword params[7];
word rid,mid;
} kresParams;
//! defines place of logical arguments in kresParams structure.
#define KPARAM1(p) p->params[4]
#define KPARAM2(p) p->params[6]
#define KPARAM3(p) p->params[5]
#define KPARAM4(p) p->params[1]
#define KPARAM5(p) p->params[0]
thus the system service code just has to use KPARAM1(params) to access parameter #1 of the call
-
- Member
- Posts: 1600
- Joined: Wed Oct 18, 2006 11:59 am
- Location: Vienna/Austria
- Contact:
Re:Syscall again
thanks for explanation.
but, pype, wouldn't it make the code a little bit fuzzy to read -> having to know the exact position of the parameter on the stack to fetch it?
Ok, it is a question of design and ease of coding. As far as I have seen in clicker source, you are a fan of macro definition to ease your life )
Your approach looks a bit difficult to understand at first glance. at second glance, one gets a ping in the head and starts getting things in a row.
but, pype, wouldn't it make the code a little bit fuzzy to read -> having to know the exact position of the parameter on the stack to fetch it?
Ok, it is a question of design and ease of coding. As far as I have seen in clicker source, you are a fan of macro definition to ease your life )
Your approach looks a bit difficult to understand at first glance. at second glance, one gets a ping in the head and starts getting things in a row.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
BlueillusionOS iso image
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Syscall again
not exactly: roles are separated : the system-calls support module knows how to encode and decode arguments for the system call and therefore must guarantee the coherency between syscall.asm and syscall.h / resource.hbeyond infinity wrote: thanks for explanation.
but, pype, wouldn't it make the code a little bit fuzzy to read -> having to know the exact position of the parameter on the stack to fetch it?
once this is done, other modules (both syscall users and providers) don't have to bother about parameter passing: the 1st argument the client put (in the function arguments order) is the argument retrieved by KPARAM1(params).
hehey. yes. i'm a #-addict :p And now i even took it one step further with perl scripts that generate repetitive preprocessing rules based on a meta-language (check .idl and .api files for services definition, for instance )Ok, it is a question of design and ease of coding. As far as I have seen in clicker source, you are a fan of macro definition to ease your life )
now, i admit i could have replaced those __scbegin and __scend stuffs with expanded code. I think that's something coming straight from the Linux Kernel ...
Re:Syscall again
HI,
thanks for all the answers.
Tim, you not use the int way to implement the syscall, isn't it?
thanks for all the answers.
Tim, you not use the int way to implement the syscall, isn't it?
Re:Syscall again
Hi,
A silly question, but I don't see the point of sticking paramaters in the registers (at least on x86 anyway).
For example, you have a function that sticks its 4 paramaters in eax- edx.
What is the first thing that the called function will do? Even for a simple addition, the paramaters will have to be moved out of the registers and stuck back in memory.
So you may as well pass paramaters via the stack....
Maybe I am missing something????
A silly question, but I don't see the point of sticking paramaters in the registers (at least on x86 anyway).
For example, you have a function that sticks its 4 paramaters in eax- edx.
What is the first thing that the called function will do? Even for a simple addition, the paramaters will have to be moved out of the registers and stuck back in memory.
So you may as well pass paramaters via the stack....
Maybe I am missing something????
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Syscall again
problem is that when you're calling the system, the user and the system *are not* on the same stack. Thus using stack-based parameters passing means you must first locate the user stack, then locate the arguments on it ...
and all this must be done with software boundary checking to prevent kernel to be fooled by the user that would set a bad stack segment prior to call the syscall ...
Now Call Gates can automatically copy N arguments from the caller's stack to the callee's stack, so no need for register passing.
Otherwise, it's the simplest (and fastest) way to go ...
And, Mobius seems to use INTs.
and all this must be done with software boundary checking to prevent kernel to be fooled by the user that would set a bad stack segment prior to call the syscall ...
Now Call Gates can automatically copy N arguments from the caller's stack to the callee's stack, so no need for register passing.
Otherwise, it's the simplest (and fastest) way to go ...
And, Mobius seems to use INTs.
Re:Syscall again
The problem lies in the answer Pype gave. But yes, it *is* possible and FreeBSD does it this way. It pushes the arguments on the stack rather than copying them into the registers (what Linux does).tom1000000 wrote: So you may as well pass paramaters via the stack....
Re:Syscall again
Mobius uses ints, with one register set to the ESP at the time of the interrupt. The kernel looks in this register, deducts some space from the kernel stack, copies the parameters there, and calls the appropriate syscall function. This function then sees the parameters the program gave it as real function parameters.