OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Apr 24, 2024 6:33 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: Making a syscall from a C function causes problem
PostPosted: Fri Apr 03, 2020 1:10 pm 
Offline
Member
Member

Joined: Fri Jan 26, 2018 11:43 am
Posts: 64
To give a more specific but still brief description of the problem: When I make any syscall from my C function - which itself is called from a userspace assembly procedure - the syscall returns to the C function, but then the C function doesn't return to the assembly procedure which called it.

Here's the code segment which calls the C function:
Code:
welcome db "Welcome!",10,"This is a test", 0

extern entry_in_c

global userspace_entry
userspace_entry:
    mov eax, 0
    mov ebx, welcome
    int 0x80

    xchg bx, bx

    call entry_in_c

    jmp $


Here is the C function which is called:
Code:
void entry_in_c(void) {
    asm("xchg %bx, %bx;\
         mov $5, %eax;\
         int $0x80;");
}


And finally, here's a very minimal example for my syscall ISR which causes the issue:
Code:
isr_syscall:
    cli

    sti
    iret


As I step through the program to debug it in bochs, I monitor the stack. Here's what I notice:

At the beginning of the C function, the correct return address is at the top of the stack (happens to be 0x100755). So here, the stack looks like this:

    (mem addr: value)
    0x104ffb: 0x100755

The C function then pushed ebp (which here is 0) to the stack. It then saves esp into ebp.

    0x104ff4: 0x0
    0x104ffb: 0x100755

As soon as the C function calls int $0x80 (which is what I've chosen to be my syscall), four numbers are pushed to the stack:

    0x104fec: 0x100764
    0x104ff0: 0x1b
    0x104ff4: 0x202
    0x104ff8: 0x104ff4 <- this is equal to ebp... why?
    ...

The worrying part here is that this seems to have overwritten the 0x0 and the 0x100755 which were previously at the top of the stack. They're nowhere to be found on the stack whatsoever anymore, so, this is where I think it all went wrong.

When it returns to the C function it has popped the top two things from the stack, so the top now looks like this:

    0x104ff4: 0x202
    0x104ff8: 0x104ff4

And from there, it pops 0x202 into ebp (which is wrong), and then fatally, it returns to the address 0x104ff4, which is where the stack was at some point. From there, it just executed garbage memory and crashes.

So, any idea what's going on here? I'm not so familiar with using C functions with assembly, and have quite likely made a beginner's mistake here.

Thanks a lot :)


Top
 Profile  
 
 Post subject: Re: Making a syscall from a C function causes problem
PostPosted: Fri Apr 03, 2020 2:48 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5144
Did you perhaps set ESP0 in your TSS to the same value you use for your ring 3 program's initial ESP? If so, every switch to ring 0 will clobber your program's stack.

I saw a couple other issues:

j4cobgarby wrote:
Code:
    asm("xchg %bx, %bx;\
         mov $5, %eax;\
         int $0x80;");

This inline assembly modifies EAX without telling the compiler.

j4cobgarby wrote:
Code:
isr_syscall:
    cli

    sti
    iret

Use an interrupt gate to clear the interrupt flag at the beginning of your interrupt handler instead of CLI. (Use a trap gate if you want to set the interrupt flag.) Don't bother messing with the interrupt flag immediately before IRET, since IRET will pop the flags from the stack anyway.


Top
 Profile  
 
 Post subject: Re: Making a syscall from a C function causes problem
PostPosted: Fri Apr 03, 2020 5:27 pm 
Offline
Member
Member

Joined: Fri Jan 26, 2018 11:43 am
Posts: 64
Octocontrabass wrote:
Did you perhaps set ESP0 in your TSS to the same value you use for your ring 3 program's initial ESP? If so, every switch to ring 0 will clobber your program's stack.

I saw a couple other issues:

j4cobgarby wrote:
Code:
    asm("xchg %bx, %bx;\
         mov $5, %eax;\
         int $0x80;");

This inline assembly modifies EAX without telling the compiler.

j4cobgarby wrote:
Code:
isr_syscall:
    cli

    sti
    iret

Use an interrupt gate to clear the interrupt flag at the beginning of your interrupt handler instead of CLI. (Use a trap gate if you want to set the interrupt flag.) Don't bother messing with the interrupt flag immediately before IRET, since IRET will pop the flags from the stack anyway.

Ah, yes, I was setting my ring 3 ESP to the same as my ESP0 in the TSS (I think, at least... I haven't looked at that code in a while). What's the usual solution? Reserve another bit of memory for ESP0 in the TSS?

EDIT: I've fixed it! So it was basically what you said, but just in case anyone's stuck looking at this in the future, I reserves some new memory for a second stack in .bss, and when iret'ing into userspace i told it to use this stack in ESP.


Top
 Profile  
 
 Post subject: Re: Making a syscall from a C function causes problem
PostPosted: Fri Apr 03, 2020 6:39 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5144
j4cobgarby wrote:
What's the usual solution?

The usual solution is to put everything belonging to the kernel (in ring 0) in the highest 2GB of address space, and leave the remainder for the current user (ring 3).

But then, usually the ring 3 code isn't part of the kernel, so that may not be the best setup for you. Fortunately, anything that separates your ring 0 and ring 3 stacks will work, so you're free to do that however you like.


Top
 Profile  
 
 Post subject: Re: Making a syscall from a C function causes problem
PostPosted: Sat Apr 04, 2020 12:46 pm 
Offline
Member
Member

Joined: Fri Jan 26, 2018 11:43 am
Posts: 64
Octocontrabass wrote:
j4cobgarby wrote:
What's the usual solution?

The usual solution is to put everything belonging to the kernel (in ring 0) in the highest 2GB of address space, and leave the remainder for the current user (ring 3).

But then, usually the ring 3 code isn't part of the kernel, so that may not be the best setup for you. Fortunately, anything that separates your ring 0 and ring 3 stacks will work, so you're free to do that however you like.

The only reason there's ring 3 code in the kernel here is just to test ring 3 code. Usually, ring 3 code will be loaded from the filesystem like normal, I just haven't implemented the file system yet.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Majestic-12 [Bot] and 214 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group