Subject: Question on syscall()

From: <[email-masked]>
Date: Tue, 13 Jul 1999 09:01:44 -0500 (CDT)

Greetings,

I am running 2.2.10-rmk2-stk1 on an ebsa-285 like board.  I have
implemented my own system call which reads out some data stored in the
kernel, or lets the user change this data depending on what arguments
they pass in.  It takes 4 arguments:

asmlinkage int sys_vend_param(void *old, size_t *oldlen,
				void *new, size_t newlen)

What I've found is that if I set it up this way, and call the system
call using syscall() as follows:

---
#define OS_VERSION      9
#define VP_SYSCALL      (191 ^ (OS_VERSION << 20))

struct vend_params my_vp;
size_t my_vp_size = sizeof(struct vend_params);

if ((i = syscall(VP_SYSCALL, &my_vp, &my_vp_size, 0, 0)) < 0)
---

what appears to happen is that the first argument passed to my system
call is actually VP_SYSCALL.  I don't think this is right.  But, looking
at the wrapper for sys_syscall in entry-common.S, I saw the following:

@ r0 = syscall number
@ r5 = syscall table
SYMBOL_NAME(sys_syscall):
	eor     r6, r0, #OS_NUMBER << 20
	cmp     r6, #NR_syscalls	@ check range
	ldmleib sp, {r0 - r4}		@ get our args
	strle   r4, [sp]		@ Put our arg on the stack
	ldrle	pc, [r5, r6, lsl #2]
	mov 	r0, #-ENOSYS
	mov     pc, lr

It looks like it actually pushes all 5 arguments passed to it onto the
stack, and thus the reason for the syscall number being the first
argument to my sys_vend_param() function.  If I put a dummy int as the
first argument to my sys_vend_param() routine, things seem to work fine.

Is this expected behaviour?

--
Kyle Mestery			| StorageTek's Storage Networking Group
[email-masked]		| http://www.freebsd.org/
[email-masked]		| http://www.netwinder.org/
	Protect your right to privacy: www.freecrypto.org

unsubscribe: body of `unsubscribe linux-arm' to [email-masked]

---

From: Philip Blundell <[email-masked]>
Date: Tue, 13 Jul 1999 15:14:46 +0100

>they pass in.  It takes 4 arguments:

You should probably consider using sysctl for this, incidentally.

>if ((i = syscall(VP_SYSCALL, &my_vp, &my_vp_size, 0, 0)) < 0)

Where is your definition of `syscall' coming from; can you post the 
preprocessed output and/or assembler that it generates?

>Is this expected behaviour?

Kind of.  The ARM Linux ABI puts the syscall number in the SWI instruction 
rather than in a register.  So yes, it is expected that all five arguments to 
the syscall are simply passed straight through to your routine, but no it is 
not expected that one of them is your syscall number.

p.

---

From: <[email-masked]>
Date: Tue, 13 Jul 1999 09:25:30 -0500 (CDT)

> You should probably consider using sysctl for this, incidentally.
Actually, this is already implemented as a sysctl, I just wanted to try
and implement it as a system call also.

> preprocessed output and/or assembler that it generates?
Okay, both are attached.

> not expected that one of them is your syscall number.
Interesting.  I didn't think this was the way it was supposed to work.

---

From: <[email-masked]>
Date: Tue, 13 Jul 1999 09:38:51 -0500 (CDT)

Ooops!  Attached is the correct SYS.s.  Sorry about that.

---

From: Philip Blundell <[email-masked]>
Date: Tue, 13 Jul 1999 15:51:32 +0100

>and implement it as a system call also.

Fair enough.

>Okay, both are attached.

Sorry, I didn't read your first message carefully enough.  I thought you 
were using __syscall from <asm/unistd.h> (or its moral equivalent) rather than 
the library routine and SYS_syscall.  Duh.

Yes, it does look as if you are right and sys_syscall is doing the wrong 
thing.

p.

---

From: <[email-masked]>
Date: Tue, 13 Jul 1999 10:05:38 -0500 (CDT)

> Yes, it does look as if you are right and sys_syscall is doing the wrong 
So the correct fix would be to simply push r1-r4 onto the stack instead
of r0-r4 in sys_syscall?  I'm guessing somewhere the order they are
popped off would have to be changed, but I haven't quite figured out
where that is yet.

---

From: Philip Blundell <[email-masked]>
Date: Tue, 13 Jul 1999 16:37:28 +0100

>popped off would have to be changed, but I haven't quite figured out

No, I don't think so.  What sys_syscall is actually doing is retrieving the 
arg registers that were previously pushed onto the stack by the entry code.  
My guess from a quick look at the code is that it's getting an off-by-one 
result because R4 has gotten pushed underneath R0; you could try changing it 
to be something like

	addle	ip, sp, #4		@ discard old R0
	ldmleib	ip, {r0 - r4}		@ get our args from original R1..R5

Russell can probably give you a more definitive answer.  I don't really have 
time to experiment with it right now.

p.

---

From: Russell King - ARM Linux Admin <[email-masked]>
Date: Tue, 13 Jul 1999 19:19:43 +0100 (BST)

> time to experiment with it right now.

No, I don't see anything wrong with the code.  It's highly optimised tho...
Here's the explaination of how it works:

The SP is pointing at the stacked r0, hence:

                  r5
                  r4
                  r3
                  r2
                  r1
           SP->   r0

The LDMIB loads into r0 to r4 the values of r1 to r5, hence shifting
the arguments down one register (LDMIB increments before the load
operation).  This is done since the arguments to the syscall are
(syscall_number, arg0, arg1, arg2, ...) and we want arg0 in r0.

Next, to be compliant with APCS r4 is stacked by replacing the original
r0.  This is ok, since the value will overwritten later.  We now have
the arguments for the system call in r0 to r3, with the fifth argument
on the stack.  Plus, more importantly, original r1 - r5 stacking is left
untouched in case we need to redo the call.

We now call the real syscall.
   _____
  |_____| ------------------------------------------------- ---+---+-
  |   |        Russell King       [email-masked]      --- ---
  | | | |  http://www.arm.linux.org.uk/~rmk/armlinux.html    /  /  |
  | +-+-+                                                     --- -+-
  /   |               THE developer of ARM Linux              |+| /|\
 /  | | |                                                     ---  |
    +-+-+ -------------------------------------------------  /\\\  |
unsubscribe: body of `unsubscribe linux-arm' to [email-masked]

---

From: <[email-masked]>
Date: Tue, 13 Jul 1999 13:52:59 -0500 (CDT)

Hi,

> We now call the real syscall.
Okay, I understand the above.  But, when I looked at kernel 2.3.6, I saw
the following section of code.  It differs from 2.2.10, and follows
along the lines of how Phil told me to modify 2.2.10:

@ r0 = syscall number
@ r1 = syscall r0
@ r5 = syscall r4
@ ip = syscall table
SYMBOL_NAME(sys_syscall):
	mov     r6, r0
	eor     r6, r6, #OS_NUMBER << 20
	cmp     r6, #NR_syscalls	@ check range
	movgt	r0, #-ENOSYS
	movgt	pc, lr
	add	sp, sp, #4 		@ take of the save of our r4
	ldmib	sp, {r0 - r4}		@ get our args
	str	r4, [sp, #-4]!		@ Put our arg on the stack
	ldr	pc, [ip, r6, lsl #2]

So, if I follow this route in 2.2.10, things work as expected.

---

From: Russell King - ARM Linux Admin <[email-masked]>
Date: Tue, 13 Jul 1999 20:08:02 +0100 (BST)

> So, if I follow this route in 2.2.10, things work as expected.

I've just checked my code, and it's not changed.  I don't know where
this has come from - sounds like someone is distributing rogue
patches.
   _____
  |_____| ------------------------------------------------- ---+---+-
  |   |        Russell King       [email-masked]      --- ---
  | | | |  http://www.arm.linux.org.uk/~rmk/armlinux.html    /  /  |
  | +-+-+                                                     --- -+-
  /   |               THE developer of ARM Linux              |+| /|\
 /  | | |                                                     ---  |
    +-+-+ -------------------------------------------------  /\\\  |
unsubscribe: body of `unsubscribe linux-arm' to [email-masked]

---

From: Russell King - ARM Linux Admin <[email-masked]>
Date: Tue, 13 Jul 1999 20:09:23 +0100 (BST)

What is this stk1 patch?
   _____

---

From: <[email-masked]>
Date: Tue, 13 Jul 1999 14:15:18 -0500 (CDT)

Hi,

> this has come from - sounds like someone is distributing rogue
That is straight from 2.3.6, I believe without your patch (but I'll have
to check).  I am downloading 2.3.9 now and your latest 2.3 patch to
verify what's in there.

---

From: <[email-masked]>
Date: Tue, 13 Jul 1999 14:17:09 -0500 (CDT)

> What is this stk1 patch?
This is a patchset I made that has support for our hardware.  It has
subtle differences from the ebsa-285, and also has more devices which
I've added support for, along with some in kernel data structures which
I provide userland programs access to via sysctl() and syscall.  Other
than that, nothing else has changed.

---

From: Russell King - ARM Linux Admin <[email-masked]>
Date: Tue, 13 Jul 1999 20:17:55 +0100 (BST)

> to check).  I am downloading 2.3.9 now and your latest 2.3 patch to

