OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 3:30 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Getting int 0x6 when issuing system call (int)
PostPosted: Mon Apr 22, 2019 8:39 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
Hi, it's again me, as expected. Sorry, but, uh...
I'm getting an 0x06 (inv. opcode) fault when I call my syscall. The handler is written in C and ASM.
I mean, I push registers in ASM and then I call a C function that do the rest.
syscall.c
Code:
#include <kernel/kernel.h>
#include <kernel/terminal.h>

struct __system_stack* stack;

void syscall_wrapper(void)
{
    switch (stack->rax) {
        case 4:
            print_string(stack->rcx); /* The error happens exactly here */
            break;
        default:
            break;
    }
    return;
}

idt.asm (290-312)
Code:
isr128:
    cli
    push byte 0
    push byte 80

   ; The System V x86_64 calling convention...
    push r9
    push r8
   push rcx
   push rdx
   push rsi
   push rdi
   
    cld
    call syscall_wrapper

    pop rdi
   pop rsi
   pop rdx
   pop rcx
    pop r8
    pop r9
    jmp isr_common_stub


I disassembled all the functions involved here (disassemble in gdb), and there's no weird SSE or MMX instructions, or any other thing.
Just in case, here is the qemu -d regs dump:
Code:
check_exception old: 0xffffffff new 0x6
    94: v=06 e=0000 i=0 cpl=0 IP=0008:0000000000100040 pc=0000000000100040 SP=0000:000000000010aee8 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=000000000010aef2 RCX=0000000000105000 RDX=0000000000000000
RSI=00000000000003d5 RDI=0000000000000054 RBP=000000002badb002 RSP=000000000010aee8
R8 =00000000000003d4 R9 =00000000000b8f00 R10=0000000000000000 R11=0000000000000050
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000100040 RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0008 0000000000000000 00000000 00209800 DPL=0 CS64 [---]
SS =0000 0000000000000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     0000000000104000 0000000f
IDT=     0000000000106180 00000fff
CR0=80000013 CR2=0000000000000000 CR3=0000000000108000 CR4=00000620
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000044 CCD=000000000010aeb8 CCO=EFLAGS
EFER=0000000000000500

Thanks :S
edit: not working yet
Still not working, what the f***? nothing works with me, f***. Forget this, I'm gonna to be only ring0 so the programs can directly access hardware. Problem done. (Anyways, the wiki says nothing useful about ring3)


Last edited by deleted8917 on Fri Apr 26, 2019 5:36 pm, edited 3 times in total.

Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call
PostPosted: Mon Apr 22, 2019 9:53 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
Well, what is the disassembly of the actually failing function? Without that we can only stab at the fog, which isn't terribly productive. Bascially we need to see address 0x10040 and a bit of context.

And how is your syscall wrapper supposed to work? Why the CLI at the start? If you make your IDT entry into an interrupt gate (see AMD/Intel documentation for details), the interrupt flag will always be disabled when the code comes there. Your syscall wrapper depends on a global variable called stack which is weird design (why not just an argument?) And that variable is not set up in your ISR stub. Bug? Oh, another detail: You are not saving RAX in your register saving code, but you are accessing it in C, meaning that your register struct and your ASM code likely don't fit together.

And why does your struct __system_stack have two underscores in front of it? What's wrong with struct system_stack? Besides not being a very descriptive name, I mean.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call
PostPosted: Mon Apr 22, 2019 11:46 pm 
Offline
Member
Member
User avatar

Joined: Mon Jul 13, 2009 5:52 am
Posts: 99
Location: Denmark
With the code in your post the *stack variable is never initialized. The *stack variable should be an argument of syscall_wrapper, such that

Code:
#include <kernel/kernel.h>
#include <kernel/terminal.h>

void syscall_wrapper(struct __system_stack* stack)
{
    switch (stack->rax) {
        case 4:
            print_string(stack->rcx); /* The error happens exactly here */
            break;
        default:
            break;
    }
    return;
}


EDIT: In your assembler code you also need to add a line before the call, because rdi is the first argument to syscall_wrapper.
Code:
...
cld
mov rdi, rsp
call syscall_wrapper
...

