From 8318c5181964469aa30f2368b23a8a2248e470bd Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 12 Jan 2013 19:48:27 +0100 Subject: [PATCH] Allow syscall parameters and return values larger than native words. Note: This is an incompatible ABI change. --- libc/Makefile | 1 + libc/include/sys/syscall.h | 206 ++++++++++--------------------------- libc/x64/syscall.s | 60 +++++++++++ libc/x86/syscall.s | 64 ++++++++++++ sortix/x64/syscall.s | 8 +- sortix/x64/thread.cpp | 2 +- sortix/x86/syscall.s | 14 +-- sortix/x86/thread.cpp | 2 +- 8 files changed, 195 insertions(+), 162 deletions(-) create mode 100644 libc/x64/syscall.s create mode 100644 libc/x86/syscall.s diff --git a/libc/Makefile b/libc/Makefile index 0f844786..82a9fdd8 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -134,6 +134,7 @@ clock.o \ close.o \ $(CPUDIR)/fork.o \ $(CPUDIR)/signal.o \ +$(CPUDIR)/syscall.o \ dlfcn.o \ dup.o \ env.o \ diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 4fd4ee9d..3d774d67 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of the Sortix C Library. @@ -23,7 +23,7 @@ *******************************************************************************/ #if defined(SORTIX_KERNEL) -#error This part of libc should not be built in kernel mode +#error "This file is part of user-space and should not be built in kernel mode" #endif #ifndef _SYS_SYSCALL_H @@ -31,164 +31,72 @@ #include #include -#include /* Should not be exposed here; use an eventual __errno.h. */ -__BEGIN_DECLS +/* Expand a macro and convert it to string. */ +#define SYSCALL_STRINGIFY_EXPAND(foo) #foo -#define DECL_SYSCALL0(type,fn) type fn(); -#define DECL_SYSCALL1(type,fn,p1) type fn(p1); -#define DECL_SYSCALL2(type,fn,p1,p2) type fn(p1,p2); -#define DECL_SYSCALL3(type,fn,p1,p2,p3) type fn(p1,p2,p3); -#define DECL_SYSCALL4(type,fn,p1,p2,p3,p4) type fn(p1,p2,p3,p4); -#define DECL_SYSCALL5(type,fn,p1,p2,p3,p4,p5) type fn(p1,p2,p3,p4,p5); - -// System call functions for i386. (IA-32) +/* Implement the body of a function that selects the right system call and + jumps into the generic implementation of system calls. */ #if defined(__i386__) -#define DEFN_SYSCALL0(type, fn, num) \ -inline type fn() \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} +#define SYSCALL_FUNCTION_BODY(syscall_index) \ +" mov $" SYSCALL_STRINGIFY_EXPAND(syscall_index) ", %eax\n" \ +" jmp asm_syscall\n" -#define DEFN_SYSCALL1(type, fn, num, P1) \ -inline type fn(P1 p1) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((unsigned long)p1)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL2(type, fn, num, P1, P2) \ -inline type fn(P1 p1, P2 p2) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((unsigned long)p1), "c" ((unsigned long)p2)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL3(type, fn, num, P1, P2, P3) \ -inline type fn(P1 p1, P2 p2, P3 p3) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((unsigned long)p1), "c" ((unsigned long)p2), "d" ((unsigned long)p3)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL4(type, fn, num, P1, P2, P3, P4) \ -inline type fn(P1 p1, P2 p2, P3 p3, P4 p4) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((unsigned long)p1), "c" ((unsigned long)p2), "d" ((unsigned long)p3), "D" ((unsigned long)p4)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL5(type, fn, num, P1, P2, P3, P4, P5) \ -inline type fn(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num), "b" ((unsigned long)p1), "c" ((unsigned long)p2), "d" ((unsigned long)p3), "D" ((unsigned long)p4), "S" ((unsigned long)p5)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -// System call functions for x86_64. (amd64) #elif defined(__x86_64__) -// TODO: Make these inline - though that requires a move advanced inline -// assembly stub to force parameters into the right registers. +#define SYSCALL_FUNCTION_BODY(syscall_index) \ +" mov $" SYSCALL_STRINGIFY_EXPAND(syscall_index) ", %rax\n" \ +" jmp asm_syscall\n" -#define DEFN_SYSCALL0(type, fn, num) \ -type fn() \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL1(type, fn, num, P1) \ -type fn(P1) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL2(type, fn, num, P1, P2) \ -type fn(P1, P2) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL3(type, fn, num, P1, P2, P3) \ -type fn(P1, P2, P3) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL4(type, fn, num, P1, P2, P3, P4) \ -type fn(P1, P2, P3, P4) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -#define DEFN_SYSCALL5(type, fn, num, P1, P2, P3, P4, P5) \ -type fn(P1, P2, P3, P4, P5) \ -{ \ - type a; \ - int reterrno; \ - asm volatile("int $0x80" : "=a" (a) : "0" (num)); \ - asm volatile("movl %%edx, %0" : "=r"(reterrno)); \ - if ( reterrno ) { errno = reterrno; } \ - return a; \ -} - -// Unknown platform with no implementation available. #else -#error System call interface is not declared for host system. + +#error Provide an implementation for your platform. #endif -__END_DECLS +/* Create a function that selects the right system call and jumps into the + generic implementation of system calls. */ +#define SYSCALL_FUNCTION(syscall_name, syscall_index) \ +asm("\n" \ +".pushsection .text\n" \ +".type " #syscall_name ", @function\n" \ +#syscall_name ":\n" \ +SYSCALL_FUNCTION_BODY(syscall_index) \ +".popsection\n" \ +); + +/* Create a function that performs the system call by injecting the right + instructions into the compiler assembly output. Then provide a declaration of + the function that looks just like the caller wants it. */ +#define DEFINE_SYSCALL(syscall_type, syscall_name, syscall_index, syscall_formals) \ +SYSCALL_FUNCTION(syscall_name, syscall_index) \ +__BEGIN_DECLS \ +extern "C" { syscall_type syscall_name syscall_formals; } \ +__END_DECLS \ + +/* System call accepting no parameters. */ +#define DEFN_SYSCALL0(type, fn, num) \ +DEFINE_SYSCALL(type, fn, num, ()) + +/* System call accepting 1 parameter. */ +#define DEFN_SYSCALL1(type, fn, num, t1) \ +DEFINE_SYSCALL(type, fn, num, (t1 p1)) + +/* System call accepting 2 parameters. */ +#define DEFN_SYSCALL2(type, fn, num, t1, t2) \ +DEFINE_SYSCALL(type, fn, num, (t1 p1, t2 p2)) + +/* System call accepting 3 parameters. */ +#define DEFN_SYSCALL3(type, fn, num, t1, t2, t3) \ +DEFINE_SYSCALL(type, fn, num, (t1 p1, t2 p2, t3 p3)) + +/* System call accepting 4 parameters. */ +#define DEFN_SYSCALL4(type, fn, num, t1, t2, t3, t4) \ +DEFINE_SYSCALL(type, fn, num, (t1 p1, t2 p2, t3 p3, t4 p4)) + +/* System call accepting 5 parameters. */ +#define DEFN_SYSCALL5(type, fn, num, t1, t2, t3, t4, t5) \ +DEFINE_SYSCALL(type, fn, num, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5)) #endif diff --git a/libc/x64/syscall.s b/libc/x64/syscall.s new file mode 100644 index 00000000..b21149bc --- /dev/null +++ b/libc/x64/syscall.s @@ -0,0 +1,60 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + x64/syscall.s + Function for performing system calls. + +*******************************************************************************/ + +# x86_64 system call conventions: +# interrupt 128 +# system call number: %rax +# parameters: %rdi, %rsi, %rdx, %rcx, %r8, %r9 +# return value: %rax, %rdx +# return errno: %rcx +# clobbered: %rdi, %rsi, %r8, %r9, %r10, %r11 +# preserved: %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15 + +.section .text + +.global asm_syscall +asm_syscall: /* syscall num in %rax. */ + push %rbp + mov %rsp, %rbp + int $0x80 + test %ecx, %ecx + jnz 1f + pop %rbp + ret +1: + push %rbx + push %r12 + push %r13 + mov %ecx, %ebx # preserve: ret_errno + mov %rax, %r12 # preserve: ret_low + mov %rdx, %r13 # preserve: ret_high + call get_errno_location # get_errno_location() + mov %ebx, (%rax) # *get_errno_location() = ret_errno + mov %r12, %rax # restore: ret_low + mov %r13, %rdx # restore: ret_high + pop %r13 + pop %r12 + pop %rbx + pop %rbp + ret diff --git a/libc/x86/syscall.s b/libc/x86/syscall.s new file mode 100644 index 00000000..baede451 --- /dev/null +++ b/libc/x86/syscall.s @@ -0,0 +1,64 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + x86/syscall.s + Function for performing system calls. + +*******************************************************************************/ + +# i386 system call conventions: +# interrupt 128 +# system call number: %eax +# parameters: %ebx, %ecx, %edx, %edi, %esi +# return value: %eax, %edx +# return errno: %ecx +# clobbered: %ebx, %edi, %esi +# preserved: %ebp, %esp + +.section .text +.global asm_syscall +asm_syscall: /* syscall num in %eax. */ + push %ebp + mov %esp, %ebp + push %ebx + push %edi + push %esi + # 0 (%ebp) # saved_ebp + # 4 (%ebp) # return_eip + mov 8 (%ebp), %ebx # param_word1 + mov 12(%ebp), %ecx # param_word2 + mov 16(%ebp), %edx # param_word3 + mov 20(%ebp), %edi # param_word4 + mov 24(%ebp), %esi # param_word5 + int $0x80 + test %ecx, %ecx # ret_errno & ret_errno + jz 1f # if ( !(ret_errno & ret_errno) ) + mov %eax, %ebx # preserve: ret_low + mov %edx, %edi # preserve: ret_high + mov %ecx, %esi # preserve: ret_errno + call get_errno_location # get_errno_location() + mov %esi, (%eax) # *get_errno_location() = ret_errno + mov %ebx, %eax # restore: ret_low + mov %edi, %edx # restore: ret_high +1: + pop %esi + pop %edi + pop %ebx + pop %ebp + ret diff --git a/sortix/x64/syscall.s b/sortix/x64/syscall.s index 2ae2bf49..9c6b27a7 100644 --- a/sortix/x64/syscall.s +++ b/sortix/x64/syscall.s @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -65,9 +65,9 @@ valid_syscall: movl %ebp, %fs movl %ebp, %gs - # Return to user-space, system call result in %rax, errno in %edx. + # Return to user-space, system call result in %rax:%rdx, errno in %ecx. popq %rbp - movl global_errno, %edx + movl global_errno, %ecx # If any signals are pending, fire them now. movq asm_signal_is_pending, %rdi @@ -88,7 +88,7 @@ call_signal_dispatcher: # handle it for us when the signal is over. movq 0(%rsp), %rdi # userspace rip movq 16(%rsp), %rsi # userspace rflags - movq 24(%rsp), %rcx # userspace rsp, note %rdx is used for errno + movq 24(%rsp), %r8 # userspace rsp, note %rcx is used for errno int $130 # Deliver pending signals. # If we end up here, it means that the signal didn't override anything and # that we should just go ahead and return to userspace ourselves. diff --git a/sortix/x64/thread.cpp b/sortix/x64/thread.cpp index 4f092d00..85096a3f 100644 --- a/sortix/x64/thread.cpp +++ b/sortix/x64/thread.cpp @@ -119,7 +119,7 @@ namespace Sortix return; regs->rip = regs->rdi; regs->rflags = regs->rsi; - regs->userrsp = regs->rcx; + regs->userrsp = regs->r8; regs->cs = UCS | URPL; regs->ds = UDS | URPL; regs->ss = UDS | URPL; diff --git a/sortix/x86/syscall.s b/sortix/x86/syscall.s index 418bf92c..4c321968 100644 --- a/sortix/x86/syscall.s +++ b/sortix/x86/syscall.s @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with Sortix. If not, see . - syscall.s + x86/syscall.s An assembly stub that acts as glue for system calls. *******************************************************************************/ @@ -69,13 +69,13 @@ valid_syscall: movl %ebp, %fs movl %ebp, %gs - # Return to user-space, system call result in %eax, errno in %edx. + # Return to user-space, system call result in %eax:%edx, errno in %ecx. popl %ebp - movl global_errno, %edx + movl global_errno, %ecx # If any signals are pending, fire them now. - movl asm_signal_is_pending, %ecx - testl %ecx, %ecx + movl asm_signal_is_pending, %ebx + testl %ebx, %ebx jnz call_signal_dispatcher iretl @@ -90,7 +90,7 @@ call_signal_dispatcher: # call is made this stack will get reused and all our nice temporaries wil # be garbage. We therefore pass the kernel the state to return to and it'll # handle it for us when the signal is over. - movl %esp, %ecx + movl %esp, %ebx int $130 # Deliver pending signals. # If we end up here, it means that the signal didn't override anything and # that we should just go ahead and return to userspace ourselves. diff --git a/sortix/x86/thread.cpp b/sortix/x86/thread.cpp index fc0680e4..86306813 100644 --- a/sortix/x86/thread.cpp +++ b/sortix/x86/thread.cpp @@ -96,7 +96,7 @@ namespace Sortix { if ( regs->InUserspace() ) return; - uint32_t* params = (uint32_t*) regs->ecx; + uint32_t* params = (uint32_t*) regs->ebx; regs->eip = params[0]; regs->eflags = params[2]; regs->useresp = params[3];