Page 1 of 1
system call help
Posted: Sun Jun 05, 2005 4:38 pm
by GLneo
hello everybody, ok, i am going to try to do system calls,
1.) the user calls the functions in c: putint(5);
2.) gcc hopefully puts 5 on stack
3.) my include file:
hopefully gcc wont pop 5 of stack, if it does ill do it in asm
4.) in my kernel:
that should pop it off stack and print it
will this work or am i clueless ???
Re:system call help
Posted: Sun Jun 05, 2005 6:52 pm
by AR
I wouldn't recommend it, in C you have no control of the stackframe, and passing values to the kernel on the stack adds complexity and decreases performance if there are less than 6 parameters [and you aren't using a call gate]. You'd be better off with:
Code: Select all
extern "C" int putint(int value);
extern "C" int SomeFunc(int Val, char *string);
Code: Select all
.global putint
putint:
push %ebx
mov $1, %eax /* EAX=1, Kernel Function putint */
movl %ss:4(%esp), %ebx
int $0x30
pop %ebx
/* Return value is always stored in %eax */
ret
.global SomeFunc
SomeFunc:
push %ebx
mov $2, %eax /* EAX=2, Kernel Function SomeFunc */
movl %ss:4(%esp), %ebx
movl %ss:8(%esp), %ecx
int $0x30
pop %ebx
ret
/* Optimization note: Supposedly GCC doesn't care if you corrupt ECX or EDX, EAX is the return value but EBX must be saved */
Re:system call help
Posted: Mon Jun 06, 2005 7:26 am
by GLneo
thx, that will probly work better, but, how do i link the asm and c code to one .o ??? and in my c kernel what do i do with eax ??? push it in asm and pop it in c for use, i am clueless.
Re:system call help
Posted: Mon Jun 06, 2005 7:45 am
by AR
That GAS Assembly I wrote can be copied into a file and built by GCC (Create a file like KSysCall.S and gcc -o KSysCall.o -c KSysCall.S [Note: Capital S extension is preprocessed, lowercase S isn't]). Insert the
extern "C" declarations into a header and link KSysCall.o against the user space program.
In your kernel with the Interrupt Service Routine you'll have something along the lines:
Code: Select all
.global ISR
ISR:
pusha
push %ds
push %es
mov %ss, %eax
mov %eax, %ds
mov %eax, %es
call DoSysCall
pop %es
pop %ds
popa
iret
Code: Select all
struct UserSpaceRegisters
{
unsigned int EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX;
};
void DoSysCall(UINT32 ES, UINT32 DS, UserSpaceRegisters Regs)
{
/* Use Regs.EAX for the return value, the other values as whatever parameters the function takes */
switch(Regs.EAX)
{
case 1:
Regs.EAX = putint(Regs.EBX);
case 2:
Regs.EAX = SomeFunc(Regs.EBX, Regs.ECX);
default:
Regs.EAX = -1;
}
}
Note: I modified the earlier example to reflect this example, this is only an example though, it's been a while since I've played with ISRs so "some assembly required".
Re:system call help
Posted: Mon Jun 06, 2005 8:02 am
by Pype.Clicker
What you could do (and what is done e.g. in Linux iirc), is to have a sort of "generic" interrupt handler (e.g. all system calls go through int 0x30, but the value of eax tells what call you actually want to perform). That handler will then push every register on the kernel stack and pass the 'real' handler a pointer to that stack area.
That may sound overkill in terms of performances, but at least it will mean you have a common stub that doesn't need to care about whether some registers will be trashed or not.