You must always use my patches.  The code in Linus' distributions are
not complete.
   _____

---

From: Philip Blundell <[email-masked]>
Date: Tue, 13 Jul 1999 20:30:03 +0100

>The SP is pointing at the stacked r0, hence:

It's that bit that I didn't agree with.  It looked to me as though SP was 
pointing at the copy of R4 that had been pushed by the earlier syscall entry 
(ie the fifth argument to sys_syscall).  But maybe I overlooked something.

p.

---

From: Russell King - ARM Linux Admin <[email-masked]>
Date: Tue, 13 Jul 1999 21:02:53 +0100 (BST)

> (ie the fifth argument to sys_syscall).  But maybe I overlooked something.

Argh, looks like you're right.

The code around sys_syscall should read:

	add	ip, sp, #4
	ldmleib	ip, {r0 - r4}

This will be fixed in my next patch (why hasn't anything complained about
it?)
   _____

---

From: Philip Blundell <[email-masked]>
Date: Tue, 13 Jul 1999 21:11:02 +0100

>This will be fixed in my next patch (why hasn't anything complained about

Well, under Linux hardly anything uses sys_syscall - in fact I can't think of 
any common program at all that does, off the top of my head.  The BSD crt code 
makes heavy use of it but there's a completely separate handler for that 
anyway.

It did work at one point not all that long ago; I suspect it got broken when 
the syscall handling was rearranged a few months back.

p.