Return Value from Syscall

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.
amirsadig

Return Value from Syscall

Post by amirsadig »

I use GCC inline assembly to call syscalls, but I can get the right return value. I have readed that the return value stored in EAX. but I receive what I have put on EAX before I call the interrupt.
here is the code which call Sys_read

__asm__ __volatile__(
    "pushl %%ebx;"
"pushl %%ecx;"
"pushl %%eax;"
"mov %1, %%ebx;"
"mov $1, %%ecx;"
"mov $1, %%eax;"
"int $0x80 ;"
    "movl %%eax, %0;"
   :"=r"(ret):"r"(c)
);

I receive allways 1 as return value, but I am sure the return value should be -1.
virusx

Re:Return Value from Syscall

Post by virusx »

hi,
Does your syscall handler puts proper values to the eax at the end of syscall.
eg,
syscall_handler:
if syscall fails,
movl $-1, %eax
...
iret

also, you can send the value directly.
__asm__ __volatile__(
"pushl %%ebx;"
"pushl %%ecx;"
"pushl %%eax;"
"mov %1, %%ebx;"
"mov $1, %%ecx;"
"mov $1, %%eax;"
"int $0x80 ;"
:"=a"(ret):"r"(c)
);
amirsadig

Re:Return Value from Syscall

Post by amirsadig »

I dont think my syscall handler done that.

I am not Assembly hacher, there for I have used for IDT and the routines for Interrupt this code:

push byte 0         ; ( 0) fake error code
   PUSHB %1         ; ( 2) exception number
   push gs            ; ( 4) push segment registers
   push fs            ; ( 6)
   push es            ; ( 8)
   push ds            ; ( 9)
   pusha            ; (10) push GP registers
      mov ax,LINEAR_DATA_SEL   ; (11) put known-good values...
      mov ds,eax      ; (15) ...in segment registers
      mov es,eax      ; (17)
      mov fs,eax      ; (19)
      mov gs,eax      ; (21)
      mov eax,esp      ; (23)
      push eax      ; (25) push pointer to regs_t
.1:
; setvect() changes the operand of the CALL instruction at run-time,
; so we need its location = 27 bytes from start of stub. We also want
; the CALL to use absolute addressing instead of EIP-relative, so:
         mov eax,fault   ; (26)
         call eax   ; (31)
         jmp all_ints   ; (33)

then I use setvect() to change the call statement at runtime to call syscall function in my kernel, when 0X80 occure. as see here after syscall has been called then I should return to original function which has been interrupted by CPU. this the function of all_ints routine :

all_ints:
      pop eax
   popa            ; pop GP registers
   pop ds            ; pop segment registers
   pop es
   pop fs
   pop gs
   add esp,8         ; drop exception number and error code
   iret

I have taken a look to the assembly code of the syscall and gcc store the return value in eax. but it like the all_ints routine pop the old eax value.
BI lazy

Re:Return Value from Syscall

Post by BI lazy »

what about placing the return code in the eax-placeholder in regs_t - you know, the isr stack frame pushed/popped to/from the ring0 stack.

you can access it in c as simple as:

Code: Select all

regs_t *regs;
regs=(regs_t *)current_process->esp0;
regs->eax= syscall_retcode;
eax is popped from the stack with popad, and voila, your returncode is present where it is usually expected.

If writing a microkernel, the returncode is delivered simply by sending a message back to the calling process - which is expected to receive().

hth&ccw
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Return Value from Syscall

Post by Candy »

is it (in similar context) possible to use

Code: Select all

struct regs {
  uint32 edi, esi, ebp, esp, ebx, edx, ecx, pad, eax;
}

void something(struct regs sth) {
  regs.eax = -1;
}

do_call:
  push eax
  pusha
  call something
  popa
  pop eax
  iret
?
BI lazy

Re:Return Value from Syscall

Post by BI lazy »

this would overwrite the value of eax - as stored in regs in the isr-prologue and restored after isr-execution in the isr-epilogue with the value pushed on the stack at the beginning of the isr-prologue, as you show it.

to be exactly, it would overwrite the -1 you put onto the stack with void something.

btw: this works as long as we remain on the same stack, doesn't it? you can access the elements of it as function parameters - which are placed on the stack. Just that I understand correctly, what happens there.
BI lazy

Re:Return Value from Syscall

Post by BI lazy »

to clarify: popa (popad) and pusha(pushad)
handle the "general purpose" registers of the processor:

eax,ebx,ecx,edx,esi,edi,ebp,esp

that's why one usually doesnt need to handle eax specially in an isr stub.
amirsadig

Re:Return Value from Syscall

Post by amirsadig »

take look to this code. the interrupt handler for 0X80 call syscall, which call the correct sys call from sys_call_table
then I store the return value in regs->eax. as you mentionded above.

Code: Select all

unsigned long sys_call_table[] = {sys_write, sys_read};

void syscall(regs_t *regs)
{
  //unsigned long fnc_addr;
  //fnc_addr = (unsigned long)sys_write ;
  disable();
  __asm__ __volatile__(
   "mov %1, %%ebx;"
         "mov %2, %%ecx;"
         "pushl %%ecx ;"
         "pushl %%ebx ;"
         "call *sys_call_table(,%3, 4) ;"
         "popl %%ebx;"
         "popl %%ecx; "
   :"=a" (regs->eax):"r"(regs->ebx), "r"(regs->ecx), "r" (regs->eax)
);
  enable();
}
but still i don't receive the return value
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Return Value from Syscall

