system call help

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
GLneo

system call help

Post 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:

Code: Select all

putint()
{
    int 30h
}
hopefully gcc wont pop 5 of stack, if it does ill do it in asm
4.) in my kernel:

Code: Select all

int30h(int foo)
{
    putint(foo);
}
that should pop it off stack and print it

will this work or am i clueless ???
AR

Re:system call help

Post 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 */
GLneo

Re:system call help

Post 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.
AR

Re:system call help

Post 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".
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:system call help

Post 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.
Post Reply