1
2/*--------------------------------------------------------------------*/
3/*--- Doing syscalls.                                  m_syscall.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
9
10   Copyright (C) 2000-2013 Julian Seward
11      jseward@acm.org
12
13   This program is free software; you can redistribute it and/or
14   modify it under the terms of the GNU General Public License as
15   published by the Free Software Foundation; either version 2 of the
16   License, or (at your option) any later version.
17
18   This program is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   General Public License for more details.
22
23   You should have received a copy of the GNU General Public License
24   along with this program; if not, write to the Free Software
25   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26   02111-1307, USA.
27
28   The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "pub_core_basics.h"
32#include "pub_core_libcassert.h"
33#include "pub_core_vki.h"
34#include "pub_core_vkiscnums.h"
35#include "pub_core_syscall.h"
36
37/* ---------------------------------------------------------------------
38   Building syscall return values.
39   ------------------------------------------------------------------ */
40
41#if defined(VGO_linux)
42
43/* Make a SysRes value from a syscall return value.  This is
44   Linux-specific.
45
46   From:
47   http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/sysdeps/unix/sysv/
48   linux/i386/sysdep.h?
49   rev=1.28&content-type=text/x-cvsweb-markup&cvsroot=glibc
50
51   Linux uses a negative return value to indicate syscall errors,
52   unlike most Unices, which use the condition codes' carry flag.
53
54   Since version 2.1 the return value of a system call might be
55   negative even if the call succeeded.  E.g., the 'lseek' system call
56   might return a large offset.  Therefore we must not anymore test
57   for < 0, but test for a real error by making sure the value in %eax
58   is a real error number.  Linus said he will make sure the no
59   syscall returns a value in -1 .. -4095 as a valid result so we can
60   safely test with -4095.
61*/
62
63SysRes VG_(mk_SysRes_x86_linux) ( Int val ) {
64   SysRes res;
65   res._valEx   = 0; /* unused except on mips-linux */
66   res._isError = val >= -4095 && val <= -1;
67   if (res._isError) {
68      res._val = (UInt)(-val);
69   } else {
70      res._val = (UInt)val;
71   }
72   return res;
73}
74
75/* Similarly .. */
76SysRes VG_(mk_SysRes_amd64_linux) ( Long val ) {
77   SysRes res;
78   res._valEx   = 0; /* unused except on mips-linux */
79   res._isError = val >= -4095 && val <= -1;
80   if (res._isError) {
81      res._val = (ULong)(-val);
82   } else {
83      res._val = (ULong)val;
84   }
85   return res;
86}
87
88/* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speak) */
89/* Note this must be in the bottom bit of the second arg */
90SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ) {
91   SysRes res;
92   res._valEx   = 0; /* unused except on mips-linux */
93   res._isError = (cr0so & 1) != 0;
94   res._val     = val;
95   return res;
96}
97
98/* As per ppc32 version, cr0.so must be in l.s.b. of 2nd arg */
99SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ) {
100   SysRes res;
101   res._valEx   = 0; /* unused except on mips-linux */
102   res._isError = (cr0so & 1) != 0;
103   res._val     = val;
104   return res;
105}
106
107SysRes VG_(mk_SysRes_s390x_linux) ( Long val ) {
108   SysRes res;
109   res._valEx   = 0; /* unused except on mips-linux */
110   res._isError = val >= -4095 && val <= -1;
111   if (res._isError) {
112      res._val = -val;
113   } else {
114      res._val = val;
115   }
116   return res;
117}
118
119SysRes VG_(mk_SysRes_arm_linux) ( Int val ) {
120   SysRes res;
121   res._valEx   = 0; /* unused except on mips-linux */
122   res._isError = val >= -4095 && val <= -1;
123   if (res._isError) {
124      res._val = (UInt)(-val);
125   } else {
126      res._val = (UInt)val;
127   }
128   return res;
129}
130
131SysRes VG_(mk_SysRes_arm64_linux) ( Long val ) {
132   SysRes res;
133   res._valEx   = 0; /* unused except on mips-linux */
134   res._isError = val >= -4095 && val <= -1;
135   if (res._isError) {
136      res._val = (ULong)(-val);
137   } else {
138      res._val = (ULong)val;
139   }
140   return res;
141}
142
143/* MIPS uses a3 != 0 to flag an error */
144SysRes VG_(mk_SysRes_mips32_linux) ( UWord v0, UWord v1, UWord a3 ) {
145   SysRes res;
146   res._isError = (a3 != (UWord)0);
147   res._val     = v0;
148   res._valEx   = v1;
149   return res;
150}
151
152/* MIPS uses a3 != 0 to flag an error */
153SysRes VG_(mk_SysRes_mips64_linux) ( ULong v0, ULong v1, ULong a3 ) {
154   SysRes res;
155   res._isError = (a3 != (ULong)0);
156   res._val     = v0;
157   res._valEx   = v1;
158   return res;
159}
160
161/* Generic constructors. */
162SysRes VG_(mk_SysRes_Error) ( UWord err ) {
163   SysRes r;
164   r._valEx   = 0; /* unused except on mips-linux */
165   r._isError = True;
166   r._val     = err;
167   return r;
168}
169
170SysRes VG_(mk_SysRes_Success) ( UWord res ) {
171   SysRes r;
172   r._valEx   = 0; /* unused except on mips-linux */
173   r._isError = False;
174   r._val     = res;
175   return r;
176}
177
178
179#elif defined(VGO_darwin)
180
181/* Darwin: Some syscalls return a double-word result. */
182SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
183                                   UInt wHI, UInt wLO )
184{
185   SysRes res;
186   res._wHI  = 0;
187   res._wLO  = 0;
188   res._mode = 0; /* invalid */
189   vg_assert(isErr == False || isErr == True);
190   vg_assert(sizeof(UWord) == sizeof(UInt));
191   switch (scclass) {
192      case VG_DARWIN_SYSCALL_CLASS_UNIX:
193         res._wLO  = wLO;
194         res._wHI  = wHI;
195         res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
196         break;
197      case VG_DARWIN_SYSCALL_CLASS_MACH:
198         vg_assert(!isErr);
199         vg_assert(wHI == 0);
200         res._wLO  = wLO;
201         res._mode = SysRes_MACH;
202         break;
203      case VG_DARWIN_SYSCALL_CLASS_MDEP:
204         vg_assert(!isErr);
205         vg_assert(wHI == 0);
206         res._wLO  = wLO;
207         res._mode = SysRes_MDEP;
208         break;
209      default:
210         vg_assert(0);
211   }
212   return res;
213}
214
215SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
216                                     ULong wHI, ULong wLO )
217{
218   SysRes res;
219   res._wHI  = 0;
220   res._wLO  = 0;
221   res._mode = 0; /* invalid */
222   vg_assert(isErr == False || isErr == True);
223   vg_assert(sizeof(UWord) == sizeof(ULong));
224   switch (scclass) {
225      case VG_DARWIN_SYSCALL_CLASS_UNIX:
226         res._wLO  = wLO;
227         res._wHI  = wHI;
228         res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
229         break;
230      case VG_DARWIN_SYSCALL_CLASS_MACH:
231         vg_assert(!isErr);
232         vg_assert(wHI == 0);
233         res._wLO  = wLO;
234         res._mode = SysRes_MACH;
235         break;
236      case VG_DARWIN_SYSCALL_CLASS_MDEP:
237         vg_assert(!isErr);
238         vg_assert(wHI == 0);
239         res._wLO  = wLO;
240         res._mode = SysRes_MDEP;
241         break;
242      default:
243         vg_assert(0);
244   }
245   return res;
246}
247
248/* Generic constructors.  We assume (without checking if this makes
249   any sense, from the caller's point of view) that these are for the
250   UNIX style of syscall. */
251SysRes VG_(mk_SysRes_Error) ( UWord err ) {
252   SysRes r;
253   r._wHI  = 0;
254   r._wLO  = err;
255   r._mode = SysRes_UNIX_ERR;
256   return r;
257}
258
259SysRes VG_(mk_SysRes_Success) ( UWord res ) {
260   SysRes r;
261   r._wHI  = 0;
262   r._wLO  = res;
263   r._mode = SysRes_UNIX_OK;
264   return r;
265}
266
267
268#else
269#  error "Unknown OS"
270#endif
271
272
273/* ---------------------------------------------------------------------
274   VG_(do_syscall): A function for doing syscalls.
275   ------------------------------------------------------------------ */
276
277#if defined(VGP_x86_linux)
278/* Incoming args (syscall number + up to 6 args) come on the stack.
279   (ie. the C calling convention).
280
281   The syscall number goes in %eax.  The args are passed to the syscall in
282   the regs %ebx, %ecx, %edx, %esi, %edi, %ebp, ie. the kernel's syscall
283   calling convention.
284
285   %eax gets the return value.  Not sure which registers the kernel
286   clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
287   %ebp).
288*/
289extern UWord do_syscall_WRK (
290          UWord syscall_no,
291          UWord a1, UWord a2, UWord a3,
292          UWord a4, UWord a5, UWord a6
293       );
294asm(
295".text\n"
296".globl do_syscall_WRK\n"
297"do_syscall_WRK:\n"
298"	push	%esi\n"
299"	push	%edi\n"
300"	push	%ebx\n"
301"	push	%ebp\n"
302"	movl	16+ 4(%esp),%eax\n"
303"	movl	16+ 8(%esp),%ebx\n"
304"	movl	16+12(%esp),%ecx\n"
305"	movl	16+16(%esp),%edx\n"
306"	movl	16+20(%esp),%esi\n"
307"	movl	16+24(%esp),%edi\n"
308"	movl	16+28(%esp),%ebp\n"
309"	int	$0x80\n"
310"	popl	%ebp\n"
311"	popl	%ebx\n"
312"	popl	%edi\n"
313"	popl	%esi\n"
314"	ret\n"
315".previous\n"
316);
317
318#elif defined(VGP_amd64_linux)
319/* Incoming args (syscall number + up to 6 args) come in %rdi, %rsi,
320   %rdx, %rcx, %r8, %r9, and the last one on the stack (ie. the C
321   calling convention).
322
323   The syscall number goes in %rax.  The args are passed to the syscall in
324   the regs %rdi, %rsi, %rdx, %r10, %r8, %r9 (yes, really %r10, not %rcx),
325   ie. the kernel's syscall calling convention.
326
327   %rax gets the return value.  %rcx and %r11 are clobbered by the syscall;
328   no matter, they are caller-save (the syscall clobbers no callee-save
329   regs, so we don't have to do any register saving/restoring).
330*/
331extern UWord do_syscall_WRK (
332          UWord syscall_no,
333          UWord a1, UWord a2, UWord a3,
334          UWord a4, UWord a5, UWord a6
335       );
336asm(
337".text\n"
338".globl do_syscall_WRK\n"
339"do_syscall_WRK:\n"
340        /* Convert function calling convention --> syscall calling
341           convention */
342"	movq	%rdi, %rax\n"
343"	movq	%rsi, %rdi\n"
344"	movq	%rdx, %rsi\n"
345"	movq	%rcx, %rdx\n"
346"	movq	%r8,  %r10\n"
347"	movq	%r9,  %r8\n"
348"	movq    8(%rsp), %r9\n"	 /* last arg from stack */
349"	syscall\n"
350"	ret\n"
351".previous\n"
352);
353
354#elif defined(VGP_ppc32_linux)
355/* Incoming args (syscall number + up to 6 args) come in %r3:%r9.
356
357   The syscall number goes in %r0.  The args are passed to the syscall in
358   the regs %r3:%r8, i.e. the kernel's syscall calling convention.
359
360   The %cr0.so bit flags an error.
361   We return the syscall return value in %r3, and the %cr0.so in
362   the lowest bit of %r4.
363   We return a ULong, of which %r3 is the high word, and %r4 the low.
364   No callee-save regs are clobbered, so no saving/restoring is needed.
365*/
366extern ULong do_syscall_WRK (
367          UWord syscall_no,
368          UWord a1, UWord a2, UWord a3,
369          UWord a4, UWord a5, UWord a6
370       );
371asm(
372".text\n"
373".globl do_syscall_WRK\n"
374"do_syscall_WRK:\n"
375"        mr      0,3\n"
376"        mr      3,4\n"
377"        mr      4,5\n"
378"        mr      5,6\n"
379"        mr      6,7\n"
380"        mr      7,8\n"
381"        mr      8,9\n"
382"        sc\n"                  /* syscall: sets %cr0.so on error         */
383"        mfcr    4\n"           /* %cr -> low word of return var          */
384"        rlwinm  4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
385"        blr\n"                 /* and return                             */
386".previous\n"
387);
388
389#elif defined(VGP_ppc64_linux)
390/* Due to the need to return 65 bits of result, this is completely
391   different from the ppc32 case.  The single arg register points to a
392   7-word block containing the syscall # and the 6 args.  The syscall
393   result proper is put in [0] of the block, and %cr0.so is in the
394   bottom bit of [1]. */
395extern void do_syscall_WRK ( ULong* argblock );
396asm(
397".align   2\n"
398".globl   do_syscall_WRK\n"
399".section \".opd\",\"aw\"\n"
400".align   3\n"
401"do_syscall_WRK:\n"
402".quad    .do_syscall_WRK,.TOC.@tocbase,0\n"
403".previous\n"
404".type    .do_syscall_WRK,@function\n"
405".globl   .do_syscall_WRK\n"
406".do_syscall_WRK:\n"
407"        std  3,-16(1)\n"  /* stash arg */
408"        ld   8, 48(3)\n"  /* sc arg 6 */
409"        ld   7, 40(3)\n"  /* sc arg 5 */
410"        ld   6, 32(3)\n"  /* sc arg 4 */
411"        ld   5, 24(3)\n"  /* sc arg 3 */
412"        ld   4, 16(3)\n"  /* sc arg 2 */
413"        ld   0,  0(3)\n"  /* sc number */
414"        ld   3,  8(3)\n"  /* sc arg 1 */
415"        sc\n"             /* result in r3 and cr0.so */
416"        ld   5,-16(1)\n"  /* reacquire argblock ptr (r5 is caller-save) */
417"        std  3,0(5)\n"    /* argblock[0] = r3 */
418"        mfcr 3\n"
419"        srwi 3,3,28\n"
420"        andi. 3,3,1\n"
421"        std  3,8(5)\n"    /* argblock[1] = cr0.s0 & 1 */
422"        blr\n"
423);
424
425#elif defined(VGP_arm_linux)
426/* I think the conventions are:
427   args  in r0 r1 r2 r3 r4 r5
428   sysno in r7
429   return value in r0, w/ same conventions as x86-linux, viz r0 in
430   -4096 .. -1 is an error value.  All other values are success
431   values.
432*/
433extern UWord do_syscall_WRK (
434          UWord a1, UWord a2, UWord a3,
435          UWord a4, UWord a5, UWord a6,
436          UWord syscall_no
437       );
438asm(
439".text\n"
440".globl do_syscall_WRK\n"
441"do_syscall_WRK:\n"
442"         push    {r4, r5, r7}\n"
443"         ldr     r4, [sp, #12]\n"
444"         ldr     r5, [sp, #16]\n"
445"         ldr     r7, [sp, #20]\n"
446"         svc     0x0\n"
447"         pop     {r4, r5, r7}\n"
448"         bx      lr\n"
449".previous\n"
450);
451
452#elif defined(VGP_arm64_linux)
453/* I think the conventions are:
454   args  in r0 r1 r2 r3 r4 r5
455   sysno in r8
456   return value in r0, w/ same conventions as x86-linux, viz r0 in
457   -4096 .. -1 is an error value.  All other values are success
458   values.
459
460   r0 to r5 remain unchanged, but syscall_no is in r6 and needs
461   to be moved to r8 (??)
462*/
463extern UWord do_syscall_WRK (
464          UWord a1, UWord a2, UWord a3,
465          UWord a4, UWord a5, UWord a6,
466          UWord syscall_no
467       );
468asm(
469".text\n"
470".globl do_syscall_WRK\n"
471"do_syscall_WRK:\n"
472"        mov x8, x6\n"
473"        mov x6, 0\n"
474"        mov x7, 0\n"
475"        svc 0\n"
476"        ret\n"
477".previous\n"
478);
479
480#elif defined(VGP_x86_darwin)
481
482/* Incoming args (syscall number + up to 8 args) come in on the stack
483
484   The kernel's syscall calling convention is:
485   * the syscall number goes in eax
486   * the args are passed to the syscall on the stack,
487     pushed onto the stack R->L (that is, the usual x86
488     calling conventions, with the leftmost arg at the lowest
489     address)
490   Call instruction:
491   * UNIX: sysenter
492   * UNIX: int $0x80
493   * MACH: int $0x81
494   * MDEP: int $0x82
495   Note that the call type can be determined from the syscall number;
496   there is no need to inspect the actual instruction.  Although obviously
497   the instruction must match.
498   Return value:
499   * MACH,MDEP: the return value comes back in eax
500   * UNIX: the return value comes back in edx:eax (hi32:lo32)
501   Error:
502   * MACH,MDEP: no error is returned
503   * UNIX: the carry flag indicates success or failure
504
505   nb here, sizeof(UWord) == sizeof(UInt)
506*/
507
508__private_extern__ ULong
509do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
510                      UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
511                      UWord a7, UWord a8, /* 28(esp)..32(esp) */
512                      UWord syscall_no, /* 36(esp) */
513                      /*OUT*/UInt* errflag /* 40(esp) */ );
514// Unix syscall: 64-bit return in edx:eax, with LSB in eax
515// error indicated by carry flag: clear=good, set=bad
516asm(".private_extern _do_syscall_unix_WRK\n"
517    "_do_syscall_unix_WRK:\n"
518    "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
519    "        movl    $0, (%ecx)       \n"
520    "        movl    36(%esp), %eax   \n"
521    "        int     $0x80            \n"
522    "        jnc     1f               \n"  /* jump if success */
523    "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
524    "        movl    $1, (%ecx)       \n"
525    "    1:  ret                      \n"
526    );
527
528__private_extern__ UInt
529do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
530                      UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
531                      UWord a7, UWord a8, /* 28(esp)..32(esp) */
532                      UWord syscall_no /* 36(esp) */ );
533// Mach trap: 32-bit result in %eax, no error flag
534asm(".private_extern _do_syscall_mach_WRK\n"
535    "_do_syscall_mach_WRK:\n"
536    "        movl    36(%esp), %eax   \n"
537    "        int     $0x81            \n"
538    "        ret                      \n"
539    );
540
541__private_extern__ UInt
542do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
543                      UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
544                      UWord a7, UWord a8, /* 28(esp)..32(esp) */
545                      UWord syscall_no /* 36(esp) */ );
546// mdep trap: 32-bit result in %eax, no error flag
547asm(
548    ".private_extern _do_syscall_mdep_WRK\n"
549    "_do_syscall_mdep_WRK:\n"
550    "        movl    36(%esp), %eax   \n"
551    "        int     $0x82            \n"
552    "        ret                      \n"
553    );
554
555
556#elif defined(VGP_amd64_darwin)
557
558/* Incoming args (syscall number + up to 8 args) come in registers and stack
559
560   The kernel's syscall calling convention is:
561   * the syscall number goes in rax
562   * the args are passed to the syscall in registers and the stack
563   * the call instruction is 'syscall'
564   Return value:
565   * MACH,MDEP: the return value comes back in rax
566   * UNIX: the return value comes back in rdx:rax (hi64:lo64)
567   Error:
568   * MACH,MDEP: no error is returned
569   * UNIX: the carry flag indicates success or failure
570
571   nb here, sizeof(UWord) == sizeof(ULong)
572*/
573
574__private_extern__ UWord
575do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
576                      UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
577                      UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
578                      UWord syscall_no,             /* 24(rsp) */
579                      /*OUT*/ULong* errflag,        /* 32(rsp) */
580                      /*OUT*/ULong* res2 );         /* 40(rsp) */
581// Unix syscall: 128-bit return in rax:rdx, with LSB in rax
582// error indicated by carry flag: clear=good, set=bad
583asm(".private_extern _do_syscall_unix_WRK\n"
584    "_do_syscall_unix_WRK:\n"
585    "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
586    "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
587    "        movq    $0, (%rax)       \n"
588    "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
589    "        syscall                  \n"
590    "        jnc     1f               \n"  /* jump if success */
591    "        movq    32(%rsp), %rcx   \n"  /* syscall failed - set *errflag */
592    "        movq    $1, (%rcx)       \n"
593    "    1:  movq    40(%rsp), %rcx   \n"  /* save 2nd result word */
594    "        movq    %rdx, (%rcx)     \n"
595    "        retq                     \n"  /* return 1st result word */
596    );
597
598__private_extern__ UWord
599do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
600                      UWord a4, UWord a5, UWord a6, /* rcx, r8,  r9 */
601                      UWord a7, UWord a8,           /* 8(rsp), 16(rsp) */
602                      UWord syscall_no );           /* 24(rsp) */
603// Mach trap: 64-bit result, no error flag
604asm(".private_extern _do_syscall_mach_WRK\n"
605    "_do_syscall_mach_WRK:\n"
606    "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
607    "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
608    "        syscall                  \n"
609    "        retq                     \n"
610    );
611
612#elif defined(VGP_s390x_linux)
613
614static UWord do_syscall_WRK (
615   UWord syscall_no,
616   UWord arg1, UWord arg2, UWord arg3,
617   UWord arg4, UWord arg5, UWord arg6
618   )
619{
620   register UWord __arg1 asm("2") = arg1;
621   register UWord __arg2 asm("3") = arg2;
622   register UWord __arg3 asm("4") = arg3;
623   register UWord __arg4 asm("5") = arg4;
624   register UWord __arg5 asm("6") = arg5;
625   register UWord __arg6 asm("7") = arg6;
626   register ULong __svcres asm("2");
627
628   __asm__ __volatile__ (
629                 "lgr %%r1,%1\n\t"
630                 "svc 0\n\t"
631		: "=d" (__svcres)
632		: "a" (syscall_no),
633		  "0" (__arg1),
634		  "d" (__arg2),
635		  "d" (__arg3),
636		  "d" (__arg4),
637		  "d" (__arg5),
638		  "d" (__arg6)
639		: "1", "cc", "memory");
640
641   return (UWord) (__svcres);
642}
643
644#elif defined(VGP_mips32_linux)
645/* Incoming args (syscall number + up to 6 args) come in a0 - a3 and stack.
646
647   The syscall number goes in v0.  The args are passed to the syscall in
648   the regs a0 - a3 and stack, i.e. the kernel's syscall calling convention.
649
650   (a3 != 0) flags an error.
651   We return the syscall return value in v0.
652   MIPS version
653*/
654extern int do_syscall_WRK (
655          int a1, int a2, int a3,
656          int a4, int a5, int a6, int syscall_no, UWord *err,
657          UWord *valHi, UWord* valLo
658       );
659asm(
660".globl do_syscall_WRK\n"
661".ent do_syscall_WRK\n"
662".text\n"
663"do_syscall_WRK:\n"
664"   lw $2, 24($29)\n"
665"   syscall\n"
666"   lw $8, 28($29)\n"
667"   sw $7, ($8)\n"
668"   lw $8, 32($29)\n"
669"   sw $3, ($8)\n"   // store valHi
670"   lw $8, 36($29)\n"
671"   sw $2, ($8)\n"   // store valLo
672"   jr $31\n"
673"   nop\n"
674".previous\n"
675".end do_syscall_WRK\n"
676);
677
678#elif defined(VGP_mips64_linux)
679extern UWord do_syscall_WRK ( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5,
680                              UWord a6, UWord syscall_no, ULong* V1_val );
681asm (
682".text\n"
683".globl do_syscall_WRK\n"
684"do_syscall_WRK:\n"
685"   daddiu $29, $29, -8\n"
686"   sd $11, 0($29)\n"
687"   move $2, $10\n"
688"   syscall\n"
689"   ld $11, 0($29)\n"
690"   daddiu $29, $29, 8\n"
691"   sd $3, 0($11)\n"  /* store vale of v1 in last param */
692"   sd $7, 8($11)\n"  /* store vale of a3 in last param */
693"   jr $31\n"
694".previous\n"
695);
696
697#else
698#  error Unknown platform
699#endif
700
701
702/* Finally, the generic code.  This sends the call to the right
703   helper. */
704
705SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
706                                      UWord a4, UWord a5, UWord a6,
707                                      UWord a7, UWord a8 )
708{
709#  if defined(VGP_x86_linux)
710   UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
711   return VG_(mk_SysRes_x86_linux)( val );
712
713#  elif defined(VGP_amd64_linux)
714   UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
715   return VG_(mk_SysRes_amd64_linux)( val );
716
717#  elif defined(VGP_ppc32_linux)
718   ULong ret     = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
719   UInt  val     = (UInt)(ret>>32);
720   UInt  cr0so   = (UInt)(ret);
721   return VG_(mk_SysRes_ppc32_linux)( val, cr0so );
722
723#  elif defined(VGP_ppc64_linux)
724   ULong argblock[7];
725   argblock[0] = sysno;
726   argblock[1] = a1;
727   argblock[2] = a2;
728   argblock[3] = a3;
729   argblock[4] = a4;
730   argblock[5] = a5;
731   argblock[6] = a6;
732   do_syscall_WRK( &argblock[0] );
733   return VG_(mk_SysRes_ppc64_linux)( argblock[0], argblock[1] );
734
735#  elif defined(VGP_arm_linux)
736   UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
737   return VG_(mk_SysRes_arm_linux)( val );
738
739#  elif defined(VGP_arm64_linux)
740   UWord val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno);
741   return VG_(mk_SysRes_arm64_linux)( val );
742
743#  elif defined(VGP_x86_darwin)
744   UInt  wLO = 0, wHI = 0, err = 0;
745   ULong u64;
746   UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
747   switch (scclass) {
748      case VG_DARWIN_SYSCALL_CLASS_UNIX:
749         u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
750                                   VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err);
751         wLO = (UInt)u64;
752         wHI = (UInt)(u64 >> 32);
753         break;
754      case VG_DARWIN_SYSCALL_CLASS_MACH:
755         wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
756                                   VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
757         err = 0;
758         break;
759      case VG_DARWIN_SYSCALL_CLASS_MDEP:
760         wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
761                                   VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
762         err = 0;
763         break;
764      default:
765         vg_assert(0);
766         break;
767   }
768   return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
769
770#  elif defined(VGP_amd64_darwin)
771   ULong wLO = 0, wHI = 0, err = 0;
772   UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
773   switch (scclass) {
774      case VG_DARWIN_SYSCALL_CLASS_UNIX:
775         wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
776                                   VG_DARWIN_SYSNO_FOR_KERNEL(sysno), &err, &wHI);
777         break;
778      case VG_DARWIN_SYSCALL_CLASS_MACH:
779      case VG_DARWIN_SYSCALL_CLASS_MDEP:
780         wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
781                                   VG_DARWIN_SYSNO_FOR_KERNEL(sysno));
782         err = 0;
783         break;
784      default:
785         vg_assert(0);
786         break;
787   }
788   return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
789
790#elif defined(VGP_s390x_linux)
791   UWord val;
792
793   if (sysno == __NR_mmap) {
794     ULong argbuf[6];
795
796     argbuf[0] = a1;
797     argbuf[1] = a2;
798     argbuf[2] = a3;
799     argbuf[3] = a4;
800     argbuf[4] = a5;
801     argbuf[5] = a6;
802     val = do_syscall_WRK(sysno,(UWord)&argbuf[0],0,0,0,0,0);
803   } else {
804     val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
805   }
806
807   return VG_(mk_SysRes_s390x_linux)( val );
808
809#elif defined(VGP_mips32_linux)
810   UWord err   = 0;
811   UWord valHi = 0;
812   UWord valLo = 0;
813   (void) do_syscall_WRK(a1,a2,a3,a4,a5,a6, sysno,&err,&valHi,&valLo);
814   return VG_(mk_SysRes_mips32_linux)( valLo, valHi, (ULong)err );
815
816#elif defined(VGP_mips64_linux)
817   ULong v1_a3[2];
818   v1_a3[0] = 0xFF00;
819   v1_a3[1] = 0xFF00;
820   ULong V0 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,sysno,v1_a3);
821   ULong V1 = (ULong)v1_a3[0];
822   ULong A3 = (ULong)v1_a3[1];
823   return VG_(mk_SysRes_mips64_linux)( V0, V1, A3 );
824
825#else
826#  error Unknown platform
827#endif
828}
829
830/* ---------------------------------------------------------------------
831   Names of errors.
832   ------------------------------------------------------------------ */
833
834/* Return a string which gives the name of an error value.  Note,
835   unlike the standard C syserror fn, the returned string is not
836   malloc-allocated or writable -- treat it as a constant.
837   TODO: implement this properly. */
838
839const HChar* VG_(strerror) ( UWord errnum )
840{
841   switch (errnum) {
842   case VKI_EPERM:       return "Operation not permitted";
843   case VKI_ENOENT:      return "No such file or directory";
844   case VKI_ESRCH:       return "No such process";
845   case VKI_EINTR:       return "Interrupted system call";
846   case VKI_EIO:         return "Input/output error";
847   case VKI_ENXIO:       return "No such device or address";
848   case VKI_E2BIG:       return "Argument list too long";
849   case VKI_ENOEXEC:     return "Exec format error";
850   case VKI_EBADF:       return "Bad file descriptor";
851   case VKI_ECHILD:      return "No child processes";
852   case VKI_EAGAIN:      return "Resource temporarily unavailable";
853   case VKI_ENOMEM:      return "Cannot allocate memory";
854   case VKI_EACCES:      return "Permission denied";
855   case VKI_EFAULT:      return "Bad address";
856   case VKI_ENOTBLK:     return "Block device required";
857   case VKI_EBUSY:       return "Device or resource busy";
858   case VKI_EEXIST:      return "File exists";
859   case VKI_EXDEV:       return "Invalid cross-device link";
860   case VKI_ENODEV:      return "No such device";
861   case VKI_ENOTDIR:     return "Not a directory";
862   case VKI_EISDIR:      return "Is a directory";
863   case VKI_EINVAL:      return "Invalid argument";
864   case VKI_ENFILE:      return "Too many open files in system";
865   case VKI_EMFILE:      return "Too many open files";
866   case VKI_ENOTTY:      return "Inappropriate ioctl for device";
867   case VKI_ETXTBSY:     return "Text file busy";
868   case VKI_EFBIG:       return "File too large";
869   case VKI_ENOSPC:      return "No space left on device";
870   case VKI_ESPIPE:      return "Illegal seek";
871   case VKI_EROFS:       return "Read-only file system";
872   case VKI_EMLINK:      return "Too many links";
873   case VKI_EPIPE:       return "Broken pipe";
874   case VKI_EDOM:        return "Numerical argument out of domain";
875   case VKI_ERANGE:      return "Numerical result out of range";
876
877   case VKI_ENOSYS:      return "Function not implemented";
878   case VKI_EOVERFLOW:   return "Value too large for defined data type";
879#     if defined(VKI_ERESTARTSYS)
880      case VKI_ERESTARTSYS: return "ERESTARTSYS";
881#     endif
882   default:              return "VG_(strerror): unknown error";
883   }
884}
885
886
887/*--------------------------------------------------------------------*/
888/*--- end                                                          ---*/
889/*--------------------------------------------------------------------*/
890