diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-01-18 20:06:33 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-01-18 20:06:33 +0000 |
commit | 831b78254cfa752d5e6542542a663468e650bcb3 (patch) | |
tree | afb0c05de53519b72564dad4e305454ce6bd65f3 /darwin-user | |
parent | 54421cb17bc744bad15f2b1adb4adefdaea83c10 (diff) |
Darwin userspace emulation, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2332 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'darwin-user')
-rw-r--r-- | darwin-user/commpage.c | 358 | ||||
-rw-r--r-- | darwin-user/ioctls.h | 4 | ||||
-rw-r--r-- | darwin-user/ioctls_types.h | 1 | ||||
-rw-r--r-- | darwin-user/machload.c | 903 | ||||
-rw-r--r-- | darwin-user/main.c | 922 | ||||
-rw-r--r-- | darwin-user/mmap.c | 411 | ||||
-rw-r--r-- | darwin-user/qemu.h | 179 | ||||
-rw-r--r-- | darwin-user/signal.c | 463 | ||||
-rw-r--r-- | darwin-user/syscall.c | 1315 | ||||
-rw-r--r-- | darwin-user/syscalls.h | 384 |
10 files changed, 4940 insertions, 0 deletions
diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c new file mode 100644 index 0000000000..12ee1da029 --- /dev/null +++ b/darwin-user/commpage.c @@ -0,0 +1,358 @@ + /* + * Commpage syscalls + * + * Copyright (c) 2006 Pierre d'Herbemont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include <mach/message.h> +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <libkern/OSAtomic.h> + +#include "qemu.h" + +//#define DEBUG_COMMPAGE + +#ifdef DEBUG_COMMPAGE +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) +#else +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) +#endif + +/******************************************************************** + * Commpage definitions + */ +#ifdef TARGET_I386 +/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */ +# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */ +# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */ +#elif defined(TARGET_PPC) +/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */ +# define COMMPAGE_START (-8*4096) +# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */ +#endif + +void do_compare_and_swap32(void *cpu_env, int num); +void do_compare_and_swap64(void *cpu_env, int num); +void do_add_atomic_word32(void *cpu_env, int num); +void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1); +void do_nanotime(void *cpu_env, int num); + +void unimpl_commpage(void *cpu_env, int num); + +typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8); +typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1, + uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, + uint32_t arg6, uint32_t arg7, uint32_t arg8); + +#define HAS_PTR 0x10 +#define NO_PTR 0x20 +#define CALL_DIRECT 0x1 +#define CALL_INDIRECT 0x2 + +#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \ + { #name, offset, nargs, options, (commpage_8args_function_t)func } + +struct commpage_entry { + char * name; + int offset; + int nargs; + char options; + commpage_8args_function_t function; +}; + +static inline int commpage_code_num(struct commpage_entry *entry) +{ + if((entry->options & HAS_PTR)) + return entry->offset + 4; + else + return entry->offset; +} + +static inline int commpage_is_indirect(struct commpage_entry *entry) +{ + return !(entry->options & CALL_DIRECT); +} + +/******************************************************************** + * Commpage entry + */ +static struct commpage_entry commpage_entries[] = +{ + COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR), + COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR), + COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR), + COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR), + + COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT), + COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT), + COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(gettimeofday, 1, 0x2c0, do_cgettimeofday, CALL_INDIRECT), + COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(pthread_self, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + + COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT), + +#ifdef TARGET_I386 + COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT), +#endif + + COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT), + COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT), + COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT), + +#ifdef TARGET_I386 + COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT), + COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT), + + COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT), + + COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT), +#elif TARGET_PPC + COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT), +#endif +}; + + +/******************************************************************** + * Commpage backdoor + */ +static inline void print_commpage_entry(struct commpage_entry entry) +{ + printf("@0x%x %s\n", entry.offset, entry.name); +} + +static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry) +{ +#ifdef TARGET_I386 + char * commpage = (char*)(COMMPAGE_START+entry.offset); + int c = 0; + if(entry.options & HAS_PTR) + { + commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff; + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff; + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff; + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff; + } + commpage[c++] = 0xcd; + commpage[c++] = 0x79; /* int 0x79 */ + commpage[c++] = 0xc3; /* ret */ +#else + qerror("can't install the commpage on this arch\n"); +#endif +} + +/******************************************************************** + * Commpage initialization + */ +void commpage_init(void) +{ +#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC)) + int i; + void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE, + PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if((int)commpage != COMMPAGE_START) + qerror("can't allocate the commpage\n"); + + bzero(commpage, COMMPAGE_SIZE); + + /* XXX: commpage data not handled */ + + for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) + install_commpage_backdoor_for_entry(commpage_entries[i]); +#else + /* simply map our pages so they can be executed + XXX: we don't really want to do that since in the ppc on ppc situation we may + not able to run commpages host optimized instructions (like G5's on a G5), + hence this is sometimes a broken fix. */ + page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID); +#endif +} + +/******************************************************************** + * Commpage implementation + */ +void do_compare_and_swap32(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX]; + uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX]; + DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value); + + if(value && old == tswap32(*value)) + { + uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX]; + *value = tswap32(new); + /* set zf flag */ + ((CPUX86State*)cpu_env)->eflags |= 0x40; + } + else + { + ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value); + /* unset zf flag */ + ((CPUX86State*)cpu_env)->eflags &= ~0x40; + } +#else + qerror("do_compare_and_swap32 unimplemented"); +#endif +} + +void do_compare_and_swap64(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */ + uint64_t old, new, swapped_val; + uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI]; + old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX]; + + DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value); + swapped_val = tswap64(*value); + + if(old == swapped_val) + { + new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX]; + *value = tswap64(new); + /* set zf flag */ + ((CPUX86State*)cpu_env)->eflags |= 0x40; + } + else + { + ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val); + ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32); + /* unset zf flag */ + ((CPUX86State*)cpu_env)->eflags &= ~0x40; + } +#else + qerror("do_compare_and_swap64 unimplemented"); +#endif +} + +void do_add_atomic_word32(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX]; + uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX]; + uint32_t swapped_value = tswap32(*value); + + DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value); + + /* old value in EAX */ + ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value; + *value = tswap32(swapped_value + amt); +#else + qerror("do_add_atomic_word32 unimplemented"); +#endif +} + +void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1) +{ +#ifdef TARGET_I386 + extern int __commpage_gettimeofday(struct timeval *); + DPRINTF("commpage: gettimeofday(0x%x)\n", arg1); + struct timeval *time = (struct timeval *)arg1; + int ret = __commpage_gettimeofday(time); + tswap32s((uint32_t*)&time->tv_sec); + tswap32s((uint32_t*)&time->tv_usec); + ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */ +#else + qerror("do_gettimeofday unimplemented"); +#endif +} + +void do_nanotime(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + uint64_t t = mach_absolute_time(); + ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff); + ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff); +#else + qerror("do_nanotime unimplemented"); +#endif +} + +void unimpl_commpage(void *cpu_env, int num) +{ + gemu_log("qemu: commpage function 0x%x not implemented\n", num); +} + +/******************************************************************** + * do_commpage - called by the main cpu loop + */ +void +do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8) +{ + int i, found = 0; + + arg1 = tswap32(arg1); + arg2 = tswap32(arg2); + arg3 = tswap32(arg3); + arg4 = tswap32(arg4); + arg5 = tswap32(arg5); + arg6 = tswap32(arg6); + arg7 = tswap32(arg7); + arg8 = tswap32(arg8); + + num = num-COMMPAGE_START-2; + + for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) { + if( num == commpage_code_num(&commpage_entries[i]) ) + { + DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]"); + found = 1; + if(commpage_is_indirect(&commpage_entries[i])) + { + commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function; + function(cpu_env, num, arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + } + else + { + commpage_entries[i].function(arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + } + break; + } + } + + if(!found) + { + gemu_log("qemu: commpage function 0x%x not defined\n", num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(-1); + } +} diff --git a/darwin-user/ioctls.h b/darwin-user/ioctls.h new file mode 100644 index 0000000000..dc73af259c --- /dev/null +++ b/darwin-user/ioctls.h @@ -0,0 +1,4 @@ + /* emulated ioctl list */ + + IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) diff --git a/darwin-user/ioctls_types.h b/darwin-user/ioctls_types.h new file mode 100644 index 0000000000..63e65f031b --- /dev/null +++ b/darwin-user/ioctls_types.h @@ -0,0 +1 @@ +STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)
\ No newline at end of file diff --git a/darwin-user/machload.c b/darwin-user/machload.c new file mode 100644 index 0000000000..3ba417ed0d --- /dev/null +++ b/darwin-user/machload.c @@ -0,0 +1,903 @@ +/* + * Mach-O object file loading + * + * Copyright (c) 2006 Pierre d'Herbemont + * + * This 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 2 of the License, or (at your option) any later version. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "qemu.h" +#include "disas.h" + +#include <mach-o/loader.h> +#include <mach-o/fat.h> +#include <mach-o/nlist.h> +#include <mach-o/reloc.h> +#include <mach-o/ppc/reloc.h> + +//#define DEBUG_MACHLOAD + +#ifdef DEBUG_MACHLOAD +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) +#else +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) +#endif + +# define check_mach_header(x) (x.magic == MH_CIGAM) + +extern const char *interp_prefix; + +/* we don't have a good implementation for this */ +#define DONT_USE_DYLD_SHARED_MAP + +/* Pass extra arg to DYLD for debug */ +//#define ACTIVATE_DYLD_TRACE + +//#define OVERRIDE_DYLINKER + +#ifdef OVERRIDE_DYLINKER +# ifdef TARGET_I386 +# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld" +# else +# define DYLINKER_NAME "/usr/lib/dyld" +# endif +#endif + +/* XXX: in an include */ +struct nlist_extended +{ + union { + char *n_name; + long n_strx; + } n_un; + unsigned char n_type; + unsigned char n_sect; + short st_desc; + unsigned long st_value; + unsigned long st_size; +}; + +/* Print symbols in gdb */ +void *macho_text_sect = 0; +int macho_offset = 0; + +int load_object(const char *filename, struct target_pt_regs * regs, void ** mh); +void qerror(const char *format, ...); +#ifdef TARGET_I386 +typedef struct mach_i386_thread_state { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int esp; + unsigned int ss; + unsigned int eflags; + unsigned int eip; + unsigned int cs; + unsigned int ds; + unsigned int es; + unsigned int fs; + unsigned int gs; +} mach_i386_thread_state_t; + +void bswap_i386_thread_state(struct mach_i386_thread_state *ts) +{ + bswap32s((uint32_t*)&ts->eax); + bswap32s((uint32_t*)&ts->ebx); + bswap32s((uint32_t*)&ts->ecx); + bswap32s((uint32_t*)&ts->edx); + bswap32s((uint32_t*)&ts->edi); + bswap32s((uint32_t*)&ts->esi); + bswap32s((uint32_t*)&ts->ebp); + bswap32s((uint32_t*)&ts->esp); + bswap32s((uint32_t*)&ts->ss); + bswap32s((uint32_t*)&ts->eflags); + bswap32s((uint32_t*)&ts->eip); + bswap32s((uint32_t*)&ts->cs); + bswap32s((uint32_t*)&ts->ds); + bswap32s((uint32_t*)&ts->es); + bswap32s((uint32_t*)&ts->fs); + bswap32s((uint32_t*)&ts->gs); +} +#define target_thread_state mach_i386_thread_state +#define TARGET_CPU_TYPE CPU_TYPE_I386 +#define TARGET_CPU_NAME "i386" +#endif + +#ifdef TARGET_PPC +struct mach_ppc_thread_state { + unsigned int srr0; /* Instruction address register (PC) */ + unsigned int srr1; /* Machine state register (supervisor) */ + unsigned int r0; + unsigned int r1; + unsigned int r2; + unsigned int r3; + unsigned int r4; + unsigned int r5; + unsigned int r6; + unsigned int r7; + unsigned int r8; + unsigned int r9; + unsigned int r10; + unsigned int r11; + unsigned int r12; + unsigned int r13; + unsigned int r14; + unsigned int r15; + unsigned int r16; + unsigned int r17; + unsigned int r18; + unsigned int r19; + unsigned int r20; + unsigned int r21; + unsigned int r22; + unsigned int r23; + unsigned int r24; + unsigned int r25; + unsigned int r26; + unsigned int r27; + unsigned int r28; + unsigned int r29; + unsigned int r30; + unsigned int r31; + + unsigned int cr; /* Condition register */ + unsigned int xer; /* User's integer exception register */ + unsigned int lr; /* Link register */ + unsigned int ctr; /* Count register */ + unsigned int mq; /* MQ register (601 only) */ + + unsigned int vrsave; /* Vector Save Register */ +}; + +void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts) +{ + bswap32s((uint32_t*)&ts->srr0); + bswap32s((uint32_t*)&ts->srr1); + bswap32s((uint32_t*)&ts->r0); + bswap32s((uint32_t*)&ts->r1); + bswap32s((uint32_t*)&ts->r2); + bswap32s((uint32_t*)&ts->r3); + bswap32s((uint32_t*)&ts->r4); + bswap32s((uint32_t*)&ts->r5); + bswap32s((uint32_t*)&ts->r6); + bswap32s((uint32_t*)&ts->r7); + bswap32s((uint32_t*)&ts->r8); + bswap32s((uint32_t*)&ts->r9); + bswap32s((uint32_t*)&ts->r10); + bswap32s((uint32_t*)&ts->r11); + bswap32s((uint32_t*)&ts->r12); + bswap32s((uint32_t*)&ts->r13); + bswap32s((uint32_t*)&ts->r14); + bswap32s((uint32_t*)&ts->r15); + bswap32s((uint32_t*)&ts->r16); + bswap32s((uint32_t*)&ts->r17); + bswap32s((uint32_t*)&ts->r18); + bswap32s((uint32_t*)&ts->r19); + bswap32s((uint32_t*)&ts->r20); + bswap32s((uint32_t*)&ts->r21); + bswap32s((uint32_t*)&ts->r22); + bswap32s((uint32_t*)&ts->r23); + bswap32s((uint32_t*)&ts->r24); + bswap32s((uint32_t*)&ts->r25); + bswap32s((uint32_t*)&ts->r26); + bswap32s((uint32_t*)&ts->r27); + bswap32s((uint32_t*)&ts->r28); + bswap32s((uint32_t*)&ts->r29); + bswap32s((uint32_t*)&ts->r30); + bswap32s((uint32_t*)&ts->r31); + + bswap32s((uint32_t*)&ts->cr); + bswap32s((uint32_t*)&ts->xer); + bswap32s((uint32_t*)&ts->lr); + bswap32s((uint32_t*)&ts->ctr); + bswap32s((uint32_t*)&ts->mq); + + bswap32s((uint32_t*)&ts->vrsave); +} + +#define target_thread_state mach_ppc_thread_state +#define TARGET_CPU_TYPE CPU_TYPE_POWERPC +#define TARGET_CPU_NAME "PowerPC" +#endif + +struct target_thread_command { + unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */ + unsigned long cmdsize; /* total size of this command */ + unsigned long flavor; /* flavor of thread state */ + unsigned long count; /* count of longs in thread state */ + struct target_thread_state state; /* thread state for this flavor */ +}; + +void bswap_tc(struct target_thread_command *tc) +{ + bswap32s((uint32_t*)(&tc->flavor)); + bswap32s((uint32_t*)&tc->count); +#if defined(TARGET_I386) + bswap_i386_thread_state(&tc->state); +#elif defined(TARGET_PPC) + bswap_ppc_thread_state(&tc->state); +#else +# error unknown TARGET_CPU_TYPE +#endif +} + +void bswap_mh(struct mach_header *mh) +{ + bswap32s((uint32_t*)(&mh->magic)); + bswap32s((uint32_t*)&mh->cputype); + bswap32s((uint32_t*)&mh->cpusubtype); + bswap32s((uint32_t*)&mh->filetype); + bswap32s((uint32_t*)&mh->ncmds); + bswap32s((uint32_t*)&mh->sizeofcmds); + bswap32s((uint32_t*)&mh->flags); +} + +void bswap_lc(struct load_command *lc) +{ + bswap32s((uint32_t*)&lc->cmd); + bswap32s((uint32_t*)&lc->cmdsize); +} + + +void bswap_fh(struct fat_header *fh) +{ + bswap32s((uint32_t*)&fh->magic); + bswap32s((uint32_t*)&fh->nfat_arch); +} + +void bswap_fa(struct fat_arch *fa) +{ + bswap32s((uint32_t*)&fa->cputype); + bswap32s((uint32_t*)&fa->cpusubtype); + bswap32s((uint32_t*)&fa->offset); + bswap32s((uint32_t*)&fa->size); + bswap32s((uint32_t*)&fa->align); +} + +void bswap_segcmd(struct segment_command *sc) +{ + bswap32s((uint32_t*)&sc->vmaddr); + bswap32s((uint32_t*)&sc->vmsize); + bswap32s((uint32_t*)&sc->fileoff); + bswap32s((uint32_t*)&sc->filesize); + bswap32s((uint32_t*)&sc->maxprot); + bswap32s((uint32_t*)&sc->initprot); + bswap32s((uint32_t*)&sc->nsects); + bswap32s((uint32_t*)&sc->flags); +} + +void bswap_symtabcmd(struct symtab_command *stc) +{ + bswap32s((uint32_t*)&stc->cmd); + bswap32s((uint32_t*)&stc->cmdsize); + bswap32s((uint32_t*)&stc->symoff); + bswap32s((uint32_t*)&stc->nsyms); + bswap32s((uint32_t*)&stc->stroff); + bswap32s((uint32_t*)&stc->strsize); +} + +void bswap_sym(struct nlist *n) +{ + bswap32s((uint32_t*)&n->n_un.n_strx); + bswap16s((uint16_t*)&n->n_desc); + bswap32s((uint32_t*)&n->n_value); +} + +int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap) +{ + int entry; + if(need_bswap) + bswap_tc(tc); +#if defined(TARGET_I386) + entry = tc->state.eip; + DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n", + tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp, + tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es, + tc->state.fs, tc->state.gs ); +#define reg_copy(reg) regs->reg = tc->state.reg + if(regs) + { + reg_copy(eax); + reg_copy(ebx); + reg_copy(ecx); + reg_copy(edx); + + reg_copy(edi); + reg_copy(esi); + + reg_copy(ebp); + reg_copy(esp); + + reg_copy(eflags); + reg_copy(eip); + /* + reg_copy(ss); + reg_copy(cs); + reg_copy(ds); + reg_copy(es); + reg_copy(fs); + reg_copy(gs);*/ + } +#undef reg_copy +#elif defined(TARGET_PPC) + entry = tc->state.srr0; +#endif + DPRINTF("load_thread: entry 0x%x\n", entry); + return entry; +} + +int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap) +{ + int size; + char * dylinker_name; + size = dc->cmdsize - sizeof(struct dylinker_command); + + if(need_bswap) + dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc); + else + dylinker_name = (char*)((dc->name.offset)+(int)dc); + +#ifdef OVERRIDE_DYLINKER + dylinker_name = DYLINKER_NAME; +#else + if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1) + qerror("can't allocate the new dylinker name\n"); +#endif + + DPRINTF("dylinker_name %s\n", dylinker_name); + return load_object(dylinker_name, NULL, NULL); +} + +int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide) +{ + unsigned long addr = sc->vmaddr; + unsigned long size = sc->filesize; + unsigned long error = 0; + + if(need_bswap) + bswap_segcmd(sc); + + if(sc->vmaddr == 0) + { + DPRINTF("load_segment: sc->vmaddr == 0 returning\n"); + return -1; + } + + if (strcmp(sc->segname, "__PAGEZERO") == 0) + { + DPRINTF("load_segment: __PAGEZERO returning\n"); + return -1; + } + + /* Right now mmap memory */ + /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */ + DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide); + + if(sc->filesize > 0) + { + int opt = 0; + + if(fixed) + opt |= MAP_FIXED; + + DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide); + + addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff); + + if(addr==-1) + qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); + + error = addr-sc->vmaddr; + } + else + { + addr = sc->vmaddr+slide; + error = slide; + } + + if(sc->vmsize > sc->filesize) + { + addr += sc->filesize; + size = sc->vmsize-sc->filesize; + addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if(addr==-1) + qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); + } + + return error; +} + +void *load_data(int fd, long offset, unsigned int size) +{ + char *data; + + data = malloc(size); + if (!data) + return NULL; + lseek(fd, offset, SEEK_SET); + if (read(fd, data, size) != size) { + free(data); + return NULL; + } + return data; +} + +/* load a mach-o object file */ +int load_object(const char *filename, struct target_pt_regs * regs, void ** mh) +{ + int need_bswap = 0; + int entry_point = 0; + int dyld_entry_point = 0; + int slide, mmapfixed; + int fd; + struct load_command *lcmds, *lc; + int is_fat = 0; + unsigned int i, magic; + int mach_hdr_pos = 0; + struct mach_header mach_hdr; + + /* for symbol lookup whith -d flag. */ + struct symtab_command * symtabcmd = 0; + struct nlist_extended *symtab, *sym; + struct nlist *symtab_std, *syment; + char *strtab; + + fd = open(filename, O_RDONLY); + if (fd < 0) + qerror("can't open file '%s'", filename); + + /* Read magic header. */ + if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) + qerror("unable to read Magic of '%s'", filename); + + /* Check Mach identification. */ + if(magic == MH_MAGIC) + { + is_fat = 0; + need_bswap = 0; + } else if (magic == MH_CIGAM) + { + is_fat = 0; + need_bswap = 1; + } else if (magic == FAT_MAGIC) + { + is_fat = 1; + need_bswap = 0; + } else if (magic == FAT_CIGAM) + { + is_fat = 1; + need_bswap = 1; + } + else + qerror("Not a Mach-O file.", filename); + + DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]"); + if(is_fat) + { + int found = 0; + struct fat_header fh; + struct fat_arch *fa; + + lseek(fd, 0, SEEK_SET); + + /* Read Fat header. */ + if (read(fd, &fh, sizeof (fh)) != sizeof (fh)) + qerror("unable to read file header"); + + if(need_bswap) + bswap_fh(&fh); + + /* Read Fat Arch. */ + fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch); + + if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch) + qerror("unable to read file header"); + + for( i = 0; i < fh.nfat_arch; i++, fa++) + { + if(need_bswap) + bswap_fa(fa); + if(fa->cputype == TARGET_CPU_TYPE) + { + mach_hdr_pos = fa->offset; + lseek(fd, mach_hdr_pos, SEEK_SET); + + /* Read Mach header. */ + + if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header)) + qerror("unable to read file header"); + + if(mach_hdr.magic == MH_MAGIC) + need_bswap = 0; + else if (mach_hdr.magic == MH_CIGAM) + need_bswap = 1; + else + qerror("Invalid mach header in Fat Mach-O File"); + found = 1; + break; + } + } + if(!found) + qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME); + } + else + { + lseek(fd, 0, SEEK_SET); + /* Read Mach header */ + if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr)) + qerror("%s: unable to read file header", filename); + } + + if(need_bswap) + bswap_mh(&mach_hdr); + + if ((mach_hdr.cputype) != TARGET_CPU_TYPE) + qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME); + + + switch(mach_hdr.filetype) + { + case MH_EXECUTE: break; + case MH_FVMLIB: + case MH_DYLIB: + case MH_DYLINKER: break; + default: + qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype); + } + + /* read segment headers */ + lcmds = malloc(mach_hdr.sizeofcmds); + + if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds) + qerror("%s: unable to read load_command", filename); + slide = 0; + mmapfixed = 0; + for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++) + { + + if(need_bswap) + bswap_lc(lc); + switch(lc->cmd) + { + case LC_SEGMENT: + /* The main_exe can't be relocated */ + if(mach_hdr.filetype == MH_EXECUTE) + mmapfixed = 1; + + slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide); + + /* other segment must be mapped according to slide exactly, if load_segment did something */ + if(slide != -1) + mmapfixed = 1; + else + slide = 0; /* load_segment didn't map the segment */ + + if(mach_hdr.filetype == MH_EXECUTE && slide != 0) + qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide); + + if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0) + { + /* Text section */ + if(mach_hdr.filetype == MH_EXECUTE) + { + /* return the mach_header */ + *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide); + } + else + { + /* it is dyld save the section for gdb, we will be interested in dyld symbol + while debuging */ + macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide); + macho_offset = slide; + } + } + break; + case LC_LOAD_DYLINKER: + dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap ); + break; + case LC_LOAD_DYLIB: + /* dyld will do that for us */ + break; + case LC_THREAD: + case LC_UNIXTHREAD: + { + struct target_pt_regs * _regs; + if(mach_hdr.filetype == MH_DYLINKER) + _regs = regs; + else + _regs = 0; + entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap ); + } + break; + case LC_SYMTAB: + /* Save the symtab and strtab */ + symtabcmd = (struct symtab_command *)lc; + break; + case LC_ID_DYLINKER: + case LC_ID_DYLIB: + case LC_UUID: + case LC_DYSYMTAB: + case LC_TWOLEVEL_HINTS: + case LC_PREBIND_CKSUM: + case LC_SUB_LIBRARY: + break; + default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename); + } + lc = (struct load_command*)((int)(lc)+(lc->cmdsize)); + } + + if(symtabcmd) + { + if(need_bswap) + bswap_symtabcmd(symtabcmd); + + symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist)); + strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize); + + symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms); + + if(need_bswap) + { + for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++) + bswap_sym(syment); + } + + for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++) + { + struct nlist *sym_follow, *sym_next = 0; + unsigned int j; + memset(sym, 0, sizeof(*sym)); + + sym->n_type = syment->n_type; + if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */ + continue; + + memcpy(sym, syment, sizeof(*syment)); + + /* Find the following symbol in order to get the current symbol size */ + for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) { + if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value)) + continue; + if(!sym_next) { + sym_next = sym_follow; + continue; + } + if(!(sym_next->n_value > sym_follow->n_value)) + continue; + sym_next = sym_follow; + } + if(sym_next) + sym->st_size = sym_next->n_value - sym->st_value; + else + sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */ + + sym->st_value += slide; + } + + free((void*)symtab_std); + + { + DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms); + struct syminfo *s; + s = malloc(sizeof(*s)); + s->disas_symtab = symtab; + s->disas_strtab = strtab; + s->disas_num_syms = symtabcmd->nsyms; + s->next = syminfos; + syminfos = s; + } + } + close(fd); + if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point) + return dyld_entry_point; + else + return entry_point+slide; +} + +extern unsigned long stack_size; + +unsigned long setup_arg_pages(void * mh, char ** argv, char ** env) +{ + unsigned long stack_base, error, size; + int i; + int * stack; + int argc, envc; + + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ + size = stack_size; + + error = target_mmap(0, + size + qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (error == -1) + qerror("stk mmap"); + + /* we reserve one extra page at the top of the stack as guard */ + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); + + stack_base = error + size; + stack = (void*)stack_base; +/* + * | STRING AREA | + * +-------------+ + * | 0 | +* +-------------+ + * | apple[n] | + * +-------------+ + * : + * +-------------+ + * | apple[0] | + * +-------------+ + * | 0 | + * +-------------+ + * | env[n] | + * +-------------+ + * : + * : + * +-------------+ + * | env[0] | + * +-------------+ + * | 0 | + * +-------------+ + * | arg[argc-1] | + * +-------------+ + * : + * : + * +-------------+ + * | arg[0] | + * +-------------+ + * | argc | + * +-------------+ + * sp-> | mh | address of where the a.out's file offset 0 is in memory + * +-------------+ +*/ + /* Construct the stack Stack grows down */ + stack--; + + /* XXX: string should go up there */ + + *stack = 0; + stack--; + + /* Push the absolute path of our executable */ + DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]); + stl(stack, (int) argv[0]); + + stack--; + + stl(stack, 0); + stack--; + + /* Get envc */ + for(envc = 0; env[envc]; envc++); + + for(i = envc-1; i >= 0; i--) + { + DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]); + stl(stack, (int)env[i]); + stack--; + + /* XXX: remove that when string will be on top of the stack */ + page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID); + } + + /* Add on the stack the interp_prefix choosen if so */ + if(interp_prefix[0]) + { + char *dyld_root; + asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix); + page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID); + + stl(stack, (int)dyld_root); + stack--; + } + +#ifdef DONT_USE_DYLD_SHARED_MAP + { + char *shared_map_mode; + asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid"); + page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID); + + stl(stack, (int)shared_map_mode); + stack--; + } +#endif + +#ifdef ACTIVATE_DYLD_TRACE + char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes", + "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes", + "DYLD_PRINT_INITIALIZERS=yes", + "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" }; + + char ** extra_env = malloc(sizeof(extra_env_static)); + bcopy(extra_env_static, extra_env, sizeof(extra_env_static)); + page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID); + + for(i = 0; i<9; i++) + { + DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]); + stl(stack, (int) extra_env[i]); + stack--; + } +#endif + + stl(stack, 0); + stack--; + + /* Get argc */ + for(argc = 0; argv[argc]; argc++); + + for(i = argc-1; i >= 0; i--) + { + DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]); + stl(stack, (int) argv[i]); + stack--; + + /* XXX: remove that when string will be on top of the stack */ + page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID); + } + + DPRINTF("pushing argc %d \n", argc); + stl(stack, argc); + stack--; + + DPRINTF("pushing mh 0x%x \n", (int)mh); + stl(stack, (int) mh); + + /* Stack points on the mh */ + return (unsigned long)stack; +} + +int mach_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs) +{ + int entrypoint, stack; + void * mh; /* the Mach Header that will be used by dyld */ + + DPRINTF("mach_exec at 0x%x\n", (int)mach_exec); + + entrypoint = load_object(filename, regs, &mh); + stack = setup_arg_pages(mh, argv, envp); +#if defined(TARGET_I386) + regs->eip = entrypoint; + regs->esp = stack; +#elif defined(TARGET_PPC) + regs->nip = entrypoint; + regs->gpr[1] = stack; +#endif + DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh); + + if(!entrypoint) + qerror("%s: no entry point!\n", filename); + + return 0; +} diff --git a/darwin-user/main.c b/darwin-user/main.c new file mode 100644 index 0000000000..259aab324e --- /dev/null +++ b/darwin-user/main.c @@ -0,0 +1,922 @@ +/* + * qemu user main + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2006 Pierre d'Herbemont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include <sys/syscall.h> +#include <sys/mman.h> + +#include "qemu.h" + +#define DEBUG_LOGFILE "/tmp/qemu.log" + +#ifdef __APPLE__ +#include <crt_externs.h> +# define environ (*_NSGetEnviron()) +#endif + +#include <mach/mach_init.h> +#include <mach/vm_map.h> + +const char *interp_prefix = ""; + +asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000"); + +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + we allocate a bigger stack. Need a better solution, for example + by remapping the process stack directly at the right place */ +unsigned long stack_size = 512 * 1024; + +void qerror(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void cpu_outb(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); +} + +void cpu_outw(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); +} + +void cpu_outl(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); +} + +int cpu_inb(CPUState *env, int addr) +{ + fprintf(stderr, "inb: port=0x%04x\n", addr); + return 0; +} + +int cpu_inw(CPUState *env, int addr) +{ + fprintf(stderr, "inw: port=0x%04x\n", addr); + return 0; +} + +int cpu_inl(CPUState *env, int addr) +{ + fprintf(stderr, "inl: port=0x%04x\n", addr); + return 0; +} + +int cpu_get_pic_interrupt(CPUState *env) +{ + return -1; +} +#ifdef TARGET_PPC + +static inline uint64_t cpu_ppc_get_tb (CPUState *env) +{ + /* TO FIX */ + return 0; +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) +{ + /* TO FIX */ +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + /* TO FIX */ + return -1; +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + /* TO FIX */ +} + +void cpu_loop(CPUPPCState *env) +{ + int trapnr; + uint32_t ret; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_ppc_exec(env); + if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && + trapnr != EXCP_TRACE) { + if (loglevel > 0) { + cpu_dump_state(env, logfile, fprintf, 0); + } + } + switch(trapnr) { + case EXCP_NONE: + break; + case EXCP_SYSCALL_USER: + /* system call */ + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) + ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]*/); + else if(((int)env->gpr[0])<0) + ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]); + else + ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]); + + /* Unix syscall error signaling */ + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) + { + if( (int)ret < 0 ) + env->nip += 0; + else + env->nip += 4; + } + + /* Return value */ + env->gpr[3] = ret; + break; + case EXCP_RESET: + /* Should not happen ! */ + fprintf(stderr, "RESET asked... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + abort(); + case EXCP_MACHINE_CHECK: + fprintf(stderr, "Machine check exeption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_OBJERR; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + case EXCP_DSI: +#ifndef DAR +/* To deal with multiple qemu header version as host for the darwin-user code */ +# define DAR SPR_DAR +#endif + fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); + if (loglevel) { + fprintf(logfile, "Invalid data memory access: 0x%08x\n", + env->spr[DAR]); + } + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + + info.si_addr = (void*)env->nip; + queue_signal(info.si_signo, &info); + break; + case EXCP_ISI: + fprintf(stderr, "Invalid instruction fetch\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction fetch\n"); + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_EXTERNAL: + /* Should not happen ! */ + fprintf(stderr, "External interruption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "External interruption... Stop emulation\n"); + abort(); + case EXCP_ALIGN: + fprintf(stderr, "Invalid unaligned memory access\n"); + if (loglevel) + fprintf(logfile, "Invalid unaligned memory access\n"); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_PROGRAM: + switch (env->error_code & ~0xF) { + case EXCP_FP: + fprintf(stderr, "Program exception\n"); + if (loglevel) + fprintf(logfile, "Program exception\n"); + /* Set FX */ + env->fpscr[7] |= 0x8; + /* Finally, update FEX */ + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) + env->fpscr[7] |= 0x4; + info.si_signo = SIGFPE; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_FP_OX: + info.si_code = FPE_FLTOVF; + break; + case EXCP_FP_UX: + info.si_code = FPE_FLTUND; + break; + case EXCP_FP_ZX: + case EXCP_FP_VXZDZ: + info.si_code = FPE_FLTDIV; + break; + case EXCP_FP_XX: + info.si_code = FPE_FLTRES; + break; + case EXCP_FP_VXSOFT: + info.si_code = FPE_FLTINV; + break; + case EXCP_FP_VXNAN: + case EXCP_FP_VXISI: + case EXCP_FP_VXIDI: + case EXCP_FP_VXIMZ: + case EXCP_FP_VXVC: + case EXCP_FP_VXSQRT: + case EXCP_FP_VXCVI: + info.si_code = FPE_FLTSUB; + break; + default: + fprintf(stderr, "Unknown floating point exception " + "(%02x)\n", env->error_code); + if (loglevel) { + fprintf(logfile, "Unknown floating point exception " + "(%02x)\n", env->error_code & 0xF); + } + } + break; + case EXCP_INVAL: + fprintf(stderr, "Invalid instruction\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_INVAL_INVAL: + info.si_code = ILL_ILLOPC; + break; + case EXCP_INVAL_LSWX: + info.si_code = ILL_ILLOPN; + break; + case EXCP_INVAL_SPR: + info.si_code = ILL_PRVREG; + break; + case EXCP_INVAL_FP: + info.si_code = ILL_COPROC; + break; + default: + fprintf(stderr, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + if (loglevel) { + fprintf(logfile, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + } + info.si_code = ILL_ILLADR; + break; + } + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + break; + case EXCP_PRIV: + fprintf(stderr, "Privilege violation\n"); + if (loglevel) + fprintf(logfile, "Privilege violation\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_PRIV_OPC: + info.si_code = ILL_PRVOPC; + break; + case EXCP_PRIV_REG: + info.si_code = ILL_PRVREG; + break; + default: + fprintf(stderr, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); + info.si_code = ILL_PRVOPC; + break; + } + break; + case EXCP_TRAP: + fprintf(stderr, "Tried to call a TRAP\n"); + if (loglevel) + fprintf(logfile, "Tried to call a TRAP\n"); + abort(); + default: + /* Should not happen ! */ + fprintf(stderr, "Unknown program exception (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Unknwon program exception (%02x)\n", + env->error_code); + } + abort(); + } + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_NO_FP: + fprintf(stderr, "No floating point allowed\n"); + if (loglevel) + fprintf(logfile, "No floating point allowed\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_COPROC; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_DECR: + /* Should not happen ! */ + fprintf(stderr, "Decrementer exception\n"); + if (loglevel) + fprintf(logfile, "Decrementer exception\n"); + abort(); + case EXCP_TRACE: + /* Pass to gdb: we use this to trace execution */ + gdb_handlesig (env, SIGTRAP); + break; + case EXCP_FP_ASSIST: + /* Should not happen ! */ + fprintf(stderr, "Floating point assist exception\n"); + if (loglevel) + fprintf(logfile, "Floating point assist exception\n"); + abort(); + case EXCP_MTMSR: + /* We reloaded the msr, just go on */ + if (msr_pr == 0) { + fprintf(stderr, "Tried to go into supervisor mode !\n"); + if (loglevel) + fprintf(logfile, "Tried to go into supervisor mode !\n"); + abort(); + } + break; + case EXCP_BRANCH: + /* We stopped because of a jump... */ + break; + case EXCP_INTERRUPT: + /* Don't know why this should ever happen... */ + fprintf(stderr, "EXCP_INTERRUPT\n"); + break; + case EXCP_DEBUG: + gdb_handlesig (env, SIGTRAP); + break; + default: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + if (loglevel) { + fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " + "0x%02x - aborting\n", trapnr, env->error_code); + } + abort(); + } + process_pending_signals(env); + } +} +#endif + + +#ifdef TARGET_I386 + +/***********************************************************/ +/* CPUX86 core interface */ + +uint64_t cpu_get_tsc(CPUX86State *env) +{ + return cpu_get_real_ticks(); +} + +void +write_dt(void *ptr, unsigned long addr, unsigned long limit, + int flags) +{ + unsigned int e1, e2; + e1 = (addr << 16) | (limit & 0xffff); + e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); + e2 |= flags; + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + unsigned long addr, unsigned int sel) +{ + unsigned int e1, e2; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +#define GDT_TABLE_SIZE 14 +#define LDT_TABLE_SIZE 15 +#define IDT_TABLE_SIZE 256 +#define TSS_SIZE 104 +uint64_t gdt_table[GDT_TABLE_SIZE]; +uint64_t ldt_table[LDT_TABLE_SIZE]; +uint64_t idt_table[IDT_TABLE_SIZE]; +uint32_t tss[TSS_SIZE]; + +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate(idt_table + n, 0, dpl, 0, 0); +} + +/* ABI convention: after a syscall if there was an error the CF flag is set */ +static inline set_error(CPUX86State *env, int ret) +{ + if(ret<0) + env->eflags = env->eflags | 0x1; + else + env->eflags &= ~0x1; + env->regs[R_EAX] = ret; +} + +void cpu_loop(CPUX86State *env) +{ + int trapnr; + int ret; + uint8_t *pc; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_x86_exec(env); + uint32_t *params = (uint32_t *)env->regs[R_ESP]; + switch(trapnr) { + case 0x79: /* Our commpage hack back door exit is here */ + do_commpage(env, env->eip, *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)); + break; + case 0x81: /* mach syscall */ + { + ret = do_mach_syscall(env, env->regs[R_EAX], + *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)); + set_error(env, ret); + break; + } + case 0x90: /* unix backdoor */ + { + /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/ + int saved_stack = env->regs[R_ESP]; + env->regs[R_ESP] = env->regs[R_ECX]; + + ret = do_unix_syscall(env, env->regs[R_EAX]); + + env->regs[R_ECX] = env->regs[R_ESP]; + env->regs[R_ESP] = saved_stack; + + set_error(env, ret); + break; + } + case 0x80: /* unix syscall */ + { + ret = do_unix_syscall(env, env->regs[R_EAX]/*, + *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)*/); + set_error(env, ret); + break; + } + case 0x82: /* thread syscall */ + { + ret = do_thread_syscall(env, env->regs[R_EAX], + *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)); + set_error(env, ret); + break; + } + case EXCP0B_NOSEG: + case EXCP0C_STACK: + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_NOOP; + info.si_addr = 0; + gdb_handlesig (env, SIGBUS); + queue_signal(info.si_signo, &info); + break; + case EXCP0D_GPF: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_NOOP; + info.si_addr = 0; + gdb_handlesig (env, SIGSEGV); + queue_signal(info.si_signo, &info); + break; + case EXCP0E_PAGE: + info.si_signo = SIGSEGV; + info.si_errno = 0; + if (!(env->error_code & 1)) + info.si_code = SEGV_MAPERR; + else + info.si_code = SEGV_ACCERR; + info.si_addr = (void*)env->cr[2]; + gdb_handlesig (env, SIGSEGV); + queue_signal(info.si_signo, &info); + break; + case EXCP00_DIVZ: + /* division by zero */ + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = FPE_INTDIV; + info.si_addr = (void*)env->eip; + gdb_handlesig (env, SIGFPE); + queue_signal(info.si_signo, &info); + break; + case EXCP01_SSTP: + case EXCP03_INT3: + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void*)env->eip; + gdb_handlesig (env, SIGTRAP); + queue_signal(info.si_signo, &info); + break; + case EXCP04_INTO: + case EXCP05_BOUND: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_NOOP; + info.si_addr = 0; + gdb_handlesig (env, SIGSEGV); + queue_signal(info.si_signo, &info); + break; + case EXCP06_ILLOP: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPN; + info.si_addr = (void*)env->eip; + gdb_handlesig (env, SIGILL); + queue_signal(info.si_signo, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + pc = (void*)(env->segs[R_CS].base + env->eip); + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + (long)pc, trapnr); + abort(); + } + process_pending_signals(env); + } +} +#endif + +void usage(void) +{ + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" + "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" + "Darwin CPU emulator (compiled for %s emulation)\n" + "\n" + "-h print this help\n" + "-L path set the elf interpreter prefix (default=%s)\n" + "-s size set the stack size in bytes (default=%ld)\n" + "\n" + "debug options:\n" +#ifdef USE_CODE_COPY + "-no-code-copy disable code copy acceleration\n" +#endif + "-d options activate log (logfile=%s)\n" + "-g wait for gdb on port 1234\n" + "-p pagesize set the host page size to 'pagesize'\n", + TARGET_ARCH, + interp_prefix, + stack_size, + DEBUG_LOGFILE); + _exit(1); +} + +/* XXX: currently only used for async signals (see signal.c) */ +CPUState *global_env; +/* used only if single thread */ +CPUState *cpu_single_env = NULL; + +/* used to free thread contexts */ +TaskState *first_task_state; + +int main(int argc, char **argv) +{ + const char *filename; + struct target_pt_regs regs1, *regs = ®s1; + TaskState ts1, *ts = &ts1; + CPUState *env; + int optind; + short use_gdbstub = 0; + const char *r; + + if (argc <= 1) + usage(); + + /* init debug */ + cpu_set_log_filename(DEBUG_LOGFILE); + + optind = 1; + for(;;) { + if (optind >= argc) + break; + r = argv[optind]; + if (r[0] != '-') + break; + optind++; + r++; + if (!strcmp(r, "-")) { + break; + } else if (!strcmp(r, "d")) { + int mask; + CPULogItem *item; + + if (optind >= argc) + break; + + r = argv[optind++]; + mask = cpu_str_to_log_mask(r); + if (!mask) { + printf("Log items (comma separated):\n"); + for(item = cpu_log_items; item->mask != 0; item++) { + printf("%-10s %s\n", item->name, item->help); + } + exit(1); + } + cpu_set_log(mask); + } else if (!strcmp(r, "s")) { + r = argv[optind++]; + stack_size = strtol(r, (char **)&r, 0); + if (stack_size <= 0) + usage(); + if (*r == 'M') + stack_size *= 1024 * 1024; + else if (*r == 'k' || *r == 'K') + stack_size *= 1024; + } else if (!strcmp(r, "L")) { + interp_prefix = argv[optind++]; + } else if (!strcmp(r, "p")) { + qemu_host_page_size = atoi(argv[optind++]); + if (qemu_host_page_size == 0 || + (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { + fprintf(stderr, "page size must be a power of two\n"); + exit(1); + } + } else + if (!strcmp(r, "g")) { + use_gdbstub = 1; + } else +#ifdef USE_CODE_COPY + if (!strcmp(r, "no-code-copy")) { + code_copy_enabled = 0; + } else +#endif + { + usage(); + } + } + if (optind >= argc) + usage(); + filename = argv[optind]; + + /* Zero out regs */ + memset(regs, 0, sizeof(struct target_pt_regs)); + +#if 0 + /* Scan interp_prefix dir for replacement files. */ + init_paths(interp_prefix); +#endif + + /* NOTE: we need to init the CPU at this stage to get + qemu_host_page_size */ + env = cpu_init(); + + printf("Starting %s with qemu\n----------------\n", filename); + + commpage_init(); + + if (mach_exec(filename, argv+optind, environ, regs) != 0) { + printf("Error loading %s\n", filename); + _exit(1); + } + + syscall_init(); + signal_init(); + global_env = env; + + /* build Task State */ + memset(ts, 0, sizeof(TaskState)); + env->opaque = ts; + ts->used = 1; + env->user_mode_only = 1; + +#if defined(TARGET_I386) + cpu_x86_set_cpl(env, 3); + + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; + env->hflags |= HF_PE_MASK; + + if (env->cpuid_features & CPUID_SSE) { + env->cr[4] |= CR4_OSFXSR_MASK; + env->hflags |= HF_OSFXSR_MASK; + } + + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags |= IF_MASK; + + /* darwin register setup */ + env->regs[R_EAX] = regs->eax; + env->regs[R_EBX] = regs->ebx; + env->regs[R_ECX] = regs->ecx; + env->regs[R_EDX] = regs->edx; + env->regs[R_ESI] = regs->esi; + env->regs[R_EDI] = regs->edi; + env->regs[R_EBP] = regs->ebp; + env->regs[R_ESP] = regs->esp; + env->eip = regs->eip; + + /* Darwin LDT setup */ + /* 2 - User code segment + 3 - User data segment + 4 - User cthread */ + bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0])); + env->ldt.base = (uint32_t) ldt_table; + env->ldt.limit = sizeof(ldt_table) - 1; + + write_dt(ldt_table + 2, 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); + write_dt(ldt_table + 3, 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + write_dt(ldt_table + 4, 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + + /* Darwin GDT setup. + * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86, + now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */ + bzero(gdt_table, sizeof(gdt_table)); + env->gdt.base = (uint32_t)gdt_table; + env->gdt.limit = sizeof(gdt_table) - 1; + + /* Set up a back door to handle sysenter syscalls (unix) */ + char * syscallbackdoor = malloc(64); + page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID); + + int i = 0; + syscallbackdoor[i++] = 0xcd; + syscallbackdoor[i++] = 0x90; /* int 0x90 */ + syscallbackdoor[i++] = 0x0F; + syscallbackdoor[i++] = 0x35; /* sysexit */ + + /* Darwin sysenter/sysexit setup */ + env->sysenter_cs = 0x1; //XXX + env->sysenter_eip = (int)syscallbackdoor; + env->sysenter_esp = (int)malloc(64); + + /* Darwin TSS setup + This must match up with GDT[4] */ + env->tr.base = (uint32_t) tss; + env->tr.limit = sizeof(tss) - 1; + env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT); + stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment + + /* Darwin interrupt setup */ + bzero(idt_table, sizeof(idt_table)); + env->idt.base = (uint32_t) idt_table; + env->idt.limit = sizeof(idt_table) - 1; + set_idt(0, 0); + set_idt(1, 0); + set_idt(2, 0); + set_idt(3, 3); + set_idt(4, 3); + set_idt(5, 3); + set_idt(6, 0); + set_idt(7, 0); + set_idt(8, 0); + set_idt(9, 0); + set_idt(10, 0); + set_idt(11, 0); + set_idt(12, 0); + set_idt(13, 0); + set_idt(14, 0); + set_idt(15, 0); + set_idt(16, 0); + set_idt(17, 0); + set_idt(18, 0); + set_idt(19, 0); + /* Syscalls are done via + int 0x80 (unix) (rarely used) + int 0x81 (mach) + int 0x82 (thread) + int 0x83 (diag) (not handled here) + sysenter/sysexit (unix) -> we redirect that to int 0x90 */ + set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */ + set_idt(0x80, 3); /* Unix Syscall */ + set_idt(0x81, 3); /* Mach Syscalls */ + set_idt(0x82, 3); /* thread Syscalls */ + + set_idt(0x90, 3); /* Unix Syscall backdoor */ + + + cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_FS, __USER_DS); + cpu_x86_load_seg(env, R_GS, __USER_DS); + +#elif defined(TARGET_PPC) + { + int i; + env->nip = regs->nip; + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->gpr[i]; + } + } +#else +#error unsupported target CPU +#endif + + if (use_gdbstub) { + printf("Waiting for gdb Connection on port 1234...\n"); + gdbserver_start (1234); + gdb_handlesig(env, 0); + } + + cpu_loop(env); + /* never exits */ + return 0; +} diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c new file mode 100644 index 0000000000..ada613d361 --- /dev/null +++ b/darwin-user/mmap.c @@ -0,0 +1,411 @@ +/* + * mmap support for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/mman.h> + +#include "qemu.h" + +//#define DEBUG_MMAP + +/* NOTE: all the constants are the HOST ones */ +int target_mprotect(unsigned long start, unsigned long len, int prot) +{ + unsigned long end, host_start, host_end, addr; + int prot1, ret; + +#ifdef DEBUG_MMAP + printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); +#endif + + if ((start & ~TARGET_PAGE_MASK) != 0) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return -EINVAL; + if (len == 0) + return 0; + + host_start = start & qemu_host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + if (start > host_start) { + /* handle host page containing start */ + prot1 = prot; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + if (host_end == host_start + qemu_host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + end = host_end; + } + ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_start += qemu_host_page_size; + } + if (end < host_end) { + prot1 = prot; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size, + prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_end -= qemu_host_page_size; + } + + /* handle the pages in the middle */ + if (host_start < host_end) { + ret = mprotect((void *)host_start, host_end - host_start, prot); + if (ret != 0) + return ret; + } + page_set_flags(start, start + len, prot | PAGE_VALID); + return 0; +} + +/* map an incomplete host page */ +int mmap_frag(unsigned long host_start, + unsigned long start, unsigned long end, + int prot, int flags, int fd, unsigned long offset) +{ + unsigned long host_end, ret, addr; + int prot1, prot_new; + + host_end = host_start + qemu_host_page_size; + + /* get the protection of the target pages outside the mapping */ + prot1 = 0; + for(addr = host_start; addr < host_end; addr++) { + if (addr < start || addr >= end) + prot1 |= page_get_flags(addr); + } + + if (prot1 == 0) { + /* no page was there, so we allocate one */ + ret = (long)mmap((void *)host_start, qemu_host_page_size, prot, + flags | MAP_ANONYMOUS, -1, 0); + if (ret == -1) + return ret; + } + prot1 &= PAGE_BITS; + + prot_new = prot | prot1; + if (!(flags & MAP_ANONYMOUS)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ +#ifndef __APPLE__ + if ((flags & MAP_TYPE) == MAP_SHARED && +#else + if ((flags & MAP_SHARED) && +#endif + (prot & PROT_WRITE)) + return -EINVAL; + + /* adjust protection to be able to read */ + if (!(prot1 & PROT_WRITE)) + mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE); + + /* read the corresponding file data */ + pread(fd, (void *)start, end - start, offset); + + /* put final protection */ + if (prot_new != (prot1 | PROT_WRITE)) + mprotect((void *)host_start, qemu_host_page_size, prot_new); + } else { + /* just update the protection */ + if (prot_new != prot1) { + mprotect((void *)host_start, qemu_host_page_size, prot_new); + } + } + return 0; +} + +/* NOTE: all the constants are the HOST ones */ +long target_mmap(unsigned long start, unsigned long len, int prot, + int flags, int fd, unsigned long offset) +{ + unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) + static unsigned long last_start = 0x40000000; +#endif + +#ifdef DEBUG_MMAP + { + printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", + start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); + if (flags & MAP_FIXED) + printf("MAP_FIXED "); + if (flags & MAP_ANONYMOUS) + printf("MAP_ANON "); +#ifndef MAP_TYPE +# define MAP_TYPE 0x3 +#endif + switch(flags & MAP_TYPE) { + case MAP_PRIVATE: + printf("MAP_PRIVATE "); + break; + case MAP_SHARED: + printf("MAP_SHARED "); + break; + default: + printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); + break; + } + printf("fd=%d offset=%lx\n", fd, offset); + } +#endif + + if (offset & ~TARGET_PAGE_MASK) + return -EINVAL; + + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return start; + host_start = start & qemu_host_page_mask; + + if (!(flags & MAP_FIXED)) { +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) + /* tell the kenel to search at the same place as i386 */ + if (host_start == 0) { + host_start = last_start; + last_start += HOST_PAGE_ALIGN(len); + } +#endif + if (qemu_host_page_size != qemu_real_host_page_size) { + /* NOTE: this code is only for debugging with '-p' option */ + /* reserve a memory area */ + host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; + host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (host_start == -1) + return host_start; + host_end = host_start + host_len; + start = HOST_PAGE_ALIGN(host_start); + end = start + HOST_PAGE_ALIGN(len); + if (start > host_start) + munmap((void *)host_start, start - host_start); + if (end < host_end) + munmap((void *)end, host_end - end); + /* use it as a fixed mapping */ + flags |= MAP_FIXED; + } else { + /* if not fixed, no need to do anything */ + host_offset = offset & qemu_host_page_mask; + host_len = len + offset - host_offset; + start = (long)mmap((void *)host_start, host_len, + prot, flags, fd, host_offset); + if (start == -1) + return start; + /* update start so that it points to the file position at 'offset' */ + if (!(flags & MAP_ANONYMOUS)) + start += offset - host_offset; + goto the_end1; + } + } + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + end = start + len; + host_end = HOST_PAGE_ALIGN(end); + + /* worst case: we cannot map the file because the offset is not + aligned, so we read it */ + if (!(flags & MAP_ANONYMOUS) && + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ +#ifndef __APPLE__ + if ((flags & MAP_TYPE) == MAP_SHARED && +#else + if ((flags & MAP_SHARED) && +#endif + (prot & PROT_WRITE)) + return -EINVAL; + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (retaddr == -1) + return retaddr; + pread(fd, (void *)start, len, offset); + if (!(prot & PROT_WRITE)) { + ret = target_mprotect(start, len, prot); + if (ret != 0) + return ret; + } + goto the_end; + } + + /* handle the start of the mapping */ + if (start > host_start) { + if (host_end == host_start + qemu_host_page_size) { + /* one single host page */ + ret = mmap_frag(host_start, start, end, + prot, flags, fd, offset); + if (ret == -1) + return ret; + goto the_end1; + } + ret = mmap_frag(host_start, start, host_start + qemu_host_page_size, + prot, flags, fd, offset); + if (ret == -1) + return ret; + host_start += qemu_host_page_size; + } + /* handle the end of the mapping */ + if (end < host_end) { + ret = mmap_frag(host_end - qemu_host_page_size, + host_end - qemu_host_page_size, host_end, + prot, flags, fd, + offset + host_end - qemu_host_page_size - start); + if (ret == -1) + return ret; + host_end -= qemu_host_page_size; + } + + /* map the middle (easier) */ + if (host_start < host_end) { + unsigned long offset1; + if (flags & MAP_ANONYMOUS) + offset1 = 0; + else + offset1 = offset + host_start - start; + ret = (long)mmap((void *)host_start, host_end - host_start, + prot, flags, fd, offset1); + if (ret == -1) + return ret; + } + the_end1: + page_set_flags(start, start + len, prot | PAGE_VALID); + the_end: +#ifdef DEBUG_MMAP + printf("target_mmap: ret=0x%lx\n", (long)start); + page_dump(stdout); + printf("\n"); +#endif + return start; +} + +int target_munmap(unsigned long start, unsigned long len) +{ + unsigned long end, host_start, host_end, addr; + int prot, ret; + +#ifdef DEBUG_MMAP + printf("munmap: start=0x%lx len=0x%lx\n", start, len); +#endif + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return -EINVAL; + end = start + len; + host_start = start & qemu_host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + + if (start > host_start) { + /* handle host page containing start */ + prot = 0; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (host_end == host_start + qemu_host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + end = host_end; + } + if (prot != 0) + host_start += qemu_host_page_size; + } + if (end < host_end) { + prot = 0; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (prot != 0) + host_end -= qemu_host_page_size; + } + + /* unmap what we can */ + if (host_start < host_end) { + ret = munmap((void *)host_start, host_end - host_start); + if (ret != 0) + return ret; + } + + page_set_flags(start, start + len, 0); + return 0; +} + +/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED + blocks which have been allocated starting on a host page */ +long target_mremap(unsigned long old_addr, unsigned long old_size, + unsigned long new_size, unsigned long flags, + unsigned long new_addr) +{ +#ifndef __APPLE__ + /* XXX: use 5 args syscall */ + new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); + if (new_addr == -1) + return new_addr; + prot = page_get_flags(old_addr); + page_set_flags(old_addr, old_addr + old_size, 0); + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); + return new_addr; +#else + qerror("target_mremap: unsupported\n"); +#endif + +} + +int target_msync(unsigned long start, unsigned long len, int flags) +{ + unsigned long end; + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (end == start) + return 0; + + start &= qemu_host_page_mask; + return msync((void *)start, end - start, flags); +} + diff --git a/darwin-user/qemu.h b/darwin-user/qemu.h new file mode 100644 index 0000000000..4d7713b500 --- /dev/null +++ b/darwin-user/qemu.h @@ -0,0 +1,179 @@ +#ifndef GEMU_H +#define GEMU_H + +#include "thunk.h" + +#include <signal.h> +#include <string.h> + +#include "cpu.h" + +#include "gdbstub.h" + +typedef siginfo_t target_siginfo_t; +#define target_sigaction sigaction +#ifdef TARGET_I386 +struct target_pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; +struct target_sigcontext { + int sc_onstack; + int sc_mask; + int sc_eax; + int sc_ebx; + int sc_ecx; + int sc_edx; + int sc_edi; + int sc_esi; + int sc_ebp; + int sc_esp; + int sc_ss; + int sc_eflags; + int sc_eip; + int sc_cs; + int sc_ds; + int sc_es; + int sc_fs; + int sc_gs; +}; + +#define __USER_CS (0x17) +#define __USER_DS (0x1F) + +#elif defined(TARGET_PPC) +struct target_pt_regs { + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ +}; + +struct target_sigcontext { + int sc_onstack; /* sigstack state to restore */ + int sc_mask; /* signal mask to restore */ + int sc_ir; /* pc */ + int sc_psw; /* processor status word */ + int sc_sp; /* stack pointer if sc_regs == NULL */ + void *sc_regs; /* (kernel private) saved state */ +}; + +#endif + +typedef struct TaskState { + struct TaskState *next; + int used; /* non zero if used */ + uint8_t stack[0]; +} __attribute__((aligned(16))) TaskState; + +void syscall_init(void); +long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); +long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); +long do_unix_syscall(void *cpu_env, int num); +int do_sigaction(int sig, const struct sigaction *act, + struct sigaction *oact); +int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss); + +void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +void qerror(const char *fmt, ...); + +void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags); + +extern CPUState *global_env; +void cpu_loop(CPUState *env); +void init_paths(const char *prefix); +const char *path(const char *pathname); + +extern int loglevel; +extern FILE *logfile; + +/* commpage.c */ +void commpage_init(); +void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); + +/* signal.c */ +void process_pending_signals(void *cpu_env); +void signal_init(void); +int queue_signal(int sig, target_siginfo_t *info); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +long do_sigreturn(CPUState *env, int num); + +/* machload.c */ +int mach_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs); + +/* mmap.c */ +int target_mprotect(unsigned long start, unsigned long len, int prot); +long target_mmap(unsigned long start, unsigned long len, int prot, + int flags, int fd, unsigned long offset); +int target_munmap(unsigned long start, unsigned long len); +long target_mremap(unsigned long old_addr, unsigned long old_size, + unsigned long new_size, unsigned long flags, + unsigned long new_addr); +int target_msync(unsigned long start, unsigned long len, int flags); + +/* user access */ + +/* XXX: todo protect every memory access */ +#define lock_user(x,y,z) (void*)(x) +#define unlock_user(x,y,z) + +/* Mac OS X ABI arguments processing */ +#ifdef TARGET_I386 +static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env) +{ + uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i); + *i+=4; + return tswap32(*args); +} +static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env) +{ + uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i); + *i+=8; + return tswap64(*args); +} +#elif defined(TARGET_PPC) +static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env) +{ + /* XXX: won't work when args goes on stack after gpr10 */ + uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]); + *i+=4; + return tswap32(args); +} +static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env) +{ + /* XXX: won't work when args goes on stack after gpr10 */ + uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]); + *i+=(8 << 8) + 8; + return tswap64(args); +} +#endif + +#endif diff --git a/darwin-user/signal.c b/darwin-user/signal.c new file mode 100644 index 0000000000..a0b9f89dcc --- /dev/null +++ b/darwin-user/signal.c @@ -0,0 +1,463 @@ +/* + * Emulation of Linux signals + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sys/ucontext.h> + +#ifdef __ia64__ +#undef uc_mcontext +#undef uc_sigmask +#undef uc_stack +#undef uc_link +#endif + +#include <signal.h> + +#include "qemu.h" + +#define DEBUG_SIGNAL + +#define MAX_SIGQUEUE_SIZE 1024 + +struct sigqueue { + struct sigqueue *next; + target_siginfo_t info; +}; + +struct emulated_sigaction { + struct target_sigaction sa; + int pending; /* true if signal is pending */ + struct sigqueue *first; + struct sigqueue info; /* in order to always have memory for the + first signal, we put it here */ +}; + +struct sigaltstack target_sigaltstack_used = { + 0, 0, SA_DISABLE +}; + +static struct emulated_sigaction sigact_table[NSIG]; +static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ +static struct sigqueue *first_free; /* first free siginfo queue entry */ +static int signal_pending; /* non zero if a signal may be pending */ + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc); + + +static inline int host_to_target_signal(int sig) +{ + return sig; +} + +static inline int target_to_host_signal(int sig) +{ + return sig; +} + +/* siginfo conversion */ + + + +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) +{ + +} + +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) +{ + +} + +void signal_init(void) +{ + struct sigaction act; + int i; + + /* set all host signal handlers. ALL signals are blocked during + the handlers to serialize them. */ + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = host_signal_handler; + for(i = 1; i < NSIG; i++) { + sigaction(i, &act, NULL); + } + + memset(sigact_table, 0, sizeof(sigact_table)); + + first_free = &sigqueue_table[0]; + for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) + sigqueue_table[i].next = &sigqueue_table[i + 1]; + sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; +} + +/* signal queue handling */ + +static inline struct sigqueue *alloc_sigqueue(void) +{ + struct sigqueue *q = first_free; + if (!q) + return NULL; + first_free = q->next; + return q; +} + +static inline void free_sigqueue(struct sigqueue *q) +{ + q->next = first_free; + first_free = q; +} + +/* abort execution with signal */ +void __attribute((noreturn)) force_sig(int sig) +{ + int host_sig; + host_sig = target_to_host_signal(sig); + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", + sig, strsignal(host_sig)); + _exit(-host_sig); +} + +/* queue a signal so that it will be send to the virtual CPU as soon + as possible */ +int queue_signal(int sig, target_siginfo_t *info) +{ + struct emulated_sigaction *k; + struct sigqueue *q, **pq; + target_ulong handler; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "queue_signal: sig=%d\n", + sig); +#endif + k = &sigact_table[sig - 1]; + handler = (target_ulong)k->sa.sa_handler; + if (handler == SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != SIGCHLD && + sig != SIGURG && + sig != SIGWINCH) { + force_sig(sig); + } else { + return 0; /* indicate ignored */ + } + } else if (handler == host_to_target_signal(SIG_IGN)) { + /* ignore signal */ + return 0; + } else if (handler == host_to_target_signal(SIG_ERR)) { + force_sig(sig); + } else { + pq = &k->first; + if (!k->pending) { + /* first signal */ + q = &k->info; + } else { + q = alloc_sigqueue(); + if (!q) + return -EAGAIN; + while (*pq != NULL) + pq = &(*pq)->next; + } + *pq = q; + q->info = *info; + q->next = NULL; + k->pending = 1; + /* signal that a new signal is pending */ + signal_pending = 1; + return 1; /* indicates that the signal was queued */ + } +} + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc) +{ + int sig; + target_siginfo_t tinfo; + + /* the CPU emulator uses some host signals to detect exceptions, + we we forward to it some signals */ + if (host_signum == SIGSEGV || host_signum == SIGBUS +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + || host_signum == SIGFPE +#endif + ) { + if (cpu_signal_handler(host_signum, (void*)info, puc)) + return; + } + + /* get target signal number */ + sig = host_to_target_signal(host_signum); + if (sig < 1 || sig > NSIG) + return; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "qemu: got signal %d\n", sig); +#endif + if (queue_signal(sig, &tinfo) == 1) { + /* interrupt the virtual CPU as soon as possible */ + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); + } +} + +int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss) +{ + /* XXX: test errors */ + if(oss) + { + oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp); + oss->ss_size = tswap32(target_sigaltstack_used.ss_size); + oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags); + } + if(ss) + { + target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp); + target_sigaltstack_used.ss_size = tswap32(ss->ss_size); + target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags); + } + return 0; +} + +int do_sigaction(int sig, const struct sigaction *act, + struct sigaction *oact) +{ + struct emulated_sigaction *k; + struct sigaction act1; + int host_sig; + + if (sig < 1 || sig > NSIG) + return -EINVAL; + + k = &sigact_table[sig - 1]; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n", + sig, (int)act, (int)oact); +#endif + if (oact) { +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n", + sig, (int)act, (int)oact); +#endif + + oact->sa_handler = tswapl(k->sa.sa_handler); + oact->sa_flags = tswapl(k->sa.sa_flags); + oact->sa_mask = tswapl(k->sa.sa_mask); + } + if (act) { +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n", + act->sa_handler, act->sa_flags, act->sa_mask); +#endif + + k->sa.sa_handler = tswapl(act->sa_handler); + k->sa.sa_flags = tswapl(act->sa_flags); + k->sa.sa_mask = tswapl(act->sa_mask); + /* we update the host signal state */ + host_sig = target_to_host_signal(sig); + if (host_sig != SIGSEGV && host_sig != SIGBUS) { +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction handler going to call sigaction\n", + act->sa_handler, act->sa_flags, act->sa_mask); +#endif + + sigfillset(&act1.sa_mask); + act1.sa_flags = SA_SIGINFO; + if (k->sa.sa_flags & SA_RESTART) + act1.sa_flags |= SA_RESTART; + /* NOTE: it is important to update the host kernel signal + ignore state to avoid getting unexpected interrupted + syscalls */ + if (k->sa.sa_handler == SIG_IGN) { + act1.sa_sigaction = (void *)SIG_IGN; + } else if (k->sa.sa_handler == SIG_DFL) { + act1.sa_sigaction = (void *)SIG_DFL; + } else { + act1.sa_sigaction = host_signal_handler; + } + sigaction(host_sig, &act1, NULL); + } + } + return 0; +} + + +#ifdef TARGET_I386 + +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) +{ + /* XXX Fix that */ + if(target_sigaltstack_used.ss_flags & SA_DISABLE) + { + int esp; + /* Default to using normal stack */ + esp = env->regs[R_ESP]; + + return (void *)((esp - frame_size) & -8ul); + } + else + { + return target_sigaltstack_used.ss_sp; + } +} + +static void setup_frame(int sig, struct emulated_sigaction *ka, + void *set, CPUState *env) +{ + void *frame; + int i, err = 0; + + fprintf(stderr, "setup_frame %d\n", sig); + frame = get_sigframe(ka, env, sizeof(*frame)); + + /* Set up registers for signal handler */ + env->regs[R_ESP] = (unsigned long) frame; + env->eip = (unsigned long) ka->sa.sa_handler; + + env->eflags &= ~TF_MASK; + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV /* , current */); +} + +long do_sigreturn(CPUState *env, int num) +{ + int i = 0; + struct target_sigcontext *scp = get_int_arg(&i, env); + /* XXX Get current signal number */ + /* XXX Adjust accordin to sc_onstack, sc_mask */ + if(tswapl(scp->sc_onstack) & 0x1) + target_sigaltstack_used.ss_flags |= ~SA_DISABLE; + else + target_sigaltstack_used.ss_flags &= SA_DISABLE; + int set = tswapl(scp->sc_eax); + sigprocmask(SIG_SETMASK, &set, NULL); + + fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx)); + fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi)); + fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip)); + + env->regs[R_EAX] = tswapl(scp->sc_eax); + env->regs[R_EBX] = tswapl(scp->sc_ebx); + env->regs[R_ECX] = tswapl(scp->sc_ecx); + env->regs[R_EDX] = tswapl(scp->sc_edx); + env->regs[R_EDI] = tswapl(scp->sc_edi); + env->regs[R_ESI] = tswapl(scp->sc_esi); + env->regs[R_EBP] = tswapl(scp->sc_ebp); + env->regs[R_ESP] = tswapl(scp->sc_esp); + env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss); + env->eflags = tswapl(scp->sc_eflags); + env->eip = tswapl(scp->sc_eip); + env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs); + env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds); + env->segs[R_ES].selector = (void*)tswapl(scp->sc_es); + env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs); + env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs); + + /* Again, because our caller's caller will reset EAX */ + return env->regs[R_EAX]; +} + +#else + +static void setup_frame(int sig, struct emulated_sigaction *ka, + void *set, CPUState *env) +{ + fprintf(stderr, "setup_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env, int num) +{ + int i = 0; + struct target_sigcontext *scp = get_int_arg(&i, env); + fprintf(stderr, "do_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#endif + +void process_pending_signals(void *cpu_env) +{ + struct emulated_sigaction *k; + struct sigqueue *q; + target_ulong handler; + int sig; + + if (!signal_pending) + return; + + k = sigact_table; + + for(sig = 1; sig <= NSIG; sig++) { + if (k->pending) + goto handle_signal; + k++; + } + + /* if no signal is pending, just return */ + signal_pending = 0; + return; +handle_signal: + #ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: process signal %d\n", sig); + #endif + /* dequeue signal */ + q = k->first; + k->first = q->next; + if (!k->first) + k->pending = 0; + + sig = gdb_handlesig (cpu_env, sig); + if (!sig) { + fprintf (stderr, "Lost signal\n"); + abort(); + } + + handler = k->sa.sa_handler; + if (handler == SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != SIGCHLD && + sig != SIGURG && + sig != SIGWINCH) { + force_sig(sig); + } + } else if (handler == SIG_IGN) { + /* ignore sig */ + } else if (handler == SIG_ERR) { + force_sig(sig); + } else { + + setup_frame(sig, k, 0, cpu_env); + if (k->sa.sa_flags & SA_RESETHAND) + k->sa.sa_handler = SIG_DFL; + } + if (q != &k->info) + free_sigqueue(q); +} + + diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c new file mode 100644 index 0000000000..50725e633f --- /dev/null +++ b/darwin-user/syscall.c @@ -0,0 +1,1315 @@ +/* + * Darwin syscalls + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2006 Pierre d'Herbemont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include <mach/message.h> +#include <mach/mach.h> +#include <mach/mach_time.h> + +#include <pthread.h> +#include <dirent.h> + +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/dirent.h> +#include <sys/uio.h> +#include <sys/termios.h> +#include <sys/ptrace.h> +#include <net/if.h> + +#include <sys/param.h> +#include <sys/mount.h> + +#include <sys/attr.h> + +#include <mach/ndr.h> +#include <mach/mig_errors.h> + +#include "qemu.h" + +//#define DEBUG_SYSCALL + +#ifdef DEBUG_SYSCALL +# define DEBUG_FORCE_ENABLE_LOCAL() int __DEBUG_qemu_user_force_enable = 1 +# define DEBUG_BEGIN_ENABLE __DEBUG_qemu_user_force_enable = 1; +# define DEBUG_END_ENABLE __DEBUG_qemu_user_force_enable = 0; + +# define DEBUG_DISABLE_ALL() static int __DEBUG_qemu_user_force_enable = 0 +# define DEBUG_ENABLE_ALL() static int __DEBUG_qemu_user_force_enable = 1 + DEBUG_ENABLE_ALL(); + +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); \ + if(__DEBUG_qemu_user_force_enable) fprintf(stderr, __VA_ARGS__); \ + } while(0) +#else +# define DEBUG_FORCE_ENABLE_LOCAL() +# define DEBUG_BEGIN_ENABLE +# define DEBUG_END_ENABLE + +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) +#endif + +enum { + bswap_out = 0, + bswap_in = 1 +}; + +extern const char *interp_prefix; + +static inline long get_errno(long ret) +{ + if (ret == -1) + return -errno; + else + return ret; +} + +static inline int is_error(long ret) +{ + return (unsigned long)ret >= (unsigned long)(-4096); +} + +/* ------------------------------------------------------------ + Mach syscall handling +*/ + +void static inline print_description_msg_header(mach_msg_header_t *hdr) +{ + char *name = NULL; + int i; + struct { int number; char *name; } msg_name[] = + { + /* see http://fxr.watson.org/fxr/source/compat/mach/mach_namemap.c?v=NETBSD */ + { 200, "host_info" }, + { 202, "host_page_size" }, + { 206, "host_get_clock_service" }, + { 206, "host_get_clock_service" }, + { 206, "host_get_clock_service" }, + { 306, "host_get_clock_service" }, + { 3204, "mach_port_allocate" }, + { 3206, "mach_port_deallocate" }, + { 3404, "mach_ports_lookup" }, + { 3409, "mach_task_get_special_port" }, + { 3414, "mach_task_get_exception_ports" }, + { 3418, "mach_semaphore_create" }, + { 3504, "mach_semaphore_create" }, + { 3509, "mach_semaphore_create" }, + { 3518, "semaphore_create" }, + { 3616, "thread_policy" }, + { 3801, "vm_allocate" }, + { 3802, "vm_deallocate" }, + { 3802, "vm_deallocate" }, + { 3803, "vm_protect" }, + { 3812, "vm_map" }, + { 4241776, "lu_message_send_id" }, /* lookupd */ + { 4241876, "lu_message_reply_id" }, /* lookupd */ + }; + + for(i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { + if(msg_name[i].number == hdr->msgh_id) + { + name = msg_name[i].name; + break; + } + } + if(!name) + DPRINTF("unknown mach msg %d 0x%x\n", hdr->msgh_id, hdr->msgh_id); + else + DPRINTF("%s\n", name); +#if 0 + DPRINTF("Bits: %8x\n", hdr->msgh_bits); + DPRINTF("Size: %8x\n", hdr->msgh_size); + DPRINTF("Rmte: %8x\n", hdr->msgh_remote_port); + DPRINTF("Locl: %8x\n", hdr->msgh_local_port); + DPRINTF("Rsrv: %8x\n", hdr->msgh_reserved); + + DPRINTF("Id : %8x\n", hdr->msgh_id); + + NDR_record_t *ndr = (NDR_record_t *)(hdr + 1); + DPRINTF("hdr = %p, sizeof(hdr) = %x, NDR = %p\n", hdr, (unsigned int)sizeof(mach_msg_header_t), ndr); + DPRINTF("%d %d %d %d %d %d %d %d\n", + ndr->mig_vers, ndr->if_vers, ndr->reserved1, ndr->mig_encoding, + ndr->int_rep, ndr->char_rep, ndr->float_rep, ndr->reserved2); +#endif +} + +static inline void print_mach_msg_return(mach_msg_return_t ret) +{ + int i, found = 0; +#define MACH_MSG_RET(msg) { msg, #msg } + struct { int code; char *name; } msg_name[] = + { + /* ref: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/osfmk/man/mach_msg.html */ + /* send message */ + MACH_MSG_RET(MACH_SEND_MSG_TOO_SMALL), + MACH_MSG_RET(MACH_SEND_NO_BUFFER), + MACH_MSG_RET(MACH_SEND_INVALID_DATA), + MACH_MSG_RET(MACH_SEND_INVALID_HEADER), + MACH_MSG_RET(MACH_SEND_INVALID_DEST), + MACH_MSG_RET(MACH_SEND_INVALID_NOTIFY), + MACH_MSG_RET(MACH_SEND_INVALID_REPLY), + MACH_MSG_RET(MACH_SEND_INVALID_TRAILER), + MACH_MSG_RET(MACH_SEND_INVALID_MEMORY), + MACH_MSG_RET(MACH_SEND_INVALID_RIGHT), + MACH_MSG_RET(MACH_SEND_INVALID_TYPE), + MACH_MSG_RET(MACH_SEND_INTERRUPTED), + MACH_MSG_RET(MACH_SEND_TIMED_OUT), + + MACH_MSG_RET(MACH_RCV_BODY_ERROR), + MACH_MSG_RET(MACH_RCV_HEADER_ERROR), + + MACH_MSG_RET(MACH_RCV_IN_SET), + MACH_MSG_RET(MACH_RCV_INTERRUPTED), + + MACH_MSG_RET(MACH_RCV_INVALID_DATA), + MACH_MSG_RET(MACH_RCV_INVALID_NAME), + MACH_MSG_RET(MACH_RCV_INVALID_NOTIFY), + MACH_MSG_RET(MACH_RCV_INVALID_TRAILER), + MACH_MSG_RET(MACH_RCV_INVALID_TYPE), + + MACH_MSG_RET(MACH_RCV_PORT_CHANGED), + MACH_MSG_RET(MACH_RCV_PORT_DIED), + + MACH_MSG_RET(MACH_RCV_SCATTER_SMALL), + MACH_MSG_RET(MACH_RCV_TIMED_OUT), + MACH_MSG_RET(MACH_RCV_TOO_LARGE) + }; +#undef MACH_MSG_RET + + if( ret == MACH_MSG_SUCCESS) + DPRINTF("MACH_MSG_SUCCESS\n"); + else + { + for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { + if(msg_name[0].code & ret) { + DPRINTF("%s ", msg_name[0].name); + found = 1; + } + } + if(!found) + qerror("unknow mach message ret code %d\n", ret); + else + DPRINTF("\n"); + } +} + +static inline void swap_mach_msg_header(mach_msg_header_t *hdr) +{ + hdr->msgh_bits = tswap32(hdr->msgh_bits); + hdr->msgh_size = tswap32(hdr->msgh_size); + hdr->msgh_remote_port = tswap32(hdr->msgh_remote_port); + hdr->msgh_local_port = tswap32(hdr->msgh_local_port); + hdr->msgh_reserved = tswap32(hdr->msgh_reserved); + hdr->msgh_id = tswap32(hdr->msgh_id); +} + +struct complex_msg { + mach_msg_header_t hdr; + mach_msg_body_t body; +}; + +static inline void * swap_mach_msg_body(struct complex_msg *complex_msg, int bswap) +{ + mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1); + int i,j; + void *additional_data; + + if(bswap == bswap_in) + tswap32s(&complex_msg->body.msgh_descriptor_count); + + DPRINTF("body.msgh_descriptor_count %d\n", complex_msg->body.msgh_descriptor_count); + + for(i = 0; i < complex_msg->body.msgh_descriptor_count; i++) { + switch(descr->type) + { + case MACH_MSG_PORT_DESCRIPTOR: + tswap32s(&descr->name); + descr++; + break; + case MACH_MSG_OOL_DESCRIPTOR: + { + mach_msg_ool_descriptor_t *ool = (void *)descr; + tswap32s((uint32_t *)&ool->address); + tswap32s(&ool->size); + + descr = (mach_msg_port_descriptor_t *)(ool+1); + break; + } + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + { + mach_msg_ool_ports_descriptor_t *ool_ports = (void *)descr; + mach_port_name_t * port_names; + + if(bswap == bswap_in) + { + tswap32s((uint32_t *)&ool_ports->address); + tswap32s(&ool_ports->count); + } + + port_names = ool_ports->address; + + for(j = 0; j < ool_ports->count; j++) + tswap32s(&port_names[j]); + + if(bswap == bswap_out) + { + tswap32s((uint32_t *)&ool_ports->address); + tswap32s(&ool_ports->count); + } + + descr = (mach_msg_port_descriptor_t *)(ool_ports+1); + break; + } + default: qerror("unknow mach msg descriptor type %x\n", descr->type); + } + } + if(bswap == bswap_out) + tswap32s(&complex_msg->body.msgh_descriptor_count); + additional_data = descr; + return additional_data; +} + +static inline uint32_t target_mach_msg_trap( + mach_msg_header_t *hdr, uint32_t options, uint32_t send_size, + uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify ) +{ + extern int mach_msg_trap(mach_msg_header_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + mach_msg_audit_trailer_t *trailer; + mach_msg_id_t msg_id; + uint32_t ret = 0; + char *additional_data; + int i; + + swap_mach_msg_header(hdr); + + print_description_msg_header(hdr); + + msg_id = hdr->msgh_id; + + if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) + additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_in); + else + additional_data = (void*)(hdr+1); + + ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify); + + print_mach_msg_return(ret); + + if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) + additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_out); + else + additional_data = (void*)(hdr+1); + + if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) ) + { + /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should + probably always bswap it */ + /* warning: according to Mac OS X Internals (the book) msg_size might be expressed in + natural_t units but according to xnu/osfmk/mach/message.h: "The size of + the message must be specified in bytes" */ + trailer = (mach_msg_audit_trailer_t *)((uint8_t *)hdr + hdr->msgh_size); + /* XXX: Should probably do that based on the option asked by the sender, but dealing + with kernel answer seems more sound */ + switch(trailer->msgh_trailer_size) + { + case sizeof(mach_msg_audit_trailer_t): + for(i = 0; i < 8; i++) + tswap32s(&trailer->msgh_audit.val[i]); + /* Fall in mach_msg_security_trailer_t case */ + case sizeof(mach_msg_security_trailer_t): + tswap32s(&trailer->msgh_sender.val[0]); + tswap32s(&trailer->msgh_sender.val[1]); + /* Fall in mach_msg_seqno_trailer_t case */ + case sizeof(mach_msg_seqno_trailer_t): + tswap32s(&trailer->msgh_seqno); + /* Fall in mach_msg_trailer_t case */ + case sizeof(mach_msg_trailer_t): + tswap32s(&trailer->msgh_trailer_type); + tswap32s(&trailer->msgh_trailer_size); + break; + case 0: + /* Safer not to byteswap, but probably wrong */ + break; + default: + qerror("unknow trailer type given its size %d\n", trailer->msgh_trailer_size); + break; + } + } + + /* Special message handling */ + switch (msg_id) { + case 200: /* host_info */ + { + mig_reply_error_t *err = (mig_reply_error_t *)hdr; + struct { + uint32_t unknow1; + uint32_t maxcpu; + uint32_t numcpu; + uint32_t memsize; + uint32_t cpu_type; + uint32_t cpu_subtype; + } *data = (void *)(err+1); + + DPRINTF("maxcpu = 0x%x\n", data->maxcpu); + DPRINTF("numcpu = 0x%x\n", data->maxcpu); + DPRINTF("memsize = 0x%x\n", data->memsize); + +#if defined(TARGET_I386) + data->cpu_type = CPU_TYPE_I386; + DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type); +#elif defined(TARGET_PPC) + data->cpu_type = CPU_TYPE_POWERPC; + DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type); +#else +# error target not supported +#endif + +#if defined(TARGET_I386) + data->cpu_subtype = CPU_SUBTYPE_PENT; + DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype); +#elif defined(TARGET_PPC) + data->cpu_subtype = CPU_SUBTYPE_POWERPC_750; + DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype); +#else +# error target not supported +#endif + break; + } + case 202: /* host_page_size */ + { + mig_reply_error_t *err = (mig_reply_error_t *)hdr; + uint32_t *pagesize = (uint32_t *)(err+1); + + DPRINTF("pagesize = %d\n", *pagesize); + break; + } + default: break; + } + + swap_mach_msg_header(hdr); + + return ret; +} + +long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8) +{ + extern uint32_t mach_reply_port(); + + long ret = 0; + + arg1 = tswap32(arg1); + arg2 = tswap32(arg2); + arg3 = tswap32(arg3); + arg4 = tswap32(arg4); + arg5 = tswap32(arg5); + arg6 = tswap32(arg6); + arg7 = tswap32(arg7); + arg8 = tswap32(arg8); + + DPRINTF("mach syscall %d : " , num); + + switch(num) { + /* see xnu/osfmk/mach/syscall_sw.h */ + case -26: + DPRINTF("mach_reply_port()\n"); + ret = mach_reply_port(); + break; + case -27: + DPRINTF("mach_thread_self()\n"); + ret = mach_thread_self(); + break; + case -28: + DPRINTF("mach_task_self()\n"); + ret = mach_task_self(); + break; + case -29: + DPRINTF("mach_host_self()\n"); + ret = mach_host_self(); + break; + case -31: + DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + break; + case -36: + DPRINTF("semaphore_wait_trap(0x%x)\n", arg1); + extern int semaphore_wait_trap(int); // XXX: is there any header for that? + ret = semaphore_wait_trap(arg1); + break; + case -43: + DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + arg1, arg2, arg3, arg4, arg5); + ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5); + tswap32s((uint32_t*)arg3); + break; + case -89: + DPRINTF("mach_timebase_info(0x%x)\n", arg1); + struct mach_timebase_info info; + ret = mach_timebase_info(&info); + if(!is_error(ret)) + { + struct mach_timebase_info *outInfo = (void*)arg1; + outInfo->numer = tswap32(info.numer); + outInfo->denom = tswap32(info.denom); + } + break; + case -90: + DPRINTF("mach_wait_until()\n"); + extern int mach_wait_until(uint64_t); // XXX: is there any header for that? + ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1); + break; + case -91: + DPRINTF("mk_timer_create()\n"); + extern int mk_timer_create(); // XXX: is there any header for that? + ret = mk_timer_create(); + break; + case -92: + DPRINTF("mk_timer_destroy()\n"); + extern int mk_timer_destroy(int); // XXX: is there any header for that? + ret = mk_timer_destroy(arg1); + break; + case -93: + DPRINTF("mk_timer_create()\n"); + extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that? + ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2); + break; + case -94: + DPRINTF("mk_timer_cancel()\n"); + extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that? + ret = mk_timer_cancel(arg1, (uint64_t *)arg2); + if((!is_error(ret)) && arg2) + tswap64s((uint64_t *)arg2); + break; + default: + gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(0); + break; + } + return ret; +} + +/* ------------------------------------------------------------ + thread type syscall handling +*/ +long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8) +{ + extern uint32_t cthread_set_self(uint32_t); + extern uint32_t processor_facilities_used(); + long ret = 0; + + arg1 = tswap32(arg1); + arg2 = tswap32(arg2); + arg3 = tswap32(arg3); + arg4 = tswap32(arg4); + arg5 = tswap32(arg5); + arg6 = tswap32(arg6); + arg7 = tswap32(arg7); + arg8 = tswap32(arg8); + + DPRINTF("thread syscall %d : " , num); + + switch(num) { +#ifdef TARGET_I386 + case 0x3: +#endif + case 0x7FF1: /* cthread_set_self */ + DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1); + ret = cthread_set_self(arg1); +#ifdef TARGET_I386 + /* we need to update the LDT with the address of the thread */ + write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + /* New i386 convention, %gs should be set to our this LDT entry */ + cpu_x86_load_seg(cpu_env, R_GS, 0x27); + /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/ + ret = 0x27; +#endif + break; + case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */ + DPRINTF("pthread_self()\n"); + ret = (uint32_t)pthread_self(); + break; + case 0x7FF3: + DPRINTF("processor_facilities_used()\n"); +#ifdef __i386__ + qerror("processor_facilities_used: not implemented!\n"); +#else + ret = (uint32_t)processor_facilities_used(); +#endif + break; + default: + gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(0); + break; + } + return ret; +} + +/* ------------------------------------------------------------ + ioctl handling +*/ +static inline void byteswap_termios(struct termios *t) +{ + tswap32s((uint32_t*)&t->c_iflag); + tswap32s((uint32_t*)&t->c_oflag); + tswap32s((uint32_t*)&t->c_cflag); + tswap32s((uint32_t*)&t->c_lflag); + /* 20 (char) bytes then */ + tswap32s((uint32_t*)&t->c_ispeed); + tswap32s((uint32_t*)&t->c_ospeed); +} + +static inline void byteswap_winsize(struct winsize *w) +{ + tswap16s(&w->ws_row); + tswap16s(&w->ws_col); + tswap16s(&w->ws_xpixel); + tswap16s(&w->ws_ypixel); +} + +#define STRUCT(name, list...) STRUCT_ ## name, +#define STRUCT_SPECIAL(name) STRUCT_ ## name, +enum { +#include "ioctls_types.h" +}; +#undef STRUCT +#undef STRUCT_SPECIAL + +#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; +#define STRUCT_SPECIAL(name) +#include "ioctls_types.h" +#undef STRUCT +#undef STRUCT_SPECIAL + +typedef struct IOCTLEntry { + unsigned int target_cmd; + unsigned int host_cmd; + const char *name; + int access; + const argtype arg_type[5]; +} IOCTLEntry; + +#define IOC_R 0x0001 +#define IOC_W 0x0002 +#define IOC_RW (IOC_R | IOC_W) + +#define MAX_STRUCT_SIZE 4096 + +IOCTLEntry ioctl_entries[] = { +#define IOCTL(cmd, access, types...) \ + { cmd, cmd, #cmd, access, { types } }, +#include "ioctls.h" + { 0, 0, }, +}; + +/* ??? Implement proper locking for ioctls. */ +static long do_ioctl(long fd, long cmd, long arg) +{ + const IOCTLEntry *ie; + const argtype *arg_type; + int ret; + uint8_t buf_temp[MAX_STRUCT_SIZE]; + int target_size; + void *argptr; + + ie = ioctl_entries; + for(;;) { + if (ie->target_cmd == 0) { + gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); + return -ENOSYS; + } + if (ie->target_cmd == cmd) + break; + ie++; + } + arg_type = ie->arg_type; +#if defined(DEBUG) + gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); +#endif + switch(arg_type[0]) { + case TYPE_NULL: + /* no argument */ + ret = get_errno(ioctl(fd, ie->host_cmd)); + break; + case TYPE_PTRVOID: + case TYPE_INT: + /* int argment */ + ret = get_errno(ioctl(fd, ie->host_cmd, arg)); + break; + case TYPE_PTR: + arg_type++; + target_size = thunk_type_size(arg_type, 0); + switch(ie->access) { + case IOC_R: + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + case IOC_W: + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + break; + default: + case IOC_RW: + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + } + break; + default: + gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); + ret = -ENOSYS; + break; + } + return ret; +} + +/* ------------------------------------------------------------ + Unix syscall handling +*/ + +static inline void byteswap_attrlist(struct attrlist *a) +{ + tswap16s(&a->bitmapcount); + tswap16s(&a->reserved); + tswap32s(&a->commonattr); + tswap32s(&a->volattr); + tswap32s(&a->dirattr); + tswap32s(&a->fileattr); + tswap32s(&a->forkattr); +} + +struct attrbuf_header { + unsigned long length; +}; + +static inline void byteswap_attrbuf(struct attrbuf_header *attrbuf, struct attrlist *attrlist) +{ + DPRINTF("attrBuf.lenght %lx\n", attrbuf->length); +} + +static inline void byteswap_statfs(struct statfs *s) +{ + tswap16s((uint16_t*)&s->f_otype); + tswap16s((uint16_t*)&s->f_oflags); + tswap32s((uint32_t*)&s->f_bsize); + tswap32s((uint32_t*)&s->f_iosize); + tswap32s((uint32_t*)&s->f_blocks); + tswap32s((uint32_t*)&s->f_bfree); + tswap32s((uint32_t*)&s->f_bavail); + tswap32s((uint32_t*)&s->f_files); + tswap32s((uint32_t*)&s->f_ffree); + tswap32s((uint32_t*)&s->f_fsid.val[0]); + tswap32s((uint32_t*)&s->f_fsid.val[1]); + tswap16s((uint16_t*)&s->f_reserved1); + tswap16s((uint16_t*)&s->f_type); + tswap32s((uint32_t*)&s->f_flags); +} + +static inline void byteswap_stat(struct stat *s) +{ + tswap32s((uint32_t*)&s->st_dev); + tswap32s(&s->st_ino); + tswap16s(&s->st_mode); + tswap16s(&s->st_nlink); + tswap32s(&s->st_uid); + tswap32s(&s->st_gid); + tswap32s((uint32_t*)&s->st_rdev); + tswap32s((uint32_t*)&s->st_atimespec.tv_sec); + tswap32s((uint32_t*)&s->st_atimespec.tv_nsec); + tswap32s((uint32_t*)&s->st_mtimespec.tv_sec); + tswap32s((uint32_t*)&s->st_mtimespec.tv_nsec); + tswap32s((uint32_t*)&s->st_ctimespec.tv_sec); + tswap32s((uint32_t*)&s->st_ctimespec.tv_nsec); + tswap64s((uint64_t*)&s->st_size); + tswap64s((uint64_t*)&s->st_blocks); + tswap32s((uint32_t*)&s->st_blksize); + tswap32s(&s->st_flags); + tswap32s(&s->st_gen); +} + +static inline void byteswap_dirents(struct dirent *d, int bytes) +{ + char *b; + for( b = (char*)d; (int)b < (int)d+bytes; ) + { + unsigned short s = ((struct dirent *)b)->d_reclen; + tswap32s(&((struct dirent *)b)->d_ino); + tswap16s(&((struct dirent *)b)->d_reclen); + if(s<=0) + break; + b += s; + } +} + +static inline void byteswap_iovec(struct iovec *v, int n) +{ + int i; + for(i = 0; i < n; i++) + { + tswap32s((uint32_t*)&v[i].iov_base); + tswap32s((uint32_t*)&v[i].iov_len); + } +} + +static inline void byteswap_timeval(struct timeval *t) +{ + tswap32s((uint32_t*)&t->tv_sec); + tswap32s((uint32_t*)&t->tv_usec); +} + +long do_unix_syscall_indirect(void *cpu_env, int num); +long do_sync(); +long do_exit(uint32_t arg1); +long do_getlogin(char *out, uint32_t size); +long do_open(char * arg1, uint32_t arg2, uint32_t arg3); +long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3); +long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3); +long do_execve(char* arg1, char ** arg2, char ** arg3); +long do_getgroups(uint32_t arg1, gid_t * arg2); +long do_gettimeofday(struct timeval * arg1, void * arg2); +long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3); +long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3); +long do_utimes(char * arg1, struct timeval * arg2); +long do_futimes(uint32_t arg1, struct timeval * arg2); +long do_statfs(char * arg1, struct statfs * arg2); +long do_fstatfs(uint32_t arg1, struct statfs * arg2); +long do_stat(char * arg1, struct stat * arg2); +long do_fstat(uint32_t arg1, struct stat * arg2); +long do_lstat(char * arg1, struct stat * arg2); +long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4); +long do_lseek(void *cpu_env, int num); +long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6); +long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5); +long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8); + +long no_syscall(void *cpu_env, int num); + +long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4) +{ + //DPRINTF("0x%x, 0x%x, 0x%x, 0x%llx\n", arg1, arg2, arg3, arg4); + long ret = (pread(arg1, arg2, arg3, arg4)); + DPRINTF("0x%x\n", *(int*)arg2); + return ret; +} +long unimpl_unix_syscall(void *cpu_env, int num); + +typedef long (*syscall_function_t)(void *cpu_env, int num); + + +/* define a table that will handle the syscall number->function association */ +#define VOID void +#define INT (uint32_t)get_int_arg(&i, cpu_env) +#define INT64 (uint64_t)get_int64_arg(&i, cpu_env) +#define UINT (unsigned int)INT +#define PTR (void*)INT + +#define SIZE INT +#define OFFSET INT64 + +#define WRAPPER_CALL_DIRECT_0(function, args) long __qemu_##function(void *cpu_env) { return (long)function(); } +#define WRAPPER_CALL_DIRECT_1(function, _arg1) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; return (long)function(arg1); } +#define WRAPPER_CALL_DIRECT_2(function, _arg1, _arg2) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; return (long)function(arg1, arg2); } +#define WRAPPER_CALL_DIRECT_3(function, _arg1, _arg2, _arg3) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; return (long)function(arg1, arg2, arg3); } +#define WRAPPER_CALL_DIRECT_4(function, _arg1, _arg2, _arg3, _arg4) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; return (long)function(arg1, arg2, arg3, arg4); } +#define WRAPPER_CALL_DIRECT_5(function, _arg1, _arg2, _arg3, _arg4, _arg5) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; return (long)function(arg1, arg2, arg3, arg4, arg5); } +#define WRAPPER_CALL_DIRECT_6(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6); } +#define WRAPPER_CALL_DIRECT_7(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } +#define WRAPPER_CALL_DIRECT_8(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; typeof(_arg8) arg8 = _arg8; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } +#define WRAPPER_CALL_DIRECT(function, nargs, args...) WRAPPER_CALL_DIRECT_##nargs(function, args) +#define WRAPPER_CALL_NOERRNO(function, nargs, args...) WRAPPER_CALL_DIRECT(function, nargs, args) +#define WRAPPER_CALL_INDIRECT(function, nargs, args...) +#define ENTRY(name, number, function, nargs, call_type, args...) WRAPPER_##call_type(function, nargs, args) + +#include "syscalls.h" + +#undef ENTRY +#undef WRAPPER_CALL_DIRECT +#undef WRAPPER_CALL_NOERRNO +#undef WRAPPER_CALL_INDIRECT +#undef OFFSET +#undef SIZE +#undef INT +#undef PTR +#undef INT64 + +#define _ENTRY(name, number, function, nargs, call_type) [number] = {\ + name, \ + number, \ + (syscall_function_t)function, \ + nargs, \ + call_type \ + }, + +#define ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, __qemu_##function, nargs, call_type) +#define ENTRY_CALL_NOERRNO(name, number, function, nargs, call_type) ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) +#define ENTRY_CALL_INDIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, function, nargs, call_type) +#define ENTRY(name, number, function, nargs, call_type, args...) ENTRY_##call_type(name, number, function, nargs, call_type) + +#define CALL_DIRECT 1 +#define CALL_INDIRECT 2 +#define CALL_NOERRNO (CALL_DIRECT | 4 /* = 5 */) + +struct unix_syscall { + char * name; + int number; + syscall_function_t function; + int nargs; + int call_type; +} unix_syscall_table[SYS_MAXSYSCALL] = { +#include "syscalls.h" +}; + +#undef ENTRY +#undef _ENTRY +#undef ENTRY_CALL_DIRECT +#undef ENTRY_CALL_INDIRECT +#undef ENTRY_CALL_NOERRNO + +/* Actual syscalls implementation */ + +long do_unix_syscall_indirect(void *cpu_env, int num) +{ + long ret; + int new_num; + int i = 0; + + new_num = get_int_arg(&i, cpu_env); +#ifdef TARGET_I386 + ((CPUX86State*)cpu_env)->regs[R_ESP] += 4; + /* XXX: not necessary */ + ((CPUX86State*)cpu_env)->regs[R_EAX] = new_num; +#elif TARGET_PPC + { + int i; + uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr; + for(i = 3; i < 11; i++) + *regs[i] = *regs[i+1]; + /* XXX: not necessary */ + *regs[0] = new_num; + } +#endif + ret = do_unix_syscall(cpu_env, new_num); +#ifdef TARGET_I386 + ((CPUX86State*)cpu_env)->regs[R_ESP] -= 4; + /* XXX: not necessary */ + ((CPUX86State*)cpu_env)->regs[R_EAX] = num; +#elif TARGET_PPC + { + int i; + /* XXX: not really needed those regs are volatile accross calls */ + uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr; + for(i = 11; i > 3; i--) + *regs[i] = *regs[i-1]; + regs[3] = new_num; + *regs[0] = num; + } +#endif + return ret; +} + +long do_exit(uint32_t arg1) +{ + exit(arg1); + /* not reached */ + return -1; +} + +long do_sync() +{ + sync(); + return 0; +} + +long do_getlogin(char *out, uint32_t size) +{ + char *login = getlogin(); + if(!login) + return -1; + memcpy(out, login, size); + return 0; +} +long do_open(char * arg1, uint32_t arg2, uint32_t arg3) +{ + /* XXX: don't let the %s stay in there */ + DPRINTF("open(%s, 0x%x, 0x%x)\n", arg1, arg2, arg3); + return get_errno(open(arg1, arg2, arg3)); +} + +long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3) +{ + long ret; + DPRINTF("getfsstat(%p, 0x%x, 0x%x)\n", arg1, arg2, arg3); + ret = get_errno(getfsstat(arg1, arg2, arg3)); + if((!is_error(ret)) && arg1) + byteswap_statfs(arg1); + return ret; +} + +long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3) +{ + long ret; + DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3); + gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3); + if(arg2) + tswap32s(arg2); + ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3)); + if((!is_error(ret)) && arg3) + tswap32s(arg3); + if(arg2) + tswap32s(arg2); + return ret; +} + +long do_execve(char* arg1, char ** arg2, char ** arg3) +{ + long ret; + char **argv = arg2; + char **envp = arg3; + int argc; + int envc; + + /* XXX: don't let the %s stay in here */ + DPRINTF("execve(%s, %p, %p)\n", arg1, arg2, arg3); + + for(argc = 0; argv[argc]; argc++); + for(envc = 0; envp[envc]; envc++); + + argv = (char**)malloc(sizeof(char*)*argc); + envp = (char**)malloc(sizeof(char*)*envc); + + for(; argc >= 0; argc--) + argv[argc] = (char*)tswap32((uint32_t)(arg2)[argc]); + + for(; envc >= 0; envc--) + envp[envc] = (char*)tswap32((uint32_t)(arg3)[envc]); + + ret = get_errno(execve(arg1, argv, envp)); + free(argv); + free(envp); + return ret; +} + +long do_getgroups(uint32_t arg1, gid_t * arg2) +{ + long ret; + int i; + DPRINTF("getgroups(0x%x, %p)\n", arg1, arg2); + ret = get_errno(getgroups(arg1, arg2)); + if(ret > 0) + for(i = 0; i < arg1; i++) + tswap32s(&arg2[i]); + return ret; +} + +long do_gettimeofday(struct timeval * arg1, void * arg2) +{ + long ret; + DPRINTF("gettimeofday(%p, %p)\n", + arg1, arg2); + ret = get_errno(gettimeofday(arg1, arg2)); + if(!is_error(ret)) + { + /* timezone no longer used according to the manpage, so don't bother with it */ + byteswap_timeval(arg1); + } + return ret; +} + +long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3) +{ + long ret; + DPRINTF("readv(0x%x, %p, 0x%x)\n", arg1, arg2, arg3); + if(arg2) + byteswap_iovec(arg2, arg3); + ret = get_errno(readv(arg1, arg2, arg3)); + if((!is_error(ret)) && arg2) + byteswap_iovec(arg2, arg3); + return ret; +} + +long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3) +{ + long ret; + DPRINTF("writev(0x%x, %p, 0x%x)\n", arg1, arg2, arg3); + if(arg2) + byteswap_iovec(arg2, arg3); + ret = get_errno(writev(arg1, arg2, arg3)); + if((!is_error(ret)) && arg2) + byteswap_iovec(arg2, arg3); + return ret; +} + +long do_utimes(char * arg1, struct timeval * arg2) +{ + DPRINTF("utimes(%p, %p)\n", arg1, arg2); + if(arg2) + { + byteswap_timeval(arg2); + byteswap_timeval(arg2+1); + } + return get_errno(utimes(arg1, arg2)); +} + +long do_futimes(uint32_t arg1, struct timeval * arg2) +{ + DPRINTF("futimes(0x%x, %p)\n", arg1, arg2); + if(arg2) + { + byteswap_timeval(arg2); + byteswap_timeval(arg2+1); + } + return get_errno(futimes(arg1, arg2)); +} + +long do_statfs(char * arg1, struct statfs * arg2) +{ + long ret; + DPRINTF("statfs(%p, %p)\n", arg1, arg2); + ret = get_errno(statfs(arg1, arg2)); + if(!is_error(ret)) + byteswap_statfs(arg2); + return ret; +} + +long do_fstatfs(uint32_t arg1, struct statfs* arg2) +{ + long ret; + DPRINTF("fstatfs(0x%x, %p)\n", + arg1, arg2); + ret = get_errno(fstatfs(arg1, arg2)); + if(!is_error(ret)) + byteswap_statfs(arg2); + + return ret; +} + +long do_stat(char * arg1, struct stat * arg2) +{ + long ret; + /* XXX: don't let the %s stay in there */ + DPRINTF("stat(%s, %p)\n", arg1, arg2); + ret = get_errno(stat(arg1, arg2)); + if(!is_error(ret)) + byteswap_stat(arg2); + return ret; +} + +long do_fstat(uint32_t arg1, struct stat * arg2) +{ + long ret; + DPRINTF("fstat(0x%x, %p)\n", arg1, arg2); + ret = get_errno(fstat(arg1, arg2)); + if(!is_error(ret)) + byteswap_stat(arg2); + return ret; +} + +long do_lstat(char * arg1, struct stat * arg2) +{ + long ret; + /* XXX: don't let the %s stay in there */ + DPRINTF("lstat(%s, %p)\n", (const char *)arg1, arg2); + ret = get_errno(lstat(arg1, arg2)); + if(!is_error(ret)) + byteswap_stat(arg2); + return ret; +} + +long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4) +{ + long ret; + DPRINTF("getdirentries(0x%x, %p, 0x%x, %p)\n", arg1, arg2, arg3, arg4); + if(arg4) + tswap32s((uint32_t *)arg4); + ret = get_errno(getdirentries(arg1, arg2, arg3, arg4)); + if(arg4) + tswap32s((uint32_t *)arg4); + if(!is_error(ret)) + byteswap_dirents(arg2, ret); + return ret; +} + +long do_lseek(void *cpu_env, int num) +{ + long ret; + int i = 0; + uint32_t arg1 = get_int_arg(&i, cpu_env); + uint64_t offset = get_int64_arg(&i, cpu_env); + uint32_t arg3 = get_int_arg(&i, cpu_env); + uint64_t r = lseek(arg1, offset, arg3); +#ifdef TARGET_I386 + /* lowest word in eax, highest in edx */ + ret = r & 0xffffffff; /* will be set to eax after do_unix_syscall exit */ + ((CPUX86State *)cpu_env)->regs[R_EDX] = (uint32_t)((r >> 32) & 0xffffffff) ; +#elif defined TARGET_PPC + ret = r & 0xffffffff; /* will be set to r3 after do_unix_syscall exit */ + ((CPUPPCState *)cpu_env)->gpr[4] = (uint32_t)((r >> 32) & 0xffffffff) ; +#else + qerror("64 bit ret value on your arch?"); +#endif + return get_errno(ret); +} + +long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6) +{ + long ret = 0; + int i; + DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n", + arg1, arg2, arg3, arg4, arg5, arg6); + if(arg1) { + i = 0; + do { *((int *) arg1 + i) = tswap32(*((int *) arg1 + i)); } while (++i < arg2); + } + + if(arg4) + *(int *) arg4 = tswap32(*(int *) arg4); + if(arg1) + ret = get_errno(sysctl((void *)arg1, arg2, (void *)arg3, (void *)arg4, (void *)arg5, arg6)); + + if ((ret == 0) && (arg2 == 2) && (*((int *) arg1) == 0) && (*((int *) arg1 + 1) == 3)) { + /* The output here is the new id - we need to swap it so it can be passed + back in (and then unswapped) */ + int count = (*(int *) arg4) / sizeof(int); + i = 0; + do { + *((int *) arg3 + i) = tswap32(*((int *) arg3 + i)); + } while (++i < count); + } + *(int *) arg4 = tswap32(*(int *) arg4); + + return ret; +} + +long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5) +{ + struct attrlist * attrlist = (void *)arg2; + long ret; + +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) + qerror("SYS_getdirentriesattr unimplemented\n"); +#endif + /* XXX: don't let the %s stay in there */ + DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n", + (char *)arg1, arg2, arg3, arg4, arg5); + + if(arg2) /* XXX: We should handle that in a copy especially + if the structure is not writable */ + byteswap_attrlist(attrlist); + + ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5)); + + if(!is_error(ret)) + { + byteswap_attrbuf((void *)arg3, attrlist); + byteswap_attrlist(attrlist); + } + return ret; +} + +long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8) +{ + DPRINTF("getdirentriesattr(0x%x, %p, %p, 0x%lx, %p, %p, %p, 0x%x)\n", + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) + qerror("SYS_getdirentriesattr unimplemented\n"); +#endif + + return get_errno(getdirentriesattr( arg1, (struct attrlist * )arg2, (void *)arg3, arg4, + (unsigned long *)arg5, (unsigned long *)arg6, + (unsigned long *)arg7, arg8)); +} + + +long no_syscall(void *cpu_env, int num) +{ + /* XXX: We should probably fordward it to the host kernel */ + qerror("no unix syscall %d\n", num); + /* not reached */ + return -1; +} + +long unimpl_unix_syscall(void *cpu_env, int num) +{ + if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) + qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); + + gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(-1); +} + +long do_unix_syscall(void *cpu_env, int num) +{ + long ret = 0; + + DPRINTF("unix syscall %d: " , num); + + if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) + qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); + + DPRINTF("%s [%s]", unix_syscall_table[num].name, unix_syscall_table[num].call_type & CALL_DIRECT ? "direct" : "indirect" ); + ret = unix_syscall_table[num].function(cpu_env, num); + + if(!(unix_syscall_table[num].call_type & CALL_NOERRNO)) + ret = get_errno(ret); + + DPRINTF("[returned 0x%x(%d)]\n", (int)ret, (int)ret); + return ret; +} + +/* ------------------------------------------------------------ + syscall_init +*/ +void syscall_init(void) +{ + /* Nothing yet */ +} diff --git a/darwin-user/syscalls.h b/darwin-user/syscalls.h new file mode 100644 index 0000000000..d04295bed3 --- /dev/null +++ b/darwin-user/syscalls.h @@ -0,0 +1,384 @@ +/* generated from xnu/bsd/kern/syscalls.master */ + + ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */ + ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */ + ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */ + ENTRY("read", SYS_read, read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */ + ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */ + ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */ + ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */ + ENTRY("wait4", SYS_wait4, wait4, 4, CALL_DIRECT, INT, PTR, INT, PTR) /* 7 */ + ENTRY("", 8, no_syscall, 0, CALL_INDIRECT, VOID) /* 8 old creat */ + ENTRY("link", SYS_link, link, 2, CALL_DIRECT, PTR, PTR) /* 9 */ + ENTRY("unlink", SYS_unlink, unlink, 1, CALL_DIRECT, PTR) /* 10 */ + ENTRY("", 11, no_syscall, 0, CALL_INDIRECT, VOID) /* 11 old execv */ + ENTRY("chdir", SYS_chdir, chdir, 1, CALL_DIRECT, PTR) /* 12 */ + ENTRY("fchdir", SYS_fchdir, fchdir, 1, CALL_DIRECT, INT) /* 13 */ + ENTRY("mknod", SYS_mknod, mknod, 3, CALL_DIRECT, PTR, INT, INT) /* 14 */ + ENTRY("chmod", SYS_chmod, chmod, 2, CALL_DIRECT, PTR, INT) /* 15 */ + ENTRY("chown", SYS_chown, chown, 3, CALL_DIRECT, PTR, INT, INT) /* 16 */ + ENTRY("obreak", SYS_obreak, no_syscall, 1, CALL_INDIRECT, VOID) /* 17 old break */ + ENTRY("ogetfsstat", 18, unimpl_unix_syscall, 3, CALL_INDIRECT, PTR, INT, INT) /* 18 */ + ENTRY("", 19, no_syscall, 0, CALL_INDIRECT, VOID) /* 19 old lseek */ + ENTRY("getpid", SYS_getpid, getpid, 0, CALL_NOERRNO, VOID) /* 20 */ + ENTRY("", 21, no_syscall, 0, CALL_INDIRECT, VOID) /* 21 old mount */ + ENTRY("", 22, no_syscall, 0, CALL_INDIRECT, VOID) /* 22 old umount */ + ENTRY("setuid", SYS_setuid, setuid, 1, CALL_DIRECT, INT) /* 23 */ + ENTRY("getuid", SYS_getuid, getuid, 0, CALL_NOERRNO, VOID) /* 24 */ + ENTRY("geteuid", SYS_geteuid, geteuid, 0, CALL_NOERRNO, VOID) /* 25 */ + ENTRY("ptrace", SYS_ptrace, ptrace, 4, CALL_DIRECT, INT, INT, PTR, INT) /* 26 */ + ENTRY("recvmsg", SYS_recvmsg, recvmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 27 */ + ENTRY("sendmsg", SYS_sendmsg, sendmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 28 */ + ENTRY("recvfrom", SYS_recvfrom, recvfrom, 6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR) /* 29 */ + ENTRY("accept", SYS_accept, accept, 3, CALL_DIRECT, INT, PTR, PTR) /* 30 */ + ENTRY("getpeername", SYS_getpeername, getpeername, 3, CALL_DIRECT, INT, PTR, PTR) /* 31 */ + ENTRY("getsockname", SYS_getsockname, getsockname, 3, CALL_DIRECT, INT, PTR, PTR) /* 32 */ + ENTRY("access", SYS_access, access, 2, CALL_DIRECT, PTR, INT) /* 33 */ + ENTRY("chflags", SYS_chflags, chflags, 2, CALL_DIRECT, PTR, INT) /* 34 */ + ENTRY("fchflags", SYS_fchflags, fchflags, 2, CALL_DIRECT, INT, INT) /* 35 */ + ENTRY("sync", SYS_sync, do_sync, 0, CALL_INDIRECT, VOID) /* 36 */ + ENTRY("kill", SYS_kill, kill, 2, CALL_DIRECT, INT, INT) /* 37 */ + ENTRY("", 38, no_syscall, 0, CALL_INDIRECT, VOID) /* 38 old stat */ + ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */ + ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */ + ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */ + ENTRY("pipe", SYS_pipe, unimpl_unix_syscall, 0, CALL_INDIRECT, PTR) /* 42 */ + ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */ + ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */ + ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */ + ENTRY("sigaction", SYS_sigaction, do_sigaction, 3, CALL_DIRECT, INT, PTR, PTR) /* 46 */ + ENTRY("getgid", SYS_getgid, getgid, 0, CALL_NOERRNO, VOID) /* 47 */ + ENTRY("sigprocmask", SYS_sigprocmask, do_sigprocmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 48 */ + ENTRY("getlogin", SYS_getlogin, do_getlogin, 2, CALL_DIRECT, PTR, UINT) /* 49 XXX */ + ENTRY("setlogin", SYS_setlogin, setlogin, 1, CALL_DIRECT, PTR) /* 50 */ + ENTRY("acct", SYS_acct, acct, 1, CALL_DIRECT, PTR) /* 51 */ + ENTRY("sigpending", SYS_sigpending, sigpending, 1, CALL_DIRECT, PTR) /* 52 */ + ENTRY("sigaltstack", SYS_sigaltstack, do_sigaltstack, 2, CALL_DIRECT, PTR, PTR) /* 53 */ + ENTRY("ioctl", SYS_ioctl, do_ioctl, 3, CALL_DIRECT, INT, INT, INT) /* 54 */ + ENTRY("reboot", SYS_reboot, unimpl_unix_syscall, 2, CALL_INDIRECT, INT, PTR) /* 55 */ + ENTRY("revoke", SYS_revoke, revoke, 1, CALL_DIRECT, PTR) /* 56 */ + ENTRY("symlink", SYS_symlink, symlink, 2, CALL_DIRECT, PTR, PTR) /* 57 */ + ENTRY("readlink", SYS_readlink, readlink, 3, CALL_DIRECT, PTR, PTR, INT) /* 58 */ + ENTRY("execve", SYS_execve, do_execve, 3, CALL_DIRECT, PTR, PTR, PTR) /* 59 */ + ENTRY("umask", SYS_umask, umask, 1, CALL_DIRECT, INT) /* 60 */ + ENTRY("chroot", SYS_chroot, chroot, 1, CALL_DIRECT, PTR) /* 61 */ + ENTRY("", 62, no_syscall, 0, CALL_INDIRECT, VOID) /* 62 old fstat */ + ENTRY("", 63, no_syscall, 0, CALL_INDIRECT, VOID) /* 63 used internally , reserved */ + ENTRY("", 64, no_syscall, 0, CALL_INDIRECT, VOID) /* 64 old getpagesize */ + ENTRY("msync", SYS_msync, target_msync, 3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT) /* 65 */ + ENTRY("vfork", SYS_vfork, vfork, 0, CALL_DIRECT, VOID) /* 66 */ + ENTRY("", 67, no_syscall, 0, CALL_INDIRECT, VOID) /* 67 old vread */ + ENTRY("", 68, no_syscall, 0, CALL_INDIRECT, VOID) /* 68 old vwrite */ + ENTRY("sbrk", SYS_sbrk, sbrk, 1, CALL_DIRECT, INT) /* 69 */ + ENTRY("sstk", SYS_sstk, no_syscall, 1, CALL_INDIRECT, VOID) /* 70 */ + ENTRY("", 71, no_syscall, 0, CALL_INDIRECT, VOID) /* 71 old mmap */ + ENTRY("ovadvise", SYS_ovadvise, no_syscall, 0, CALL_INDIRECT, VOID) /* 72 old vadvise */ + ENTRY("munmap", SYS_munmap, target_munmap, 2, CALL_DIRECT, UINT /* PTR */, SIZE) /* 73 */ + ENTRY("mprotect", SYS_mprotect, mprotect, 3, CALL_DIRECT, PTR, SIZE, INT) /* 74 */ + ENTRY("madvise", SYS_madvise, madvise, 3, CALL_DIRECT, PTR, SIZE, INT) /* 75 */ + ENTRY("", 76, no_syscall, 0, CALL_INDIRECT, VOID) /* 76 old vhangup */ + ENTRY("", 77, no_syscall, 0, CALL_INDIRECT, VOID) /* 77 old vlimit */ + ENTRY("mincore", SYS_mincore, mincore, 3, CALL_DIRECT, PTR, SIZE, PTR) /* 78 */ + ENTRY("getgroups", SYS_getgroups, do_getgroups, 2, CALL_DIRECT, UINT, PTR) /* 79 */ + ENTRY("setgroups", SYS_setgroups, setgroups, 2, CALL_DIRECT, UINT, PTR) /* 80 */ + ENTRY("getpgrp", SYS_getpgrp, getpgrp, 0, CALL_DIRECT, VOID) /* 81 */ + ENTRY("setpgid", SYS_setpgid, setpgid, 2, CALL_DIRECT, INT, INT) /* 82 */ + ENTRY("setitimer", SYS_setitimer, setitimer, 3, CALL_DIRECT, INT, PTR, PTR) /* 83 */ + ENTRY("", 84, no_syscall, 0, CALL_INDIRECT, VOID) /* 84 old wait */ + ENTRY("swapon", SYS_swapon, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 85 */ + ENTRY("getitimer", SYS_getitimer, getitimer, 2, CALL_DIRECT, INT, PTR) /* 86 */ + ENTRY("", 87, no_syscall, 0, CALL_INDIRECT, VOID) /* 87 old gethostname */ + ENTRY("", 88, no_syscall, 0, CALL_INDIRECT, VOID) /* 88 old sethostname */ + ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */ + ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */ + ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */ + ENTRY("fcntl", SYS_fcntl, fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */ + ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */ + ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */ + ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */ + ENTRY("setpriority", SYS_setpriority, setpriority, 3, CALL_DIRECT, INT, INT, INT) /* 96 */ + ENTRY("socket", SYS_socket, socket, 3, CALL_DIRECT, INT, INT, INT) /* 97 */ + ENTRY("connect", SYS_connect, connect, 3, CALL_DIRECT, INT, PTR, INT) /* 98 */ + ENTRY("", 99, no_syscall, 0, CALL_INDIRECT, VOID) /* 99 old accept */ + ENTRY("getpriority", SYS_getpriority, getpriority, 2, CALL_DIRECT, INT, INT) /* 100 */ + ENTRY("", 101, no_syscall, 0, CALL_INDIRECT, VOID) /* 101 old send */ + ENTRY("", 102, no_syscall, 0, CALL_INDIRECT, VOID) /* 102 old recv */ + ENTRY("", 103, no_syscall, 0, CALL_INDIRECT, VOID) /* 103 old sigreturn */ + ENTRY("bind", SYS_bind, bind, 3, CALL_DIRECT, INT, PTR, INT) /* 104 */ + ENTRY("setsockopt", SYS_setsockopt, setsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, INT) /* 105 */ + ENTRY("listen", SYS_listen, listen, 2, CALL_DIRECT, INT, INT) /* 106 */ + ENTRY("", 107, no_syscall, 0, CALL_INDIRECT, VOID) /* 107 old vtimes */ + ENTRY("", 108, no_syscall, 0, CALL_INDIRECT, VOID) /* 108 old sigvec */ + ENTRY("", 109, no_syscall, 0, CALL_INDIRECT, VOID) /* 109 old sigblock */ + ENTRY("", 110, no_syscall, 0, CALL_INDIRECT, VOID) /* 110 old sigsetmask */ + ENTRY("sigsuspend", SYS_sigsuspend, unimpl_unix_syscall, 1, CALL_INDIRECT, INT) /* 111 */ + ENTRY("", 112, no_syscall, 0, CALL_INDIRECT, VOID) /* 112 old sigstack */ + ENTRY("", 113, no_syscall, 0, CALL_INDIRECT, VOID) /* 113 old recvmsg */ + ENTRY("", 114, no_syscall, 0, CALL_INDIRECT, VOID) /* 114 old sendmsg */ + ENTRY("", 115, no_syscall, 0, CALL_INDIRECT, VOID) /* 115 old vtrace */ + ENTRY("gettimeofday", SYS_gettimeofday, do_gettimeofday, 2, CALL_DIRECT, PTR, PTR) /* 116 */ + ENTRY("getrusage", SYS_getrusage, getrusage, 2, CALL_DIRECT, INT, PTR) /* 117 */ + ENTRY("getsockopt", SYS_getsockopt, getsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, PTR) /* 118 */ + ENTRY("", 119, no_syscall, 0, CALL_INDIRECT, VOID) /* 119 old resuba */ + ENTRY("readv", SYS_readv, do_readv, 3, CALL_DIRECT, INT, PTR, UINT) /* 120 */ + ENTRY("writev", SYS_writev, do_writev, 3, CALL_DIRECT, INT, PTR, UINT) /* 121 */ + ENTRY("settimeofday", SYS_settimeofday, settimeofday, 2, CALL_DIRECT, PTR, PTR) /* 122 */ + ENTRY("fchown", SYS_fchown, fchown, 3, CALL_DIRECT, INT, INT, INT) /* 123 */ + ENTRY("fchmod", SYS_fchmod, fchmod, 2, CALL_DIRECT, INT, INT) /* 124 */ + ENTRY("", 125, no_syscall, 0, CALL_INDIRECT, VOID) /* 125 old recvfrom */ + ENTRY("", 126, no_syscall, 0, CALL_INDIRECT, VOID) /* 126 old setreuid */ + ENTRY("", 127, no_syscall, 0, CALL_INDIRECT, VOID) /* 127 old setregid */ + ENTRY("rename", SYS_rename, rename, 2, CALL_DIRECT, PTR, PTR) /* 128 */ + ENTRY("", 129, no_syscall, 0, CALL_INDIRECT, VOID) /* 129 old truncate */ + ENTRY("", 130, no_syscall, 0, CALL_INDIRECT, VOID) /* 130 old ftruncate */ + ENTRY("flock", SYS_flock, flock, 2, CALL_DIRECT, INT, INT) /* 131 */ + ENTRY("mkfifo", SYS_mkfifo, mkfifo, 2, CALL_DIRECT, PTR, INT) /* 132 */ + ENTRY("sendto", SYS_sendto, sendto, 6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT) /* 133 */ + ENTRY("shutdown", SYS_shutdown, shutdown, 2, CALL_DIRECT, INT, INT) /* 134 */ + ENTRY("socketpair", SYS_socketpair, socketpair, 4, CALL_DIRECT, INT, INT, INT, PTR) /* 135 */ + ENTRY("mkdir", SYS_mkdir, mkdir, 2, CALL_DIRECT, PTR, INT) /* 136 */ + ENTRY("rmdir", SYS_rmdir, rmdir, 1, CALL_DIRECT, PTR) /* 137 */ + ENTRY("utimes", SYS_utimes, do_utimes, 2, CALL_DIRECT, PTR, PTR) /* 138 */ + ENTRY("futimes", SYS_futimes, do_futimes, 2, CALL_DIRECT, INT, PTR) /* 139 */ + ENTRY("adjtime", SYS_adjtime, adjtime, 2, CALL_DIRECT, PTR, PTR) /* 140 */ + ENTRY("", 141, no_syscall, 0, CALL_INDIRECT, VOID) /* 141 old getpeername */ + ENTRY("", 142, no_syscall, 0, CALL_INDIRECT, VOID) /* 142 old gethostid */ + ENTRY("", 143, no_syscall, 0, CALL_INDIRECT, VOID) /* 143 old sethostid */ + ENTRY("", 144, no_syscall, 0, CALL_INDIRECT, VOID) /* 144 old getrlimit */ + ENTRY("", 145, no_syscall, 0, CALL_INDIRECT, VOID) /* 145 old setrlimit */ + ENTRY("", 146, no_syscall, 0, CALL_INDIRECT, VOID) /* 146 old killpg */ + ENTRY("setsid", SYS_setsid, setsid, 0, CALL_DIRECT, VOID) /* 147 */ + ENTRY("", 148, no_syscall, 0, CALL_INDIRECT, VOID) /* 148 old setquota */ + ENTRY("", 149, no_syscall, 0, CALL_INDIRECT, VOID) /* 149 old qquota */ + ENTRY("", 150, no_syscall, 0, CALL_INDIRECT, VOID) /* 150 old getsockname */ + ENTRY("getpgid", SYS_getpgid, getpgid, 1, CALL_DIRECT, INT) /* 151 */ + ENTRY("setprivexec", SYS_setprivexec, no_syscall, 1, CALL_INDIRECT, VOID) /* 152 */ + ENTRY("pread", SYS_pread, do_pread, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 153 */ + ENTRY("pwrite", SYS_pwrite, pwrite, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 154 */ +#ifdef SYS_nfssvc + ENTRY("nfssvc", SYS_nfssvc, nfssvc, 2, CALL_DIRECT, INT, PTR) /* 155 */ +#else + ENTRY("nfssvc", 155, no_syscall, 2, CALL_INDIRECT, VOID) /* 155 */ +#endif + ENTRY("", 155, no_syscall, 0, CALL_INDIRECT, VOID) /* 155 */ + ENTRY("", 156, no_syscall, 0, CALL_INDIRECT, VOID) /* 156 old getdirentries */ + ENTRY("statfs", SYS_statfs, do_statfs, 2, CALL_DIRECT, PTR, PTR) /* 157 */ + ENTRY("fstatfs", SYS_fstatfs, do_fstatfs, 2, CALL_DIRECT, INT, PTR) /* 158 */ + ENTRY("unmount", SYS_unmount, unmount, 2, CALL_DIRECT, PTR, INT) /* 159 */ + ENTRY("", 160, no_syscall, 0, CALL_INDIRECT, VOID) /* 160 old async_daemon */ + ENTRY("", 161, no_syscall, 0, CALL_INDIRECT, VOID) /* 161 */ + ENTRY("", 162, no_syscall, 0, CALL_INDIRECT, VOID) /* 162 old getdomainname */ + ENTRY("", 163, no_syscall, 0, CALL_INDIRECT, VOID) /* 163 old setdomainname */ + ENTRY("", 164, no_syscall, 0, CALL_INDIRECT, VOID) /* 164 */ + ENTRY("quotactl", SYS_quotactl, no_syscall, 4, CALL_INDIRECT, VOID) /* 165 */ + ENTRY("", 166, no_syscall, 0, CALL_INDIRECT, VOID) /* 166 old exportfs */ + ENTRY("mount", SYS_mount, mount, 4, CALL_DIRECT, PTR, PTR, INT, PTR) /* 167 */ + ENTRY("", 168, no_syscall, 0, CALL_INDIRECT, VOID) /* 168 old ustat */ + ENTRY("", 169, no_syscall, 0, CALL_INDIRECT, VOID) /* 169 */ + ENTRY("table", SYS_table, no_syscall, 0, CALL_INDIRECT, VOID) /* 170 old table */ + ENTRY("", 171, no_syscall, 0, CALL_INDIRECT, VOID) /* 171 old wait3 */ + ENTRY("", 172, no_syscall, 0, CALL_INDIRECT, VOID) /* 172 old rpause */ + ENTRY("waitid", SYS_waitid, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 173 */ + ENTRY("", 174, no_syscall, 0, CALL_INDIRECT, VOID) /* 174 old getdents */ + ENTRY("", 175, no_syscall, 0, CALL_INDIRECT, VOID) /* 175 old gc_control */ + ENTRY("add_profil", SYS_add_profil, add_profil, 4, CALL_DIRECT, PTR, SIZE, UINT, UINT) /* 176 */ + ENTRY("", 177, no_syscall, 0, CALL_INDIRECT, VOID) /* 177 */ + ENTRY("", 178, no_syscall, 0, CALL_INDIRECT, VOID) /* 178 */ + ENTRY("", 179, no_syscall, 0, CALL_INDIRECT, VOID) /* 179 */ + ENTRY("kdebug_trace", SYS_kdebug_trace, no_syscall, 6, CALL_INDIRECT, VOID) /* 180 */ + ENTRY("setgid", SYS_setgid, setgid, 1, CALL_DIRECT, INT) /* 181 */ + ENTRY("setegid", SYS_setegid, setegid, 1, CALL_DIRECT, INT) /* 182 */ + ENTRY("seteuid", SYS_seteuid, seteuid, 1, CALL_DIRECT, INT) /* 183 */ + ENTRY("sigreturn", SYS_sigreturn, do_sigreturn, 2, CALL_INDIRECT, PTR, INT) /* 184 */ + ENTRY("chud", SYS_chud, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 185 */ + ENTRY("", 186, no_syscall, 0, CALL_INDIRECT, VOID) /* 186 */ + ENTRY("", 187, no_syscall, 0, CALL_INDIRECT, VOID) /* 187 */ + ENTRY("stat", SYS_stat, do_stat, 2, CALL_DIRECT, PTR, PTR) /* 188 */ + ENTRY("fstat", SYS_fstat, do_fstat, 2, CALL_DIRECT, INT, PTR) /* 189 */ + ENTRY("lstat", SYS_lstat, do_lstat, 2, CALL_DIRECT, PTR, PTR) /* 190 */ + ENTRY("pathconf", SYS_pathconf, pathconf, 2, CALL_DIRECT, PTR, INT) /* 191 */ + ENTRY("fpathconf", SYS_fpathconf, fpathconf, 2, CALL_DIRECT, INT, INT) /* 192 */ + ENTRY("getfsstat", SYS_getfsstat, do_getfsstat, 3, CALL_DIRECT, PTR, INT, INT) /* 193 */ + ENTRY("", 193, no_syscall, 0, CALL_INDIRECT, VOID) /* 193 */ + ENTRY("getrlimit", SYS_getrlimit, getrlimit, 2, CALL_DIRECT, UINT, PTR) /* 194 */ + ENTRY("setrlimit", SYS_setrlimit, setrlimit, 2, CALL_DIRECT, UINT, PTR) /* 195 */ + ENTRY("getdirentries", SYS_getdirentries, do_getdirentries, 4, CALL_DIRECT, INT, PTR, UINT, PTR) /* 196 */ + ENTRY("mmap", SYS_mmap, target_mmap, 6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET) /* 197 */ + ENTRY("", 198, no_syscall, 0, CALL_INDIRECT, VOID) /* 198 __syscall */ + ENTRY("lseek", SYS_lseek, do_lseek, 3, CALL_INDIRECT, INT, OFFSET, INT) /* 199 */ + ENTRY("truncate", SYS_truncate, truncate, 2, CALL_DIRECT, PTR, OFFSET) /* 200 */ + ENTRY("ftruncate", SYS_ftruncate, ftruncate, 2, CALL_DIRECT, INT, OFFSET) /* 201 */ + ENTRY("__sysctl", SYS___sysctl, do___sysctl, 6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE) /* 202 */ + ENTRY("mlock", SYS_mlock, mlock, 2, CALL_DIRECT, PTR, SIZE) /* 203 */ + ENTRY("munlock", SYS_munlock, munlock, 2, CALL_DIRECT, PTR, SIZE) /* 204 */ + ENTRY("undelete", SYS_undelete, undelete, 1, CALL_DIRECT, PTR) /* 205 */ + ENTRY("ATsocket", SYS_ATsocket, no_syscall, 1, CALL_INDIRECT, VOID) /* 206 */ + ENTRY("ATgetmsg", SYS_ATgetmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 207 */ + ENTRY("ATputmsg", SYS_ATputmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 208 */ + ENTRY("ATPsndreq", SYS_ATPsndreq, no_syscall, 4, CALL_INDIRECT, VOID) /* 209 */ + ENTRY("ATPsndrsp", SYS_ATPsndrsp, no_syscall, 4, CALL_INDIRECT, VOID) /* 210 */ + ENTRY("ATPgetreq", SYS_ATPgetreq, no_syscall, 3, CALL_INDIRECT, VOID) /* 211 */ + ENTRY("ATPgetrsp", SYS_ATPgetrsp, no_syscall, 2, CALL_INDIRECT, VOID) /* 212 */ + ENTRY("", 213, no_syscall, 0, CALL_INDIRECT, VOID) /* 213 Reserved for AppleTalk */ + ENTRY("kqueue_from_portset_np", SYS_kqueue_from_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 214 */ + ENTRY("kqueue_portset_np", SYS_kqueue_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 215 */ + ENTRY("mkcomplex", SYS_mkcomplex, no_syscall, 3, CALL_INDIRECT, VOID) /* 216 soon to be obsolete */ + ENTRY("statv", SYS_statv, no_syscall, 2, CALL_INDIRECT, VOID) /* 217 soon to be obsolete */ + ENTRY("lstatv", SYS_lstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 218 soon to be obsolete */ + ENTRY("fstatv", SYS_fstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 219 soon to be obsolete */ + ENTRY("getattrlist", SYS_getattrlist, do_getattrlist, 5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT) /* 220 */ + ENTRY("setattrlist", SYS_setattrlist, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 221 */ + ENTRY("getdirentriesattr", SYS_getdirentriesattr, do_getdirentriesattr, 8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT) /* 222 */ + ENTRY("exchangedata", SYS_exchangedata, exchangedata, 3, CALL_DIRECT, PTR, PTR, UINT) /* 223 */ + ENTRY("checkuseraccess", SYS_checkuseraccess, checkuseraccess, 6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT) /* 224 */ + ENTRY("", 224, no_syscall, 0, CALL_INDIRECT, VOID) /* 224 HFS checkuseraccess check access to a file */ + ENTRY("searchfs", SYS_searchfs, searchfs, 6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR) /* 225 */ + ENTRY("delete", SYS_delete, no_syscall, 1, CALL_INDIRECT, VOID) /* 226 private delete ( Carbon semantics ) */ + ENTRY("copyfile", SYS_copyfile, no_syscall, 4, CALL_INDIRECT, VOID) /* 227 */ + ENTRY("", 228, no_syscall, 0, CALL_INDIRECT, VOID) /* 228 */ + ENTRY("", 229, no_syscall, 0, CALL_INDIRECT, VOID) /* 229 */ + ENTRY("poll", SYS_poll, no_syscall, 3, CALL_INDIRECT, VOID) /* 230 */ + ENTRY("watchevent", SYS_watchevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 231 */ + ENTRY("waitevent", SYS_waitevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 232 */ + ENTRY("modwatch", SYS_modwatch, no_syscall, 2, CALL_INDIRECT, VOID) /* 233 */ + ENTRY("getxattr", SYS_getxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 234 */ + ENTRY("fgetxattr", SYS_fgetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 235 */ + ENTRY("setxattr", SYS_setxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 236 */ + ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */ + ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */ + ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */ + ENTRY("listxattr", SYS_listxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 240 */ + ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */ + ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */ + ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */ + ENTRY("", 244, no_syscall, 0, CALL_INDIRECT, VOID) /* 244 */ + ENTRY("", 245, no_syscall, 0, CALL_INDIRECT, VOID) /* 245 */ + ENTRY("", 246, no_syscall, 0, CALL_INDIRECT, VOID) /* 246 */ +#ifdef SYS_nfsclnt + ENTRY("nfsclnt", SYS_nfsclnt, nfsclnt, 2, CALL_DIRECT, INT, PTR) /* 247 */ +#else + ENTRY("nfsclnt", 247, no_syscall, 2, CALL_INDIRECT, VOID) /* 247 */ +#endif + ENTRY("", 247, no_syscall, 0, CALL_INDIRECT, VOID) /* 247 */ + ENTRY("", 248, no_syscall, 0, CALL_INDIRECT, VOID) /* 248 */ + ENTRY("", 249, no_syscall, 0, CALL_INDIRECT, VOID) /* 249 */ + ENTRY("minherit", SYS_minherit, minherit, 3, CALL_DIRECT, PTR, INT, INT) /* 250 */ + ENTRY("semsys", SYS_semsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 251 */ + ENTRY("msgsys", SYS_msgsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 252 */ + ENTRY("shmsys", SYS_shmsys, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 253 */ + ENTRY("semctl", SYS_semctl, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 254 */ + ENTRY("semget", SYS_semget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 255 */ + ENTRY("semop", SYS_semop, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 256 */ + ENTRY("", 257, no_syscall, 0, CALL_INDIRECT, VOID) /* 257 */ + ENTRY("msgctl", SYS_msgctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 258 */ + ENTRY("msgget", SYS_msgget, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 259 */ + ENTRY("msgsnd", SYS_msgsnd, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 260 */ + ENTRY("msgrcv", SYS_msgrcv, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 261 */ + ENTRY("shmat", SYS_shmat, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 262 */ + ENTRY("shmctl", SYS_shmctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 263 */ + ENTRY("shmdt", SYS_shmdt, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 264 */ + ENTRY("shmget", SYS_shmget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 265 */ + ENTRY("shm_open", SYS_shm_open, shm_open, 3, CALL_DIRECT, PTR, INT, INT) /* 266 */ + ENTRY("shm_unlink", SYS_shm_unlink, shm_unlink, 1, CALL_DIRECT, PTR) /* 267 */ + ENTRY("sem_open", SYS_sem_open, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 268 */ + ENTRY("sem_close", SYS_sem_close, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 269 */ + ENTRY("sem_unlink", SYS_sem_unlink, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 270 */ + ENTRY("sem_wait", SYS_sem_wait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 271 */ + ENTRY("sem_trywait", SYS_sem_trywait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 272 */ + ENTRY("sem_post", SYS_sem_post, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 273 */ + ENTRY("sem_getvalue", SYS_sem_getvalue, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 274 */ + ENTRY("sem_init", SYS_sem_init, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 275 */ + ENTRY("sem_destroy", SYS_sem_destroy, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 276 */ + ENTRY("open_extended", SYS_open_extended, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 277 */ + ENTRY("umask_extended", SYS_umask_extended, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 278 */ + ENTRY("stat_extended", SYS_stat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 279 */ + ENTRY("lstat_extended", SYS_lstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 280 */ + ENTRY("fstat_extended", SYS_fstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 281 */ + ENTRY("chmod_extended", SYS_chmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 282 */ + ENTRY("fchmod_extended", SYS_fchmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 283 */ + ENTRY("access_extended", SYS_access_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 284 */ + ENTRY("settid", SYS_settid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 285 */ + ENTRY("gettid", SYS_gettid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 286 */ + ENTRY("setsgroups", SYS_setsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 287 */ + ENTRY("getsgroups", SYS_getsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 288 */ + ENTRY("setwgroups", SYS_setwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 289 */ + ENTRY("getwgroups", SYS_getwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 290 */ + ENTRY("mkfifo_extended", SYS_mkfifo_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 291 */ + ENTRY("mkdir_extended", SYS_mkdir_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 292 */ + ENTRY("identitysvc", SYS_identitysvc, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 293 */ + ENTRY("", 294, no_syscall, 0, CALL_INDIRECT, VOID) /* 294 */ + ENTRY("", 295, no_syscall, 0, CALL_INDIRECT, VOID) /* 295 */ + ENTRY("load_shared_file", SYS_load_shared_file, unimpl_unix_syscall, 7, CALL_INDIRECT, VOID) /* 296 */ + ENTRY("reset_shared_file", SYS_reset_shared_file, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 297 */ + ENTRY("new_system_shared_regions", SYS_new_system_shared_regions, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 298 */ + ENTRY("shared_region_map_file_np", SYS_shared_region_map_file_np, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 299 */ + ENTRY("shared_region_make_private_np", SYS_shared_region_make_private_np, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 300 */ + ENTRY("", 301, no_syscall, 0, CALL_INDIRECT, VOID) /* 301 */ + ENTRY("", 302, no_syscall, 0, CALL_INDIRECT, VOID) /* 302 */ + ENTRY("", 303, no_syscall, 0, CALL_INDIRECT, VOID) /* 303 */ + ENTRY("", 304, no_syscall, 0, CALL_INDIRECT, VOID) /* 304 */ + ENTRY("", 305, no_syscall, 0, CALL_INDIRECT, VOID) /* 305 */ + ENTRY("", 306, no_syscall, 0, CALL_INDIRECT, VOID) /* 306 */ + ENTRY("", 307, no_syscall, 0, CALL_INDIRECT, VOID) /* 307 */ + ENTRY("", 308, no_syscall, 0, CALL_INDIRECT, VOID) /* 308 */ + ENTRY("", 309, no_syscall, 0, CALL_INDIRECT, VOID) /* 309 */ + ENTRY("getsid", SYS_getsid, getsid, 1, CALL_DIRECT, INT) /* 310 */ + ENTRY("settid_with_pid", SYS_settid_with_pid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 311 */ + ENTRY("", 312, no_syscall, 0, CALL_INDIRECT, VOID) /* 312 */ + ENTRY("aio_fsync", SYS_aio_fsync, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 313 */ + ENTRY("aio_return", SYS_aio_return, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 314 */ + ENTRY("aio_suspend", SYS_aio_suspend, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 315 */ + ENTRY("aio_cancel", SYS_aio_cancel, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 316 */ + ENTRY("aio_error", SYS_aio_error, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 317 */ + ENTRY("aio_read", SYS_aio_read, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 318 */ + ENTRY("aio_write", SYS_aio_write, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 319 */ + ENTRY("lio_listio", SYS_lio_listio, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 320 */ + ENTRY("", 321, no_syscall, 0, CALL_INDIRECT, VOID) /* 321 */ + ENTRY("", 322, no_syscall, 0, CALL_INDIRECT, VOID) /* 322 */ + ENTRY("", 323, no_syscall, 0, CALL_INDIRECT, VOID) /* 323 */ + ENTRY("mlockall", SYS_mlockall, mlockall, 1, CALL_DIRECT, INT) /* 324 */ + ENTRY("munlockall", SYS_munlockall, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 325 */ + ENTRY("", 326, no_syscall, 0, CALL_INDIRECT, VOID) /* 326 */ + ENTRY("issetugid", SYS_issetugid, issetugid, 0, CALL_DIRECT, VOID) /* 327 */ + ENTRY("__pthread_kill", SYS___pthread_kill, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 328 */ + ENTRY("pthread_sigmask", SYS_pthread_sigmask, pthread_sigmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 329 */ + ENTRY("sigwait", SYS_sigwait, sigwait, 2, CALL_DIRECT, PTR, PTR) /* 330 */ + ENTRY("__disable_threadsignal", SYS___disable_threadsignal, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 331 */ + ENTRY("__pthread_markcancel", SYS___pthread_markcancel, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 332 */ + ENTRY("__pthread_canceled", SYS___pthread_canceled, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 333 */ + ENTRY("__semwait_signal", SYS___semwait_signal, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 334 */ + ENTRY("utrace", SYS_utrace, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 335 */ + ENTRY("proc_info", SYS_proc_info, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 336 */ + ENTRY("", 337, no_syscall, 0, CALL_INDIRECT, VOID) /* 337 */ + ENTRY("", 338, no_syscall, 0, CALL_INDIRECT, VOID) /* 338 */ + ENTRY("", 339, no_syscall, 0, CALL_INDIRECT, VOID) /* 339 */ + ENTRY("", 340, no_syscall, 0, CALL_INDIRECT, VOID) /* 340 */ + ENTRY("", 341, no_syscall, 0, CALL_INDIRECT, VOID) /* 341 */ + ENTRY("", 342, no_syscall, 0, CALL_INDIRECT, VOID) /* 342 */ + ENTRY("", 343, no_syscall, 0, CALL_INDIRECT, VOID) /* 343 */ + ENTRY("", 344, no_syscall, 0, CALL_INDIRECT, VOID) /* 344 */ + ENTRY("", 345, no_syscall, 0, CALL_INDIRECT, VOID) /* 345 */ + ENTRY("", 346, no_syscall, 0, CALL_INDIRECT, VOID) /* 346 */ + ENTRY("", 347, no_syscall, 0, CALL_INDIRECT, VOID) /* 347 */ + ENTRY("", 348, no_syscall, 0, CALL_INDIRECT, VOID) /* 348 */ + ENTRY("", 349, no_syscall, 0, CALL_INDIRECT, VOID) /* 349 */ + ENTRY("audit", SYS_audit, audit, 2, CALL_DIRECT, PTR, INT) /* 350 */ + ENTRY("auditon", SYS_auditon, auditon, 3, CALL_DIRECT, INT, PTR, INT) /* 351 */ + ENTRY("", 352, no_syscall, 0, CALL_INDIRECT, VOID) /* 352 */ + ENTRY("getauid", SYS_getauid, getauid, 1, CALL_DIRECT, PTR) /* 353 */ + ENTRY("setauid", SYS_setauid, setauid, 1, CALL_DIRECT, PTR) /* 354 */ + ENTRY("getaudit", SYS_getaudit, getaudit, 1, CALL_DIRECT, PTR) /* 355 */ + ENTRY("setaudit", SYS_setaudit, setaudit, 1, CALL_DIRECT, PTR) /* 356 */ + ENTRY("getaudit_addr", SYS_getaudit_addr, getaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 357 */ + ENTRY("setaudit_addr", SYS_setaudit_addr, setaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 358 */ + ENTRY("auditctl", SYS_auditctl, auditctl, 1, CALL_DIRECT, PTR) /* 359 */ + ENTRY("", 360, no_syscall, 0, CALL_INDIRECT, VOID) /* 360 */ + ENTRY("", 361, no_syscall, 0, CALL_INDIRECT, VOID) /* 361 */ + ENTRY("kqueue", SYS_kqueue, kqueue, 0, CALL_DIRECT, VOID) /* 362 */ + ENTRY("kevent", SYS_kevent, kevent, 6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR) /* 363 */ + ENTRY("lchown", SYS_lchown, lchown, 3, CALL_DIRECT, PTR, INT , INT) /* 364 */ + ENTRY("stack_snapshot", SYS_stack_snapshot, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 365 */ + ENTRY("", 366, no_syscall, 0, CALL_INDIRECT, VOID) /* 366 */ + ENTRY("", 367, no_syscall, 0, CALL_INDIRECT, VOID) /* 367 */ + ENTRY("", 368, no_syscall, 0, CALL_INDIRECT, VOID) /* 368 */ + ENTRY("", 369, no_syscall, 0, CALL_INDIRECT, VOID) /* 369 */ |