However, because you only push a subset of the registers before calling syscall_wrapper, you will not be able to access rax, rcx, etc...


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call
PostPosted: Tue Apr 23, 2019 7:31 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
nullplan wrote:
Well, what is the disassembly of the actually failing function? Without that we can only stab at the fog, which isn't terribly productive. Bascially we need to see address 0x10040 and a bit of context.

And how is your syscall wrapper supposed to work? Why the CLI at the start? If you make your IDT entry into an interrupt gate (see AMD/Intel documentation for details), the interrupt flag will always be disabled when the code comes there. Your syscall wrapper depends on a global variable called stack which is weird design (why not just an argument?) And that variable is not set up in your ISR stub. Bug? Oh, another detail: You are not saving RAX in your register saving code, but you are accessing it in C, meaning that your register struct and your ASM code likely don't fit together.

And why does your struct __system_stack have two underscores in front of it? What's wrong with struct system_stack? Besides not being a very descriptive name, I mean.

Sorry, I mean sorry, I don't know in what I was thinking... but relax...
zity wrote:
With the code in your post the *stack variable is never initialized. The *stack variable should be an argument of syscall_wrapper, such that

Code:
#include <kernel/kernel.h>
#include <kernel/terminal.h>

void syscall_wrapper(struct __system_stack* stack)
{
    switch (stack->rax) {
        case 4:
            print_string(stack->rcx); /* The error happens exactly here */
            break;
        default:
            break;
    }
    return;
}


EDIT: In your assembler code you also need to add a line before the call, because rdi is the first argument to syscall_wrapper.
Code:
...
cld
mov rdi, rsp
call syscall_wrapper
...

However, because you only push a subset of the registers before calling syscall_wrapper, you will not be able to access rax, rcx, etc...

Thanks, now working. That goddamn and tricky calling convention! Now it is working, but I need to access to the scratch registers (rax, rdi, rsi). How I can do it?


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call
PostPosted: Tue Apr 23, 2019 8:24 pm 
Offline
Member
Member

Joined: Fri Jun 28, 2013 1:48 am
Posts: 62
What's the code of your user program? How do you issue system call, `int 0x80`, `syscall` or `sysenter`?

If you use SYSCALL instruction on intel cpu and did not set IA32_EFER.SCE, then you'll get #UD exception.

_________________
Reinventing the Wheel, code: https://github.com/songziming/wheel


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call
PostPosted: Tue Apr 23, 2019 8:55 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
songziming wrote:
What's the code of your user program? How do you issue system call, `int 0x80`, `syscall` or `sysenter`?

If you use SYSCALL instruction on intel cpu and did not set IA32_EFER.SCE, then you'll get #UD exception.

No, I still using int 0x80. I didn't managed yet how to use sycall/sysret. I think that I should change the title.


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call
PostPosted: Tue Apr 23, 2019 11:36 pm 
Offline
Member
Member
User avatar

Joined: Mon Jul 13, 2009 5:52 am
Posts: 99
Location: Denmark
hextakatt wrote:
Thanks, now working. That goddamn and tricky calling convention! Now it is working, but I need to access to the scratch registers (rax, rdi, rsi). How I can do it?


At the moment you are correctly pushing/popping the variables specified in the x86_64 System V ABI. If you want to access additional registers, you also need to push/pop those in your assembly code. Moreover, remember that the "struct __system_stack" must contain the list of pushed registers in reverse order, because the stack grows downwards.


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call (int)
PostPosted: Wed Apr 24, 2019 7:29 pm 
Offline
Member
Member

Joined: Wed Dec 12, 2018 12:16 pm
Posts: 119
trying to push rax to stack, but still getting 0x06...
Code:
    push byte 0
    push byte 80

   ; The System V x86_64 calling convention...
   push rax
    push rcx
    push rdx
    push rsi
    push rdi

    cld
    mov rdi, rsp
    call syscall_wrapper

    pop rdi
   pop rsi
   pop rdx
   pop rcx
    pop rax
    jmp isr_common_stub

Code:
void syscall_wrapper(uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t rax)
{
    switch (rax) {
        case 4:
            print_string((char*)rcx);
            break;
        default:
            break;
    }
    return;
}


Top
 Profile  
 
 Post subject: Re: Getting int 0x6 when issuing system call (int)
