Re: Calling syscalls from x86-64 kernel results in a crash on Opteronmachines

From: Brian Gerst
Date: Mon Sep 13 2004 - 10:20:01 EST


Constantine Gavrilov wrote:
Hello:

We have a piece of kernel code that calls some system calls in kernel context (from a process with mm and a daemonized kernel thread that does not have mm). This works fine on IA64 and i386 architectures.

When I try this on x86-64 kernel on Opteron machines, it results in immediate crash. I have tried standard _syscall() macros from asm/unistd.h. The system panics when returning from the system call.
The disassembled code shows that gcc has often a hard time deciding which registers (32-bit or 64-bit) it will use. For example, it puts the system call number to eax, while it should put it to rax. However, this register thing is not a problem. I have tried my own gcc hand-crafted inline assembly and glibc inline syscall assembly that results in "correct" disassembled code. The result is always the same -- kernel crash when calling a function defined by _syscall() macros or when using an "inline" block defined by glibc macros.

Attached please find a test module that tries to call the umask() (JUST TO DEMONSTRATE a problem) via the syscall machanism. Both methods (the _syscall1() marco and GLIBC INLINE_SYCALL() were used.

The assembly dump of the umask() called via _syscall(1) and via INLINE_SYSCALL() as well as the disassembly of umask() from glibc are provided in a separate attachement. The crash dump (captured with a serial console) is provided along with disassembly of the main module function.

It seems that segmentation is changed during the syscall and not restored properly, or some other REALLY BAD THING happens. The entry.S for x86_64 architecture is very informative, but I am not an expert in Opteron architecture and I do not know how the syscall instruction is supposed to work.

Can someone explain the reason for the crash? Can you think of a workaround? Comments and ideas are very welcome (except of the kind that it can be implemented in the user space or with a help of a user proxy process).

You should never use the unistd.h macros from kernel space. Call sys_foo() directly. This may mean you have to export it. The reason it crashes is that the "syscall" opcode used by the x86-64 macros (unlike the "int $0x80" for i386) causes a fault when already running in kernel space.

--
Brian Gerst
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/