Post by distantvoices »

I'm not good at reading gcc inline assembly.

ARe you sure you pass the correct pointer to this function?

where do you manipulate eax of the process/task issueing the system call? are you sure, you are still operating in the correct stack frame? What does your stack frame look like? do you have a definition of it at hands?

Mark: just place the return code in regs.eax of the current process/task. Upon Iret - in the isr epilogue - eax is per magic wand provided with the return code, as you want it.

HtH
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
amirsadig

Re:Return Value from Syscall

Post by amirsadig »

I am sure I pass correct pointer to syscall, because the task push the number of system call (for examble 0 for system write) and that work very fine. I have define three task one of them work in user mode (am image loaded via grub then) and it call sys_write to write some text on screen.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Return Value from Syscall

Post by distantvoices »

In your code for the isr_stub i see

Code: Select all

mov eax,esp
push eax ;saving position of esp
mov eax,fault ;(sure, you call *fault(regs_t *regs), not
syscall(regs_t *regs)?

does fault() have a proper declaration/definition to handle the pointer to the stack of the interrupted process?

well ... you have an int 0x80 for software interrupts. You know, it is no sense to put parameters for a system call via int xx interface onto the user stack. You need to pass them via registers.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
amirsadig

Re:Return Value from Syscall

Post by amirsadig »

fault function is the default for all Interrupt routines. but I can change it with another function called "setvect()" which change the call to whatever I want.
in runtime I change the interrput routine for 0x80 to call syscall (not fault).

seconldy I don't use stack to send parameters to syscall, I use registers.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Return Value from Syscall

Post by distantvoices »

Ok, seems like I've misread some of your statements. ;-) Pls take my apologies for this.

But once again:

do you pass the pointer to regs, which you are passing to fault() to syscall after changing the call?

To be more exact, could you post the relevant functions?

1: call to fault(regs_t *regs). fault shall get the pointer to esp(regs).
2: fault redirects the call to syscall, if int 0x80 's been invoked: if(int0x80) syscall(regs).

I'd like to check exactly this passing of the pointer to regs.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
amirsadig

Re:Return Value from Syscall

Post by amirsadig »

I have put above the Interrupt routine for all interrupt (see my second post), then this function

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:         setvect
; action:      writes interrupt vector
; in:         [EBP + 12] = vector number,
;         vector stored at address given by [EBP + 8]
; out:         (nothing)
; modifies:      EAX, EDX
; minimum CPU:      '386+
; notes:      C prototype:
;         typedef struct
;         {   unsigned access_byte, eip; } vector_t;
;         getvect(vector_t *v, unsigned vect_num);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EXP setvect
   push ebp
      mov ebp,esp
      push esi
      push ebx
         mov esi,[ebp + 8]

; store access byte in IDT[i]
         mov eax,[esi + 0]
         xor ebx,ebx
         mov bl,[ebp + 12]
         shl ebx,3
         mov [idt + ebx + 5],al

; store handler address in stub
         mov eax,isr1
         sub eax,isr0   ; assume stub size < 256 bytes
         mul byte [ebp + 12]
         mov ebx,eax
         add ebx,isr0
         mov eax,[esi + 4]
         mov [ebx + (isr0.1 - isr0 + 1)],eax
      pop ebx
      pop esi
   pop ebp
   ret
change "move eax, fault" to whatever you give it to call ( for examble "move eax, syscall" and it change also the Access byte on IDT. all these done when initialize the the system.

at startup I define 254 function for interrupt routines ( using assembly), which in default call fault routine. then (in c code) i call setvect() to replace the fault routine with another routine to handle the interrupt. exactly I replace it for (IRQ6 floppy) Timer and System call. when others Interrput occure the cpu call fault routine

Code: Select all

void syscall(regs_t *regs)
{
  
  disable();
  __asm__ __volatile__(
   "mov %1, %%ebx;"
        "mov %2, %%ecx;"
        "pushl %%ecx ;"
        "pushl %%ebx ;"
        "call *sys_call_table(,%3, 4) ;"
        "popl %%ebx;"
        "popl %%ecx; "
   :"=a" (regs->eax):"r"(regs->ebx), "r"(regs->ecx), "r" (regs->eax)
);
  enable();
}
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Return Value from Syscall

Post by distantvoices »

Now, I see it better. :-) sorry asking so much question.

I have a proposal, since I am not sure whether "=a"(regs->eax) does exactly what you want it to do. That's interpreted and formed to assembly by the compiler.

What about:

Code: Select all

 __asm__ __volatile__(
  "mov %1, %%ebx;"
        "mov %2, %%ecx;"
        "pushl %%ecx ;"
        "pushl %%ebx ;"
        "call *sys_call_table(,%3, 4) ;"
        "mov %0,%%eax;" //added by me!!
        "popl %%ebx;"
        "popl %%ecx; "
  :"=a" (regs->eax):"r"(regs->ebx), "r"(regs->ecx), "r" (regs->eax)
);
:"=a"(regs->eax) means according the gcc inline asm howto, that this operand is stored in eax. How to determine whether it is an address or a value in AT&T syntax I don't know, so take my addition as a suggestion. Nevertheless, I suppose you *assign* the return value to the field in regs.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
Post Reply