PostPosted: Wed Apr 24, 2019 11:58 pm 
Offline
Member
Member
User avatar

Joined: Mon Jul 13, 2009 5:52 am
Posts: 99
Location: Denmark
You are clearly struggeling with this, so let me try to explain several things in more detail.

Let's start again with the System V x86_64 ABI. When discussing the registers, there are four different things that you must be aware of.

  • The first six arguments (assuming they are integers or pointers) are passed via the registers (rdi, rsi, rdx, rcx, r8, r9). If there are additional arguments (or the arguments are NOT integers/pointers), the values are stored on the stack. I will not discuss this.
  • The registers (rbp, rbx, r12, r13, r14, r15) are so-called "callee-save registers", which means that these registers must be saved by the function that you are calling (in this case your interrupt handler).
  • All remaining registers are "caller-save registers", which means that these registers must be saved by the function that makes the call. Of course, these registers should only be saved if they actually contain information needed after the call has completed.
  • The rax register is used to store the return value from the callee.

However, to ensure that all of these things are satisfied, it might be simpler if you save ALL the general purpose registers in the interrupt handler, to ensure that nothing breaks. This is probably what you already do in your code for exception handling.

Now concerning your code, it seems that you are mixing your syscall handler and your exception handler. This is wrong, these two things have nothing in common, except that the assembly code looks similar, because it has to save and restore register.
Code:
isr128:
    cli
    push byte 0  ; THIS IS RELATED TO YOUR EXCEPTION HANDLER, IT DOES NOT SERVE ANY PURPOSE HERE
    push byte 80 ; THIS IS RELATED TO YOUR EXCEPTION HANDLER, IT DOES NOT SERVE ANY PURPOSE HERE

   ; The System V x86_64 calling convention...
    push rax ; THE PURPOSE OF PUSHING THESE VALUES ON THE STACK IS TO ACCESS THEM IN syscall_wrapper NOT TO SAVE THEM
    push rcx
    push rdx
    push rsi
    push rdi

    cld
    mov rdi, rsp
    call syscall_wrapper

    pop rdi
   pop rsi
   pop rdx
   pop rcx
    pop rax
    jmp isr_common_stub ; HERE YOU ARE (PRESUMABLY) CALLING YOUR EXCEPTION HANDLER, WHY?


Depending on how you invoke the above assembly code, the arguments for the syscall_wrapper are, as previously mentioned, stored in the registers (rdi, rsi, rdx, rcx, r8, r9). If we simply want something that works (but not necessarily something that is particularly clever), we can do the following.

Code:
isr128:
   cli
   push rax ; Push all general purpose registers
   push rbx
   push rcx
   push rdx
   push rdi
   push rsi
   push rbp
   push r8
   push r9
   push r10
   push r11
   push r12
   push r13
   push r14
   push r15

   mov rdi, rsp ; Store the stack pointer in rdi. The first argument of syscall_wrapper is now a pointer to the values stored on the stack.
   call syscall_wrapper

   pop r15
   pop r14
   pop r13
   pop r12
   pop r11
   pop r10
   pop r9
   pop r8
   pop rbp
   pop rsi
   pop rdi
   pop rdx
   pop rcx
   pop rbx
   pop rax

   iretq

Code:
struct _stack {
   uint64_t r15;
   uint64_t r14;
   uint64_t r13;
   uint64_t r12;
   uint64_t r11;
   uint64_t r10;
   uint64_t r9;
   uint64_t r8;
   uint64_t rbp;
   uint64_t rsi;
   uint64_t rdi;
   uint64_t rdx;
   uint64_t rcx;
   uint64_t rbx;
   uint64_t rax;
};

void syscall_wrapper(struct _stack *stack)
{
    switch (stack->rax) {
        case 4:
            print_string((char*)stack->rcx);
            break;
        default:
            break;
    }
}


In this code, pushing all the general purpose registers has a dual purpose. We want these registers to be accessible in syscall_wrapper and we want to ensure that they are correctly restored when the function returns. Again, depending on how you invoke "isr128" this can perhaps be done in a smarter way, but then it really depends on the specific design details.

In the above code, we also restore rax. If (at some point) you want to return a value from your syscall_wrapper function, then you should not pop the rax register, but simply adjust rsp instead.

I hope this helps a bit.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 67 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