Commit 831b78254cfa752d5e6542542a663468e650bcb3
1 parent
54421cb1
Darwin userspace emulation, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2332 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
11 changed files
with
4611 additions
and
10 deletions
Too many changes to show.
To preserve performance only 11 of 13 files are displayed.
Makefile.target
@@ -13,7 +13,11 @@ endif | @@ -13,7 +13,11 @@ endif | ||
13 | TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) | 13 | TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) |
14 | VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio | 14 | VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio |
15 | CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) | 15 | CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) |
16 | -ifdef CONFIG_USER_ONLY | 16 | +ifdef CONFIG_DARWIN_USER |
17 | +VPATH+=:$(SRC_PATH)/darwin-user | ||
18 | +CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) | ||
19 | +endif | ||
20 | +ifdef CONFIG_LINUX_USER | ||
17 | VPATH+=:$(SRC_PATH)/linux-user | 21 | VPATH+=:$(SRC_PATH)/linux-user |
18 | CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) | 22 | CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) |
19 | endif | 23 | endif |
@@ -85,12 +89,14 @@ endif | @@ -85,12 +89,14 @@ endif | ||
85 | ifdef USE_I386_LD | 89 | ifdef USE_I386_LD |
86 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld | 90 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
87 | else | 91 | else |
92 | +ifdef CONFIG_LINUX_USER | ||
88 | # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object | 93 | # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object |
89 | # that the kernel ELF loader considers as an executable. I think this | 94 | # that the kernel ELF loader considers as an executable. I think this |
90 | # is the simplest way to make it self virtualizable! | 95 | # is the simplest way to make it self virtualizable! |
91 | BASE_LDFLAGS+=-Wl,-shared | 96 | BASE_LDFLAGS+=-Wl,-shared |
92 | endif | 97 | endif |
93 | endif | 98 | endif |
99 | +endif | ||
94 | 100 | ||
95 | ifeq ($(ARCH),x86_64) | 101 | ifeq ($(ARCH),x86_64) |
96 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld | 102 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
@@ -98,8 +104,10 @@ endif | @@ -98,8 +104,10 @@ endif | ||
98 | 104 | ||
99 | ifeq ($(ARCH),ppc) | 105 | ifeq ($(ARCH),ppc) |
100 | CPPFLAGS+= -D__powerpc__ | 106 | CPPFLAGS+= -D__powerpc__ |
107 | +ifdef CONFIG_LINUX_USER | ||
101 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld | 108 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
102 | endif | 109 | endif |
110 | +endif | ||
103 | 111 | ||
104 | ifeq ($(ARCH),s390) | 112 | ifeq ($(ARCH),s390) |
105 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld | 113 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
@@ -186,6 +194,7 @@ BASE_LDFLAGS+=-p | @@ -186,6 +194,7 @@ BASE_LDFLAGS+=-p | ||
186 | main.o: BASE_CFLAGS+=-p | 194 | main.o: BASE_CFLAGS+=-p |
187 | endif | 195 | endif |
188 | 196 | ||
197 | +ifdef CONFIG_LINUX_USER | ||
189 | OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ | 198 | OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ |
190 | elfload.o linuxload.o | 199 | elfload.o linuxload.o |
191 | ifdef TARGET_HAS_BFLT | 200 | ifdef TARGET_HAS_BFLT |
@@ -203,6 +212,12 @@ endif | @@ -203,6 +212,12 @@ endif | ||
203 | ifeq ($(TARGET_ARCH), m68k) | 212 | ifeq ($(TARGET_ARCH), m68k) |
204 | OBJS+= m68k-sim.o m68k-semi.o | 213 | OBJS+= m68k-sim.o m68k-semi.o |
205 | endif | 214 | endif |
215 | +endif #CONFIG_LINUX_USER | ||
216 | + | ||
217 | +ifdef CONFIG_DARWIN_USER | ||
218 | +OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o | ||
219 | +endif | ||
220 | + | ||
206 | SRCS:= $(OBJS:.o=.c) | 221 | SRCS:= $(OBJS:.o=.c) |
207 | OBJS+= libqemu.a | 222 | OBJS+= libqemu.a |
208 | 223 |
configure
@@ -94,7 +94,8 @@ cocoa="no" | @@ -94,7 +94,8 @@ cocoa="no" | ||
94 | check_gfx="yes" | 94 | check_gfx="yes" |
95 | check_gcc="yes" | 95 | check_gcc="yes" |
96 | softmmu="yes" | 96 | softmmu="yes" |
97 | -user="no" | 97 | +linux_user="no" |
98 | +darwin_user="no" | ||
98 | build_docs="no" | 99 | build_docs="no" |
99 | uname_release="" | 100 | uname_release="" |
100 | 101 | ||
@@ -126,6 +127,7 @@ oss="yes" | @@ -126,6 +127,7 @@ oss="yes" | ||
126 | Darwin) | 127 | Darwin) |
127 | bsd="yes" | 128 | bsd="yes" |
128 | darwin="yes" | 129 | darwin="yes" |
130 | +darwin_user="yes" | ||
129 | OS_CFLAGS="-mdynamic-no-pic" | 131 | OS_CFLAGS="-mdynamic-no-pic" |
130 | ;; | 132 | ;; |
131 | SunOS) | 133 | SunOS) |
@@ -134,7 +136,7 @@ solaris="yes" | @@ -134,7 +136,7 @@ solaris="yes" | ||
134 | *) | 136 | *) |
135 | oss="yes" | 137 | oss="yes" |
136 | linux="yes" | 138 | linux="yes" |
137 | -user="yes" | 139 | +linux_user="yes" |
138 | if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then | 140 | if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then |
139 | kqemu="yes" | 141 | kqemu="yes" |
140 | fi | 142 | fi |
@@ -240,9 +242,13 @@ for opt do | @@ -240,9 +242,13 @@ for opt do | ||
240 | ;; | 242 | ;; |
241 | --enable-system) softmmu="yes" | 243 | --enable-system) softmmu="yes" |
242 | ;; | 244 | ;; |
243 | - --disable-user) user="no" | 245 | + --disable-linux-user) linux_user="no" |
244 | ;; | 246 | ;; |
245 | - --enable-user) user="yes" | 247 | + --enable-linux-user) linux_user="yes" |
248 | + ;; | ||
249 | + --disable-darwin-user) darwin_user="no" | ||
250 | + ;; | ||
251 | + --enable-darwin-user) darwin_user="yes" | ||
246 | ;; | 252 | ;; |
247 | --enable-uname-release=*) uname_release="$optarg" | 253 | --enable-uname-release=*) uname_release="$optarg" |
248 | ;; | 254 | ;; |
@@ -287,8 +293,10 @@ echo " --enable-fmod enable FMOD audio driver" | @@ -287,8 +293,10 @@ echo " --enable-fmod enable FMOD audio driver" | ||
287 | echo " --enabled-dsound enable DirectSound audio driver" | 293 | echo " --enabled-dsound enable DirectSound audio driver" |
288 | echo " --enable-system enable all system emulation targets" | 294 | echo " --enable-system enable all system emulation targets" |
289 | echo " --disable-system disable all system emulation targets" | 295 | echo " --disable-system disable all system emulation targets" |
290 | -echo " --enable-user enable all linux usermode emulation targets" | ||
291 | -echo " --disable-user disable all linux usermode emulation targets" | 296 | +echo " --enable-linux-user enable all linux usermode emulation targets" |
297 | +echo " --disable-linux-user disable all linux usermode emulation targets" | ||
298 | +echo " --enable-darwin-user enable all darwin usermode emulation targets" | ||
299 | +echo " --disable-darwin-user disable all darwin usermode emulation targets" | ||
292 | echo " --fmod-lib path to FMOD library" | 300 | echo " --fmod-lib path to FMOD library" |
293 | echo " --fmod-inc path to FMOD includes" | 301 | echo " --fmod-inc path to FMOD includes" |
294 | echo " --enable-uname-release=R Return R for uname -r in usermode emulation" | 302 | echo " --enable-uname-release=R Return R for uname -r in usermode emulation" |
@@ -408,8 +416,12 @@ if test -z "$target_list" ; then | @@ -408,8 +416,12 @@ if test -z "$target_list" ; then | ||
408 | target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu" | 416 | target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu" |
409 | fi | 417 | fi |
410 | # the following are Linux specific | 418 | # the following are Linux specific |
411 | - if [ "$user" = "yes" ] ; then | ||
412 | - target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user m68k-user $target_list" | 419 | + if [ "$linux_user" = "yes" ] ; then |
420 | + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user $target_list" | ||
421 | + fi | ||
422 | +# the following are Darwin specific | ||
423 | + if [ "$darwin_user" = "yes" ] ; then | ||
424 | + target_list="i386-darwin-user ppc-darwin-user $target_list" | ||
413 | fi | 425 | fi |
414 | else | 426 | else |
415 | target_list=`echo "$target_list" | sed -e 's/,/ /g'` | 427 | target_list=`echo "$target_list" | sed -e 's/,/ /g'` |
@@ -787,6 +799,16 @@ if expr $target : '.*-user' > /dev/null ; then | @@ -787,6 +799,16 @@ if expr $target : '.*-user' > /dev/null ; then | ||
787 | target_user_only="yes" | 799 | target_user_only="yes" |
788 | fi | 800 | fi |
789 | 801 | ||
802 | +target_linux_user="no" | ||
803 | +if expr $target : '.*-linux-user' > /dev/null ; then | ||
804 | + target_linux_user="yes" | ||
805 | +fi | ||
806 | + | ||
807 | +target_darwin_user="no" | ||
808 | +if expr $target : '.*-darwin-user' > /dev/null ; then | ||
809 | + target_darwin_user="yes" | ||
810 | +fi | ||
811 | + | ||
790 | if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ | 812 | if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ |
791 | -a "$sdl" = "no" -a "$cocoa" = "no" ; then | 813 | -a "$sdl" = "no" -a "$cocoa" = "no" ; then |
792 | echo "ERROR: QEMU requires SDL or Cocoa for graphical output" | 814 | echo "ERROR: QEMU requires SDL or Cocoa for graphical output" |
@@ -799,7 +821,7 @@ fi | @@ -799,7 +821,7 @@ fi | ||
799 | 821 | ||
800 | mkdir -p $target_dir | 822 | mkdir -p $target_dir |
801 | mkdir -p $target_dir/fpu | 823 | mkdir -p $target_dir/fpu |
802 | -if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then | 824 | +if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then |
803 | mkdir -p $target_dir/nwfpe | 825 | mkdir -p $target_dir/nwfpe |
804 | fi | 826 | fi |
805 | if test "$target_user_only" = "no" ; then | 827 | if test "$target_user_only" = "no" ; then |
@@ -894,6 +916,14 @@ if test "$target_user_only" = "yes" ; then | @@ -894,6 +916,14 @@ if test "$target_user_only" = "yes" ; then | ||
894 | echo "CONFIG_USER_ONLY=yes" >> $config_mak | 916 | echo "CONFIG_USER_ONLY=yes" >> $config_mak |
895 | echo "#define CONFIG_USER_ONLY 1" >> $config_h | 917 | echo "#define CONFIG_USER_ONLY 1" >> $config_h |
896 | fi | 918 | fi |
919 | +if test "$target_linux_user" = "yes" ; then | ||
920 | + echo "CONFIG_LINUX_USER=yes" >> $config_mak | ||
921 | + echo "#define CONFIG_LINUX_USER 1" >> $config_h | ||
922 | +fi | ||
923 | +if test "$target_darwin_user" = "yes" ; then | ||
924 | + echo "CONFIG_DARWIN_USER=yes" >> $config_mak | ||
925 | + echo "#define CONFIG_DARWIN_USER 1" >> $config_h | ||
926 | +fi | ||
897 | 927 | ||
898 | if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then | 928 | if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then |
899 | echo "CONFIG_SOFTFLOAT=yes" >> $config_mak | 929 | echo "CONFIG_SOFTFLOAT=yes" >> $config_mak |
darwin-user/commpage.c
0 โ 100644
1 | + /* | ||
2 | + * Commpage syscalls | ||
3 | + * | ||
4 | + * Copyright (c) 2006 Pierre d'Herbemont | ||
5 | + * | ||
6 | + * This program is free software; you can redistribute it and/or modify | ||
7 | + * it under the terms of the GNU General Public License as published by | ||
8 | + * the Free Software Foundation; either version 2 of the License, or | ||
9 | + * (at your option) any later version. | ||
10 | + * | ||
11 | + * This program is distributed in the hope that it will be useful, | ||
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | + * GNU General Public License for more details. | ||
15 | + * | ||
16 | + * You should have received a copy of the GNU General Public License | ||
17 | + * along with this program; if not, write to the Free Software | ||
18 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | + */ | ||
20 | +#include <fcntl.h> | ||
21 | +#include <stdio.h> | ||
22 | +#include <stdlib.h> | ||
23 | +#include <errno.h> | ||
24 | + | ||
25 | +#include <mach/message.h> | ||
26 | +#include <mach/mach.h> | ||
27 | +#include <mach/mach_time.h> | ||
28 | +#include <sys/time.h> | ||
29 | +#include <sys/mman.h> | ||
30 | +#include <libkern/OSAtomic.h> | ||
31 | + | ||
32 | +#include "qemu.h" | ||
33 | + | ||
34 | +//#define DEBUG_COMMPAGE | ||
35 | + | ||
36 | +#ifdef DEBUG_COMMPAGE | ||
37 | +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) | ||
38 | +#else | ||
39 | +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) | ||
40 | +#endif | ||
41 | + | ||
42 | +/******************************************************************** | ||
43 | + * Commpage definitions | ||
44 | + */ | ||
45 | +#ifdef TARGET_I386 | ||
46 | +/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */ | ||
47 | +# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */ | ||
48 | +# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */ | ||
49 | +#elif defined(TARGET_PPC) | ||
50 | +/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */ | ||
51 | +# define COMMPAGE_START (-8*4096) | ||
52 | +# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */ | ||
53 | +#endif | ||
54 | + | ||
55 | +void do_compare_and_swap32(void *cpu_env, int num); | ||
56 | +void do_compare_and_swap64(void *cpu_env, int num); | ||
57 | +void do_add_atomic_word32(void *cpu_env, int num); | ||
58 | +void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1); | ||
59 | +void do_nanotime(void *cpu_env, int num); | ||
60 | + | ||
61 | +void unimpl_commpage(void *cpu_env, int num); | ||
62 | + | ||
63 | +typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
64 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, | ||
65 | + uint32_t arg8); | ||
66 | +typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1, | ||
67 | + uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, | ||
68 | + uint32_t arg6, uint32_t arg7, uint32_t arg8); | ||
69 | + | ||
70 | +#define HAS_PTR 0x10 | ||
71 | +#define NO_PTR 0x20 | ||
72 | +#define CALL_DIRECT 0x1 | ||
73 | +#define CALL_INDIRECT 0x2 | ||
74 | + | ||
75 | +#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \ | ||
76 | + { #name, offset, nargs, options, (commpage_8args_function_t)func } | ||
77 | + | ||
78 | +struct commpage_entry { | ||
79 | + char * name; | ||
80 | + int offset; | ||
81 | + int nargs; | ||
82 | + char options; | ||
83 | + commpage_8args_function_t function; | ||
84 | +}; | ||
85 | + | ||
86 | +static inline int commpage_code_num(struct commpage_entry *entry) | ||
87 | +{ | ||
88 | + if((entry->options & HAS_PTR)) | ||
89 | + return entry->offset + 4; | ||
90 | + else | ||
91 | + return entry->offset; | ||
92 | +} | ||
93 | + | ||
94 | +static inline int commpage_is_indirect(struct commpage_entry *entry) | ||
95 | +{ | ||
96 | + return !(entry->options & CALL_DIRECT); | ||
97 | +} | ||
98 | + | ||
99 | +/******************************************************************** | ||
100 | + * Commpage entry | ||
101 | + */ | ||
102 | +static struct commpage_entry commpage_entries[] = | ||
103 | +{ | ||
104 | + COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR), | ||
105 | + COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR), | ||
106 | + COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT), | ||
107 | + COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT), | ||
108 | + COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT), | ||
109 | + COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR), | ||
110 | + COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR), | ||
111 | + | ||
112 | + COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT), | ||
113 | + COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT), | ||
114 | + COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT), | ||
115 | + COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT), | ||
116 | + COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), | ||
117 | + COMMPAGE_ENTRY(gettimeofday, 1, 0x2c0, do_cgettimeofday, CALL_INDIRECT), | ||
118 | + COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), | ||
119 | + COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), | ||
120 | + COMMPAGE_ENTRY(pthread_self, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), | ||
121 | + | ||
122 | + COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT), | ||
123 | + | ||
124 | +#ifdef TARGET_I386 | ||
125 | + COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT), | ||
126 | + COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT), | ||
127 | +#endif | ||
128 | + | ||
129 | + COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT), | ||
130 | + COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT), | ||
131 | + COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT), | ||
132 | + | ||
133 | +#ifdef TARGET_I386 | ||
134 | + COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT), | ||
135 | + COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT), | ||
136 | + COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT), | ||
137 | + | ||
138 | + COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT), | ||
139 | + | ||
140 | + COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT), | ||
141 | +#elif TARGET_PPC | ||
142 | + COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT), | ||
143 | + COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT), | ||
144 | + COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT), | ||
145 | + COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT), | ||
146 | +#endif | ||
147 | +}; | ||
148 | + | ||
149 | + | ||
150 | +/******************************************************************** | ||
151 | + * Commpage backdoor | ||
152 | + */ | ||
153 | +static inline void print_commpage_entry(struct commpage_entry entry) | ||
154 | +{ | ||
155 | + printf("@0x%x %s\n", entry.offset, entry.name); | ||
156 | +} | ||
157 | + | ||
158 | +static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry) | ||
159 | +{ | ||
160 | +#ifdef TARGET_I386 | ||
161 | + char * commpage = (char*)(COMMPAGE_START+entry.offset); | ||
162 | + int c = 0; | ||
163 | + if(entry.options & HAS_PTR) | ||
164 | + { | ||
165 | + commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff; | ||
166 | + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff; | ||
167 | + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff; | ||
168 | + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff; | ||
169 | + } | ||
170 | + commpage[c++] = 0xcd; | ||
171 | + commpage[c++] = 0x79; /* int 0x79 */ | ||
172 | + commpage[c++] = 0xc3; /* ret */ | ||
173 | +#else | ||
174 | + qerror("can't install the commpage on this arch\n"); | ||
175 | +#endif | ||
176 | +} | ||
177 | + | ||
178 | +/******************************************************************** | ||
179 | + * Commpage initialization | ||
180 | + */ | ||
181 | +void commpage_init(void) | ||
182 | +{ | ||
183 | +#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC)) | ||
184 | + int i; | ||
185 | + void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE, | ||
186 | + PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0); | ||
187 | + if((int)commpage != COMMPAGE_START) | ||
188 | + qerror("can't allocate the commpage\n"); | ||
189 | + | ||
190 | + bzero(commpage, COMMPAGE_SIZE); | ||
191 | + | ||
192 | + /* XXX: commpage data not handled */ | ||
193 | + | ||
194 | + for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) | ||
195 | + install_commpage_backdoor_for_entry(commpage_entries[i]); | ||
196 | +#else | ||
197 | + /* simply map our pages so they can be executed | ||
198 | + XXX: we don't really want to do that since in the ppc on ppc situation we may | ||
199 | + not able to run commpages host optimized instructions (like G5's on a G5), | ||
200 | + hence this is sometimes a broken fix. */ | ||
201 | + page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID); | ||
202 | +#endif | ||
203 | +} | ||
204 | + | ||
205 | +/******************************************************************** | ||
206 | + * Commpage implementation | ||
207 | + */ | ||
208 | +void do_compare_and_swap32(void *cpu_env, int num) | ||
209 | +{ | ||
210 | +#ifdef TARGET_I386 | ||
211 | + uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX]; | ||
212 | + uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX]; | ||
213 | + DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value); | ||
214 | + | ||
215 | + if(value && old == tswap32(*value)) | ||
216 | + { | ||
217 | + uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX]; | ||
218 | + *value = tswap32(new); | ||
219 | + /* set zf flag */ | ||
220 | + ((CPUX86State*)cpu_env)->eflags |= 0x40; | ||
221 | + } | ||
222 | + else | ||
223 | + { | ||
224 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value); | ||
225 | + /* unset zf flag */ | ||
226 | + ((CPUX86State*)cpu_env)->eflags &= ~0x40; | ||
227 | + } | ||
228 | +#else | ||
229 | + qerror("do_compare_and_swap32 unimplemented"); | ||
230 | +#endif | ||
231 | +} | ||
232 | + | ||
233 | +void do_compare_and_swap64(void *cpu_env, int num) | ||
234 | +{ | ||
235 | +#ifdef TARGET_I386 | ||
236 | + /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */ | ||
237 | + uint64_t old, new, swapped_val; | ||
238 | + uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI]; | ||
239 | + old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX]; | ||
240 | + | ||
241 | + DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value); | ||
242 | + swapped_val = tswap64(*value); | ||
243 | + | ||
244 | + if(old == swapped_val) | ||
245 | + { | ||
246 | + new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX]; | ||
247 | + *value = tswap64(new); | ||
248 | + /* set zf flag */ | ||
249 | + ((CPUX86State*)cpu_env)->eflags |= 0x40; | ||
250 | + } | ||
251 | + else | ||
252 | + { | ||
253 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val); | ||
254 | + ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32); | ||
255 | + /* unset zf flag */ | ||
256 | + ((CPUX86State*)cpu_env)->eflags &= ~0x40; | ||
257 | + } | ||
258 | +#else | ||
259 | + qerror("do_compare_and_swap64 unimplemented"); | ||
260 | +#endif | ||
261 | +} | ||
262 | + | ||
263 | +void do_add_atomic_word32(void *cpu_env, int num) | ||
264 | +{ | ||
265 | +#ifdef TARGET_I386 | ||
266 | + uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX]; | ||
267 | + uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX]; | ||
268 | + uint32_t swapped_value = tswap32(*value); | ||
269 | + | ||
270 | + DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value); | ||
271 | + | ||
272 | + /* old value in EAX */ | ||
273 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value; | ||
274 | + *value = tswap32(swapped_value + amt); | ||
275 | +#else | ||
276 | + qerror("do_add_atomic_word32 unimplemented"); | ||
277 | +#endif | ||
278 | +} | ||
279 | + | ||
280 | +void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1) | ||
281 | +{ | ||
282 | +#ifdef TARGET_I386 | ||
283 | + extern int __commpage_gettimeofday(struct timeval *); | ||
284 | + DPRINTF("commpage: gettimeofday(0x%x)\n", arg1); | ||
285 | + struct timeval *time = (struct timeval *)arg1; | ||
286 | + int ret = __commpage_gettimeofday(time); | ||
287 | + tswap32s((uint32_t*)&time->tv_sec); | ||
288 | + tswap32s((uint32_t*)&time->tv_usec); | ||
289 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */ | ||
290 | +#else | ||
291 | + qerror("do_gettimeofday unimplemented"); | ||
292 | +#endif | ||
293 | +} | ||
294 | + | ||
295 | +void do_nanotime(void *cpu_env, int num) | ||
296 | +{ | ||
297 | +#ifdef TARGET_I386 | ||
298 | + uint64_t t = mach_absolute_time(); | ||
299 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff); | ||
300 | + ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff); | ||
301 | +#else | ||
302 | + qerror("do_nanotime unimplemented"); | ||
303 | +#endif | ||
304 | +} | ||
305 | + | ||
306 | +void unimpl_commpage(void *cpu_env, int num) | ||
307 | +{ | ||
308 | + gemu_log("qemu: commpage function 0x%x not implemented\n", num); | ||
309 | +} | ||
310 | + | ||
311 | +/******************************************************************** | ||
312 | + * do_commpage - called by the main cpu loop | ||
313 | + */ | ||
314 | +void | ||
315 | +do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
316 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, | ||
317 | + uint32_t arg8) | ||
318 | +{ | ||
319 | + int i, found = 0; | ||
320 | + | ||
321 | + arg1 = tswap32(arg1); | ||
322 | + arg2 = tswap32(arg2); | ||
323 | + arg3 = tswap32(arg3); | ||
324 | + arg4 = tswap32(arg4); | ||
325 | + arg5 = tswap32(arg5); | ||
326 | + arg6 = tswap32(arg6); | ||
327 | + arg7 = tswap32(arg7); | ||
328 | + arg8 = tswap32(arg8); | ||
329 | + | ||
330 | + num = num-COMMPAGE_START-2; | ||
331 | + | ||
332 | + for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) { | ||
333 | + if( num == commpage_code_num(&commpage_entries[i]) ) | ||
334 | + { | ||
335 | + DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]"); | ||
336 | + found = 1; | ||
337 | + if(commpage_is_indirect(&commpage_entries[i])) | ||
338 | + { | ||
339 | + commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function; | ||
340 | + function(cpu_env, num, arg1, arg2, arg3, | ||
341 | + arg4, arg5, arg6, arg7, arg8); | ||
342 | + } | ||
343 | + else | ||
344 | + { | ||
345 | + commpage_entries[i].function(arg1, arg2, arg3, | ||
346 | + arg4, arg5, arg6, arg7, arg8); | ||
347 | + } | ||
348 | + break; | ||
349 | + } | ||
350 | + } | ||
351 | + | ||
352 | + if(!found) | ||
353 | + { | ||
354 | + gemu_log("qemu: commpage function 0x%x not defined\n", num); | ||
355 | + gdb_handlesig (cpu_env, SIGTRAP); | ||
356 | + exit(-1); | ||
357 | + } | ||
358 | +} |
darwin-user/ioctls.h
0 โ 100644
darwin-user/ioctls_types.h
0 โ 100644
darwin-user/machload.c
0 โ 100644
1 | +/* | ||
2 | + * Mach-O object file loading | ||
3 | + * | ||
4 | + * Copyright (c) 2006 Pierre d'Herbemont | ||
5 | + * | ||
6 | + * This library is free software; you can redistribute it and/or | ||
7 | + * modify it under the terms of the GNU Lesser General Public | ||
8 | + * License as published by the Free Software Foundation; either | ||
9 | + * version 2 of the License, or (at your option) any later version. | ||
10 | + * | ||
11 | + * This library is distributed in the hope that it will be useful, | ||
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | + * Lesser General Public License for more details. | ||
15 | + * | ||
16 | + * You should have received a copy of the GNU Lesser General Public | ||
17 | + * License along with this library; if not, write to the Free Software | ||
18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | + */ | ||
20 | +#include <stdio.h> | ||
21 | +#include <sys/types.h> | ||
22 | +#include <fcntl.h> | ||
23 | +#include <sys/stat.h> | ||
24 | +#include <errno.h> | ||
25 | +#include <unistd.h> | ||
26 | +#include <sys/mman.h> | ||
27 | +#include <stdlib.h> | ||
28 | +#include <string.h> | ||
29 | + | ||
30 | +#include "qemu.h" | ||
31 | +#include "disas.h" | ||
32 | + | ||
33 | +#include <mach-o/loader.h> | ||
34 | +#include <mach-o/fat.h> | ||
35 | +#include <mach-o/nlist.h> | ||
36 | +#include <mach-o/reloc.h> | ||
37 | +#include <mach-o/ppc/reloc.h> | ||
38 | + | ||
39 | +//#define DEBUG_MACHLOAD | ||
40 | + | ||
41 | +#ifdef DEBUG_MACHLOAD | ||
42 | +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) | ||
43 | +#else | ||
44 | +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) | ||
45 | +#endif | ||
46 | + | ||
47 | +# define check_mach_header(x) (x.magic == MH_CIGAM) | ||
48 | + | ||
49 | +extern const char *interp_prefix; | ||
50 | + | ||
51 | +/* we don't have a good implementation for this */ | ||
52 | +#define DONT_USE_DYLD_SHARED_MAP | ||
53 | + | ||
54 | +/* Pass extra arg to DYLD for debug */ | ||
55 | +//#define ACTIVATE_DYLD_TRACE | ||
56 | + | ||
57 | +//#define OVERRIDE_DYLINKER | ||
58 | + | ||
59 | +#ifdef OVERRIDE_DYLINKER | ||
60 | +# ifdef TARGET_I386 | ||
61 | +# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld" | ||
62 | +# else | ||
63 | +# define DYLINKER_NAME "/usr/lib/dyld" | ||
64 | +# endif | ||
65 | +#endif | ||
66 | + | ||
67 | +/* XXX: in an include */ | ||
68 | +struct nlist_extended | ||
69 | +{ | ||
70 | + union { | ||
71 | + char *n_name; | ||
72 | + long n_strx; | ||
73 | + } n_un; | ||
74 | + unsigned char n_type; | ||
75 | + unsigned char n_sect; | ||
76 | + short st_desc; | ||
77 | + unsigned long st_value; | ||
78 | + unsigned long st_size; | ||
79 | +}; | ||
80 | + | ||
81 | +/* Print symbols in gdb */ | ||
82 | +void *macho_text_sect = 0; | ||
83 | +int macho_offset = 0; | ||
84 | + | ||
85 | +int load_object(const char *filename, struct target_pt_regs * regs, void ** mh); | ||
86 | +void qerror(const char *format, ...); | ||
87 | +#ifdef TARGET_I386 | ||
88 | +typedef struct mach_i386_thread_state { | ||
89 | + unsigned int eax; | ||
90 | + unsigned int ebx; | ||
91 | + unsigned int ecx; | ||
92 | + unsigned int edx; | ||
93 | + unsigned int edi; | ||
94 | + unsigned int esi; | ||
95 | + unsigned int ebp; | ||
96 | + unsigned int esp; | ||
97 | + unsigned int ss; | ||
98 | + unsigned int eflags; | ||
99 | + unsigned int eip; | ||
100 | + unsigned int cs; | ||
101 | + unsigned int ds; | ||
102 | + unsigned int es; | ||
103 | + unsigned int fs; | ||
104 | + unsigned int gs; | ||
105 | +} mach_i386_thread_state_t; | ||
106 | + | ||
107 | +void bswap_i386_thread_state(struct mach_i386_thread_state *ts) | ||
108 | +{ | ||
109 | + bswap32s((uint32_t*)&ts->eax); | ||
110 | + bswap32s((uint32_t*)&ts->ebx); | ||
111 | + bswap32s((uint32_t*)&ts->ecx); | ||
112 | + bswap32s((uint32_t*)&ts->edx); | ||
113 | + bswap32s((uint32_t*)&ts->edi); | ||
114 | + bswap32s((uint32_t*)&ts->esi); | ||
115 | + bswap32s((uint32_t*)&ts->ebp); | ||
116 | + bswap32s((uint32_t*)&ts->esp); | ||
117 | + bswap32s((uint32_t*)&ts->ss); | ||
118 | + bswap32s((uint32_t*)&ts->eflags); | ||
119 | + bswap32s((uint32_t*)&ts->eip); | ||
120 | + bswap32s((uint32_t*)&ts->cs); | ||
121 | + bswap32s((uint32_t*)&ts->ds); | ||
122 | + bswap32s((uint32_t*)&ts->es); | ||
123 | + bswap32s((uint32_t*)&ts->fs); | ||
124 | + bswap32s((uint32_t*)&ts->gs); | ||
125 | +} | ||
126 | +#define target_thread_state mach_i386_thread_state | ||
127 | +#define TARGET_CPU_TYPE CPU_TYPE_I386 | ||
128 | +#define TARGET_CPU_NAME "i386" | ||
129 | +#endif | ||
130 | + | ||
131 | +#ifdef TARGET_PPC | ||
132 | +struct mach_ppc_thread_state { | ||
133 | + unsigned int srr0; /* Instruction address register (PC) */ | ||
134 | + unsigned int srr1; /* Machine state register (supervisor) */ | ||
135 | + unsigned int r0; | ||
136 | + unsigned int r1; | ||
137 | + unsigned int r2; | ||
138 | + unsigned int r3; | ||
139 | + unsigned int r4; | ||
140 | + unsigned int r5; | ||
141 | + unsigned int r6; | ||
142 | + unsigned int r7; | ||
143 | + unsigned int r8; | ||
144 | + unsigned int r9; | ||
145 | + unsigned int r10; | ||
146 | + unsigned int r11; | ||
147 | + unsigned int r12; | ||
148 | + unsigned int r13; | ||
149 | + unsigned int r14; | ||
150 | + unsigned int r15; | ||
151 | + unsigned int r16; | ||
152 | + unsigned int r17; | ||
153 | + unsigned int r18; | ||
154 | + unsigned int r19; | ||
155 | + unsigned int r20; | ||
156 | + unsigned int r21; | ||
157 | + unsigned int r22; | ||
158 | + unsigned int r23; | ||
159 | + unsigned int r24; | ||
160 | + unsigned int r25; | ||
161 | + unsigned int r26; | ||
162 | + unsigned int r27; | ||
163 | + unsigned int r28; | ||
164 | + unsigned int r29; | ||
165 | + unsigned int r30; | ||
166 | + unsigned int r31; | ||
167 | + | ||
168 | + unsigned int cr; /* Condition register */ | ||
169 | + unsigned int xer; /* User's integer exception register */ | ||
170 | + unsigned int lr; /* Link register */ | ||
171 | + unsigned int ctr; /* Count register */ | ||
172 | + unsigned int mq; /* MQ register (601 only) */ | ||
173 | + | ||
174 | + unsigned int vrsave; /* Vector Save Register */ | ||
175 | +}; | ||
176 | + | ||
177 | +void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts) | ||
178 | +{ | ||
179 | + bswap32s((uint32_t*)&ts->srr0); | ||
180 | + bswap32s((uint32_t*)&ts->srr1); | ||
181 | + bswap32s((uint32_t*)&ts->r0); | ||
182 | + bswap32s((uint32_t*)&ts->r1); | ||
183 | + bswap32s((uint32_t*)&ts->r2); | ||
184 | + bswap32s((uint32_t*)&ts->r3); | ||
185 | + bswap32s((uint32_t*)&ts->r4); | ||
186 | + bswap32s((uint32_t*)&ts->r5); | ||
187 | + bswap32s((uint32_t*)&ts->r6); | ||
188 | + bswap32s((uint32_t*)&ts->r7); | ||
189 | + bswap32s((uint32_t*)&ts->r8); | ||
190 | + bswap32s((uint32_t*)&ts->r9); | ||
191 | + bswap32s((uint32_t*)&ts->r10); | ||
192 | + bswap32s((uint32_t*)&ts->r11); | ||
193 | + bswap32s((uint32_t*)&ts->r12); | ||
194 | + bswap32s((uint32_t*)&ts->r13); | ||
195 | + bswap32s((uint32_t*)&ts->r14); | ||
196 | + bswap32s((uint32_t*)&ts->r15); | ||
197 | + bswap32s((uint32_t*)&ts->r16); | ||
198 | + bswap32s((uint32_t*)&ts->r17); | ||
199 | + bswap32s((uint32_t*)&ts->r18); | ||
200 | + bswap32s((uint32_t*)&ts->r19); | ||
201 | + bswap32s((uint32_t*)&ts->r20); | ||
202 | + bswap32s((uint32_t*)&ts->r21); | ||
203 | + bswap32s((uint32_t*)&ts->r22); | ||
204 | + bswap32s((uint32_t*)&ts->r23); | ||
205 | + bswap32s((uint32_t*)&ts->r24); | ||
206 | + bswap32s((uint32_t*)&ts->r25); | ||
207 | + bswap32s((uint32_t*)&ts->r26); | ||
208 | + bswap32s((uint32_t*)&ts->r27); | ||
209 | + bswap32s((uint32_t*)&ts->r28); | ||
210 | + bswap32s((uint32_t*)&ts->r29); | ||
211 | + bswap32s((uint32_t*)&ts->r30); | ||
212 | + bswap32s((uint32_t*)&ts->r31); | ||
213 | + | ||
214 | + bswap32s((uint32_t*)&ts->cr); | ||
215 | + bswap32s((uint32_t*)&ts->xer); | ||
216 | + bswap32s((uint32_t*)&ts->lr); | ||
217 | + bswap32s((uint32_t*)&ts->ctr); | ||
218 | + bswap32s((uint32_t*)&ts->mq); | ||
219 | + | ||
220 | + bswap32s((uint32_t*)&ts->vrsave); | ||
221 | +} | ||
222 | + | ||
223 | +#define target_thread_state mach_ppc_thread_state | ||
224 | +#define TARGET_CPU_TYPE CPU_TYPE_POWERPC | ||
225 | +#define TARGET_CPU_NAME "PowerPC" | ||
226 | +#endif | ||
227 | + | ||
228 | +struct target_thread_command { | ||
229 | + unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */ | ||
230 | + unsigned long cmdsize; /* total size of this command */ | ||
231 | + unsigned long flavor; /* flavor of thread state */ | ||
232 | + unsigned long count; /* count of longs in thread state */ | ||
233 | + struct target_thread_state state; /* thread state for this flavor */ | ||
234 | +}; | ||
235 | + | ||
236 | +void bswap_tc(struct target_thread_command *tc) | ||
237 | +{ | ||
238 | + bswap32s((uint32_t*)(&tc->flavor)); | ||
239 | + bswap32s((uint32_t*)&tc->count); | ||
240 | +#if defined(TARGET_I386) | ||
241 | + bswap_i386_thread_state(&tc->state); | ||
242 | +#elif defined(TARGET_PPC) | ||
243 | + bswap_ppc_thread_state(&tc->state); | ||
244 | +#else | ||
245 | +# error unknown TARGET_CPU_TYPE | ||
246 | +#endif | ||
247 | +} | ||
248 | + | ||
249 | +void bswap_mh(struct mach_header *mh) | ||
250 | +{ | ||
251 | + bswap32s((uint32_t*)(&mh->magic)); | ||
252 | + bswap32s((uint32_t*)&mh->cputype); | ||
253 | + bswap32s((uint32_t*)&mh->cpusubtype); | ||
254 | + bswap32s((uint32_t*)&mh->filetype); | ||
255 | + bswap32s((uint32_t*)&mh->ncmds); | ||
256 | + bswap32s((uint32_t*)&mh->sizeofcmds); | ||
257 | + bswap32s((uint32_t*)&mh->flags); | ||
258 | +} | ||
259 | + | ||
260 | +void bswap_lc(struct load_command *lc) | ||
261 | +{ | ||
262 | + bswap32s((uint32_t*)&lc->cmd); | ||
263 | + bswap32s((uint32_t*)&lc->cmdsize); | ||
264 | +} | ||
265 | + | ||
266 | + | ||
267 | +void bswap_fh(struct fat_header *fh) | ||
268 | +{ | ||
269 | + bswap32s((uint32_t*)&fh->magic); | ||
270 | + bswap32s((uint32_t*)&fh->nfat_arch); | ||
271 | +} | ||
272 | + | ||
273 | +void bswap_fa(struct fat_arch *fa) | ||
274 | +{ | ||
275 | + bswap32s((uint32_t*)&fa->cputype); | ||
276 | + bswap32s((uint32_t*)&fa->cpusubtype); | ||
277 | + bswap32s((uint32_t*)&fa->offset); | ||
278 | + bswap32s((uint32_t*)&fa->size); | ||
279 | + bswap32s((uint32_t*)&fa->align); | ||
280 | +} | ||
281 | + | ||
282 | +void bswap_segcmd(struct segment_command *sc) | ||
283 | +{ | ||
284 | + bswap32s((uint32_t*)&sc->vmaddr); | ||
285 | + bswap32s((uint32_t*)&sc->vmsize); | ||
286 | + bswap32s((uint32_t*)&sc->fileoff); | ||
287 | + bswap32s((uint32_t*)&sc->filesize); | ||
288 | + bswap32s((uint32_t*)&sc->maxprot); | ||
289 | + bswap32s((uint32_t*)&sc->initprot); | ||
290 | + bswap32s((uint32_t*)&sc->nsects); | ||
291 | + bswap32s((uint32_t*)&sc->flags); | ||
292 | +} | ||
293 | + | ||
294 | +void bswap_symtabcmd(struct symtab_command *stc) | ||
295 | +{ | ||
296 | + bswap32s((uint32_t*)&stc->cmd); | ||
297 | + bswap32s((uint32_t*)&stc->cmdsize); | ||
298 | + bswap32s((uint32_t*)&stc->symoff); | ||
299 | + bswap32s((uint32_t*)&stc->nsyms); | ||
300 | + bswap32s((uint32_t*)&stc->stroff); | ||
301 | + bswap32s((uint32_t*)&stc->strsize); | ||
302 | +} | ||
303 | + | ||
304 | +void bswap_sym(struct nlist *n) | ||
305 | +{ | ||
306 | + bswap32s((uint32_t*)&n->n_un.n_strx); | ||
307 | + bswap16s((uint16_t*)&n->n_desc); | ||
308 | + bswap32s((uint32_t*)&n->n_value); | ||
309 | +} | ||
310 | + | ||
311 | +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) | ||
312 | +{ | ||
313 | + int entry; | ||
314 | + if(need_bswap) | ||
315 | + bswap_tc(tc); | ||
316 | +#if defined(TARGET_I386) | ||
317 | + entry = tc->state.eip; | ||
318 | + 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", | ||
319 | + tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp, | ||
320 | + tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es, | ||
321 | + tc->state.fs, tc->state.gs ); | ||
322 | +#define reg_copy(reg) regs->reg = tc->state.reg | ||
323 | + if(regs) | ||
324 | + { | ||
325 | + reg_copy(eax); | ||
326 | + reg_copy(ebx); | ||
327 | + reg_copy(ecx); | ||
328 | + reg_copy(edx); | ||
329 | + | ||
330 | + reg_copy(edi); | ||
331 | + reg_copy(esi); | ||
332 | + | ||
333 | + reg_copy(ebp); | ||
334 | + reg_copy(esp); | ||
335 | + | ||
336 | + reg_copy(eflags); | ||
337 | + reg_copy(eip); | ||
338 | + /* | ||
339 | + reg_copy(ss); | ||
340 | + reg_copy(cs); | ||
341 | + reg_copy(ds); | ||
342 | + reg_copy(es); | ||
343 | + reg_copy(fs); | ||
344 | + reg_copy(gs);*/ | ||
345 | + } | ||
346 | +#undef reg_copy | ||
347 | +#elif defined(TARGET_PPC) | ||
348 | + entry = tc->state.srr0; | ||
349 | +#endif | ||
350 | + DPRINTF("load_thread: entry 0x%x\n", entry); | ||
351 | + return entry; | ||
352 | +} | ||
353 | + | ||
354 | +int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap) | ||
355 | +{ | ||
356 | + int size; | ||
357 | + char * dylinker_name; | ||
358 | + size = dc->cmdsize - sizeof(struct dylinker_command); | ||
359 | + | ||
360 | + if(need_bswap) | ||
361 | + dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc); | ||
362 | + else | ||
363 | + dylinker_name = (char*)((dc->name.offset)+(int)dc); | ||
364 | + | ||
365 | +#ifdef OVERRIDE_DYLINKER | ||
366 | + dylinker_name = DYLINKER_NAME; | ||
367 | +#else | ||
368 | + if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1) | ||
369 | + qerror("can't allocate the new dylinker name\n"); | ||
370 | +#endif | ||
371 | + | ||
372 | + DPRINTF("dylinker_name %s\n", dylinker_name); | ||
373 | + return load_object(dylinker_name, NULL, NULL); | ||
374 | +} | ||
375 | + | ||
376 | +int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide) | ||
377 | +{ | ||
378 | + unsigned long addr = sc->vmaddr; | ||
379 | + unsigned long size = sc->filesize; | ||
380 | + unsigned long error = 0; | ||
381 | + | ||
382 | + if(need_bswap) | ||
383 | + bswap_segcmd(sc); | ||
384 | + | ||
385 | + if(sc->vmaddr == 0) | ||
386 | + { | ||
387 | + DPRINTF("load_segment: sc->vmaddr == 0 returning\n"); | ||
388 | + return -1; | ||
389 | + } | ||
390 | + | ||
391 | + if (strcmp(sc->segname, "__PAGEZERO") == 0) | ||
392 | + { | ||
393 | + DPRINTF("load_segment: __PAGEZERO returning\n"); | ||
394 | + return -1; | ||
395 | + } | ||
396 | + | ||
397 | + /* Right now mmap memory */ | ||
398 | + /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */ | ||
399 | + DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide); | ||
400 | + | ||
401 | + if(sc->filesize > 0) | ||
402 | + { | ||
403 | + int opt = 0; | ||
404 | + | ||
405 | + if(fixed) | ||
406 | + opt |= MAP_FIXED; | ||
407 | + | ||
408 | + DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide); | ||
409 | + | ||
410 | + addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff); | ||
411 | + | ||
412 | + if(addr==-1) | ||
413 | + qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); | ||
414 | + | ||
415 | + error = addr-sc->vmaddr; | ||
416 | + } | ||
417 | + else | ||
418 | + { | ||
419 | + addr = sc->vmaddr+slide; | ||
420 | + error = slide; | ||
421 | + } | ||
422 | + | ||
423 | + if(sc->vmsize > sc->filesize) | ||
424 | + { | ||
425 | + addr += sc->filesize; | ||
426 | + size = sc->vmsize-sc->filesize; | ||
427 | + addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0); | ||
428 | + if(addr==-1) | ||
429 | + qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); | ||
430 | + } | ||
431 | + | ||
432 | + return error; | ||
433 | +} | ||
434 | + | ||
435 | +void *load_data(int fd, long offset, unsigned int size) | ||
436 | +{ | ||
437 | + char *data; | ||
438 | + | ||
439 | + data = malloc(size); | ||
440 | + if (!data) | ||
441 | + return NULL; | ||
442 | + lseek(fd, offset, SEEK_SET); | ||
443 | + if (read(fd, data, size) != size) { | ||
444 | + free(data); | ||
445 | + return NULL; | ||
446 | + } | ||
447 | + return data; | ||
448 | +} | ||
449 | + | ||
450 | +/* load a mach-o object file */ | ||
451 | +int load_object(const char *filename, struct target_pt_regs * regs, void ** mh) | ||
452 | +{ | ||
453 | + int need_bswap = 0; | ||
454 | + int entry_point = 0; | ||
455 | + int dyld_entry_point = 0; | ||
456 | + int slide, mmapfixed; | ||
457 | + int fd; | ||
458 | + struct load_command *lcmds, *lc; | ||
459 | + int is_fat = 0; | ||
460 | + unsigned int i, magic; | ||
461 | + int mach_hdr_pos = 0; | ||
462 | + struct mach_header mach_hdr; | ||
463 | + | ||
464 | + /* for symbol lookup whith -d flag. */ | ||
465 | + struct symtab_command * symtabcmd = 0; | ||
466 | + struct nlist_extended *symtab, *sym; | ||
467 | + struct nlist *symtab_std, *syment; | ||
468 | + char *strtab; | ||
469 | + | ||
470 | + fd = open(filename, O_RDONLY); | ||
471 | + if (fd < 0) | ||
472 | + qerror("can't open file '%s'", filename); | ||
473 | + | ||
474 | + /* Read magic header. */ | ||
475 | + if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) | ||
476 | + qerror("unable to read Magic of '%s'", filename); | ||
477 | + | ||
478 | + /* Check Mach identification. */ | ||
479 | + if(magic == MH_MAGIC) | ||
480 | + { | ||
481 | + is_fat = 0; | ||
482 | + need_bswap = 0; | ||
483 | + } else if (magic == MH_CIGAM) | ||
484 | + { | ||
485 | + is_fat = 0; | ||
486 | + need_bswap = 1; | ||
487 | + } else if (magic == FAT_MAGIC) | ||
488 | + { | ||
489 | + is_fat = 1; | ||
490 | + need_bswap = 0; | ||
491 | + } else if (magic == FAT_CIGAM) | ||
492 | + { | ||
493 | + is_fat = 1; | ||
494 | + need_bswap = 1; | ||
495 | + } | ||
496 | + else | ||
497 | + qerror("Not a Mach-O file.", filename); | ||
498 | + | ||
499 | + DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]"); | ||
500 | + if(is_fat) | ||
501 | + { | ||
502 | + int found = 0; | ||
503 | + struct fat_header fh; | ||
504 | + struct fat_arch *fa; | ||
505 | + | ||
506 | + lseek(fd, 0, SEEK_SET); | ||
507 | + | ||
508 | + /* Read Fat header. */ | ||
509 | + if (read(fd, &fh, sizeof (fh)) != sizeof (fh)) | ||
510 | + qerror("unable to read file header"); | ||
511 | + | ||
512 | + if(need_bswap) | ||
513 | + bswap_fh(&fh); | ||
514 | + | ||
515 | + /* Read Fat Arch. */ | ||
516 | + fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch); | ||
517 | + | ||
518 | + if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch) | ||
519 | + qerror("unable to read file header"); | ||
520 | + | ||
521 | + for( i = 0; i < fh.nfat_arch; i++, fa++) | ||
522 | + { | ||
523 | + if(need_bswap) | ||
524 | + bswap_fa(fa); | ||
525 | + if(fa->cputype == TARGET_CPU_TYPE) | ||
526 | + { | ||
527 | + mach_hdr_pos = fa->offset; | ||
528 | + lseek(fd, mach_hdr_pos, SEEK_SET); | ||
529 | + | ||
530 | + /* Read Mach header. */ | ||
531 | + | ||
532 | + if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header)) | ||
533 | + qerror("unable to read file header"); | ||
534 | + | ||
535 | + if(mach_hdr.magic == MH_MAGIC) | ||
536 | + need_bswap = 0; | ||
537 | + else if (mach_hdr.magic == MH_CIGAM) | ||
538 | + need_bswap = 1; | ||
539 | + else | ||
540 | + qerror("Invalid mach header in Fat Mach-O File"); | ||
541 | + found = 1; | ||
542 | + break; | ||
543 | + } | ||
544 | + } | ||
545 | + if(!found) | ||
546 | + qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME); | ||
547 | + } | ||
548 | + else | ||
549 | + { | ||
550 | + lseek(fd, 0, SEEK_SET); | ||
551 | + /* Read Mach header */ | ||
552 | + if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr)) | ||
553 | + qerror("%s: unable to read file header", filename); | ||
554 | + } | ||
555 | + | ||
556 | + if(need_bswap) | ||
557 | + bswap_mh(&mach_hdr); | ||
558 | + | ||
559 | + if ((mach_hdr.cputype) != TARGET_CPU_TYPE) | ||
560 | + qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME); | ||
561 | + | ||
562 | + | ||
563 | + switch(mach_hdr.filetype) | ||
564 | + { | ||
565 | + case MH_EXECUTE: break; | ||
566 | + case MH_FVMLIB: | ||
567 | + case MH_DYLIB: | ||
568 | + case MH_DYLINKER: break; | ||
569 | + default: | ||
570 | + qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype); | ||
571 | + } | ||
572 | + | ||
573 | + /* read segment headers */ | ||
574 | + lcmds = malloc(mach_hdr.sizeofcmds); | ||
575 | + | ||
576 | + if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds) | ||
577 | + qerror("%s: unable to read load_command", filename); | ||
578 | + slide = 0; | ||
579 | + mmapfixed = 0; | ||
580 | + for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++) | ||
581 | + { | ||
582 | + | ||
583 | + if(need_bswap) | ||
584 | + bswap_lc(lc); | ||
585 | + switch(lc->cmd) | ||
586 | + { | ||
587 | + case LC_SEGMENT: | ||
588 | + /* The main_exe can't be relocated */ | ||
589 | + if(mach_hdr.filetype == MH_EXECUTE) | ||
590 | + mmapfixed = 1; | ||
591 | + | ||
592 | + slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide); | ||
593 | + | ||
594 | + /* other segment must be mapped according to slide exactly, if load_segment did something */ | ||
595 | + if(slide != -1) | ||
596 | + mmapfixed = 1; | ||
597 | + else | ||
598 | + slide = 0; /* load_segment didn't map the segment */ | ||
599 | + | ||
600 | + if(mach_hdr.filetype == MH_EXECUTE && slide != 0) | ||
601 | + qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide); | ||
602 | + | ||
603 | + if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0) | ||
604 | + { | ||
605 | + /* Text section */ | ||
606 | + if(mach_hdr.filetype == MH_EXECUTE) | ||
607 | + { | ||
608 | + /* return the mach_header */ | ||
609 | + *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide); | ||
610 | + } | ||
611 | + else | ||
612 | + { | ||
613 | + /* it is dyld save the section for gdb, we will be interested in dyld symbol | ||
614 | + while debuging */ | ||
615 | + macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide); | ||
616 | + macho_offset = slide; | ||
617 | + } | ||
618 | + } | ||
619 | + break; | ||
620 | + case LC_LOAD_DYLINKER: | ||
621 | + dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap ); | ||
622 | + break; | ||
623 | + case LC_LOAD_DYLIB: | ||
624 | + /* dyld will do that for us */ | ||
625 | + break; | ||
626 | + case LC_THREAD: | ||
627 | + case LC_UNIXTHREAD: | ||
628 | + { | ||
629 | + struct target_pt_regs * _regs; | ||
630 | + if(mach_hdr.filetype == MH_DYLINKER) | ||
631 | + _regs = regs; | ||
632 | + else | ||
633 | + _regs = 0; | ||
634 | + entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap ); | ||
635 | + } | ||
636 | + break; | ||
637 | + case LC_SYMTAB: | ||
638 | + /* Save the symtab and strtab */ | ||
639 | + symtabcmd = (struct symtab_command *)lc; | ||
640 | + break; | ||
641 | + case LC_ID_DYLINKER: | ||
642 | + case LC_ID_DYLIB: | ||
643 | + case LC_UUID: | ||
644 | + case LC_DYSYMTAB: | ||
645 | + case LC_TWOLEVEL_HINTS: | ||
646 | + case LC_PREBIND_CKSUM: | ||
647 | + case LC_SUB_LIBRARY: | ||
648 | + break; | ||
649 | + default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename); | ||
650 | + } | ||
651 | + lc = (struct load_command*)((int)(lc)+(lc->cmdsize)); | ||
652 | + } | ||
653 | + | ||
654 | + if(symtabcmd) | ||
655 | + { | ||
656 | + if(need_bswap) | ||
657 | + bswap_symtabcmd(symtabcmd); | ||
658 | + | ||
659 | + symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist)); | ||
660 | + strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize); | ||
661 | + | ||
662 | + symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms); | ||
663 | + | ||
664 | + if(need_bswap) | ||
665 | + { | ||
666 | + for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++) | ||
667 | + bswap_sym(syment); | ||
668 | + } | ||
669 | + | ||
670 | + for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++) | ||
671 | + { | ||
672 | + struct nlist *sym_follow, *sym_next = 0; | ||
673 | + unsigned int j; | ||
674 | + memset(sym, 0, sizeof(*sym)); | ||
675 | + | ||
676 | + sym->n_type = syment->n_type; | ||
677 | + if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */ | ||
678 | + continue; | ||
679 | + | ||
680 | + memcpy(sym, syment, sizeof(*syment)); | ||
681 | + | ||
682 | + /* Find the following symbol in order to get the current symbol size */ | ||
683 | + for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) { | ||
684 | + if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value)) | ||
685 | + continue; | ||
686 | + if(!sym_next) { | ||
687 | + sym_next = sym_follow; | ||
688 | + continue; | ||
689 | + } | ||
690 | + if(!(sym_next->n_value > sym_follow->n_value)) | ||
691 | + continue; | ||
692 | + sym_next = sym_follow; | ||
693 | + } | ||
694 | + if(sym_next) | ||
695 | + sym->st_size = sym_next->n_value - sym->st_value; | ||
696 | + else | ||
697 | + sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */ | ||
698 | + | ||
699 | + sym->st_value += slide; | ||
700 | + } | ||
701 | + | ||
702 | + free((void*)symtab_std); | ||
703 | + | ||
704 | + { | ||
705 | + DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms); | ||
706 | + struct syminfo *s; | ||
707 | + s = malloc(sizeof(*s)); | ||
708 | + s->disas_symtab = symtab; | ||
709 | + s->disas_strtab = strtab; | ||
710 | + s->disas_num_syms = symtabcmd->nsyms; | ||
711 | + s->next = syminfos; | ||
712 | + syminfos = s; | ||
713 | + } | ||
714 | + } | ||
715 | + close(fd); | ||
716 | + if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point) | ||
717 | + return dyld_entry_point; | ||
718 | + else | ||
719 | + return entry_point+slide; | ||
720 | +} | ||
721 | + | ||
722 | +extern unsigned long stack_size; | ||
723 | + | ||
724 | +unsigned long setup_arg_pages(void * mh, char ** argv, char ** env) | ||
725 | +{ | ||
726 | + unsigned long stack_base, error, size; | ||
727 | + int i; | ||
728 | + int * stack; | ||
729 | + int argc, envc; | ||
730 | + | ||
731 | + /* Create enough stack to hold everything. If we don't use | ||
732 | + * it for args, we'll use it for something else... | ||
733 | + */ | ||
734 | + size = stack_size; | ||
735 | + | ||
736 | + error = target_mmap(0, | ||
737 | + size + qemu_host_page_size, | ||
738 | + PROT_READ | PROT_WRITE, | ||
739 | + MAP_PRIVATE | MAP_ANONYMOUS, | ||
740 | + -1, 0); | ||
741 | + if (error == -1) | ||
742 | + qerror("stk mmap"); | ||
743 | + | ||
744 | + /* we reserve one extra page at the top of the stack as guard */ | ||
745 | + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); | ||
746 | + | ||
747 | + stack_base = error + size; | ||
748 | + stack = (void*)stack_base; | ||
749 | +/* | ||
750 | + * | STRING AREA | | ||
751 | + * +-------------+ | ||
752 | + * | 0 | | ||
753 | +* +-------------+ | ||
754 | + * | apple[n] | | ||
755 | + * +-------------+ | ||
756 | + * : | ||
757 | + * +-------------+ | ||
758 | + * | apple[0] | | ||
759 | + * +-------------+ | ||
760 | + * | 0 | | ||
761 | + * +-------------+ | ||
762 | + * | env[n] | | ||
763 | + * +-------------+ | ||
764 | + * : | ||
765 | + * : | ||
766 | + * +-------------+ | ||
767 | + * | env[0] | | ||
768 | + * +-------------+ | ||
769 | + * | 0 | | ||
770 | + * +-------------+ | ||
771 | + * | arg[argc-1] | | ||
772 | + * +-------------+ | ||
773 | + * : | ||
774 | + * : | ||
775 | + * +-------------+ | ||
776 | + * | arg[0] | | ||
777 | + * +-------------+ | ||
778 | + * | argc | | ||
779 | + * +-------------+ | ||
780 | + * sp-> | mh | address of where the a.out's file offset 0 is in memory | ||
781 | + * +-------------+ | ||
782 | +*/ | ||
783 | + /* Construct the stack Stack grows down */ | ||
784 | + stack--; | ||
785 | + | ||
786 | + /* XXX: string should go up there */ | ||
787 | + | ||
788 | + *stack = 0; | ||
789 | + stack--; | ||
790 | + | ||
791 | + /* Push the absolute path of our executable */ | ||
792 | + DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]); | ||
793 | + stl(stack, (int) argv[0]); | ||
794 | + | ||
795 | + stack--; | ||
796 | + | ||
797 | + stl(stack, 0); | ||
798 | + stack--; | ||
799 | + | ||
800 | + /* Get envc */ | ||
801 | + for(envc = 0; env[envc]; envc++); | ||
802 | + | ||
803 | + for(i = envc-1; i >= 0; i--) | ||
804 | + { | ||
805 | + DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]); | ||
806 | + stl(stack, (int)env[i]); | ||
807 | + stack--; | ||
808 | + | ||
809 | + /* XXX: remove that when string will be on top of the stack */ | ||
810 | + page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID); | ||
811 | + } | ||
812 | + | ||
813 | + /* Add on the stack the interp_prefix choosen if so */ | ||
814 | + if(interp_prefix[0]) | ||
815 | + { | ||
816 | + char *dyld_root; | ||
817 | + asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix); | ||
818 | + page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID); | ||
819 | + | ||
820 | + stl(stack, (int)dyld_root); | ||
821 | + stack--; | ||
822 | + } | ||
823 | + | ||
824 | +#ifdef DONT_USE_DYLD_SHARED_MAP | ||
825 | + { | ||
826 | + char *shared_map_mode; | ||
827 | + asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid"); | ||
828 | + page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID); | ||
829 | + | ||
830 | + stl(stack, (int)shared_map_mode); | ||
831 | + stack--; | ||
832 | + } | ||
833 | +#endif | ||
834 | + | ||
835 | +#ifdef ACTIVATE_DYLD_TRACE | ||
836 | + char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes", | ||
837 | + "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes", | ||
838 | + "DYLD_PRINT_INITIALIZERS=yes", | ||
839 | + "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" }; | ||
840 | + | ||
841 | + char ** extra_env = malloc(sizeof(extra_env_static)); | ||
842 | + bcopy(extra_env_static, extra_env, sizeof(extra_env_static)); | ||
843 | + page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID); | ||
844 | + | ||
845 | + for(i = 0; i<9; i++) | ||
846 | + { | ||
847 | + DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]); | ||
848 | + stl(stack, (int) extra_env[i]); | ||
849 | + stack--; | ||
850 | + } | ||
851 | +#endif | ||
852 | + | ||
853 | + stl(stack, 0); | ||
854 | + stack--; | ||
855 | + | ||
856 | + /* Get argc */ | ||
857 | + for(argc = 0; argv[argc]; argc++); | ||
858 | + | ||
859 | + for(i = argc-1; i >= 0; i--) | ||
860 | + { | ||
861 | + DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]); | ||
862 | + stl(stack, (int) argv[i]); | ||
863 | + stack--; | ||
864 | + | ||
865 | + /* XXX: remove that when string will be on top of the stack */ | ||
866 | + page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID); | ||
867 | + } | ||
868 | + | ||
869 | + DPRINTF("pushing argc %d \n", argc); | ||
870 | + stl(stack, argc); | ||
871 | + stack--; | ||
872 | + | ||
873 | + DPRINTF("pushing mh 0x%x \n", (int)mh); | ||
874 | + stl(stack, (int) mh); | ||
875 | + | ||
876 | + /* Stack points on the mh */ | ||
877 | + return (unsigned long)stack; | ||
878 | +} | ||
879 | + | ||
880 | +int mach_exec(const char * filename, char ** argv, char ** envp, | ||
881 | + struct target_pt_regs * regs) | ||
882 | +{ | ||
883 | + int entrypoint, stack; | ||
884 | + void * mh; /* the Mach Header that will be used by dyld */ | ||
885 | + | ||
886 | + DPRINTF("mach_exec at 0x%x\n", (int)mach_exec); | ||
887 | + | ||
888 | + entrypoint = load_object(filename, regs, &mh); | ||
889 | + stack = setup_arg_pages(mh, argv, envp); | ||
890 | +#if defined(TARGET_I386) | ||
891 | + regs->eip = entrypoint; | ||
892 | + regs->esp = stack; | ||
893 | +#elif defined(TARGET_PPC) | ||
894 | + regs->nip = entrypoint; | ||
895 | + regs->gpr[1] = stack; | ||
896 | +#endif | ||
897 | + DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh); | ||
898 | + | ||
899 | + if(!entrypoint) | ||
900 | + qerror("%s: no entry point!\n", filename); | ||
901 | + | ||
902 | + return 0; | ||
903 | +} |
darwin-user/main.c
0 โ 100644
1 | +/* | ||
2 | + * qemu user main | ||
3 | + * | ||
4 | + * Copyright (c) 2003 Fabrice Bellard | ||
5 | + * Copyright (c) 2006 Pierre d'Herbemont | ||
6 | + * | ||
7 | + * This program is free software; you can redistribute it and/or modify | ||
8 | + * it under the terms of the GNU General Public License as published by | ||
9 | + * the Free Software Foundation; either version 2 of the License, or | ||
10 | + * (at your option) any later version. | ||
11 | + * | ||
12 | + * This program is distributed in the hope that it will be useful, | ||
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | + * GNU General Public License for more details. | ||
16 | + * | ||
17 | + * You should have received a copy of the GNU General Public License | ||
18 | + * along with this program; if not, write to the Free Software | ||
19 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | + */ | ||
21 | +#include <stdlib.h> | ||
22 | +#include <stdio.h> | ||
23 | +#include <stdarg.h> | ||
24 | +#include <string.h> | ||
25 | +#include <errno.h> | ||
26 | +#include <unistd.h> | ||
27 | + | ||
28 | +#include <sys/syscall.h> | ||
29 | +#include <sys/mman.h> | ||
30 | + | ||
31 | +#include "qemu.h" | ||
32 | + | ||
33 | +#define DEBUG_LOGFILE "/tmp/qemu.log" | ||
34 | + | ||
35 | +#ifdef __APPLE__ | ||
36 | +#include <crt_externs.h> | ||
37 | +# define environ (*_NSGetEnviron()) | ||
38 | +#endif | ||
39 | + | ||
40 | +#include <mach/mach_init.h> | ||
41 | +#include <mach/vm_map.h> | ||
42 | + | ||
43 | +const char *interp_prefix = ""; | ||
44 | + | ||
45 | +asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000"); | ||
46 | + | ||
47 | +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so | ||
48 | + we allocate a bigger stack. Need a better solution, for example | ||
49 | + by remapping the process stack directly at the right place */ | ||
50 | +unsigned long stack_size = 512 * 1024; | ||
51 | + | ||
52 | +void qerror(const char *fmt, ...) | ||
53 | +{ | ||
54 | + va_list ap; | ||
55 | + | ||
56 | + va_start(ap, fmt); | ||
57 | + vfprintf(stderr, fmt, ap); | ||
58 | + va_end(ap); | ||
59 | + fprintf(stderr, "\n"); | ||
60 | + exit(1); | ||
61 | +} | ||
62 | + | ||
63 | +void gemu_log(const char *fmt, ...) | ||
64 | +{ | ||
65 | + va_list ap; | ||
66 | + | ||
67 | + va_start(ap, fmt); | ||
68 | + vfprintf(stderr, fmt, ap); | ||
69 | + va_end(ap); | ||
70 | +} | ||
71 | + | ||
72 | +void cpu_outb(CPUState *env, int addr, int val) | ||
73 | +{ | ||
74 | + fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); | ||
75 | +} | ||
76 | + | ||
77 | +void cpu_outw(CPUState *env, int addr, int val) | ||
78 | +{ | ||
79 | + fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); | ||
80 | +} | ||
81 | + | ||
82 | +void cpu_outl(CPUState *env, int addr, int val) | ||
83 | +{ | ||
84 | + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); | ||
85 | +} | ||
86 | + | ||
87 | +int cpu_inb(CPUState *env, int addr) | ||
88 | +{ | ||
89 | + fprintf(stderr, "inb: port=0x%04x\n", addr); | ||
90 | + return 0; | ||
91 | +} | ||
92 | + | ||
93 | +int cpu_inw(CPUState *env, int addr) | ||
94 | +{ | ||
95 | + fprintf(stderr, "inw: port=0x%04x\n", addr); | ||
96 | + return 0; | ||
97 | +} | ||
98 | + | ||
99 | +int cpu_inl(CPUState *env, int addr) | ||
100 | +{ | ||
101 | + fprintf(stderr, "inl: port=0x%04x\n", addr); | ||
102 | + return 0; | ||
103 | +} | ||
104 | + | ||
105 | +int cpu_get_pic_interrupt(CPUState *env) | ||
106 | +{ | ||
107 | + return -1; | ||
108 | +} | ||
109 | +#ifdef TARGET_PPC | ||
110 | + | ||
111 | +static inline uint64_t cpu_ppc_get_tb (CPUState *env) | ||
112 | +{ | ||
113 | + /* TO FIX */ | ||
114 | + return 0; | ||
115 | +} | ||
116 | + | ||
117 | +uint32_t cpu_ppc_load_tbl (CPUState *env) | ||
118 | +{ | ||
119 | + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; | ||
120 | +} | ||
121 | + | ||
122 | +uint32_t cpu_ppc_load_tbu (CPUState *env) | ||
123 | +{ | ||
124 | + return cpu_ppc_get_tb(env) >> 32; | ||
125 | +} | ||
126 | + | ||
127 | +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) | ||
128 | +{ | ||
129 | + /* TO FIX */ | ||
130 | +} | ||
131 | + | ||
132 | +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) | ||
133 | +{ | ||
134 | + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); | ||
135 | +} | ||
136 | + | ||
137 | +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) | ||
138 | +{ | ||
139 | + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); | ||
140 | +} | ||
141 | + | ||
142 | +uint32_t cpu_ppc_load_decr (CPUState *env) | ||
143 | +{ | ||
144 | + /* TO FIX */ | ||
145 | + return -1; | ||
146 | +} | ||
147 | + | ||
148 | +void cpu_ppc_store_decr (CPUState *env, uint32_t value) | ||
149 | +{ | ||
150 | + /* TO FIX */ | ||
151 | +} | ||
152 | + | ||
153 | +void cpu_loop(CPUPPCState *env) | ||
154 | +{ | ||
155 | + int trapnr; | ||
156 | + uint32_t ret; | ||
157 | + target_siginfo_t info; | ||
158 | + | ||
159 | + for(;;) { | ||
160 | + trapnr = cpu_ppc_exec(env); | ||
161 | + if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && | ||
162 | + trapnr != EXCP_TRACE) { | ||
163 | + if (loglevel > 0) { | ||
164 | + cpu_dump_state(env, logfile, fprintf, 0); | ||
165 | + } | ||
166 | + } | ||
167 | + switch(trapnr) { | ||
168 | + case EXCP_NONE: | ||
169 | + break; | ||
170 | + case EXCP_SYSCALL_USER: | ||
171 | + /* system call */ | ||
172 | + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) | ||
173 | + ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4], | ||
174 | + env->gpr[5], env->gpr[6], env->gpr[7], | ||
175 | + env->gpr[8], env->gpr[9], env->gpr[10]*/); | ||
176 | + else if(((int)env->gpr[0])<0) | ||
177 | + ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], | ||
178 | + env->gpr[5], env->gpr[6], env->gpr[7], | ||
179 | + env->gpr[8], env->gpr[9], env->gpr[10]); | ||
180 | + else | ||
181 | + ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], | ||
182 | + env->gpr[5], env->gpr[6], env->gpr[7], | ||
183 | + env->gpr[8], env->gpr[9], env->gpr[10]); | ||
184 | + | ||
185 | + /* Unix syscall error signaling */ | ||
186 | + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) | ||
187 | + { | ||
188 | + if( (int)ret < 0 ) | ||
189 | + env->nip += 0; | ||
190 | + else | ||
191 | + env->nip += 4; | ||
192 | + } | ||
193 | + | ||
194 | + /* Return value */ | ||
195 | + env->gpr[3] = ret; | ||
196 | + break; | ||
197 | + case EXCP_RESET: | ||
198 | + /* Should not happen ! */ | ||
199 | + fprintf(stderr, "RESET asked... Stop emulation\n"); | ||
200 | + if (loglevel) | ||
201 | + fprintf(logfile, "RESET asked... Stop emulation\n"); | ||
202 | + abort(); | ||
203 | + case EXCP_MACHINE_CHECK: | ||
204 | + fprintf(stderr, "Machine check exeption... Stop emulation\n"); | ||
205 | + if (loglevel) | ||
206 | + fprintf(logfile, "RESET asked... Stop emulation\n"); | ||
207 | + info.si_signo = SIGBUS; | ||
208 | + info.si_errno = 0; | ||
209 | + info.si_code = BUS_OBJERR; | ||
210 | + info.si_addr = (void*)(env->nip - 4); | ||
211 | + queue_signal(info.si_signo, &info); | ||
212 | + case EXCP_DSI: | ||
213 | +#ifndef DAR | ||
214 | +/* To deal with multiple qemu header version as host for the darwin-user code */ | ||
215 | +# define DAR SPR_DAR | ||
216 | +#endif | ||
217 | + fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); | ||
218 | + if (loglevel) { | ||
219 | + fprintf(logfile, "Invalid data memory access: 0x%08x\n", | ||
220 | + env->spr[DAR]); | ||
221 | + } | ||
222 | + /* Handle this via the gdb */ | ||
223 | + gdb_handlesig (env, SIGSEGV); | ||
224 | + | ||
225 | + info.si_addr = (void*)env->nip; | ||
226 | + queue_signal(info.si_signo, &info); | ||
227 | + break; | ||
228 | + case EXCP_ISI: | ||
229 | + fprintf(stderr, "Invalid instruction fetch\n"); | ||
230 | + if (loglevel) | ||
231 | + fprintf(logfile, "Invalid instruction fetch\n"); | ||
232 | + /* Handle this via the gdb */ | ||
233 | + gdb_handlesig (env, SIGSEGV); | ||
234 | + | ||
235 | + info.si_addr = (void*)(env->nip - 4); | ||
236 | + queue_signal(info.si_signo, &info); | ||
237 | + break; | ||
238 | + case EXCP_EXTERNAL: | ||
239 | + /* Should not happen ! */ | ||
240 | + fprintf(stderr, "External interruption... Stop emulation\n"); | ||
241 | + if (loglevel) | ||
242 | + fprintf(logfile, "External interruption... Stop emulation\n"); | ||
243 | + abort(); | ||
244 | + case EXCP_ALIGN: | ||
245 | + fprintf(stderr, "Invalid unaligned memory access\n"); | ||
246 | + if (loglevel) | ||
247 | + fprintf(logfile, "Invalid unaligned memory access\n"); | ||
248 | + info.si_signo = SIGBUS; | ||
249 | + info.si_errno = 0; | ||
250 | + info.si_code = BUS_ADRALN; | ||
251 | + info.si_addr = (void*)(env->nip - 4); | ||
252 | + queue_signal(info.si_signo, &info); | ||
253 | + break; | ||
254 | + case EXCP_PROGRAM: | ||
255 | + switch (env->error_code & ~0xF) { | ||
256 | + case EXCP_FP: | ||
257 | + fprintf(stderr, "Program exception\n"); | ||
258 | + if (loglevel) | ||
259 | + fprintf(logfile, "Program exception\n"); | ||
260 | + /* Set FX */ | ||
261 | + env->fpscr[7] |= 0x8; | ||
262 | + /* Finally, update FEX */ | ||
263 | + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & | ||
264 | + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) | ||
265 | + env->fpscr[7] |= 0x4; | ||
266 | + info.si_signo = SIGFPE; | ||
267 | + info.si_errno = 0; | ||
268 | + switch (env->error_code & 0xF) { | ||
269 | + case EXCP_FP_OX: | ||
270 | + info.si_code = FPE_FLTOVF; | ||
271 | + break; | ||
272 | + case EXCP_FP_UX: | ||
273 | + info.si_code = FPE_FLTUND; | ||
274 | + break; | ||
275 | + case EXCP_FP_ZX: | ||
276 | + case EXCP_FP_VXZDZ: | ||
277 | + info.si_code = FPE_FLTDIV; | ||
278 | + break; | ||
279 | + case EXCP_FP_XX: | ||
280 | + info.si_code = FPE_FLTRES; | ||
281 | + break; | ||
282 | + case EXCP_FP_VXSOFT: | ||
283 | + info.si_code = FPE_FLTINV; | ||
284 | + break; | ||
285 | + case EXCP_FP_VXNAN: | ||
286 | + case EXCP_FP_VXISI: | ||
287 | + case EXCP_FP_VXIDI: | ||
288 | + case EXCP_FP_VXIMZ: | ||
289 | + case EXCP_FP_VXVC: | ||
290 | + case EXCP_FP_VXSQRT: | ||
291 | + case EXCP_FP_VXCVI: | ||
292 | + info.si_code = FPE_FLTSUB; | ||
293 | + break; | ||
294 | + default: | ||
295 | + fprintf(stderr, "Unknown floating point exception " | ||
296 | + "(%02x)\n", env->error_code); | ||
297 | + if (loglevel) { | ||
298 | + fprintf(logfile, "Unknown floating point exception " | ||
299 | + "(%02x)\n", env->error_code & 0xF); | ||
300 | + } | ||
301 | + } | ||
302 | + break; | ||
303 | + case EXCP_INVAL: | ||
304 | + fprintf(stderr, "Invalid instruction\n"); | ||
305 | + if (loglevel) | ||
306 | + fprintf(logfile, "Invalid instruction\n"); | ||
307 | + info.si_signo = SIGILL; | ||
308 | + info.si_errno = 0; | ||
309 | + switch (env->error_code & 0xF) { | ||
310 | + case EXCP_INVAL_INVAL: | ||
311 | + info.si_code = ILL_ILLOPC; | ||
312 | + break; | ||
313 | + case EXCP_INVAL_LSWX: | ||
314 | + info.si_code = ILL_ILLOPN; | ||
315 | + break; | ||
316 | + case EXCP_INVAL_SPR: | ||
317 | + info.si_code = ILL_PRVREG; | ||
318 | + break; | ||
319 | + case EXCP_INVAL_FP: | ||
320 | + info.si_code = ILL_COPROC; | ||
321 | + break; | ||
322 | + default: | ||
323 | + fprintf(stderr, "Unknown invalid operation (%02x)\n", | ||
324 | + env->error_code & 0xF); | ||
325 | + if (loglevel) { | ||
326 | + fprintf(logfile, "Unknown invalid operation (%02x)\n", | ||
327 | + env->error_code & 0xF); | ||
328 | + } | ||
329 | + info.si_code = ILL_ILLADR; | ||
330 | + break; | ||
331 | + } | ||
332 | + /* Handle this via the gdb */ | ||
333 | + gdb_handlesig (env, SIGSEGV); | ||
334 | + break; | ||
335 | + case EXCP_PRIV: | ||
336 | + fprintf(stderr, "Privilege violation\n"); | ||
337 | + if (loglevel) | ||
338 | + fprintf(logfile, "Privilege violation\n"); | ||
339 | + info.si_signo = SIGILL; | ||
340 | + info.si_errno = 0; | ||
341 | + switch (env->error_code & 0xF) { | ||
342 | + case EXCP_PRIV_OPC: | ||
343 | + info.si_code = ILL_PRVOPC; | ||
344 | + break; | ||
345 | + case EXCP_PRIV_REG: | ||
346 | + info.si_code = ILL_PRVREG; | ||
347 | + break; | ||
348 | + default: | ||
349 | + fprintf(stderr, "Unknown privilege violation (%02x)\n", | ||
350 | + env->error_code & 0xF); | ||
351 | + info.si_code = ILL_PRVOPC; | ||
352 | + break; | ||
353 | + } | ||
354 | + break; | ||
355 | + case EXCP_TRAP: | ||
356 | + fprintf(stderr, "Tried to call a TRAP\n"); | ||
357 | + if (loglevel) | ||
358 | + fprintf(logfile, "Tried to call a TRAP\n"); | ||
359 | + abort(); | ||
360 | + default: | ||
361 | + /* Should not happen ! */ | ||
362 | + fprintf(stderr, "Unknown program exception (%02x)\n", | ||
363 | + env->error_code); | ||
364 | + if (loglevel) { | ||
365 | + fprintf(logfile, "Unknwon program exception (%02x)\n", | ||
366 | + env->error_code); | ||
367 | + } | ||
368 | + abort(); | ||
369 | + } | ||
370 | + info.si_addr = (void*)(env->nip - 4); | ||
371 | + queue_signal(info.si_signo, &info); | ||
372 | + break; | ||
373 | + case EXCP_NO_FP: | ||
374 | + fprintf(stderr, "No floating point allowed\n"); | ||
375 | + if (loglevel) | ||
376 | + fprintf(logfile, "No floating point allowed\n"); | ||
377 | + info.si_signo = SIGILL; | ||
378 | + info.si_errno = 0; | ||
379 | + info.si_code = ILL_COPROC; | ||
380 | + info.si_addr = (void*)(env->nip - 4); | ||
381 | + queue_signal(info.si_signo, &info); | ||
382 | + break; | ||
383 | + case EXCP_DECR: | ||
384 | + /* Should not happen ! */ | ||
385 | + fprintf(stderr, "Decrementer exception\n"); | ||
386 | + if (loglevel) | ||
387 | + fprintf(logfile, "Decrementer exception\n"); | ||
388 | + abort(); | ||
389 | + case EXCP_TRACE: | ||
390 | + /* Pass to gdb: we use this to trace execution */ | ||
391 | + gdb_handlesig (env, SIGTRAP); | ||
392 | + break; | ||
393 | + case EXCP_FP_ASSIST: | ||
394 | + /* Should not happen ! */ | ||
395 | + fprintf(stderr, "Floating point assist exception\n"); | ||
396 | + if (loglevel) | ||
397 | + fprintf(logfile, "Floating point assist exception\n"); | ||
398 | + abort(); | ||
399 | + case EXCP_MTMSR: | ||
400 | + /* We reloaded the msr, just go on */ | ||
401 | + if (msr_pr == 0) { | ||
402 | + fprintf(stderr, "Tried to go into supervisor mode !\n"); | ||
403 | + if (loglevel) | ||
404 | + fprintf(logfile, "Tried to go into supervisor mode !\n"); | ||
405 | + abort(); | ||
406 | + } | ||
407 | + break; | ||
408 | + case EXCP_BRANCH: | ||
409 | + /* We stopped because of a jump... */ | ||
410 | + break; | ||
411 | + case EXCP_INTERRUPT: | ||
412 | + /* Don't know why this should ever happen... */ | ||
413 | + fprintf(stderr, "EXCP_INTERRUPT\n"); | ||
414 | + break; | ||
415 | + case EXCP_DEBUG: | ||
416 | + gdb_handlesig (env, SIGTRAP); | ||
417 | + break; | ||
418 | + default: | ||
419 | + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | ||
420 | + trapnr); | ||
421 | + if (loglevel) { | ||
422 | + fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " | ||
423 | + "0x%02x - aborting\n", trapnr, env->error_code); | ||
424 | + } | ||
425 | + abort(); | ||
426 | + } | ||
427 | + process_pending_signals(env); | ||
428 | + } | ||
429 | +} | ||
430 | +#endif | ||
431 | + | ||
432 | + | ||
433 | +#ifdef TARGET_I386 | ||
434 | + | ||
435 | +/***********************************************************/ | ||
436 | +/* CPUX86 core interface */ | ||
437 | + | ||
438 | +uint64_t cpu_get_tsc(CPUX86State *env) | ||
439 | +{ | ||
440 | + return cpu_get_real_ticks(); | ||
441 | +} | ||
442 | + | ||
443 | +void | ||
444 | +write_dt(void *ptr, unsigned long addr, unsigned long limit, | ||
445 | + int flags) | ||
446 | +{ | ||
447 | + unsigned int e1, e2; | ||
448 | + e1 = (addr << 16) | (limit & 0xffff); | ||
449 | + e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); | ||
450 | + e2 |= flags; | ||
451 | + stl((uint8_t *)ptr, e1); | ||
452 | + stl((uint8_t *)ptr + 4, e2); | ||
453 | +} | ||
454 | + | ||
455 | +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, | ||
456 | + unsigned long addr, unsigned int sel) | ||
457 | +{ | ||
458 | + unsigned int e1, e2; | ||
459 | + e1 = (addr & 0xffff) | (sel << 16); | ||
460 | + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); | ||
461 | + stl((uint8_t *)ptr, e1); | ||
462 | + stl((uint8_t *)ptr + 4, e2); | ||
463 | +} | ||
464 | + | ||
465 | +#define GDT_TABLE_SIZE 14 | ||
466 | +#define LDT_TABLE_SIZE 15 | ||
467 | +#define IDT_TABLE_SIZE 256 | ||
468 | +#define TSS_SIZE 104 | ||
469 | +uint64_t gdt_table[GDT_TABLE_SIZE]; | ||
470 | +uint64_t ldt_table[LDT_TABLE_SIZE]; | ||
471 | +uint64_t idt_table[IDT_TABLE_SIZE]; | ||
472 | +uint32_t tss[TSS_SIZE]; | ||
473 | + | ||
474 | +/* only dpl matters as we do only user space emulation */ | ||
475 | +static void set_idt(int n, unsigned int dpl) | ||
476 | +{ | ||
477 | + set_gate(idt_table + n, 0, dpl, 0, 0); | ||
478 | +} | ||
479 | + | ||
480 | +/* ABI convention: after a syscall if there was an error the CF flag is set */ | ||
481 | +static inline set_error(CPUX86State *env, int ret) | ||
482 | +{ | ||
483 | + if(ret<0) | ||
484 | + env->eflags = env->eflags | 0x1; | ||
485 | + else | ||
486 | + env->eflags &= ~0x1; | ||
487 | + env->regs[R_EAX] = ret; | ||
488 | +} | ||
489 | + | ||
490 | +void cpu_loop(CPUX86State *env) | ||
491 | +{ | ||
492 | + int trapnr; | ||
493 | + int ret; | ||
494 | + uint8_t *pc; | ||
495 | + target_siginfo_t info; | ||
496 | + | ||
497 | + for(;;) { | ||
498 | + trapnr = cpu_x86_exec(env); | ||
499 | + uint32_t *params = (uint32_t *)env->regs[R_ESP]; | ||
500 | + switch(trapnr) { | ||
501 | + case 0x79: /* Our commpage hack back door exit is here */ | ||
502 | + do_commpage(env, env->eip, *(params + 1), *(params + 2), | ||
503 | + *(params + 3), *(params + 4), | ||
504 | + *(params + 5), *(params + 6), | ||
505 | + *(params + 7), *(params + 8)); | ||
506 | + break; | ||
507 | + case 0x81: /* mach syscall */ | ||
508 | + { | ||
509 | + ret = do_mach_syscall(env, env->regs[R_EAX], | ||
510 | + *(params + 1), *(params + 2), | ||
511 | + *(params + 3), *(params + 4), | ||
512 | + *(params + 5), *(params + 6), | ||
513 | + *(params + 7), *(params + 8)); | ||
514 | + set_error(env, ret); | ||
515 | + break; | ||
516 | + } | ||
517 | + case 0x90: /* unix backdoor */ | ||
518 | + { | ||
519 | + /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/ | ||
520 | + int saved_stack = env->regs[R_ESP]; | ||
521 | + env->regs[R_ESP] = env->regs[R_ECX]; | ||
522 | + | ||
523 | + ret = do_unix_syscall(env, env->regs[R_EAX]); | ||
524 | + | ||
525 | + env->regs[R_ECX] = env->regs[R_ESP]; | ||
526 | + env->regs[R_ESP] = saved_stack; | ||
527 | + | ||
528 | + set_error(env, ret); | ||
529 | + break; | ||
530 | + } | ||
531 | + case 0x80: /* unix syscall */ | ||
532 | + { | ||
533 | + ret = do_unix_syscall(env, env->regs[R_EAX]/*, | ||
534 | + *(params + 1), *(params + 2), | ||
535 | + *(params + 3), *(params + 4), | ||
536 | + *(params + 5), *(params + 6), | ||
537 | + *(params + 7), *(params + 8)*/); | ||
538 | + set_error(env, ret); | ||
539 | + break; | ||
540 | + } | ||
541 | + case 0x82: /* thread syscall */ | ||
542 | + { | ||
543 | + ret = do_thread_syscall(env, env->regs[R_EAX], | ||
544 | + *(params + 1), *(params + 2), | ||
545 | + *(params + 3), *(params + 4), | ||
546 | + *(params + 5), *(params + 6), | ||
547 | + *(params + 7), *(params + 8)); | ||
548 | + set_error(env, ret); | ||
549 | + break; | ||
550 | + } | ||
551 | + case EXCP0B_NOSEG: | ||
552 | + case EXCP0C_STACK: | ||
553 | + info.si_signo = SIGBUS; | ||
554 | + info.si_errno = 0; | ||
555 | + info.si_code = BUS_NOOP; | ||
556 | + info.si_addr = 0; | ||
557 | + gdb_handlesig (env, SIGBUS); | ||
558 | + queue_signal(info.si_signo, &info); | ||
559 | + break; | ||
560 | + case EXCP0D_GPF: | ||
561 | + info.si_signo = SIGSEGV; | ||
562 | + info.si_errno = 0; | ||
563 | + info.si_code = SEGV_NOOP; | ||
564 | + info.si_addr = 0; | ||
565 | + gdb_handlesig (env, SIGSEGV); | ||
566 | + queue_signal(info.si_signo, &info); | ||
567 | + break; | ||
568 | + case EXCP0E_PAGE: | ||
569 | + info.si_signo = SIGSEGV; | ||
570 | + info.si_errno = 0; | ||
571 | + if (!(env->error_code & 1)) | ||
572 | + info.si_code = SEGV_MAPERR; | ||
573 | + else | ||
574 | + info.si_code = SEGV_ACCERR; | ||
575 | + info.si_addr = (void*)env->cr[2]; | ||
576 | + gdb_handlesig (env, SIGSEGV); | ||
577 | + queue_signal(info.si_signo, &info); | ||
578 | + break; | ||
579 | + case EXCP00_DIVZ: | ||
580 | + /* division by zero */ | ||
581 | + info.si_signo = SIGFPE; | ||
582 | + info.si_errno = 0; | ||
583 | + info.si_code = FPE_INTDIV; | ||
584 | + info.si_addr = (void*)env->eip; | ||
585 | + gdb_handlesig (env, SIGFPE); | ||
586 | + queue_signal(info.si_signo, &info); | ||
587 | + break; | ||
588 | + case EXCP01_SSTP: | ||
589 | + case EXCP03_INT3: | ||
590 | + info.si_signo = SIGTRAP; | ||
591 | + info.si_errno = 0; | ||
592 | + info.si_code = TRAP_BRKPT; | ||
593 | + info.si_addr = (void*)env->eip; | ||
594 | + gdb_handlesig (env, SIGTRAP); | ||
595 | + queue_signal(info.si_signo, &info); | ||
596 | + break; | ||
597 | + case EXCP04_INTO: | ||
598 | + case EXCP05_BOUND: | ||
599 | + info.si_signo = SIGSEGV; | ||
600 | + info.si_errno = 0; | ||
601 | + info.si_code = SEGV_NOOP; | ||
602 | + info.si_addr = 0; | ||
603 | + gdb_handlesig (env, SIGSEGV); | ||
604 | + queue_signal(info.si_signo, &info); | ||
605 | + break; | ||
606 | + case EXCP06_ILLOP: | ||
607 | + info.si_signo = SIGILL; | ||
608 | + info.si_errno = 0; | ||
609 | + info.si_code = ILL_ILLOPN; | ||
610 | + info.si_addr = (void*)env->eip; | ||
611 | + gdb_handlesig (env, SIGILL); | ||
612 | + queue_signal(info.si_signo, &info); | ||
613 | + break; | ||
614 | + case EXCP_INTERRUPT: | ||
615 | + /* just indicate that signals should be handled asap */ | ||
616 | + break; | ||
617 | + case EXCP_DEBUG: | ||
618 | + { | ||
619 | + int sig; | ||
620 | + | ||
621 | + sig = gdb_handlesig (env, SIGTRAP); | ||
622 | + if (sig) | ||
623 | + { | ||
624 | + info.si_signo = sig; | ||
625 | + info.si_errno = 0; | ||
626 | + info.si_code = TRAP_BRKPT; | ||
627 | + queue_signal(info.si_signo, &info); | ||
628 | + } | ||
629 | + } | ||
630 | + break; | ||
631 | + default: | ||
632 | + pc = (void*)(env->segs[R_CS].base + env->eip); | ||
633 | + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", | ||
634 | + (long)pc, trapnr); | ||
635 | + abort(); | ||
636 | + } | ||
637 | + process_pending_signals(env); | ||
638 | + } | ||
639 | +} | ||
640 | +#endif | ||
641 | + | ||
642 | +void usage(void) | ||
643 | +{ | ||
644 | + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" | ||
645 | + "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" | ||
646 | + "Darwin CPU emulator (compiled for %s emulation)\n" | ||
647 | + "\n" | ||
648 | + "-h print this help\n" | ||
649 | + "-L path set the elf interpreter prefix (default=%s)\n" | ||
650 | + "-s size set the stack size in bytes (default=%ld)\n" | ||
651 | + "\n" | ||
652 | + "debug options:\n" | ||
653 | +#ifdef USE_CODE_COPY | ||
654 | + "-no-code-copy disable code copy acceleration\n" | ||
655 | +#endif | ||
656 | + "-d options activate log (logfile=%s)\n" | ||
657 | + "-g wait for gdb on port 1234\n" | ||
658 | + "-p pagesize set the host page size to 'pagesize'\n", | ||
659 | + TARGET_ARCH, | ||
660 | + interp_prefix, | ||
661 | + stack_size, | ||
662 | + DEBUG_LOGFILE); | ||
663 | + _exit(1); | ||
664 | +} | ||
665 | + | ||
666 | +/* XXX: currently only used for async signals (see signal.c) */ | ||
667 | +CPUState *global_env; | ||
668 | +/* used only if single thread */ | ||
669 | +CPUState *cpu_single_env = NULL; | ||
670 | + | ||
671 | +/* used to free thread contexts */ | ||
672 | +TaskState *first_task_state; | ||
673 | + | ||
674 | +int main(int argc, char **argv) | ||
675 | +{ | ||
676 | + const char *filename; | ||
677 | + struct target_pt_regs regs1, *regs = ®s1; | ||
678 | + TaskState ts1, *ts = &ts1; | ||
679 | + CPUState *env; | ||
680 | + int optind; | ||
681 | + short use_gdbstub = 0; | ||
682 | + const char *r; | ||
683 | + | ||
684 | + if (argc <= 1) | ||
685 | + usage(); | ||
686 | + | ||
687 | + /* init debug */ | ||
688 | + cpu_set_log_filename(DEBUG_LOGFILE); | ||
689 | + | ||
690 | + optind = 1; | ||
691 | + for(;;) { | ||
692 | + if (optind >= argc) | ||
693 | + break; | ||
694 | + r = argv[optind]; | ||
695 | + if (r[0] != '-') | ||
696 | + break; | ||
697 | + optind++; | ||
698 | + r++; | ||
699 | + if (!strcmp(r, "-")) { | ||
700 | + break; | ||
701 | + } else if (!strcmp(r, "d")) { | ||
702 | + int mask; | ||
703 | + CPULogItem *item; | ||
704 | + | ||
705 | + if (optind >= argc) | ||
706 | + break; | ||
707 | + | ||
708 | + r = argv[optind++]; | ||
709 | + mask = cpu_str_to_log_mask(r); | ||
710 | + if (!mask) { | ||
711 | + printf("Log items (comma separated):\n"); | ||
712 | + for(item = cpu_log_items; item->mask != 0; item++) { | ||
713 | + printf("%-10s %s\n", item->name, item->help); | ||
714 | + } | ||
715 | + exit(1); | ||
716 | + } | ||
717 | + cpu_set_log(mask); | ||
718 | + } else if (!strcmp(r, "s")) { | ||
719 | + r = argv[optind++]; | ||
720 | + stack_size = strtol(r, (char **)&r, 0); | ||
721 | + if (stack_size <= 0) | ||
722 | + usage(); | ||
723 | + if (*r == 'M') | ||
724 | + stack_size *= 1024 * 1024; | ||
725 | + else if (*r == 'k' || *r == 'K') | ||
726 | + stack_size *= 1024; | ||
727 | + } else if (!strcmp(r, "L")) { | ||
728 | + interp_prefix = argv[optind++]; | ||
729 | + } else if (!strcmp(r, "p")) { | ||
730 | + qemu_host_page_size = atoi(argv[optind++]); | ||
731 | + if (qemu_host_page_size == 0 || | ||
732 | + (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { | ||
733 | + fprintf(stderr, "page size must be a power of two\n"); | ||
734 | + exit(1); | ||
735 | + } | ||
736 | + } else | ||
737 | + if (!strcmp(r, "g")) { | ||
738 | + use_gdbstub = 1; | ||
739 | + } else | ||
740 | +#ifdef USE_CODE_COPY | ||
741 | + if (!strcmp(r, "no-code-copy")) { | ||
742 | + code_copy_enabled = 0; | ||
743 | + } else | ||
744 | +#endif | ||
745 | + { | ||
746 | + usage(); | ||
747 | + } | ||
748 | + } | ||
749 | + if (optind >= argc) | ||
750 | + usage(); | ||
751 | + filename = argv[optind]; | ||
752 | + | ||
753 | + /* Zero out regs */ | ||
754 | + memset(regs, 0, sizeof(struct target_pt_regs)); | ||
755 | + | ||
756 | +#if 0 | ||
757 | + /* Scan interp_prefix dir for replacement files. */ | ||
758 | + init_paths(interp_prefix); | ||
759 | +#endif | ||
760 | + | ||
761 | + /* NOTE: we need to init the CPU at this stage to get | ||
762 | + qemu_host_page_size */ | ||
763 | + env = cpu_init(); | ||
764 | + | ||
765 | + printf("Starting %s with qemu\n----------------\n", filename); | ||
766 | + | ||
767 | + commpage_init(); | ||
768 | + | ||
769 | + if (mach_exec(filename, argv+optind, environ, regs) != 0) { | ||
770 | + printf("Error loading %s\n", filename); | ||
771 | + _exit(1); | ||
772 | + } | ||
773 | + | ||
774 | + syscall_init(); | ||
775 | + signal_init(); | ||
776 | + global_env = env; | ||
777 | + | ||
778 | + /* build Task State */ | ||
779 | + memset(ts, 0, sizeof(TaskState)); | ||
780 | + env->opaque = ts; | ||
781 | + ts->used = 1; | ||
782 | + env->user_mode_only = 1; | ||
783 | + | ||
784 | +#if defined(TARGET_I386) | ||
785 | + cpu_x86_set_cpl(env, 3); | ||
786 | + | ||
787 | + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; | ||
788 | + env->hflags |= HF_PE_MASK; | ||
789 | + | ||
790 | + if (env->cpuid_features & CPUID_SSE) { | ||
791 | + env->cr[4] |= CR4_OSFXSR_MASK; | ||
792 | + env->hflags |= HF_OSFXSR_MASK; | ||
793 | + } | ||
794 | + | ||
795 | + /* flags setup : we activate the IRQs by default as in user mode */ | ||
796 | + env->eflags |= IF_MASK; | ||
797 | + | ||
798 | + /* darwin register setup */ | ||
799 | + env->regs[R_EAX] = regs->eax; | ||
800 | + env->regs[R_EBX] = regs->ebx; | ||
801 | + env->regs[R_ECX] = regs->ecx; | ||
802 | + env->regs[R_EDX] = regs->edx; | ||
803 | + env->regs[R_ESI] = regs->esi; | ||
804 | + env->regs[R_EDI] = regs->edi; | ||
805 | + env->regs[R_EBP] = regs->ebp; | ||
806 | + env->regs[R_ESP] = regs->esp; | ||
807 | + env->eip = regs->eip; | ||
808 | + | ||
809 | + /* Darwin LDT setup */ | ||
810 | + /* 2 - User code segment | ||
811 | + 3 - User data segment | ||
812 | + 4 - User cthread */ | ||
813 | + bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0])); | ||
814 | + env->ldt.base = (uint32_t) ldt_table; | ||
815 | + env->ldt.limit = sizeof(ldt_table) - 1; | ||
816 | + | ||
817 | + write_dt(ldt_table + 2, 0, 0xfffff, | ||
818 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | | ||
819 | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); | ||
820 | + write_dt(ldt_table + 3, 0, 0xfffff, | ||
821 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | | ||
822 | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); | ||
823 | + write_dt(ldt_table + 4, 0, 0xfffff, | ||
824 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | | ||
825 | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); | ||
826 | + | ||
827 | + /* Darwin GDT setup. | ||
828 | + * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86, | ||
829 | + now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */ | ||
830 | + bzero(gdt_table, sizeof(gdt_table)); | ||
831 | + env->gdt.base = (uint32_t)gdt_table; | ||
832 | + env->gdt.limit = sizeof(gdt_table) - 1; | ||
833 | + | ||
834 | + /* Set up a back door to handle sysenter syscalls (unix) */ | ||
835 | + char * syscallbackdoor = malloc(64); | ||
836 | + page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID); | ||
837 | + | ||
838 | + int i = 0; | ||
839 | + syscallbackdoor[i++] = 0xcd; | ||
840 | + syscallbackdoor[i++] = 0x90; /* int 0x90 */ | ||
841 | + syscallbackdoor[i++] = 0x0F; | ||
842 | + syscallbackdoor[i++] = 0x35; /* sysexit */ | ||
843 | + | ||
844 | + /* Darwin sysenter/sysexit setup */ | ||
845 | + env->sysenter_cs = 0x1; //XXX | ||
846 | + env->sysenter_eip = (int)syscallbackdoor; | ||
847 | + env->sysenter_esp = (int)malloc(64); | ||
848 | + | ||
849 | + /* Darwin TSS setup | ||
850 | + This must match up with GDT[4] */ | ||
851 | + env->tr.base = (uint32_t) tss; | ||
852 | + env->tr.limit = sizeof(tss) - 1; | ||
853 | + env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT); | ||
854 | + stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment | ||
855 | + | ||
856 | + /* Darwin interrupt setup */ | ||
857 | + bzero(idt_table, sizeof(idt_table)); | ||
858 | + env->idt.base = (uint32_t) idt_table; | ||
859 | + env->idt.limit = sizeof(idt_table) - 1; | ||
860 | + set_idt(0, 0); | ||
861 | + set_idt(1, 0); | ||
862 | + set_idt(2, 0); | ||
863 | + set_idt(3, 3); | ||
864 | + set_idt(4, 3); | ||
865 | + set_idt(5, 3); | ||
866 | + set_idt(6, 0); | ||
867 | + set_idt(7, 0); | ||
868 | + set_idt(8, 0); | ||
869 | + set_idt(9, 0); | ||
870 | + set_idt(10, 0); | ||
871 | + set_idt(11, 0); | ||
872 | + set_idt(12, 0); | ||
873 | + set_idt(13, 0); | ||
874 | + set_idt(14, 0); | ||
875 | + set_idt(15, 0); | ||
876 | + set_idt(16, 0); | ||
877 | + set_idt(17, 0); | ||
878 | + set_idt(18, 0); | ||
879 | + set_idt(19, 0); | ||
880 | + /* Syscalls are done via | ||
881 | + int 0x80 (unix) (rarely used) | ||
882 | + int 0x81 (mach) | ||
883 | + int 0x82 (thread) | ||
884 | + int 0x83 (diag) (not handled here) | ||
885 | + sysenter/sysexit (unix) -> we redirect that to int 0x90 */ | ||
886 | + set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */ | ||
887 | + set_idt(0x80, 3); /* Unix Syscall */ | ||
888 | + set_idt(0x81, 3); /* Mach Syscalls */ | ||
889 | + set_idt(0x82, 3); /* thread Syscalls */ | ||
890 | + | ||
891 | + set_idt(0x90, 3); /* Unix Syscall backdoor */ | ||
892 | + | ||
893 | + | ||
894 | + cpu_x86_load_seg(env, R_CS, __USER_CS); | ||
895 | + cpu_x86_load_seg(env, R_DS, __USER_DS); | ||
896 | + cpu_x86_load_seg(env, R_ES, __USER_DS); | ||
897 | + cpu_x86_load_seg(env, R_SS, __USER_DS); | ||
898 | + cpu_x86_load_seg(env, R_FS, __USER_DS); | ||
899 | + cpu_x86_load_seg(env, R_GS, __USER_DS); | ||
900 | + | ||
901 | +#elif defined(TARGET_PPC) | ||
902 | + { | ||
903 | + int i; | ||
904 | + env->nip = regs->nip; | ||
905 | + for(i = 0; i < 32; i++) { | ||
906 | + env->gpr[i] = regs->gpr[i]; | ||
907 | + } | ||
908 | + } | ||
909 | +#else | ||
910 | +#error unsupported target CPU | ||
911 | +#endif | ||
912 | + | ||
913 | + if (use_gdbstub) { | ||
914 | + printf("Waiting for gdb Connection on port 1234...\n"); | ||
915 | + gdbserver_start (1234); | ||
916 | + gdb_handlesig(env, 0); | ||
917 | + } | ||
918 | + | ||
919 | + cpu_loop(env); | ||
920 | + /* never exits */ | ||
921 | + return 0; | ||
922 | +} |
darwin-user/mmap.c
0 โ 100644
1 | +/* | ||
2 | + * mmap support for qemu | ||
3 | + * | ||
4 | + * Copyright (c) 2003 Fabrice Bellard | ||
5 | + * | ||
6 | + * This program is free software; you can redistribute it and/or modify | ||
7 | + * it under the terms of the GNU General Public License as published by | ||
8 | + * the Free Software Foundation; either version 2 of the License, or | ||
9 | + * (at your option) any later version. | ||
10 | + * | ||
11 | + * This program is distributed in the hope that it will be useful, | ||
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | + * GNU General Public License for more details. | ||
15 | + * | ||
16 | + * You should have received a copy of the GNU General Public License | ||
17 | + * along with this program; if not, write to the Free Software | ||
18 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | + */ | ||
20 | +#include <stdlib.h> | ||
21 | +#include <stdio.h> | ||
22 | +#include <stdarg.h> | ||
23 | +#include <string.h> | ||
24 | +#include <unistd.h> | ||
25 | +#include <errno.h> | ||
26 | +#include <sys/mman.h> | ||
27 | + | ||
28 | +#include "qemu.h" | ||
29 | + | ||
30 | +//#define DEBUG_MMAP | ||
31 | + | ||
32 | +/* NOTE: all the constants are the HOST ones */ | ||
33 | +int target_mprotect(unsigned long start, unsigned long len, int prot) | ||
34 | +{ | ||
35 | + unsigned long end, host_start, host_end, addr; | ||
36 | + int prot1, ret; | ||
37 | + | ||
38 | +#ifdef DEBUG_MMAP | ||
39 | + printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, | ||
40 | + prot & PROT_READ ? 'r' : '-', | ||
41 | + prot & PROT_WRITE ? 'w' : '-', | ||
42 | + prot & PROT_EXEC ? 'x' : '-'); | ||
43 | +#endif | ||
44 | + | ||
45 | + if ((start & ~TARGET_PAGE_MASK) != 0) | ||
46 | + return -EINVAL; | ||
47 | + len = TARGET_PAGE_ALIGN(len); | ||
48 | + end = start + len; | ||
49 | + if (end < start) | ||
50 | + return -EINVAL; | ||
51 | + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) | ||
52 | + return -EINVAL; | ||
53 | + if (len == 0) | ||
54 | + return 0; | ||
55 | + | ||
56 | + host_start = start & qemu_host_page_mask; | ||
57 | + host_end = HOST_PAGE_ALIGN(end); | ||
58 | + if (start > host_start) { | ||
59 | + /* handle host page containing start */ | ||
60 | + prot1 = prot; | ||
61 | + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { | ||
62 | + prot1 |= page_get_flags(addr); | ||
63 | + } | ||
64 | + if (host_end == host_start + qemu_host_page_size) { | ||
65 | + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { | ||
66 | + prot1 |= page_get_flags(addr); | ||
67 | + } | ||
68 | + end = host_end; | ||
69 | + } | ||
70 | + ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS); | ||
71 | + if (ret != 0) | ||
72 | + return ret; | ||
73 | + host_start += qemu_host_page_size; | ||
74 | + } | ||
75 | + if (end < host_end) { | ||
76 | + prot1 = prot; | ||
77 | + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { | ||
78 | + prot1 |= page_get_flags(addr); | ||
79 | + } | ||
80 | + ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size, | ||
81 | + prot1 & PAGE_BITS); | ||
82 | + if (ret != 0) | ||
83 | + return ret; | ||
84 | + host_end -= qemu_host_page_size; | ||
85 | + } | ||
86 | + | ||
87 | + /* handle the pages in the middle */ | ||
88 | + if (host_start < host_end) { | ||
89 | + ret = mprotect((void *)host_start, host_end - host_start, prot); | ||
90 | + if (ret != 0) | ||
91 | + return ret; | ||
92 | + } | ||
93 | + page_set_flags(start, start + len, prot | PAGE_VALID); | ||
94 | + return 0; | ||
95 | +} | ||
96 | + | ||
97 | +/* map an incomplete host page */ | ||
98 | +int mmap_frag(unsigned long host_start, | ||
99 | + unsigned long start, unsigned long end, | ||
100 | + int prot, int flags, int fd, unsigned long offset) | ||
101 | +{ | ||
102 | + unsigned long host_end, ret, addr; | ||
103 | + int prot1, prot_new; | ||
104 | + | ||
105 | + host_end = host_start + qemu_host_page_size; | ||
106 | + | ||
107 | + /* get the protection of the target pages outside the mapping */ | ||
108 | + prot1 = 0; | ||
109 | + for(addr = host_start; addr < host_end; addr++) { | ||
110 | + if (addr < start || addr >= end) | ||
111 | + prot1 |= page_get_flags(addr); | ||
112 | + } | ||
113 | + | ||
114 | + if (prot1 == 0) { | ||
115 | + /* no page was there, so we allocate one */ | ||
116 | + ret = (long)mmap((void *)host_start, qemu_host_page_size, prot, | ||
117 | + flags | MAP_ANONYMOUS, -1, 0); | ||
118 | + if (ret == -1) | ||
119 | + return ret; | ||
120 | + } | ||
121 | + prot1 &= PAGE_BITS; | ||
122 | + | ||
123 | + prot_new = prot | prot1; | ||
124 | + if (!(flags & MAP_ANONYMOUS)) { | ||
125 | + /* msync() won't work here, so we return an error if write is | ||
126 | + possible while it is a shared mapping */ | ||
127 | +#ifndef __APPLE__ | ||
128 | + if ((flags & MAP_TYPE) == MAP_SHARED && | ||
129 | +#else | ||
130 | + if ((flags & MAP_SHARED) && | ||
131 | +#endif | ||
132 | + (prot & PROT_WRITE)) | ||
133 | + return -EINVAL; | ||
134 | + | ||
135 | + /* adjust protection to be able to read */ | ||
136 | + if (!(prot1 & PROT_WRITE)) | ||
137 | + mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE); | ||
138 | + | ||
139 | + /* read the corresponding file data */ | ||
140 | + pread(fd, (void *)start, end - start, offset); | ||
141 | + | ||
142 | + /* put final protection */ | ||
143 | + if (prot_new != (prot1 | PROT_WRITE)) | ||
144 | + mprotect((void *)host_start, qemu_host_page_size, prot_new); | ||
145 | + } else { | ||
146 | + /* just update the protection */ | ||
147 | + if (prot_new != prot1) { | ||
148 | + mprotect((void *)host_start, qemu_host_page_size, prot_new); | ||
149 | + } | ||
150 | + } | ||
151 | + return 0; | ||
152 | +} | ||
153 | + | ||
154 | +/* NOTE: all the constants are the HOST ones */ | ||
155 | +long target_mmap(unsigned long start, unsigned long len, int prot, | ||
156 | + int flags, int fd, unsigned long offset) | ||
157 | +{ | ||
158 | + unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; | ||
159 | +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) | ||
160 | + static unsigned long last_start = 0x40000000; | ||
161 | +#endif | ||
162 | + | ||
163 | +#ifdef DEBUG_MMAP | ||
164 | + { | ||
165 | + printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", | ||
166 | + start, len, | ||
167 | + prot & PROT_READ ? 'r' : '-', | ||
168 | + prot & PROT_WRITE ? 'w' : '-', | ||
169 | + prot & PROT_EXEC ? 'x' : '-'); | ||
170 | + if (flags & MAP_FIXED) | ||
171 | + printf("MAP_FIXED "); | ||
172 | + if (flags & MAP_ANONYMOUS) | ||
173 | + printf("MAP_ANON "); | ||
174 | +#ifndef MAP_TYPE | ||
175 | +# define MAP_TYPE 0x3 | ||
176 | +#endif | ||
177 | + switch(flags & MAP_TYPE) { | ||
178 | + case MAP_PRIVATE: | ||
179 | + printf("MAP_PRIVATE "); | ||
180 | + break; | ||
181 | + case MAP_SHARED: | ||
182 | + printf("MAP_SHARED "); | ||
183 | + break; | ||
184 | + default: | ||
185 | + printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); | ||
186 | + break; | ||
187 | + } | ||
188 | + printf("fd=%d offset=%lx\n", fd, offset); | ||
189 | + } | ||
190 | +#endif | ||
191 | + | ||
192 | + if (offset & ~TARGET_PAGE_MASK) | ||
193 | + return -EINVAL; | ||
194 | + | ||
195 | + len = TARGET_PAGE_ALIGN(len); | ||
196 | + if (len == 0) | ||
197 | + return start; | ||
198 | + host_start = start & qemu_host_page_mask; | ||
199 | + | ||
200 | + if (!(flags & MAP_FIXED)) { | ||
201 | +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) | ||
202 | + /* tell the kenel to search at the same place as i386 */ | ||
203 | + if (host_start == 0) { | ||
204 | + host_start = last_start; | ||
205 | + last_start += HOST_PAGE_ALIGN(len); | ||
206 | + } | ||
207 | +#endif | ||
208 | + if (qemu_host_page_size != qemu_real_host_page_size) { | ||
209 | + /* NOTE: this code is only for debugging with '-p' option */ | ||
210 | + /* reserve a memory area */ | ||
211 | + host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; | ||
212 | + host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, | ||
213 | + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
214 | + if (host_start == -1) | ||
215 | + return host_start; | ||
216 | + host_end = host_start + host_len; | ||
217 | + start = HOST_PAGE_ALIGN(host_start); | ||
218 | + end = start + HOST_PAGE_ALIGN(len); | ||
219 | + if (start > host_start) | ||
220 | + munmap((void *)host_start, start - host_start); | ||
221 | + if (end < host_end) | ||
222 | + munmap((void *)end, host_end - end); | ||
223 | + /* use it as a fixed mapping */ | ||
224 | + flags |= MAP_FIXED; | ||
225 | + } else { | ||
226 | + /* if not fixed, no need to do anything */ | ||
227 | + host_offset = offset & qemu_host_page_mask; | ||
228 | + host_len = len + offset - host_offset; | ||
229 | + start = (long)mmap((void *)host_start, host_len, | ||
230 | + prot, flags, fd, host_offset); | ||
231 | + if (start == -1) | ||
232 | + return start; | ||
233 | + /* update start so that it points to the file position at 'offset' */ | ||
234 | + if (!(flags & MAP_ANONYMOUS)) | ||
235 | + start += offset - host_offset; | ||
236 | + goto the_end1; | ||
237 | + } | ||
238 | + } | ||
239 | + | ||
240 | + if (start & ~TARGET_PAGE_MASK) | ||
241 | + return -EINVAL; | ||
242 | + end = start + len; | ||
243 | + host_end = HOST_PAGE_ALIGN(end); | ||
244 | + | ||
245 | + /* worst case: we cannot map the file because the offset is not | ||
246 | + aligned, so we read it */ | ||
247 | + if (!(flags & MAP_ANONYMOUS) && | ||
248 | + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { | ||
249 | + /* msync() won't work here, so we return an error if write is | ||
250 | + possible while it is a shared mapping */ | ||
251 | +#ifndef __APPLE__ | ||
252 | + if ((flags & MAP_TYPE) == MAP_SHARED && | ||
253 | +#else | ||
254 | + if ((flags & MAP_SHARED) && | ||
255 | +#endif | ||
256 | + (prot & PROT_WRITE)) | ||
257 | + return -EINVAL; | ||
258 | + retaddr = target_mmap(start, len, prot | PROT_WRITE, | ||
259 | + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, | ||
260 | + -1, 0); | ||
261 | + if (retaddr == -1) | ||
262 | + return retaddr; | ||
263 | + pread(fd, (void *)start, len, offset); | ||
264 | + if (!(prot & PROT_WRITE)) { | ||
265 | + ret = target_mprotect(start, len, prot); | ||
266 | + if (ret != 0) | ||
267 | + return ret; | ||
268 | + } | ||
269 | + goto the_end; | ||
270 | + } | ||
271 | + | ||
272 | + /* handle the start of the mapping */ | ||
273 | + if (start > host_start) { | ||
274 | + if (host_end == host_start + qemu_host_page_size) { | ||
275 | + /* one single host page */ | ||
276 | + ret = mmap_frag(host_start, start, end, | ||
277 | + prot, flags, fd, offset); | ||
278 | + if (ret == -1) | ||
279 | + return ret; | ||
280 | + goto the_end1; | ||
281 | + } | ||
282 | + ret = mmap_frag(host_start, start, host_start + qemu_host_page_size, | ||
283 | + prot, flags, fd, offset); | ||
284 | + if (ret == -1) | ||
285 | + return ret; | ||
286 | + host_start += qemu_host_page_size; | ||
287 | + } | ||
288 | + /* handle the end of the mapping */ | ||
289 | + if (end < host_end) { | ||
290 | + ret = mmap_frag(host_end - qemu_host_page_size, | ||
291 | + host_end - qemu_host_page_size, host_end, | ||
292 | + prot, flags, fd, | ||
293 | + offset + host_end - qemu_host_page_size - start); | ||
294 | + if (ret == -1) | ||
295 | + return ret; | ||
296 | + host_end -= qemu_host_page_size; | ||
297 | + } | ||
298 | + | ||
299 | + /* map the middle (easier) */ | ||
300 | + if (host_start < host_end) { | ||
301 | + unsigned long offset1; | ||
302 | + if (flags & MAP_ANONYMOUS) | ||
303 | + offset1 = 0; | ||
304 | + else | ||
305 | + offset1 = offset + host_start - start; | ||
306 | + ret = (long)mmap((void *)host_start, host_end - host_start, | ||
307 | + prot, flags, fd, offset1); | ||
308 | + if (ret == -1) | ||
309 | + return ret; | ||
310 | + } | ||
311 | + the_end1: | ||
312 | + page_set_flags(start, start + len, prot | PAGE_VALID); | ||
313 | + the_end: | ||
314 | +#ifdef DEBUG_MMAP | ||
315 | + printf("target_mmap: ret=0x%lx\n", (long)start); | ||
316 | + page_dump(stdout); | ||
317 | + printf("\n"); | ||
318 | +#endif | ||
319 | + return start; | ||
320 | +} | ||
321 | + | ||
322 | +int target_munmap(unsigned long start, unsigned long len) | ||
323 | +{ | ||
324 | + unsigned long end, host_start, host_end, addr; | ||
325 | + int prot, ret; | ||
326 | + | ||
327 | +#ifdef DEBUG_MMAP | ||
328 | + printf("munmap: start=0x%lx len=0x%lx\n", start, len); | ||
329 | +#endif | ||
330 | + if (start & ~TARGET_PAGE_MASK) | ||
331 | + return -EINVAL; | ||
332 | + len = TARGET_PAGE_ALIGN(len); | ||
333 | + if (len == 0) | ||
334 | + return -EINVAL; | ||
335 | + end = start + len; | ||
336 | + host_start = start & qemu_host_page_mask; | ||
337 | + host_end = HOST_PAGE_ALIGN(end); | ||
338 | + | ||
339 | + if (start > host_start) { | ||
340 | + /* handle host page containing start */ | ||
341 | + prot = 0; | ||
342 | + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { | ||
343 | + prot |= page_get_flags(addr); | ||
344 | + } | ||
345 | + if (host_end == host_start + qemu_host_page_size) { | ||
346 | + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { | ||
347 | + prot |= page_get_flags(addr); | ||
348 | + } | ||
349 | + end = host_end; | ||
350 | + } | ||
351 | + if (prot != 0) | ||
352 | + host_start += qemu_host_page_size; | ||
353 | + } | ||
354 | + if (end < host_end) { | ||
355 | + prot = 0; | ||
356 | + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { | ||
357 | + prot |= page_get_flags(addr); | ||
358 | + } | ||
359 | + if (prot != 0) | ||
360 | + host_end -= qemu_host_page_size; | ||
361 | + } | ||
362 | + | ||
363 | + /* unmap what we can */ | ||
364 | + if (host_start < host_end) { | ||
365 | + ret = munmap((void *)host_start, host_end - host_start); | ||
366 | + if (ret != 0) | ||
367 | + return ret; | ||
368 | + } | ||
369 | + | ||
370 | + page_set_flags(start, start + len, 0); | ||
371 | + return 0; | ||
372 | +} | ||
373 | + | ||
374 | +/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED | ||
375 | + blocks which have been allocated starting on a host page */ | ||
376 | +long target_mremap(unsigned long old_addr, unsigned long old_size, | ||
377 | + unsigned long new_size, unsigned long flags, | ||
378 | + unsigned long new_addr) | ||
379 | +{ | ||
380 | +#ifndef __APPLE__ | ||
381 | + /* XXX: use 5 args syscall */ | ||
382 | + new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); | ||
383 | + if (new_addr == -1) | ||
384 | + return new_addr; | ||
385 | + prot = page_get_flags(old_addr); | ||
386 | + page_set_flags(old_addr, old_addr + old_size, 0); | ||
387 | + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); | ||
388 | + return new_addr; | ||
389 | +#else | ||
390 | + qerror("target_mremap: unsupported\n"); | ||
391 | +#endif | ||
392 | + | ||
393 | +} | ||
394 | + | ||
395 | +int target_msync(unsigned long start, unsigned long len, int flags) | ||
396 | +{ | ||
397 | + unsigned long end; | ||
398 | + | ||
399 | + if (start & ~TARGET_PAGE_MASK) | ||
400 | + return -EINVAL; | ||
401 | + len = TARGET_PAGE_ALIGN(len); | ||
402 | + end = start + len; | ||
403 | + if (end < start) | ||
404 | + return -EINVAL; | ||
405 | + if (end == start) | ||
406 | + return 0; | ||
407 | + | ||
408 | + start &= qemu_host_page_mask; | ||
409 | + return msync((void *)start, end - start, flags); | ||
410 | +} | ||
411 | + |
darwin-user/qemu.h
0 โ 100644
1 | +#ifndef GEMU_H | ||
2 | +#define GEMU_H | ||
3 | + | ||
4 | +#include "thunk.h" | ||
5 | + | ||
6 | +#include <signal.h> | ||
7 | +#include <string.h> | ||
8 | + | ||
9 | +#include "cpu.h" | ||
10 | + | ||
11 | +#include "gdbstub.h" | ||
12 | + | ||
13 | +typedef siginfo_t target_siginfo_t; | ||
14 | +#define target_sigaction sigaction | ||
15 | +#ifdef TARGET_I386 | ||
16 | +struct target_pt_regs { | ||
17 | + long ebx; | ||
18 | + long ecx; | ||
19 | + long edx; | ||
20 | + long esi; | ||
21 | + long edi; | ||
22 | + long ebp; | ||
23 | + long eax; | ||
24 | + int xds; | ||
25 | + int xes; | ||
26 | + long orig_eax; | ||
27 | + long eip; | ||
28 | + int xcs; | ||
29 | + long eflags; | ||
30 | + long esp; | ||
31 | + int xss; | ||
32 | +}; | ||
33 | +struct target_sigcontext { | ||
34 | + int sc_onstack; | ||
35 | + int sc_mask; | ||
36 | + int sc_eax; | ||
37 | + int sc_ebx; | ||
38 | + int sc_ecx; | ||
39 | + int sc_edx; | ||
40 | + int sc_edi; | ||
41 | + int sc_esi; | ||
42 | + int sc_ebp; | ||
43 | + int sc_esp; | ||
44 | + int sc_ss; | ||
45 | + int sc_eflags; | ||
46 | + int sc_eip; | ||
47 | + int sc_cs; | ||
48 | + int sc_ds; | ||
49 | + int sc_es; | ||
50 | + int sc_fs; | ||
51 | + int sc_gs; | ||
52 | +}; | ||
53 | + | ||
54 | +#define __USER_CS (0x17) | ||
55 | +#define __USER_DS (0x1F) | ||
56 | + | ||
57 | +#elif defined(TARGET_PPC) | ||
58 | +struct target_pt_regs { | ||
59 | + unsigned long gpr[32]; | ||
60 | + unsigned long nip; | ||
61 | + unsigned long msr; | ||
62 | + unsigned long orig_gpr3; /* Used for restarting system calls */ | ||
63 | + unsigned long ctr; | ||
64 | + unsigned long link; | ||
65 | + unsigned long xer; | ||
66 | + unsigned long ccr; | ||
67 | + unsigned long mq; /* 601 only (not used at present) */ | ||
68 | + /* Used on APUS to hold IPL value. */ | ||
69 | + unsigned long trap; /* Reason for being here */ | ||
70 | + unsigned long dar; /* Fault registers */ | ||
71 | + unsigned long dsisr; | ||
72 | + unsigned long result; /* Result of a system call */ | ||
73 | +}; | ||
74 | + | ||
75 | +struct target_sigcontext { | ||
76 | + int sc_onstack; /* sigstack state to restore */ | ||
77 | + int sc_mask; /* signal mask to restore */ | ||
78 | + int sc_ir; /* pc */ | ||
79 | + int sc_psw; /* processor status word */ | ||
80 | + int sc_sp; /* stack pointer if sc_regs == NULL */ | ||
81 | + void *sc_regs; /* (kernel private) saved state */ | ||
82 | +}; | ||
83 | + | ||
84 | +#endif | ||
85 | + | ||
86 | +typedef struct TaskState { | ||
87 | + struct TaskState *next; | ||
88 | + int used; /* non zero if used */ | ||
89 | + uint8_t stack[0]; | ||
90 | +} __attribute__((aligned(16))) TaskState; | ||
91 | + | ||
92 | +void syscall_init(void); | ||
93 | +long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
94 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); | ||
95 | +long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
96 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); | ||
97 | +long do_unix_syscall(void *cpu_env, int num); | ||
98 | +int do_sigaction(int sig, const struct sigaction *act, | ||
99 | + struct sigaction *oact); | ||
100 | +int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss); | ||
101 | + | ||
102 | +void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); | ||
103 | +void qerror(const char *fmt, ...); | ||
104 | + | ||
105 | +void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags); | ||
106 | + | ||
107 | +extern CPUState *global_env; | ||
108 | +void cpu_loop(CPUState *env); | ||
109 | +void init_paths(const char *prefix); | ||
110 | +const char *path(const char *pathname); | ||
111 | + | ||
112 | +extern int loglevel; | ||
113 | +extern FILE *logfile; | ||
114 | + | ||
115 | +/* commpage.c */ | ||
116 | +void commpage_init(); | ||
117 | +void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
118 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); | ||
119 | + | ||
120 | +/* signal.c */ | ||
121 | +void process_pending_signals(void *cpu_env); | ||
122 | +void signal_init(void); | ||
123 | +int queue_signal(int sig, target_siginfo_t *info); | ||
124 | +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); | ||
125 | +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); | ||
126 | +long do_sigreturn(CPUState *env, int num); | ||
127 | + | ||
128 | +/* machload.c */ | ||
129 | +int mach_exec(const char * filename, char ** argv, char ** envp, | ||
130 | + struct target_pt_regs * regs); | ||
131 | + | ||
132 | +/* mmap.c */ | ||
133 | +int target_mprotect(unsigned long start, unsigned long len, int prot); | ||
134 | +long target_mmap(unsigned long start, unsigned long len, int prot, | ||
135 | + int flags, int fd, unsigned long offset); | ||
136 | +int target_munmap(unsigned long start, unsigned long len); | ||
137 | +long target_mremap(unsigned long old_addr, unsigned long old_size, | ||
138 | + unsigned long new_size, unsigned long flags, | ||
139 | + unsigned long new_addr); | ||
140 | +int target_msync(unsigned long start, unsigned long len, int flags); | ||
141 | + | ||
142 | +/* user access */ | ||
143 | + | ||
144 | +/* XXX: todo protect every memory access */ | ||
145 | +#define lock_user(x,y,z) (void*)(x) | ||
146 | +#define unlock_user(x,y,z) | ||
147 | + | ||
148 | +/* Mac OS X ABI arguments processing */ | ||
149 | +#ifdef TARGET_I386 | ||
150 | +static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env) | ||
151 | +{ | ||
152 | + uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i); | ||
153 | + *i+=4; | ||
154 | + return tswap32(*args); | ||
155 | +} | ||
156 | +static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env) | ||
157 | +{ | ||
158 | + uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i); | ||
159 | + *i+=8; | ||
160 | + return tswap64(*args); | ||
161 | +} | ||
162 | +#elif defined(TARGET_PPC) | ||
163 | +static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env) | ||
164 | +{ | ||
165 | + /* XXX: won't work when args goes on stack after gpr10 */ | ||
166 | + uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]); | ||
167 | + *i+=4; | ||
168 | + return tswap32(args); | ||
169 | +} | ||
170 | +static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env) | ||
171 | +{ | ||
172 | + /* XXX: won't work when args goes on stack after gpr10 */ | ||
173 | + uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]); | ||
174 | + *i+=(8 << 8) + 8; | ||
175 | + return tswap64(args); | ||
176 | +} | ||
177 | +#endif | ||
178 | + | ||
179 | +#endif |
darwin-user/signal.c
0 โ 100644
1 | +/* | ||
2 | + * Emulation of Linux signals | ||
3 | + * | ||
4 | + * Copyright (c) 2003 Fabrice Bellard | ||
5 | + * | ||
6 | + * This program is free software; you can redistribute it and/or modify | ||
7 | + * it under the terms of the GNU General Public License as published by | ||
8 | + * the Free Software Foundation; either version 2 of the License, or | ||
9 | + * (at your option) any later version. | ||
10 | + * | ||
11 | + * This program is distributed in the hope that it will be useful, | ||
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | + * GNU General Public License for more details. | ||
15 | + * | ||
16 | + * You should have received a copy of the GNU General Public License | ||
17 | + * along with this program; if not, write to the Free Software | ||
18 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | + */ | ||
20 | +#include <stdlib.h> | ||
21 | +#include <stdio.h> | ||
22 | +#include <string.h> | ||
23 | +#include <stdarg.h> | ||
24 | +#include <unistd.h> | ||
25 | +#include <signal.h> | ||
26 | +#include <errno.h> | ||
27 | +#include <sys/ucontext.h> | ||
28 | + | ||
29 | +#ifdef __ia64__ | ||
30 | +#undef uc_mcontext | ||
31 | +#undef uc_sigmask | ||
32 | +#undef uc_stack | ||
33 | +#undef uc_link | ||
34 | +#endif | ||
35 | + | ||
36 | +#include <signal.h> | ||
37 | + | ||
38 | +#include "qemu.h" | ||
39 | + | ||
40 | +#define DEBUG_SIGNAL | ||
41 | + | ||
42 | +#define MAX_SIGQUEUE_SIZE 1024 | ||
43 | + | ||
44 | +struct sigqueue { | ||
45 | + struct sigqueue *next; | ||
46 | + target_siginfo_t info; | ||
47 | +}; | ||
48 | + | ||
49 | +struct emulated_sigaction { | ||
50 | + struct target_sigaction sa; | ||
51 | + int pending; /* true if signal is pending */ | ||
52 | + struct sigqueue *first; | ||
53 | + struct sigqueue info; /* in order to always have memory for the | ||
54 | + first signal, we put it here */ | ||
55 | +}; | ||
56 | + | ||
57 | +struct sigaltstack target_sigaltstack_used = { | ||
58 | + 0, 0, SA_DISABLE | ||
59 | +}; | ||
60 | + | ||
61 | +static struct emulated_sigaction sigact_table[NSIG]; | ||
62 | +static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ | ||
63 | +static struct sigqueue *first_free; /* first free siginfo queue entry */ | ||
64 | +static int signal_pending; /* non zero if a signal may be pending */ | ||
65 | + | ||
66 | +static void host_signal_handler(int host_signum, siginfo_t *info, | ||
67 | + void *puc); | ||
68 | + | ||
69 | + | ||
70 | +static inline int host_to_target_signal(int sig) | ||
71 | +{ | ||
72 | + return sig; | ||
73 | +} | ||
74 | + | ||
75 | +static inline int target_to_host_signal(int sig) | ||
76 | +{ | ||
77 | + return sig; | ||
78 | +} | ||
79 | + | ||
80 | +/* siginfo conversion */ | ||
81 | + | ||
82 | + | ||
83 | + | ||
84 | +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) | ||
85 | +{ | ||
86 | + | ||
87 | +} | ||
88 | + | ||
89 | +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) | ||
90 | +{ | ||
91 | + | ||
92 | +} | ||
93 | + | ||
94 | +void signal_init(void) | ||
95 | +{ | ||
96 | + struct sigaction act; | ||
97 | + int i; | ||
98 | + | ||
99 | + /* set all host signal handlers. ALL signals are blocked during | ||
100 | + the handlers to serialize them. */ | ||
101 | + sigfillset(&act.sa_mask); | ||
102 | + act.sa_flags = SA_SIGINFO; | ||
103 | + act.sa_sigaction = host_signal_handler; | ||
104 | + for(i = 1; i < NSIG; i++) { | ||
105 | + sigaction(i, &act, NULL); | ||
106 | + } | ||
107 | + | ||
108 | + memset(sigact_table, 0, sizeof(sigact_table)); | ||
109 | + | ||
110 | + first_free = &sigqueue_table[0]; | ||
111 | + for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) | ||
112 | + sigqueue_table[i].next = &sigqueue_table[i + 1]; | ||
113 | + sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; | ||
114 | +} | ||
115 | + | ||
116 | +/* signal queue handling */ | ||
117 | + | ||
118 | +static inline struct sigqueue *alloc_sigqueue(void) | ||
119 | +{ | ||
120 | + struct sigqueue *q = first_free; | ||
121 | + if (!q) | ||
122 | + return NULL; | ||
123 | + first_free = q->next; | ||
124 | + return q; | ||
125 | +} | ||
126 | + | ||
127 | +static inline void free_sigqueue(struct sigqueue *q) | ||
128 | +{ | ||
129 | + q->next = first_free; | ||
130 | + first_free = q; | ||
131 | +} | ||
132 | + | ||
133 | +/* abort execution with signal */ | ||
134 | +void __attribute((noreturn)) force_sig(int sig) | ||
135 | +{ | ||
136 | + int host_sig; | ||
137 | + host_sig = target_to_host_signal(sig); | ||
138 | + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", | ||
139 | + sig, strsignal(host_sig)); | ||
140 | + _exit(-host_sig); | ||
141 | +} | ||
142 | + | ||
143 | +/* queue a signal so that it will be send to the virtual CPU as soon | ||
144 | + as possible */ | ||
145 | +int queue_signal(int sig, target_siginfo_t *info) | ||
146 | +{ | ||
147 | + struct emulated_sigaction *k; | ||
148 | + struct sigqueue *q, **pq; | ||
149 | + target_ulong handler; | ||
150 | + | ||
151 | +#if defined(DEBUG_SIGNAL) | ||
152 | + fprintf(stderr, "queue_signal: sig=%d\n", | ||
153 | + sig); | ||
154 | +#endif | ||
155 | + k = &sigact_table[sig - 1]; | ||
156 | + handler = (target_ulong)k->sa.sa_handler; | ||
157 | + if (handler == SIG_DFL) { | ||
158 | + /* default handler : ignore some signal. The other are fatal */ | ||
159 | + if (sig != SIGCHLD && | ||
160 | + sig != SIGURG && | ||
161 | + sig != SIGWINCH) { | ||
162 | + force_sig(sig); | ||
163 | + } else { | ||
164 | + return 0; /* indicate ignored */ | ||
165 | + } | ||
166 | + } else if (handler == host_to_target_signal(SIG_IGN)) { | ||
167 | + /* ignore signal */ | ||
168 | + return 0; | ||
169 | + } else if (handler == host_to_target_signal(SIG_ERR)) { | ||
170 | + force_sig(sig); | ||
171 | + } else { | ||
172 | + pq = &k->first; | ||
173 | + if (!k->pending) { | ||
174 | + /* first signal */ | ||
175 | + q = &k->info; | ||
176 | + } else { | ||
177 | + q = alloc_sigqueue(); | ||
178 | + if (!q) | ||
179 | + return -EAGAIN; | ||
180 | + while (*pq != NULL) | ||
181 | + pq = &(*pq)->next; | ||
182 | + } | ||
183 | + *pq = q; | ||
184 | + q->info = *info; | ||
185 | + q->next = NULL; | ||
186 | + k->pending = 1; | ||
187 | + /* signal that a new signal is pending */ | ||
188 | + signal_pending = 1; | ||
189 | + return 1; /* indicates that the signal was queued */ | ||
190 | + } | ||
191 | +} | ||
192 | + | ||
193 | +static void host_signal_handler(int host_signum, siginfo_t *info, | ||
194 | + void *puc) | ||
195 | +{ | ||
196 | + int sig; | ||
197 | + target_siginfo_t tinfo; | ||
198 | + | ||
199 | + /* the CPU emulator uses some host signals to detect exceptions, | ||
200 | + we we forward to it some signals */ | ||
201 | + if (host_signum == SIGSEGV || host_signum == SIGBUS | ||
202 | +#if defined(TARGET_I386) && defined(USE_CODE_COPY) | ||
203 | + || host_signum == SIGFPE | ||
204 | +#endif | ||
205 | + ) { | ||
206 | + if (cpu_signal_handler(host_signum, (void*)info, puc)) | ||
207 | + return; | ||
208 | + } | ||
209 | + | ||
210 | + /* get target signal number */ | ||
211 | + sig = host_to_target_signal(host_signum); | ||
212 | + if (sig < 1 || sig > NSIG) | ||
213 | + return; | ||
214 | + | ||
215 | +#if defined(DEBUG_SIGNAL) | ||
216 | + fprintf(stderr, "qemu: got signal %d\n", sig); | ||
217 | +#endif | ||
218 | + if (queue_signal(sig, &tinfo) == 1) { | ||
219 | + /* interrupt the virtual CPU as soon as possible */ | ||
220 | + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); | ||
221 | + } | ||
222 | +} | ||
223 | + | ||
224 | +int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss) | ||
225 | +{ | ||
226 | + /* XXX: test errors */ | ||
227 | + if(oss) | ||
228 | + { | ||
229 | + oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp); | ||
230 | + oss->ss_size = tswap32(target_sigaltstack_used.ss_size); | ||
231 | + oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags); | ||
232 | + } | ||
233 | + if(ss) | ||
234 | + { | ||
235 | + target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp); | ||
236 | + target_sigaltstack_used.ss_size = tswap32(ss->ss_size); | ||
237 | + target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags); | ||
238 | + } | ||
239 | + return 0; | ||
240 | +} | ||
241 | + | ||
242 | +int do_sigaction(int sig, const struct sigaction *act, | ||
243 | + struct sigaction *oact) | ||
244 | +{ | ||
245 | + struct emulated_sigaction *k; | ||
246 | + struct sigaction act1; | ||
247 | + int host_sig; | ||
248 | + | ||
249 | + if (sig < 1 || sig > NSIG) | ||
250 | + return -EINVAL; | ||
251 | + | ||
252 | + k = &sigact_table[sig - 1]; | ||
253 | +#if defined(DEBUG_SIGNAL) | ||
254 | + fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n", | ||
255 | + sig, (int)act, (int)oact); | ||
256 | +#endif | ||
257 | + if (oact) { | ||
258 | +#if defined(DEBUG_SIGNAL) | ||
259 | + fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n", | ||
260 | + sig, (int)act, (int)oact); | ||
261 | +#endif | ||
262 | + | ||
263 | + oact->sa_handler = tswapl(k->sa.sa_handler); | ||
264 | + oact->sa_flags = tswapl(k->sa.sa_flags); | ||
265 | + oact->sa_mask = tswapl(k->sa.sa_mask); | ||
266 | + } | ||
267 | + if (act) { | ||
268 | +#if defined(DEBUG_SIGNAL) | ||
269 | + fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n", | ||
270 | + act->sa_handler, act->sa_flags, act->sa_mask); | ||
271 | +#endif | ||
272 | + | ||
273 | + k->sa.sa_handler = tswapl(act->sa_handler); | ||
274 | + k->sa.sa_flags = tswapl(act->sa_flags); | ||
275 | + k->sa.sa_mask = tswapl(act->sa_mask); | ||
276 | + /* we update the host signal state */ | ||
277 | + host_sig = target_to_host_signal(sig); | ||
278 | + if (host_sig != SIGSEGV && host_sig != SIGBUS) { | ||
279 | +#if defined(DEBUG_SIGNAL) | ||
280 | + fprintf(stderr, "sigaction handler going to call sigaction\n", | ||
281 | + act->sa_handler, act->sa_flags, act->sa_mask); | ||
282 | +#endif | ||
283 | + | ||
284 | + sigfillset(&act1.sa_mask); | ||
285 | + act1.sa_flags = SA_SIGINFO; | ||
286 | + if (k->sa.sa_flags & SA_RESTART) | ||
287 | + act1.sa_flags |= SA_RESTART; | ||
288 | + /* NOTE: it is important to update the host kernel signal | ||
289 | + ignore state to avoid getting unexpected interrupted | ||
290 | + syscalls */ | ||
291 | + if (k->sa.sa_handler == SIG_IGN) { | ||
292 | + act1.sa_sigaction = (void *)SIG_IGN; | ||
293 | + } else if (k->sa.sa_handler == SIG_DFL) { | ||
294 | + act1.sa_sigaction = (void *)SIG_DFL; | ||
295 | + } else { | ||
296 | + act1.sa_sigaction = host_signal_handler; | ||
297 | + } | ||
298 | + sigaction(host_sig, &act1, NULL); | ||
299 | + } | ||
300 | + } | ||
301 | + return 0; | ||
302 | +} | ||
303 | + | ||
304 | + | ||
305 | +#ifdef TARGET_I386 | ||
306 | + | ||
307 | +static inline void * | ||
308 | +get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) | ||
309 | +{ | ||
310 | + /* XXX Fix that */ | ||
311 | + if(target_sigaltstack_used.ss_flags & SA_DISABLE) | ||
312 | + { | ||
313 | + int esp; | ||
314 | + /* Default to using normal stack */ | ||
315 | + esp = env->regs[R_ESP]; | ||
316 | + | ||
317 | + return (void *)((esp - frame_size) & -8ul); | ||
318 | + } | ||
319 | + else | ||
320 | + { | ||
321 | + return target_sigaltstack_used.ss_sp; | ||
322 | + } | ||
323 | +} | ||
324 | + | ||
325 | +static void setup_frame(int sig, struct emulated_sigaction *ka, | ||
326 | + void *set, CPUState *env) | ||
327 | +{ | ||
328 | + void *frame; | ||
329 | + int i, err = 0; | ||
330 | + | ||
331 | + fprintf(stderr, "setup_frame %d\n", sig); | ||
332 | + frame = get_sigframe(ka, env, sizeof(*frame)); | ||
333 | + | ||
334 | + /* Set up registers for signal handler */ | ||
335 | + env->regs[R_ESP] = (unsigned long) frame; | ||
336 | + env->eip = (unsigned long) ka->sa.sa_handler; | ||
337 | + | ||
338 | + env->eflags &= ~TF_MASK; | ||
339 | + | ||
340 | + return; | ||
341 | + | ||
342 | +give_sigsegv: | ||
343 | + if (sig == SIGSEGV) | ||
344 | + ka->sa.sa_handler = SIG_DFL; | ||
345 | + force_sig(SIGSEGV /* , current */); | ||
346 | +} | ||
347 | + | ||
348 | +long do_sigreturn(CPUState *env, int num) | ||
349 | +{ | ||
350 | + int i = 0; | ||
351 | + struct target_sigcontext *scp = get_int_arg(&i, env); | ||
352 | + /* XXX Get current signal number */ | ||
353 | + /* XXX Adjust accordin to sc_onstack, sc_mask */ | ||
354 | + if(tswapl(scp->sc_onstack) & 0x1) | ||
355 | + target_sigaltstack_used.ss_flags |= ~SA_DISABLE; | ||
356 | + else | ||
357 | + target_sigaltstack_used.ss_flags &= SA_DISABLE; | ||
358 | + int set = tswapl(scp->sc_eax); | ||
359 | + sigprocmask(SIG_SETMASK, &set, NULL); | ||
360 | + | ||
361 | + fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx)); | ||
362 | + fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi)); | ||
363 | + fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip)); | ||
364 | + | ||
365 | + env->regs[R_EAX] = tswapl(scp->sc_eax); | ||
366 | + env->regs[R_EBX] = tswapl(scp->sc_ebx); | ||
367 | + env->regs[R_ECX] = tswapl(scp->sc_ecx); | ||
368 | + env->regs[R_EDX] = tswapl(scp->sc_edx); | ||
369 | + env->regs[R_EDI] = tswapl(scp->sc_edi); | ||
370 | + env->regs[R_ESI] = tswapl(scp->sc_esi); | ||
371 | + env->regs[R_EBP] = tswapl(scp->sc_ebp); | ||
372 | + env->regs[R_ESP] = tswapl(scp->sc_esp); | ||
373 | + env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss); | ||
374 | + env->eflags = tswapl(scp->sc_eflags); | ||
375 | + env->eip = tswapl(scp->sc_eip); | ||
376 | + env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs); | ||
377 | + env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds); | ||
378 | + env->segs[R_ES].selector = (void*)tswapl(scp->sc_es); | ||
379 | + env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs); | ||
380 | + env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs); | ||
381 | + | ||
382 | + /* Again, because our caller's caller will reset EAX */ | ||
383 | + return env->regs[R_EAX]; | ||
384 | +} | ||
385 | + | ||
386 | +#else | ||
387 | + | ||
388 | +static void setup_frame(int sig, struct emulated_sigaction *ka, | ||
389 | + void *set, CPUState *env) | ||
390 | +{ | ||
391 | + fprintf(stderr, "setup_frame: not implemented\n"); | ||
392 | +} | ||
393 | + | ||
394 | +long do_sigreturn(CPUState *env, int num) | ||
395 | +{ | ||
396 | + int i = 0; | ||
397 | + struct target_sigcontext *scp = get_int_arg(&i, env); | ||
398 | + fprintf(stderr, "do_sigreturn: not implemented\n"); | ||
399 | + return -ENOSYS; | ||
400 | +} | ||
401 | + | ||
402 | +#endif | ||
403 | + | ||
404 | +void process_pending_signals(void *cpu_env) | ||
405 | +{ | ||
406 | + struct emulated_sigaction *k; | ||
407 | + struct sigqueue *q; | ||
408 | + target_ulong handler; | ||
409 | + int sig; | ||
410 | + | ||
411 | + if (!signal_pending) | ||
412 | + return; | ||
413 | + | ||
414 | + k = sigact_table; | ||
415 | + | ||
416 | + for(sig = 1; sig <= NSIG; sig++) { | ||
417 | + if (k->pending) | ||
418 | + goto handle_signal; | ||
419 | + k++; | ||
420 | + } | ||
421 | + | ||
422 | + /* if no signal is pending, just return */ | ||
423 | + signal_pending = 0; | ||
424 | + return; | ||
425 | +handle_signal: | ||
426 | + #ifdef DEBUG_SIGNAL | ||
427 | + fprintf(stderr, "qemu: process signal %d\n", sig); | ||
428 | + #endif | ||
429 | + /* dequeue signal */ | ||
430 | + q = k->first; | ||
431 | + k->first = q->next; | ||
432 | + if (!k->first) | ||
433 | + k->pending = 0; | ||
434 | + | ||
435 | + sig = gdb_handlesig (cpu_env, sig); | ||
436 | + if (!sig) { | ||
437 | + fprintf (stderr, "Lost signal\n"); | ||
438 | + abort(); | ||
439 | + } | ||
440 | + | ||
441 | + handler = k->sa.sa_handler; | ||
442 | + if (handler == SIG_DFL) { | ||
443 | + /* default handler : ignore some signal. The other are fatal */ | ||
444 | + if (sig != SIGCHLD && | ||
445 | + sig != SIGURG && | ||
446 | + sig != SIGWINCH) { | ||
447 | + force_sig(sig); | ||
448 | + } | ||
449 | + } else if (handler == SIG_IGN) { | ||
450 | + /* ignore sig */ | ||
451 | + } else if (handler == SIG_ERR) { | ||
452 | + force_sig(sig); | ||
453 | + } else { | ||
454 | + | ||
455 | + setup_frame(sig, k, 0, cpu_env); | ||
456 | + if (k->sa.sa_flags & SA_RESETHAND) | ||
457 | + k->sa.sa_handler = SIG_DFL; | ||
458 | + } | ||
459 | + if (q != &k->info) | ||
460 | + free_sigqueue(q); | ||
461 | +} | ||
462 | + | ||
463 | + |
darwin-user/syscall.c
0 โ 100644
1 | +/* | ||
2 | + * Darwin syscalls | ||
3 | + * | ||
4 | + * Copyright (c) 2003 Fabrice Bellard | ||
5 | + * Copyright (c) 2006 Pierre d'Herbemont | ||
6 | + * | ||
7 | + * This program is free software; you can redistribute it and/or modify | ||
8 | + * it under the terms of the GNU General Public License as published by | ||
9 | + * the Free Software Foundation; either version 2 of the License, or | ||
10 | + * (at your option) any later version. | ||
11 | + * | ||
12 | + * This program is distributed in the hope that it will be useful, | ||
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | + * GNU General Public License for more details. | ||
16 | + * | ||
17 | + * You should have received a copy of the GNU General Public License | ||
18 | + * along with this program; if not, write to the Free Software | ||
19 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | + */ | ||
21 | +#include <fcntl.h> | ||
22 | +#include <stdio.h> | ||
23 | +#include <stdlib.h> | ||
24 | +#include <errno.h> | ||
25 | + | ||
26 | +#include <mach/message.h> | ||
27 | +#include <mach/mach.h> | ||
28 | +#include <mach/mach_time.h> | ||
29 | + | ||
30 | +#include <pthread.h> | ||
31 | +#include <dirent.h> | ||
32 | + | ||
33 | +#include <sys/stat.h> | ||
34 | +#include <sys/syscall.h> | ||
35 | +#include <sys/sysctl.h> | ||
36 | +#include <sys/types.h> | ||
37 | +#include <unistd.h> | ||
38 | +#include <sys/ioctl.h> | ||
39 | +#include <sys/mman.h> | ||
40 | +#include <sys/types.h> | ||
41 | +#include <sys/dirent.h> | ||
42 | +#include <sys/uio.h> | ||
43 | +#include <sys/termios.h> | ||
44 | +#include <sys/ptrace.h> | ||
45 | +#include <net/if.h> | ||
46 | + | ||
47 | +#include <sys/param.h> | ||
48 | +#include <sys/mount.h> | ||
49 | + | ||
50 | +#include <sys/attr.h> | ||
51 | + | ||
52 | +#include <mach/ndr.h> | ||
53 | +#include <mach/mig_errors.h> | ||
54 | + | ||
55 | +#include "qemu.h" | ||
56 | + | ||
57 | +//#define DEBUG_SYSCALL | ||
58 | + | ||
59 | +#ifdef DEBUG_SYSCALL | ||
60 | +# define DEBUG_FORCE_ENABLE_LOCAL() int __DEBUG_qemu_user_force_enable = 1 | ||
61 | +# define DEBUG_BEGIN_ENABLE __DEBUG_qemu_user_force_enable = 1; | ||
62 | +# define DEBUG_END_ENABLE __DEBUG_qemu_user_force_enable = 0; | ||
63 | + | ||
64 | +# define DEBUG_DISABLE_ALL() static int __DEBUG_qemu_user_force_enable = 0 | ||
65 | +# define DEBUG_ENABLE_ALL() static int __DEBUG_qemu_user_force_enable = 1 | ||
66 | + DEBUG_ENABLE_ALL(); | ||
67 | + | ||
68 | +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); \ | ||
69 | + if(__DEBUG_qemu_user_force_enable) fprintf(stderr, __VA_ARGS__); \ | ||
70 | + } while(0) | ||
71 | +#else | ||
72 | +# define DEBUG_FORCE_ENABLE_LOCAL() | ||
73 | +# define DEBUG_BEGIN_ENABLE | ||
74 | +# define DEBUG_END_ENABLE | ||
75 | + | ||
76 | +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) | ||
77 | +#endif | ||
78 | + | ||
79 | +enum { | ||
80 | + bswap_out = 0, | ||
81 | + bswap_in = 1 | ||
82 | +}; | ||
83 | + | ||
84 | +extern const char *interp_prefix; | ||
85 | + | ||
86 | +static inline long get_errno(long ret) | ||
87 | +{ | ||
88 | + if (ret == -1) | ||
89 | + return -errno; | ||
90 | + else | ||
91 | + return ret; | ||
92 | +} | ||
93 | + | ||
94 | +static inline int is_error(long ret) | ||
95 | +{ | ||
96 | + return (unsigned long)ret >= (unsigned long)(-4096); | ||
97 | +} | ||
98 | + | ||
99 | +/* ------------------------------------------------------------ | ||
100 | + Mach syscall handling | ||
101 | +*/ | ||
102 | + | ||
103 | +void static inline print_description_msg_header(mach_msg_header_t *hdr) | ||
104 | +{ | ||
105 | + char *name = NULL; | ||
106 | + int i; | ||
107 | + struct { int number; char *name; } msg_name[] = | ||
108 | + { | ||
109 | + /* see http://fxr.watson.org/fxr/source/compat/mach/mach_namemap.c?v=NETBSD */ | ||
110 | + { 200, "host_info" }, | ||
111 | + { 202, "host_page_size" }, | ||
112 | + { 206, "host_get_clock_service" }, | ||
113 | + { 206, "host_get_clock_service" }, | ||
114 | + { 206, "host_get_clock_service" }, | ||
115 | + { 306, "host_get_clock_service" }, | ||
116 | + { 3204, "mach_port_allocate" }, | ||
117 | + { 3206, "mach_port_deallocate" }, | ||
118 | + { 3404, "mach_ports_lookup" }, | ||
119 | + { 3409, "mach_task_get_special_port" }, | ||
120 | + { 3414, "mach_task_get_exception_ports" }, | ||
121 | + { 3418, "mach_semaphore_create" }, | ||
122 | + { 3504, "mach_semaphore_create" }, | ||
123 | + { 3509, "mach_semaphore_create" }, | ||
124 | + { 3518, "semaphore_create" }, | ||
125 | + { 3616, "thread_policy" }, | ||
126 | + { 3801, "vm_allocate" }, | ||
127 | + { 3802, "vm_deallocate" }, | ||
128 | + { 3802, "vm_deallocate" }, | ||
129 | + { 3803, "vm_protect" }, | ||
130 | + { 3812, "vm_map" }, | ||
131 | + { 4241776, "lu_message_send_id" }, /* lookupd */ | ||
132 | + { 4241876, "lu_message_reply_id" }, /* lookupd */ | ||
133 | + }; | ||
134 | + | ||
135 | + for(i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { | ||
136 | + if(msg_name[i].number == hdr->msgh_id) | ||
137 | + { | ||
138 | + name = msg_name[i].name; | ||
139 | + break; | ||
140 | + } | ||
141 | + } | ||
142 | + if(!name) | ||
143 | + DPRINTF("unknown mach msg %d 0x%x\n", hdr->msgh_id, hdr->msgh_id); | ||
144 | + else | ||
145 | + DPRINTF("%s\n", name); | ||
146 | +#if 0 | ||
147 | + DPRINTF("Bits: %8x\n", hdr->msgh_bits); | ||
148 | + DPRINTF("Size: %8x\n", hdr->msgh_size); | ||
149 | + DPRINTF("Rmte: %8x\n", hdr->msgh_remote_port); | ||
150 | + DPRINTF("Locl: %8x\n", hdr->msgh_local_port); | ||
151 | + DPRINTF("Rsrv: %8x\n", hdr->msgh_reserved); | ||
152 | + | ||
153 | + DPRINTF("Id : %8x\n", hdr->msgh_id); | ||
154 | + | ||
155 | + NDR_record_t *ndr = (NDR_record_t *)(hdr + 1); | ||
156 | + DPRINTF("hdr = %p, sizeof(hdr) = %x, NDR = %p\n", hdr, (unsigned int)sizeof(mach_msg_header_t), ndr); | ||
157 | + DPRINTF("%d %d %d %d %d %d %d %d\n", | ||
158 | + ndr->mig_vers, ndr->if_vers, ndr->reserved1, ndr->mig_encoding, | ||
159 | + ndr->int_rep, ndr->char_rep, ndr->float_rep, ndr->reserved2); | ||
160 | +#endif | ||
161 | +} | ||
162 | + | ||
163 | +static inline void print_mach_msg_return(mach_msg_return_t ret) | ||
164 | +{ | ||
165 | + int i, found = 0; | ||
166 | +#define MACH_MSG_RET(msg) { msg, #msg } | ||
167 | + struct { int code; char *name; } msg_name[] = | ||
168 | + { | ||
169 | + /* ref: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/osfmk/man/mach_msg.html */ | ||
170 | + /* send message */ | ||
171 | + MACH_MSG_RET(MACH_SEND_MSG_TOO_SMALL), | ||
172 | + MACH_MSG_RET(MACH_SEND_NO_BUFFER), | ||
173 | + MACH_MSG_RET(MACH_SEND_INVALID_DATA), | ||
174 | + MACH_MSG_RET(MACH_SEND_INVALID_HEADER), | ||
175 | + MACH_MSG_RET(MACH_SEND_INVALID_DEST), | ||
176 | + MACH_MSG_RET(MACH_SEND_INVALID_NOTIFY), | ||
177 | + MACH_MSG_RET(MACH_SEND_INVALID_REPLY), | ||
178 | + MACH_MSG_RET(MACH_SEND_INVALID_TRAILER), | ||
179 | + MACH_MSG_RET(MACH_SEND_INVALID_MEMORY), | ||
180 | + MACH_MSG_RET(MACH_SEND_INVALID_RIGHT), | ||
181 | + MACH_MSG_RET(MACH_SEND_INVALID_TYPE), | ||
182 | + MACH_MSG_RET(MACH_SEND_INTERRUPTED), | ||
183 | + MACH_MSG_RET(MACH_SEND_TIMED_OUT), | ||
184 | + | ||
185 | + MACH_MSG_RET(MACH_RCV_BODY_ERROR), | ||
186 | + MACH_MSG_RET(MACH_RCV_HEADER_ERROR), | ||
187 | + | ||
188 | + MACH_MSG_RET(MACH_RCV_IN_SET), | ||
189 | + MACH_MSG_RET(MACH_RCV_INTERRUPTED), | ||
190 | + | ||
191 | + MACH_MSG_RET(MACH_RCV_INVALID_DATA), | ||
192 | + MACH_MSG_RET(MACH_RCV_INVALID_NAME), | ||
193 | + MACH_MSG_RET(MACH_RCV_INVALID_NOTIFY), | ||
194 | + MACH_MSG_RET(MACH_RCV_INVALID_TRAILER), | ||
195 | + MACH_MSG_RET(MACH_RCV_INVALID_TYPE), | ||
196 | + | ||
197 | + MACH_MSG_RET(MACH_RCV_PORT_CHANGED), | ||
198 | + MACH_MSG_RET(MACH_RCV_PORT_DIED), | ||
199 | + | ||
200 | + MACH_MSG_RET(MACH_RCV_SCATTER_SMALL), | ||
201 | + MACH_MSG_RET(MACH_RCV_TIMED_OUT), | ||
202 | + MACH_MSG_RET(MACH_RCV_TOO_LARGE) | ||
203 | + }; | ||
204 | +#undef MACH_MSG_RET | ||
205 | + | ||
206 | + if( ret == MACH_MSG_SUCCESS) | ||
207 | + DPRINTF("MACH_MSG_SUCCESS\n"); | ||
208 | + else | ||
209 | + { | ||
210 | + for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { | ||
211 | + if(msg_name[0].code & ret) { | ||
212 | + DPRINTF("%s ", msg_name[0].name); | ||
213 | + found = 1; | ||
214 | + } | ||
215 | + } | ||
216 | + if(!found) | ||
217 | + qerror("unknow mach message ret code %d\n", ret); | ||
218 | + else | ||
219 | + DPRINTF("\n"); | ||
220 | + } | ||
221 | +} | ||
222 | + | ||
223 | +static inline void swap_mach_msg_header(mach_msg_header_t *hdr) | ||
224 | +{ | ||
225 | + hdr->msgh_bits = tswap32(hdr->msgh_bits); | ||
226 | + hdr->msgh_size = tswap32(hdr->msgh_size); | ||
227 | + hdr->msgh_remote_port = tswap32(hdr->msgh_remote_port); | ||
228 | + hdr->msgh_local_port = tswap32(hdr->msgh_local_port); | ||
229 | + hdr->msgh_reserved = tswap32(hdr->msgh_reserved); | ||
230 | + hdr->msgh_id = tswap32(hdr->msgh_id); | ||
231 | +} | ||
232 | + | ||
233 | +struct complex_msg { | ||
234 | + mach_msg_header_t hdr; | ||
235 | + mach_msg_body_t body; | ||
236 | +}; | ||
237 | + | ||
238 | +static inline void * swap_mach_msg_body(struct complex_msg *complex_msg, int bswap) | ||
239 | +{ | ||
240 | + mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1); | ||
241 | + int i,j; | ||
242 | + void *additional_data; | ||
243 | + | ||
244 | + if(bswap == bswap_in) | ||
245 | + tswap32s(&complex_msg->body.msgh_descriptor_count); | ||
246 | + | ||
247 | + DPRINTF("body.msgh_descriptor_count %d\n", complex_msg->body.msgh_descriptor_count); | ||
248 | + | ||
249 | + for(i = 0; i < complex_msg->body.msgh_descriptor_count; i++) { | ||
250 | + switch(descr->type) | ||
251 | + { | ||
252 | + case MACH_MSG_PORT_DESCRIPTOR: | ||
253 | + tswap32s(&descr->name); | ||
254 | + descr++; | ||
255 | + break; | ||
256 | + case MACH_MSG_OOL_DESCRIPTOR: | ||
257 | + { | ||
258 | + mach_msg_ool_descriptor_t *ool = (void *)descr; | ||
259 | + tswap32s((uint32_t *)&ool->address); | ||
260 | + tswap32s(&ool->size); | ||
261 | + | ||
262 | + descr = (mach_msg_port_descriptor_t *)(ool+1); | ||
263 | + break; | ||
264 | + } | ||
265 | + case MACH_MSG_OOL_PORTS_DESCRIPTOR: | ||
266 | + { | ||
267 | + mach_msg_ool_ports_descriptor_t *ool_ports = (void *)descr; | ||
268 | + mach_port_name_t * port_names; | ||
269 | + | ||
270 | + if(bswap == bswap_in) | ||
271 | + { | ||
272 | + tswap32s((uint32_t *)&ool_ports->address); | ||
273 | + tswap32s(&ool_ports->count); | ||
274 | + } | ||
275 | + | ||
276 | + port_names = ool_ports->address; | ||
277 | + | ||
278 | + for(j = 0; j < ool_ports->count; j++) | ||
279 | + tswap32s(&port_names[j]); | ||
280 | + | ||
281 | + if(bswap == bswap_out) | ||
282 | + { | ||
283 | + tswap32s((uint32_t *)&ool_ports->address); | ||
284 | + tswap32s(&ool_ports->count); | ||
285 | + } | ||
286 | + | ||
287 | + descr = (mach_msg_port_descriptor_t *)(ool_ports+1); | ||
288 | + break; | ||
289 | + } | ||
290 | + default: qerror("unknow mach msg descriptor type %x\n", descr->type); | ||
291 | + } | ||
292 | + } | ||
293 | + if(bswap == bswap_out) | ||
294 | + tswap32s(&complex_msg->body.msgh_descriptor_count); | ||
295 | + additional_data = descr; | ||
296 | + return additional_data; | ||
297 | +} | ||
298 | + | ||
299 | +static inline uint32_t target_mach_msg_trap( | ||
300 | + mach_msg_header_t *hdr, uint32_t options, uint32_t send_size, | ||
301 | + uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify ) | ||
302 | +{ | ||
303 | + extern int mach_msg_trap(mach_msg_header_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); | ||
304 | + mach_msg_audit_trailer_t *trailer; | ||
305 | + mach_msg_id_t msg_id; | ||
306 | + uint32_t ret = 0; | ||
307 | + char *additional_data; | ||
308 | + int i; | ||
309 | + | ||
310 | + swap_mach_msg_header(hdr); | ||
311 | + | ||
312 | + print_description_msg_header(hdr); | ||
313 | + | ||
314 | + msg_id = hdr->msgh_id; | ||
315 | + | ||
316 | + if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) | ||
317 | + additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_in); | ||
318 | + else | ||
319 | + additional_data = (void*)(hdr+1); | ||
320 | + | ||
321 | + ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify); | ||
322 | + | ||
323 | + print_mach_msg_return(ret); | ||
324 | + | ||
325 | + if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) | ||
326 | + additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_out); | ||
327 | + else | ||
328 | + additional_data = (void*)(hdr+1); | ||
329 | + | ||
330 | + if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) ) | ||
331 | + { | ||
332 | + /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should | ||
333 | + probably always bswap it */ | ||
334 | + /* warning: according to Mac OS X Internals (the book) msg_size might be expressed in | ||
335 | + natural_t units but according to xnu/osfmk/mach/message.h: "The size of | ||
336 | + the message must be specified in bytes" */ | ||
337 | + trailer = (mach_msg_audit_trailer_t *)((uint8_t *)hdr + hdr->msgh_size); | ||
338 | + /* XXX: Should probably do that based on the option asked by the sender, but dealing | ||
339 | + with kernel answer seems more sound */ | ||
340 | + switch(trailer->msgh_trailer_size) | ||
341 | + { | ||
342 | + case sizeof(mach_msg_audit_trailer_t): | ||
343 | + for(i = 0; i < 8; i++) | ||
344 | + tswap32s(&trailer->msgh_audit.val[i]); | ||
345 | + /* Fall in mach_msg_security_trailer_t case */ | ||
346 | + case sizeof(mach_msg_security_trailer_t): | ||
347 | + tswap32s(&trailer->msgh_sender.val[0]); | ||
348 | + tswap32s(&trailer->msgh_sender.val[1]); | ||
349 | + /* Fall in mach_msg_seqno_trailer_t case */ | ||
350 | + case sizeof(mach_msg_seqno_trailer_t): | ||
351 | + tswap32s(&trailer->msgh_seqno); | ||
352 | + /* Fall in mach_msg_trailer_t case */ | ||
353 | + case sizeof(mach_msg_trailer_t): | ||
354 | + tswap32s(&trailer->msgh_trailer_type); | ||
355 | + tswap32s(&trailer->msgh_trailer_size); | ||
356 | + break; | ||
357 | + case 0: | ||
358 | + /* Safer not to byteswap, but probably wrong */ | ||
359 | + break; | ||
360 | + default: | ||
361 | + qerror("unknow trailer type given its size %d\n", trailer->msgh_trailer_size); | ||
362 | + break; | ||
363 | + } | ||
364 | + } | ||
365 | + | ||
366 | + /* Special message handling */ | ||
367 | + switch (msg_id) { | ||
368 | + case 200: /* host_info */ | ||
369 | + { | ||
370 | + mig_reply_error_t *err = (mig_reply_error_t *)hdr; | ||
371 | + struct { | ||
372 | + uint32_t unknow1; | ||
373 | + uint32_t maxcpu; | ||
374 | + uint32_t numcpu; | ||
375 | + uint32_t memsize; | ||
376 | + uint32_t cpu_type; | ||
377 | + uint32_t cpu_subtype; | ||
378 | + } *data = (void *)(err+1); | ||
379 | + | ||
380 | + DPRINTF("maxcpu = 0x%x\n", data->maxcpu); | ||
381 | + DPRINTF("numcpu = 0x%x\n", data->maxcpu); | ||
382 | + DPRINTF("memsize = 0x%x\n", data->memsize); | ||
383 | + | ||
384 | +#if defined(TARGET_I386) | ||
385 | + data->cpu_type = CPU_TYPE_I386; | ||
386 | + DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type); | ||
387 | +#elif defined(TARGET_PPC) | ||
388 | + data->cpu_type = CPU_TYPE_POWERPC; | ||
389 | + DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type); | ||
390 | +#else | ||
391 | +# error target not supported | ||
392 | +#endif | ||
393 | + | ||
394 | +#if defined(TARGET_I386) | ||
395 | + data->cpu_subtype = CPU_SUBTYPE_PENT; | ||
396 | + DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype); | ||
397 | +#elif defined(TARGET_PPC) | ||
398 | + data->cpu_subtype = CPU_SUBTYPE_POWERPC_750; | ||
399 | + DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype); | ||
400 | +#else | ||
401 | +# error target not supported | ||
402 | +#endif | ||
403 | + break; | ||
404 | + } | ||
405 | + case 202: /* host_page_size */ | ||
406 | + { | ||
407 | + mig_reply_error_t *err = (mig_reply_error_t *)hdr; | ||
408 | + uint32_t *pagesize = (uint32_t *)(err+1); | ||
409 | + | ||
410 | + DPRINTF("pagesize = %d\n", *pagesize); | ||
411 | + break; | ||
412 | + } | ||
413 | + default: break; | ||
414 | + } | ||
415 | + | ||
416 | + swap_mach_msg_header(hdr); | ||
417 | + | ||
418 | + return ret; | ||
419 | +} | ||
420 | + | ||
421 | +long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
422 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, | ||
423 | + uint32_t arg8) | ||
424 | +{ | ||
425 | + extern uint32_t mach_reply_port(); | ||
426 | + | ||
427 | + long ret = 0; | ||
428 | + | ||
429 | + arg1 = tswap32(arg1); | ||
430 | + arg2 = tswap32(arg2); | ||
431 | + arg3 = tswap32(arg3); | ||
432 | + arg4 = tswap32(arg4); | ||
433 | + arg5 = tswap32(arg5); | ||
434 | + arg6 = tswap32(arg6); | ||
435 | + arg7 = tswap32(arg7); | ||
436 | + arg8 = tswap32(arg8); | ||
437 | + | ||
438 | + DPRINTF("mach syscall %d : " , num); | ||
439 | + | ||
440 | + switch(num) { | ||
441 | + /* see xnu/osfmk/mach/syscall_sw.h */ | ||
442 | + case -26: | ||
443 | + DPRINTF("mach_reply_port()\n"); | ||
444 | + ret = mach_reply_port(); | ||
445 | + break; | ||
446 | + case -27: | ||
447 | + DPRINTF("mach_thread_self()\n"); | ||
448 | + ret = mach_thread_self(); | ||
449 | + break; | ||
450 | + case -28: | ||
451 | + DPRINTF("mach_task_self()\n"); | ||
452 | + ret = mach_task_self(); | ||
453 | + break; | ||
454 | + case -29: | ||
455 | + DPRINTF("mach_host_self()\n"); | ||
456 | + ret = mach_host_self(); | ||
457 | + break; | ||
458 | + case -31: | ||
459 | + DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | ||
460 | + arg1, arg2, arg3, arg4, arg5, arg6, arg7); | ||
461 | + | ||
462 | + ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7); | ||
463 | + | ||
464 | + break; | ||
465 | + case -36: | ||
466 | + DPRINTF("semaphore_wait_trap(0x%x)\n", arg1); | ||
467 | + extern int semaphore_wait_trap(int); // XXX: is there any header for that? | ||
468 | + ret = semaphore_wait_trap(arg1); | ||
469 | + break; | ||
470 | + case -43: | ||
471 | + DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | ||
472 | + arg1, arg2, arg3, arg4, arg5); | ||
473 | + ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5); | ||
474 | + tswap32s((uint32_t*)arg3); | ||
475 | + break; | ||
476 | + case -89: | ||
477 | + DPRINTF("mach_timebase_info(0x%x)\n", arg1); | ||
478 | + struct mach_timebase_info info; | ||
479 | + ret = mach_timebase_info(&info); | ||
480 | + if(!is_error(ret)) | ||
481 | + { | ||
482 | + struct mach_timebase_info *outInfo = (void*)arg1; | ||
483 | + outInfo->numer = tswap32(info.numer); | ||
484 | + outInfo->denom = tswap32(info.denom); | ||
485 | + } | ||
486 | + break; | ||
487 | + case -90: | ||
488 | + DPRINTF("mach_wait_until()\n"); | ||
489 | + extern int mach_wait_until(uint64_t); // XXX: is there any header for that? | ||
490 | + ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1); | ||
491 | + break; | ||
492 | + case -91: | ||
493 | + DPRINTF("mk_timer_create()\n"); | ||
494 | + extern int mk_timer_create(); // XXX: is there any header for that? | ||
495 | + ret = mk_timer_create(); | ||
496 | + break; | ||
497 | + case -92: | ||
498 | + DPRINTF("mk_timer_destroy()\n"); | ||
499 | + extern int mk_timer_destroy(int); // XXX: is there any header for that? | ||
500 | + ret = mk_timer_destroy(arg1); | ||
501 | + break; | ||
502 | + case -93: | ||
503 | + DPRINTF("mk_timer_create()\n"); | ||
504 | + extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that? | ||
505 | + ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2); | ||
506 | + break; | ||
507 | + case -94: | ||
508 | + DPRINTF("mk_timer_cancel()\n"); | ||
509 | + extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that? | ||
510 | + ret = mk_timer_cancel(arg1, (uint64_t *)arg2); | ||
511 | + if((!is_error(ret)) && arg2) | ||
512 | + tswap64s((uint64_t *)arg2); | ||
513 | + break; | ||
514 | + default: | ||
515 | + gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num); | ||
516 | + gdb_handlesig (cpu_env, SIGTRAP); | ||
517 | + exit(0); | ||
518 | + break; | ||
519 | + } | ||
520 | + return ret; | ||
521 | +} | ||
522 | + | ||
523 | +/* ------------------------------------------------------------ | ||
524 | + thread type syscall handling | ||
525 | +*/ | ||
526 | +long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, | ||
527 | + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, | ||
528 | + uint32_t arg8) | ||
529 | +{ | ||
530 | + extern uint32_t cthread_set_self(uint32_t); | ||
531 | + extern uint32_t processor_facilities_used(); | ||
532 | + long ret = 0; | ||
533 | + | ||
534 | + arg1 = tswap32(arg1); | ||
535 | + arg2 = tswap32(arg2); | ||
536 | + arg3 = tswap32(arg3); | ||
537 | + arg4 = tswap32(arg4); | ||
538 | + arg5 = tswap32(arg5); | ||
539 | + arg6 = tswap32(arg6); | ||
540 | + arg7 = tswap32(arg7); | ||
541 | + arg8 = tswap32(arg8); | ||
542 | + | ||
543 | + DPRINTF("thread syscall %d : " , num); | ||
544 | + | ||
545 | + switch(num) { | ||
546 | +#ifdef TARGET_I386 | ||
547 | + case 0x3: | ||
548 | +#endif | ||
549 | + case 0x7FF1: /* cthread_set_self */ | ||
550 | + DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1); | ||
551 | + ret = cthread_set_self(arg1); | ||
552 | +#ifdef TARGET_I386 | ||
553 | + /* we need to update the LDT with the address of the thread */ | ||
554 | + write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1, | ||
555 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | | ||
556 | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); | ||
557 | + /* New i386 convention, %gs should be set to our this LDT entry */ | ||
558 | + cpu_x86_load_seg(cpu_env, R_GS, 0x27); | ||
559 | + /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/ | ||
560 | + ret = 0x27; | ||
561 | +#endif | ||
562 | + break; | ||
563 | + case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */ | ||
564 | + DPRINTF("pthread_self()\n"); | ||
565 | + ret = (uint32_t)pthread_self(); | ||
566 | + break; | ||
567 | + case 0x7FF3: | ||
568 | + DPRINTF("processor_facilities_used()\n"); | ||
569 | +#ifdef __i386__ | ||
570 | + qerror("processor_facilities_used: not implemented!\n"); | ||
571 | +#else | ||
572 | + ret = (uint32_t)processor_facilities_used(); | ||
573 | +#endif | ||
574 | + break; | ||
575 | + default: | ||
576 | + gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num); | ||
577 | + gdb_handlesig (cpu_env, SIGTRAP); | ||
578 | + exit(0); | ||
579 | + break; | ||
580 | + } | ||
581 | + return ret; | ||
582 | +} | ||
583 | + | ||
584 | +/* ------------------------------------------------------------ | ||
585 | + ioctl handling | ||
586 | +*/ | ||
587 | +static inline void byteswap_termios(struct termios *t) | ||
588 | +{ | ||
589 | + tswap32s((uint32_t*)&t->c_iflag); | ||
590 | + tswap32s((uint32_t*)&t->c_oflag); | ||
591 | + tswap32s((uint32_t*)&t->c_cflag); | ||
592 | + tswap32s((uint32_t*)&t->c_lflag); | ||
593 | + /* 20 (char) bytes then */ | ||
594 | + tswap32s((uint32_t*)&t->c_ispeed); | ||
595 | + tswap32s((uint32_t*)&t->c_ospeed); | ||
596 | +} | ||
597 | + | ||
598 | +static inline void byteswap_winsize(struct winsize *w) | ||
599 | +{ | ||
600 | + tswap16s(&w->ws_row); | ||
601 | + tswap16s(&w->ws_col); | ||
602 | + tswap16s(&w->ws_xpixel); | ||
603 | + tswap16s(&w->ws_ypixel); | ||
604 | +} | ||
605 | + | ||
606 | +#define STRUCT(name, list...) STRUCT_ ## name, | ||
607 | +#define STRUCT_SPECIAL(name) STRUCT_ ## name, | ||
608 | +enum { | ||
609 | +#include "ioctls_types.h" | ||
610 | +}; | ||
611 | +#undef STRUCT | ||
612 | +#undef STRUCT_SPECIAL | ||
613 | + | ||
614 | +#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; | ||
615 | +#define STRUCT_SPECIAL(name) | ||
616 | +#include "ioctls_types.h" | ||
617 | +#undef STRUCT | ||
618 | +#undef STRUCT_SPECIAL | ||
619 | + | ||
620 | +typedef struct IOCTLEntry { | ||
621 | + unsigned int target_cmd; | ||
622 | + unsigned int host_cmd; | ||
623 | + const char *name; | ||
624 | + int access; | ||
625 | + const argtype arg_type[5]; | ||
626 | +} IOCTLEntry; | ||
627 | + | ||
628 | +#define IOC_R 0x0001 | ||
629 | +#define IOC_W 0x0002 | ||
630 | +#define IOC_RW (IOC_R | IOC_W) | ||
631 | + | ||
632 | +#define MAX_STRUCT_SIZE 4096 | ||
633 | + | ||
634 | +IOCTLEntry ioctl_entries[] = { | ||
635 | +#define IOCTL(cmd, access, types...) \ | ||
636 | + { cmd, cmd, #cmd, access, { types } }, | ||
637 | +#include "ioctls.h" | ||
638 | + { 0, 0, }, | ||
639 | +}; | ||
640 | + | ||
641 | +/* ??? Implement proper locking for ioctls. */ | ||
642 | +static long do_ioctl(long fd, long cmd, long arg) | ||
643 | +{ | ||
644 | + const IOCTLEntry *ie; | ||
645 | + const argtype *arg_type; | ||
646 | + int ret; | ||
647 | + uint8_t buf_temp[MAX_STRUCT_SIZE]; | ||
648 | + int target_size; | ||
649 | + void *argptr; | ||
650 | + | ||
651 | + ie = ioctl_entries; | ||
652 | + for(;;) { | ||
653 | + if (ie->target_cmd == 0) { | ||
654 | + gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); | ||
655 | + return -ENOSYS; | ||
656 | + } | ||
657 | + if (ie->target_cmd == cmd) | ||
658 | + break; | ||
659 | + ie++; | ||
660 | + } | ||
661 | + arg_type = ie->arg_type; | ||
662 | +#if defined(DEBUG) | ||
663 | + gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); | ||
664 | +#endif | ||
665 | + switch(arg_type[0]) { | ||
666 | + case TYPE_NULL: | ||
667 | + /* no argument */ | ||
668 | + ret = get_errno(ioctl(fd, ie->host_cmd)); | ||
669 | + break; | ||
670 | + case TYPE_PTRVOID: | ||
671 | + case TYPE_INT: | ||
672 | + /* int argment */ | ||
673 | + ret = get_errno(ioctl(fd, ie->host_cmd, arg)); | ||
674 | + break; | ||
675 | + case TYPE_PTR: | ||
676 | + arg_type++; | ||
677 | + target_size = thunk_type_size(arg_type, 0); | ||
678 | + switch(ie->access) { | ||
679 | + case IOC_R: | ||
680 | + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); | ||
681 | + if (!is_error(ret)) { | ||
682 | + argptr = lock_user(arg, target_size, 0); | ||
683 | + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); | ||
684 | + unlock_user(argptr, arg, target_size); | ||
685 | + } | ||
686 | + break; | ||
687 | + case IOC_W: | ||
688 | + argptr = lock_user(arg, target_size, 1); | ||
689 | + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); | ||
690 | + unlock_user(argptr, arg, 0); | ||
691 | + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); | ||
692 | + break; | ||
693 | + default: | ||
694 | + case IOC_RW: | ||
695 | + argptr = lock_user(arg, target_size, 1); | ||
696 | + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); | ||
697 | + unlock_user(argptr, arg, 0); | ||
698 | + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); | ||
699 | + if (!is_error(ret)) { | ||
700 | + argptr = lock_user(arg, target_size, 0); | ||
701 | + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); | ||
702 | + unlock_user(argptr, arg, target_size); | ||
703 | + } | ||
704 | + break; | ||
705 | + } | ||
706 | + break; | ||
707 | + default: | ||
708 | + gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); | ||
709 | + ret = -ENOSYS; | ||
710 | + break; | ||
711 | + } | ||
712 | + return ret; | ||
713 | +} | ||
714 | + | ||
715 | +/* ------------------------------------------------------------ | ||
716 | + Unix syscall handling | ||
717 | +*/ | ||
718 | + | ||
719 | +static inline void byteswap_attrlist(struct attrlist *a) | ||
720 | +{ | ||
721 | + tswap16s(&a->bitmapcount); | ||
722 | + tswap16s(&a->reserved); | ||
723 | + tswap32s(&a->commonattr); | ||
724 | + tswap32s(&a->volattr); | ||
725 | + tswap32s(&a->dirattr); | ||
726 | + tswap32s(&a->fileattr); | ||
727 | + tswap32s(&a->forkattr); | ||
728 | +} | ||
729 | + | ||
730 | +struct attrbuf_header { | ||
731 | + unsigned long length; | ||
732 | +}; | ||
733 | + | ||
734 | +static inline void byteswap_attrbuf(struct attrbuf_header *attrbuf, struct attrlist *attrlist) | ||
735 | +{ | ||
736 | + DPRINTF("attrBuf.lenght %lx\n", attrbuf->length); | ||
737 | +} | ||
738 | + | ||
739 | +static inline void byteswap_statfs(struct statfs *s) | ||
740 | +{ | ||
741 | + tswap16s((uint16_t*)&s->f_otype); | ||
742 | + tswap16s((uint16_t*)&s->f_oflags); | ||
743 | + tswap32s((uint32_t*)&s->f_bsize); | ||
744 | + tswap32s((uint32_t*)&s->f_iosize); | ||
745 | + tswap32s((uint32_t*)&s->f_blocks); | ||
746 | + tswap32s((uint32_t*)&s->f_bfree); | ||
747 | + tswap32s((uint32_t*)&s->f_bavail); | ||
748 | + tswap32s((uint32_t*)&s->f_files); | ||
749 | + tswap32s((uint32_t*)&s->f_ffree); | ||
750 | + tswap32s((uint32_t*)&s->f_fsid.val[0]); | ||
751 | + tswap32s((uint32_t*)&s->f_fsid.val[1]); | ||
752 | + tswap16s((uint16_t*)&s->f_reserved1); | ||
753 | + tswap16s((uint16_t*)&s->f_type); | ||
754 | + tswap32s((uint32_t*)&s->f_flags); | ||
755 | +} | ||
756 | + | ||
757 | +static inline void byteswap_stat(struct stat *s) | ||
758 | +{ | ||
759 | + tswap32s((uint32_t*)&s->st_dev); | ||
760 | + tswap32s(&s->st_ino); | ||
761 | + tswap16s(&s->st_mode); | ||
762 | + tswap16s(&s->st_nlink); | ||
763 | + tswap32s(&s->st_uid); | ||
764 | + tswap32s(&s->st_gid); | ||
765 | + tswap32s((uint32_t*)&s->st_rdev); | ||
766 | + tswap32s((uint32_t*)&s->st_atimespec.tv_sec); | ||
767 | + tswap32s((uint32_t*)&s->st_atimespec.tv_nsec); | ||
768 | + tswap32s((uint32_t*)&s->st_mtimespec.tv_sec); | ||
769 | + tswap32s((uint32_t*)&s->st_mtimespec.tv_nsec); | ||
770 | + tswap32s((uint32_t*)&s->st_ctimespec.tv_sec); | ||
771 | + tswap32s((uint32_t*)&s->st_ctimespec.tv_nsec); | ||
772 | + tswap64s((uint64_t*)&s->st_size); | ||
773 | + tswap64s((uint64_t*)&s->st_blocks); | ||
774 | + tswap32s((uint32_t*)&s->st_blksize); | ||
775 | + tswap32s(&s->st_flags); | ||
776 | + tswap32s(&s->st_gen); | ||
777 | +} | ||
778 | + | ||
779 | +static inline void byteswap_dirents(struct dirent *d, int bytes) | ||
780 | +{ | ||
781 | + char *b; | ||
782 | + for( b = (char*)d; (int)b < (int)d+bytes; ) | ||
783 | + { | ||
784 | + unsigned short s = ((struct dirent *)b)->d_reclen; | ||
785 | + tswap32s(&((struct dirent *)b)->d_ino); | ||
786 | + tswap16s(&((struct dirent *)b)->d_reclen); | ||
787 | + if(s<=0) | ||
788 | + break; | ||
789 | + b += s; | ||
790 | + } | ||
791 | +} | ||
792 | + | ||
793 | +static inline void byteswap_iovec(struct iovec *v, int n) | ||
794 | +{ | ||
795 | + int i; | ||
796 | + for(i = 0; i < n; i++) | ||
797 | + { | ||
798 | + tswap32s((uint32_t*)&v[i].iov_base); | ||
799 | + tswap32s((uint32_t*)&v[i].iov_len); | ||
800 | + } | ||
801 | +} | ||
802 | + | ||
803 | +static inline void byteswap_timeval(struct timeval *t) | ||
804 | +{ | ||
805 | + tswap32s((uint32_t*)&t->tv_sec); | ||
806 | + tswap32s((uint32_t*)&t->tv_usec); | ||
807 | +} | ||
808 | + | ||
809 | +long do_unix_syscall_indirect(void *cpu_env, int num); | ||
810 | +long do_sync(); | ||
811 | +long do_exit(uint32_t arg1); | ||
812 | +long do_getlogin(char *out, uint32_t size); | ||
813 | +long do_open(char * arg1, uint32_t arg2, uint32_t arg3); | ||
814 | +long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3); | ||
815 | +long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3); | ||
816 | +long do_execve(char* arg1, char ** arg2, char ** arg3); | ||
817 | +long do_getgroups(uint32_t arg1, gid_t * arg2); | ||
818 | +long do_gettimeofday(struct timeval * arg1, void * arg2); | ||
819 | +long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3); | ||
820 | +long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3); | ||
821 | +long do_utimes(char * arg1, struct timeval * arg2); | ||
822 | +long do_futimes(uint32_t arg1, struct timeval * arg2); | ||
823 | +long do_statfs(char * arg1, struct statfs * arg2); | ||
824 | +long do_fstatfs(uint32_t arg1, struct statfs * arg2); | ||
825 | +long do_stat(char * arg1, struct stat * arg2); | ||
826 | +long do_fstat(uint32_t arg1, struct stat * arg2); | ||
827 | +long do_lstat(char * arg1, struct stat * arg2); | ||
828 | +long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4); | ||
829 | +long do_lseek(void *cpu_env, int num); | ||
830 | +long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6); | ||
831 | +long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5); | ||
832 | +long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8); | ||
833 | + | ||
834 | +long no_syscall(void *cpu_env, int num); | ||
835 | + | ||
836 | +long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4) | ||
837 | +{ | ||
838 | + //DPRINTF("0x%x, 0x%x, 0x%x, 0x%llx\n", arg1, arg2, arg3, arg4); | ||
839 | + long ret = (pread(arg1, arg2, arg3, arg4)); | ||
840 | + DPRINTF("0x%x\n", *(int*)arg2); | ||
841 | + return ret; | ||
842 | +} | ||
843 | +long unimpl_unix_syscall(void *cpu_env, int num); | ||
844 | + | ||
845 | +typedef long (*syscall_function_t)(void *cpu_env, int num); | ||
846 | + | ||
847 | + | ||
848 | +/* define a table that will handle the syscall number->function association */ | ||
849 | +#define VOID void | ||
850 | +#define INT (uint32_t)get_int_arg(&i, cpu_env) | ||
851 | +#define INT64 (uint64_t)get_int64_arg(&i, cpu_env) | ||
852 | +#define UINT (unsigned int)INT | ||
853 | +#define PTR (void*)INT | ||
854 | + | ||
855 | +#define SIZE INT | ||
856 | +#define OFFSET INT64 | ||
857 | + | ||
858 | +#define WRAPPER_CALL_DIRECT_0(function, args) long __qemu_##function(void *cpu_env) { return (long)function(); } | ||
859 | +#define WRAPPER_CALL_DIRECT_1(function, _arg1) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; return (long)function(arg1); } | ||
860 | +#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); } | ||
861 | +#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); } | ||
862 | +#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); } | ||
863 | +#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); } | ||
864 | +#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); } | ||
865 | +#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); } | ||
866 | +#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); } | ||
867 | +#define WRAPPER_CALL_DIRECT(function, nargs, args...) WRAPPER_CALL_DIRECT_##nargs(function, args) | ||
868 | +#define WRAPPER_CALL_NOERRNO(function, nargs, args...) WRAPPER_CALL_DIRECT(function, nargs, args) | ||
869 | +#define WRAPPER_CALL_INDIRECT(function, nargs, args...) | ||
870 | +#define ENTRY(name, number, function, nargs, call_type, args...) WRAPPER_##call_type(function, nargs, args) | ||
871 | + | ||
872 | +#include "syscalls.h" | ||
873 | + | ||
874 | +#undef ENTRY | ||
875 | +#undef WRAPPER_CALL_DIRECT | ||
876 | +#undef WRAPPER_CALL_NOERRNO | ||
877 | +#undef WRAPPER_CALL_INDIRECT | ||
878 | +#undef OFFSET | ||
879 | +#undef SIZE | ||
880 | +#undef INT | ||
881 | +#undef PTR | ||
882 | +#undef INT64 | ||
883 | + | ||
884 | +#define _ENTRY(name, number, function, nargs, call_type) [number] = {\ | ||
885 | + name, \ | ||
886 | + number, \ | ||
887 | + (syscall_function_t)function, \ | ||
888 | + nargs, \ | ||
889 | + call_type \ | ||
890 | + }, | ||
891 | + | ||
892 | +#define ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, __qemu_##function, nargs, call_type) | ||
893 | +#define ENTRY_CALL_NOERRNO(name, number, function, nargs, call_type) ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) | ||
894 | +#define ENTRY_CALL_INDIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, function, nargs, call_type) | ||
895 | +#define ENTRY(name, number, function, nargs, call_type, args...) ENTRY_##call_type(name, number, function, nargs, call_type) | ||
896 | + | ||
897 | +#define CALL_DIRECT 1 | ||
898 | +#define CALL_INDIRECT 2 | ||
899 | +#define CALL_NOERRNO (CALL_DIRECT | 4 /* = 5 */) | ||
900 | + | ||
901 | +struct unix_syscall { | ||
902 | + char * name; | ||
903 | + int number; | ||
904 | + syscall_function_t function; | ||
905 | + int nargs; | ||
906 | + int call_type; | ||
907 | +} unix_syscall_table[SYS_MAXSYSCALL] = { | ||
908 | +#include "syscalls.h" | ||
909 | +}; | ||
910 | + | ||
911 | +#undef ENTRY | ||
912 | +#undef _ENTRY | ||
913 | +#undef ENTRY_CALL_DIRECT | ||
914 | +#undef ENTRY_CALL_INDIRECT | ||
915 | +#undef ENTRY_CALL_NOERRNO | ||
916 | + | ||
917 | +/* Actual syscalls implementation */ | ||
918 | + | ||
919 | +long do_unix_syscall_indirect(void *cpu_env, int num) | ||
920 | +{ | ||
921 | + long ret; | ||
922 | + int new_num; | ||
923 | + int i = 0; | ||
924 | + | ||
925 | + new_num = get_int_arg(&i, cpu_env); | ||
926 | +#ifdef TARGET_I386 | ||
927 | + ((CPUX86State*)cpu_env)->regs[R_ESP] += 4; | ||
928 | + /* XXX: not necessary */ | ||
929 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = new_num; | ||
930 | +#elif TARGET_PPC | ||
931 | + { | ||
932 | + int i; | ||
933 | + uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr; | ||
934 | + for(i = 3; i < 11; i++) | ||
935 | + *regs[i] = *regs[i+1]; | ||
936 | + /* XXX: not necessary */ | ||
937 | + *regs[0] = new_num; | ||
938 | + } | ||
939 | +#endif | ||
940 | + ret = do_unix_syscall(cpu_env, new_num); | ||
941 | +#ifdef TARGET_I386 | ||
942 | + ((CPUX86State*)cpu_env)->regs[R_ESP] -= 4; | ||
943 | + /* XXX: not necessary */ | ||
944 | + ((CPUX86State*)cpu_env)->regs[R_EAX] = num; | ||
945 | +#elif TARGET_PPC | ||
946 | + { | ||
947 | + int i; | ||
948 | + /* XXX: not really needed those regs are volatile accross calls */ | ||
949 | + uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr; | ||
950 | + for(i = 11; i > 3; i--) | ||
951 | + *regs[i] = *regs[i-1]; | ||
952 | + regs[3] = new_num; | ||
953 | + *regs[0] = num; | ||
954 | + } | ||
955 | +#endif | ||
956 | + return ret; | ||
957 | +} | ||
958 | + | ||
959 | +long do_exit(uint32_t arg1) | ||
960 | +{ | ||
961 | + exit(arg1); | ||
962 | + /* not reached */ | ||
963 | + return -1; | ||
964 | +} | ||
965 | + | ||
966 | +long do_sync() | ||
967 | +{ | ||
968 | + sync(); | ||
969 | + return 0; | ||
970 | +} | ||
971 | + | ||
972 | +long do_getlogin(char *out, uint32_t size) | ||
973 | +{ | ||
974 | + char *login = getlogin(); | ||
975 | + if(!login) | ||
976 | + return -1; | ||
977 | + memcpy(out, login, size); | ||
978 | + return 0; | ||
979 | +} | ||
980 | +long do_open(char * arg1, uint32_t arg2, uint32_t arg3) | ||
981 | +{ | ||
982 | + /* XXX: don't let the %s stay in there */ | ||
983 | + DPRINTF("open(%s, 0x%x, 0x%x)\n", arg1, arg2, arg3); | ||
984 | + return get_errno(open(arg1, arg2, arg3)); | ||
985 | +} | ||
986 | + | ||
987 | +long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3) | ||
988 | +{ | ||
989 | + long ret; | ||
990 | + DPRINTF("getfsstat(%p, 0x%x, 0x%x)\n", arg1, arg2, arg3); | ||
991 | + ret = get_errno(getfsstat(arg1, arg2, arg3)); | ||
992 | + if((!is_error(ret)) && arg1) | ||
993 | + byteswap_statfs(arg1); | ||
994 | + return ret; | ||
995 | +} | ||
996 | + | ||
997 | +long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3) | ||
998 | +{ | ||
999 | + long ret; | ||
1000 | + DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3); | ||
1001 | + gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3); | ||
1002 | + if(arg2) | ||
1003 | + tswap32s(arg2); | ||
1004 | + ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3)); | ||
1005 | + if((!is_error(ret)) && arg3) | ||
1006 | + tswap32s(arg3); | ||
1007 | + if(arg2) | ||
1008 | + tswap32s(arg2); | ||
1009 | + return ret; | ||
1010 | +} | ||
1011 | + | ||
1012 | +long do_execve(char* arg1, char ** arg2, char ** arg3) | ||
1013 | +{ | ||
1014 | + long ret; | ||
1015 | + char **argv = arg2; | ||
1016 | + char **envp = arg3; | ||
1017 | + int argc; | ||
1018 | + int envc; | ||
1019 | + | ||
1020 | + /* XXX: don't let the %s stay in here */ | ||
1021 | + DPRINTF("execve(%s, %p, %p)\n", arg1, arg2, arg3); | ||
1022 | + | ||
1023 | + for(argc = 0; argv[argc]; argc++); | ||
1024 | + for(envc = 0; envp[envc]; envc++); | ||
1025 | + | ||
1026 | + argv = (char**)malloc(sizeof(char*)*argc); | ||
1027 | + envp = (char**)malloc(sizeof(char*)*envc); | ||
1028 | + | ||
1029 | + for(; argc >= 0; argc--) | ||
1030 | + argv[argc] = (char*)tswap32((uint32_t)(arg2)[argc]); | ||
1031 | + | ||
1032 | + for(; envc >= 0; envc--) | ||
1033 | + envp[envc] = (char*)tswap32((uint32_t)(arg3)[envc]); | ||
1034 | + | ||
1035 | + ret = get_errno(execve(arg1, argv, envp)); | ||
1036 | + free(argv); | ||
1037 | + free(envp); | ||
1038 | + return ret; | ||
1039 | +} | ||
1040 | + | ||
1041 | +long do_getgroups(uint32_t arg1, gid_t * arg2) | ||
1042 | +{ | ||
1043 | + long ret; | ||
1044 | + int i; | ||
1045 | + DPRINTF("getgroups(0x%x, %p)\n", arg1, arg2); | ||
1046 | + ret = get_errno(getgroups(arg1, arg2)); | ||
1047 | + if(ret > 0) | ||
1048 | + for(i = 0; i < arg1; i++) | ||
1049 | + tswap32s(&arg2[i]); | ||
1050 | + return ret; | ||
1051 | +} | ||
1052 | + | ||
1053 | +long do_gettimeofday(struct timeval * arg1, void * arg2) | ||
1054 | +{ | ||
1055 | + long ret; | ||
1056 | + DPRINTF("gettimeofday(%p, %p)\n", | ||
1057 | + arg1, arg2); | ||
1058 | + ret = get_errno(gettimeofday(arg1, arg2)); | ||
1059 | + if(!is_error(ret)) | ||
1060 | + { | ||
1061 | + /* timezone no longer used according to the manpage, so don't bother with it */ | ||
1062 | + byteswap_timeval(arg1); | ||
1063 | + } | ||
1064 | + return ret; | ||
1065 | +} | ||
1066 | + | ||
1067 | +long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3) | ||
1068 | +{ | ||
1069 | + long ret; | ||
1070 | + DPRINTF("readv(0x%x, %p, 0x%x)\n", arg1, arg2, arg3); | ||
1071 | + if(arg2) | ||
1072 | + byteswap_iovec(arg2, arg3); | ||
1073 | + ret = get_errno(readv(arg1, arg2, arg3)); | ||
1074 | + if((!is_error(ret)) && arg2) | ||
1075 | + byteswap_iovec(arg2, arg3); | ||
1076 | + return ret; | ||
1077 | +} | ||
1078 | + | ||
1079 | +long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3) | ||
1080 | +{ | ||
1081 | + long ret; | ||
1082 | + DPRINTF("writev(0x%x, %p, 0x%x)\n", arg1, arg2, arg3); | ||
1083 | + if(arg2) | ||
1084 | + byteswap_iovec(arg2, arg3); | ||
1085 | + ret = get_errno(writev(arg1, arg2, arg3)); | ||
1086 | + if((!is_error(ret)) && arg2) | ||
1087 | + byteswap_iovec(arg2, arg3); | ||
1088 | + return ret; | ||
1089 | +} | ||
1090 | + | ||
1091 | +long do_utimes(char * arg1, struct timeval * arg2) | ||
1092 | +{ | ||
1093 | + DPRINTF("utimes(%p, %p)\n", arg1, arg2); | ||
1094 | + if(arg2) | ||
1095 | + { | ||
1096 | + byteswap_timeval(arg2); | ||
1097 | + byteswap_timeval(arg2+1); | ||
1098 | + } | ||
1099 | + return get_errno(utimes(arg1, arg2)); | ||
1100 | +} | ||
1101 | + | ||
1102 | +long do_futimes(uint32_t arg1, struct timeval * arg2) | ||
1103 | +{ | ||
1104 | + DPRINTF("futimes(0x%x, %p)\n", arg1, arg2); | ||
1105 | + if(arg2) | ||
1106 | + { | ||
1107 | + byteswap_timeval(arg2); | ||
1108 | + byteswap_timeval(arg2+1); | ||
1109 | + } | ||
1110 | + return get_errno(futimes(arg1, arg2)); | ||
1111 | +} | ||
1112 | + | ||
1113 | +long do_statfs(char * arg1, struct statfs * arg2) | ||
1114 | +{ | ||
1115 | + long ret; | ||
1116 | + DPRINTF("statfs(%p, %p)\n", arg1, arg2); | ||
1117 | + ret = get_errno(statfs(arg1, arg2)); | ||
1118 | + if(!is_error(ret)) | ||
1119 | + byteswap_statfs(arg2); | ||
1120 | + return ret; | ||
1121 | +} | ||
1122 | + | ||
1123 | +long do_fstatfs(uint32_t arg1, struct statfs* arg2) | ||
1124 | +{ | ||
1125 | + long ret; | ||
1126 | + DPRINTF("fstatfs(0x%x, %p)\n", | ||
1127 | + arg1, arg2); | ||
1128 | + ret = get_errno(fstatfs(arg1, arg2)); | ||
1129 | + if(!is_error(ret)) | ||
1130 | + byteswap_statfs(arg2); | ||
1131 | + | ||
1132 | + return ret; | ||
1133 | +} | ||
1134 | + | ||
1135 | +long do_stat(char * arg1, struct stat * arg2) | ||
1136 | +{ | ||
1137 | + long ret; | ||
1138 | + /* XXX: don't let the %s stay in there */ | ||
1139 | + DPRINTF("stat(%s, %p)\n", arg1, arg2); | ||
1140 | + ret = get_errno(stat(arg1, arg2)); | ||
1141 | + if(!is_error(ret)) | ||
1142 | + byteswap_stat(arg2); | ||
1143 | + return ret; | ||
1144 | +} | ||
1145 | + | ||
1146 | +long do_fstat(uint32_t arg1, struct stat * arg2) | ||
1147 | +{ | ||
1148 | + long ret; | ||
1149 | + DPRINTF("fstat(0x%x, %p)\n", arg1, arg2); | ||
1150 | + ret = get_errno(fstat(arg1, arg2)); | ||
1151 | + if(!is_error(ret)) | ||
1152 | + byteswap_stat(arg2); | ||
1153 | + return ret; | ||
1154 | +} | ||
1155 | + | ||
1156 | +long do_lstat(char * arg1, struct stat * arg2) | ||
1157 | +{ | ||
1158 | + long ret; | ||
1159 | + /* XXX: don't let the %s stay in there */ | ||
1160 | + DPRINTF("lstat(%s, %p)\n", (const char *)arg1, arg2); | ||
1161 | + ret = get_errno(lstat(arg1, arg2)); | ||
1162 | + if(!is_error(ret)) | ||
1163 | + byteswap_stat(arg2); | ||
1164 | + return ret; | ||
1165 | +} | ||
1166 | + | ||
1167 | +long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4) | ||
1168 | +{ | ||
1169 | + long ret; | ||
1170 | + DPRINTF("getdirentries(0x%x, %p, 0x%x, %p)\n", arg1, arg2, arg3, arg4); | ||
1171 | + if(arg4) | ||
1172 | + tswap32s((uint32_t *)arg4); | ||
1173 | + ret = get_errno(getdirentries(arg1, arg2, arg3, arg4)); | ||
1174 | + if(arg4) | ||
1175 | + tswap32s((uint32_t *)arg4); | ||
1176 | + if(!is_error(ret)) | ||
1177 | + byteswap_dirents(arg2, ret); | ||
1178 | + return ret; | ||
1179 | +} | ||
1180 | + | ||
1181 | +long do_lseek(void *cpu_env, int num) | ||
1182 | +{ | ||
1183 | + long ret; | ||
1184 | + int i = 0; | ||
1185 | + uint32_t arg1 = get_int_arg(&i, cpu_env); | ||
1186 | + uint64_t offset = get_int64_arg(&i, cpu_env); | ||
1187 | + uint32_t arg3 = get_int_arg(&i, cpu_env); | ||
1188 | + uint64_t r = lseek(arg1, offset, arg3); | ||
1189 | +#ifdef TARGET_I386 | ||
1190 | + /* lowest word in eax, highest in edx */ | ||
1191 | + ret = r & 0xffffffff; /* will be set to eax after do_unix_syscall exit */ | ||
1192 | + ((CPUX86State *)cpu_env)->regs[R_EDX] = (uint32_t)((r >> 32) & 0xffffffff) ; | ||
1193 | +#elif defined TARGET_PPC | ||
1194 | + ret = r & 0xffffffff; /* will be set to r3 after do_unix_syscall exit */ | ||
1195 | + ((CPUPPCState *)cpu_env)->gpr[4] = (uint32_t)((r >> 32) & 0xffffffff) ; | ||
1196 | +#else | ||
1197 | + qerror("64 bit ret value on your arch?"); | ||
1198 | +#endif | ||
1199 | + return get_errno(ret); | ||
1200 | +} | ||
1201 | + | ||
1202 | +long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6) | ||
1203 | +{ | ||
1204 | + long ret = 0; | ||
1205 | + int i; | ||
1206 | + DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n", | ||
1207 | + arg1, arg2, arg3, arg4, arg5, arg6); | ||
1208 | + if(arg1) { | ||
1209 | + i = 0; | ||
1210 | + do { *((int *) arg1 + i) = tswap32(*((int *) arg1 + i)); } while (++i < arg2); | ||
1211 | + } | ||
1212 | + | ||
1213 | + if(arg4) | ||
1214 | + *(int *) arg4 = tswap32(*(int *) arg4); | ||
1215 | + if(arg1) | ||
1216 | + ret = get_errno(sysctl((void *)arg1, arg2, (void *)arg3, (void *)arg4, (void *)arg5, arg6)); | ||
1217 | + | ||
1218 | + if ((ret == 0) && (arg2 == 2) && (*((int *) arg1) == 0) && (*((int *) arg1 + 1) == 3)) { | ||
1219 | + /* The output here is the new id - we need to swap it so it can be passed | ||
1220 | + back in (and then unswapped) */ | ||
1221 | + int count = (*(int *) arg4) / sizeof(int); | ||
1222 | + i = 0; | ||
1223 | + do { | ||
1224 | + *((int *) arg3 + i) = tswap32(*((int *) arg3 + i)); | ||
1225 | + } while (++i < count); | ||
1226 | + } | ||
1227 | + *(int *) arg4 = tswap32(*(int *) arg4); | ||
1228 | + | ||
1229 | + return ret; | ||
1230 | +} | ||
1231 | + | ||
1232 | +long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5) | ||
1233 | +{ | ||
1234 | + struct attrlist * attrlist = (void *)arg2; | ||
1235 | + long ret; | ||
1236 | + | ||
1237 | +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) | ||
1238 | + qerror("SYS_getdirentriesattr unimplemented\n"); | ||
1239 | +#endif | ||
1240 | + /* XXX: don't let the %s stay in there */ | ||
1241 | + DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n", | ||
1242 | + (char *)arg1, arg2, arg3, arg4, arg5); | ||
1243 | + | ||
1244 | + if(arg2) /* XXX: We should handle that in a copy especially | ||
1245 | + if the structure is not writable */ | ||
1246 | + byteswap_attrlist(attrlist); | ||
1247 | + | ||
1248 | + ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5)); | ||
1249 | + | ||
1250 | + if(!is_error(ret)) | ||
1251 | + { | ||
1252 | + byteswap_attrbuf((void *)arg3, attrlist); | ||
1253 | + byteswap_attrlist(attrlist); | ||
1254 | + } | ||
1255 | + return ret; | ||
1256 | +} | ||
1257 | + | ||
1258 | +long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8) | ||
1259 | +{ | ||
1260 | + DPRINTF("getdirentriesattr(0x%x, %p, %p, 0x%lx, %p, %p, %p, 0x%x)\n", | ||
1261 | + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | ||
1262 | +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) | ||
1263 | + qerror("SYS_getdirentriesattr unimplemented\n"); | ||
1264 | +#endif | ||
1265 | + | ||
1266 | + return get_errno(getdirentriesattr( arg1, (struct attrlist * )arg2, (void *)arg3, arg4, | ||
1267 | + (unsigned long *)arg5, (unsigned long *)arg6, | ||
1268 | + (unsigned long *)arg7, arg8)); | ||
1269 | +} | ||
1270 | + | ||
1271 | + | ||
1272 | +long no_syscall(void *cpu_env, int num) | ||
1273 | +{ | ||
1274 | + /* XXX: We should probably fordward it to the host kernel */ | ||
1275 | + qerror("no unix syscall %d\n", num); | ||
1276 | + /* not reached */ | ||
1277 | + return -1; | ||
1278 | +} | ||
1279 | + | ||
1280 | +long unimpl_unix_syscall(void *cpu_env, int num) | ||
1281 | +{ | ||
1282 | + if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) | ||
1283 | + qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); | ||
1284 | + | ||
1285 | + gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num); | ||
1286 | + gdb_handlesig (cpu_env, SIGTRAP); | ||
1287 | + exit(-1); | ||
1288 | +} | ||
1289 | + | ||
1290 | +long do_unix_syscall(void *cpu_env, int num) | ||
1291 | +{ | ||
1292 | + long ret = 0; | ||
1293 | + | ||
1294 | + DPRINTF("unix syscall %d: " , num); | ||
1295 | + | ||
1296 | + if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) | ||
1297 | + qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); | ||
1298 | + | ||
1299 | + DPRINTF("%s [%s]", unix_syscall_table[num].name, unix_syscall_table[num].call_type & CALL_DIRECT ? "direct" : "indirect" ); | ||
1300 | + ret = unix_syscall_table[num].function(cpu_env, num); | ||
1301 | + | ||
1302 | + if(!(unix_syscall_table[num].call_type & CALL_NOERRNO)) | ||
1303 | + ret = get_errno(ret); | ||
1304 | + | ||
1305 | + DPRINTF("[returned 0x%x(%d)]\n", (int)ret, (int)ret); | ||
1306 | + return ret; | ||
1307 | +} | ||
1308 | + | ||
1309 | +/* ------------------------------------------------------------ | ||
1310 | + syscall_init | ||
1311 | +*/ | ||
1312 | +void syscall_init(void) | ||
1313 | +{ | ||
1314 | + /* Nothing yet */ | ||
1315 | +} |