summaryrefslogtreecommitdiffstats
path: root/usr/klibc/arch/m68k/syscall.S
diff options
context:
space:
mode:
Diffstat (limited to 'usr/klibc/arch/m68k/syscall.S')
-rw-r--r--usr/klibc/arch/m68k/syscall.S53
1 files changed, 53 insertions, 0 deletions
diff --git a/usr/klibc/arch/m68k/syscall.S b/usr/klibc/arch/m68k/syscall.S
new file mode 100644
index 0000000..c909e2a
--- /dev/null
+++ b/usr/klibc/arch/m68k/syscall.S
@@ -0,0 +1,53 @@
+/*
+ * arch/m68k/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are on the stack; the system call number in %d0.
+ */
+
+ .text
+ .align 2
+ .globl __syscall_common
+ .type __syscall_common, @function
+__syscall_common:
+ /*
+ * According to eglibc, separate moves are faster than movem;
+ * speed is important and this code is not duplicated anyway,
+ * so we do the same here. We use %a1 as scratch register for
+ * saving; syscall arguments are to be in %d1 to %d5 and %a0.
+ */
+ move.l 24(%sp), %a0 /* orig.sp+24: arg 6 */
+ move.l %d5, -(%sp) /* push d5 (callee saved) */
+ move.l 24(%sp), %d5 /* orig.sp+20: arg 5 */
+ move.l %d4, -(%sp) /* push d4 (callee saved) */
+ move.l 24(%sp), %d4 /* orig.sp+16: arg 4 */
+ move.l %d3, -(%sp) /* push d3 (callee saved) */
+ move.l 24(%sp), %d3 /* orig.sp+12: arg 3 */
+ move.l %d2, %a1 /* save d2 (callee saved) in a1 */
+ move.l 20(%sp), %d2 /* orig.sp+8: arg 2 */
+ move.l 16(%sp), %d1 /* orig.sp+4: arg 1 */
+ trap #0
+ move.l %a1, %d2 /* restore d2 from a1 (scratch) */
+ move.l (%sp)+, %d3 /* pop d3..d5, see above */
+ move.l (%sp)+, %d4
+ move.l (%sp)+, %d5
+
+ /* syscall is done, result in %d0, registers are restored */
+ .globl __syscall_checkandout
+__syscall_checkandout:
+ /* now check for error */
+ cmp.l #-4095, %d0
+ bcs.l 1f /* jump if _not_ error */
+
+ /* prepare for error return */
+ neg.l %d0
+ move.l %d0, (errno)
+ move.l #-1, %d0
+ /* fallthrough into common return path */
+
+1: /* copy return value to %a0 for syscalls returning pointers */
+ move.l %d0, %a0
+ rts
+
+ .size __syscall_common,.-__syscall_common