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 | 13 | TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) |
14 | 14 | VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio |
15 | 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 | 21 | VPATH+=:$(SRC_PATH)/linux-user |
18 | 22 | CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) |
19 | 23 | endif |
... | ... | @@ -85,12 +89,14 @@ endif |
85 | 89 | ifdef USE_I386_LD |
86 | 90 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
87 | 91 | else |
92 | +ifdef CONFIG_LINUX_USER | |
88 | 93 | # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object |
89 | 94 | # that the kernel ELF loader considers as an executable. I think this |
90 | 95 | # is the simplest way to make it self virtualizable! |
91 | 96 | BASE_LDFLAGS+=-Wl,-shared |
92 | 97 | endif |
93 | 98 | endif |
99 | +endif | |
94 | 100 | |
95 | 101 | ifeq ($(ARCH),x86_64) |
96 | 102 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
... | ... | @@ -98,8 +104,10 @@ endif |
98 | 104 | |
99 | 105 | ifeq ($(ARCH),ppc) |
100 | 106 | CPPFLAGS+= -D__powerpc__ |
107 | +ifdef CONFIG_LINUX_USER | |
101 | 108 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
102 | 109 | endif |
110 | +endif | |
103 | 111 | |
104 | 112 | ifeq ($(ARCH),s390) |
105 | 113 | BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld |
... | ... | @@ -186,6 +194,7 @@ BASE_LDFLAGS+=-p |
186 | 194 | main.o: BASE_CFLAGS+=-p |
187 | 195 | endif |
188 | 196 | |
197 | +ifdef CONFIG_LINUX_USER | |
189 | 198 | OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ |
190 | 199 | elfload.o linuxload.o |
191 | 200 | ifdef TARGET_HAS_BFLT |
... | ... | @@ -203,6 +212,12 @@ endif |
203 | 212 | ifeq ($(TARGET_ARCH), m68k) |
204 | 213 | OBJS+= m68k-sim.o m68k-semi.o |
205 | 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 | 221 | SRCS:= $(OBJS:.o=.c) |
207 | 222 | OBJS+= libqemu.a |
208 | 223 | ... | ... |
configure
... | ... | @@ -94,7 +94,8 @@ cocoa="no" |
94 | 94 | check_gfx="yes" |
95 | 95 | check_gcc="yes" |
96 | 96 | softmmu="yes" |
97 | -user="no" | |
97 | +linux_user="no" | |
98 | +darwin_user="no" | |
98 | 99 | build_docs="no" |
99 | 100 | uname_release="" |
100 | 101 | |
... | ... | @@ -126,6 +127,7 @@ oss="yes" |
126 | 127 | Darwin) |
127 | 128 | bsd="yes" |
128 | 129 | darwin="yes" |
130 | +darwin_user="yes" | |
129 | 131 | OS_CFLAGS="-mdynamic-no-pic" |
130 | 132 | ;; |
131 | 133 | SunOS) |
... | ... | @@ -134,7 +136,7 @@ solaris="yes" |
134 | 136 | *) |
135 | 137 | oss="yes" |
136 | 138 | linux="yes" |
137 | -user="yes" | |
139 | +linux_user="yes" | |
138 | 140 | if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then |
139 | 141 | kqemu="yes" |
140 | 142 | fi |
... | ... | @@ -240,9 +242,13 @@ for opt do |
240 | 242 | ;; |
241 | 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 | 253 | --enable-uname-release=*) uname_release="$optarg" |
248 | 254 | ;; |
... | ... | @@ -287,8 +293,10 @@ echo " --enable-fmod enable FMOD audio driver" |
287 | 293 | echo " --enabled-dsound enable DirectSound audio driver" |
288 | 294 | echo " --enable-system enable all system emulation targets" |
289 | 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 | 300 | echo " --fmod-lib path to FMOD library" |
293 | 301 | echo " --fmod-inc path to FMOD includes" |
294 | 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 | 416 | target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu" |
409 | 417 | fi |
410 | 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 | 425 | fi |
414 | 426 | else |
415 | 427 | target_list=`echo "$target_list" | sed -e 's/,/ /g'` |
... | ... | @@ -787,6 +799,16 @@ if expr $target : '.*-user' > /dev/null ; then |
787 | 799 | target_user_only="yes" |
788 | 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 | 812 | if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ |
791 | 813 | -a "$sdl" = "no" -a "$cocoa" = "no" ; then |
792 | 814 | echo "ERROR: QEMU requires SDL or Cocoa for graphical output" |
... | ... | @@ -799,7 +821,7 @@ fi |
799 | 821 | |
800 | 822 | mkdir -p $target_dir |
801 | 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 | 825 | mkdir -p $target_dir/nwfpe |
804 | 826 | fi |
805 | 827 | if test "$target_user_only" = "no" ; then |
... | ... | @@ -894,6 +916,14 @@ if test "$target_user_only" = "yes" ; then |
894 | 916 | echo "CONFIG_USER_ONLY=yes" >> $config_mak |
895 | 917 | echo "#define CONFIG_USER_ONLY 1" >> $config_h |
896 | 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 | 928 | if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then |
899 | 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 | +} | ... | ... |