提交 831b7825 编写于 作者: T ths

Darwin userspace emulation, by Pierre d'Herbemont.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2332 c046a42c-6fe2-441c-8c8c-71466251a162
上级 54421cb1
...@@ -13,7 +13,11 @@ endif ...@@ -13,7 +13,11 @@ endif
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
ifdef CONFIG_USER_ONLY ifdef CONFIG_DARWIN_USER
VPATH+=:$(SRC_PATH)/darwin-user
CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
endif
ifdef CONFIG_LINUX_USER
VPATH+=:$(SRC_PATH)/linux-user VPATH+=:$(SRC_PATH)/linux-user
CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif endif
...@@ -85,12 +89,14 @@ endif ...@@ -85,12 +89,14 @@ endif
ifdef USE_I386_LD ifdef USE_I386_LD
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else else
ifdef CONFIG_LINUX_USER
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this # that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable! # is the simplest way to make it self virtualizable!
BASE_LDFLAGS+=-Wl,-shared BASE_LDFLAGS+=-Wl,-shared
endif endif
endif endif
endif
ifeq ($(ARCH),x86_64) ifeq ($(ARCH),x86_64)
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
...@@ -98,8 +104,10 @@ endif ...@@ -98,8 +104,10 @@ endif
ifeq ($(ARCH),ppc) ifeq ($(ARCH),ppc)
CPPFLAGS+= -D__powerpc__ CPPFLAGS+= -D__powerpc__
ifdef CONFIG_LINUX_USER
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif endif
endif
ifeq ($(ARCH),s390) ifeq ($(ARCH),s390)
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
...@@ -186,6 +194,7 @@ BASE_LDFLAGS+=-p ...@@ -186,6 +194,7 @@ BASE_LDFLAGS+=-p
main.o: BASE_CFLAGS+=-p main.o: BASE_CFLAGS+=-p
endif endif
ifdef CONFIG_LINUX_USER
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
elfload.o linuxload.o elfload.o linuxload.o
ifdef TARGET_HAS_BFLT ifdef TARGET_HAS_BFLT
...@@ -203,6 +212,12 @@ endif ...@@ -203,6 +212,12 @@ endif
ifeq ($(TARGET_ARCH), m68k) ifeq ($(TARGET_ARCH), m68k)
OBJS+= m68k-sim.o m68k-semi.o OBJS+= m68k-sim.o m68k-semi.o
endif endif
endif #CONFIG_LINUX_USER
ifdef CONFIG_DARWIN_USER
OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o
endif
SRCS:= $(OBJS:.o=.c) SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a OBJS+= libqemu.a
......
...@@ -94,7 +94,8 @@ cocoa="no" ...@@ -94,7 +94,8 @@ cocoa="no"
check_gfx="yes" check_gfx="yes"
check_gcc="yes" check_gcc="yes"
softmmu="yes" softmmu="yes"
user="no" linux_user="no"
darwin_user="no"
build_docs="no" build_docs="no"
uname_release="" uname_release=""
...@@ -126,6 +127,7 @@ oss="yes" ...@@ -126,6 +127,7 @@ oss="yes"
Darwin) Darwin)
bsd="yes" bsd="yes"
darwin="yes" darwin="yes"
darwin_user="yes"
OS_CFLAGS="-mdynamic-no-pic" OS_CFLAGS="-mdynamic-no-pic"
;; ;;
SunOS) SunOS)
...@@ -134,7 +136,7 @@ solaris="yes" ...@@ -134,7 +136,7 @@ solaris="yes"
*) *)
oss="yes" oss="yes"
linux="yes" linux="yes"
user="yes" linux_user="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes" kqemu="yes"
fi fi
...@@ -240,9 +242,13 @@ for opt do ...@@ -240,9 +242,13 @@ for opt do
;; ;;
--enable-system) softmmu="yes" --enable-system) softmmu="yes"
;; ;;
--disable-user) user="no" --disable-linux-user) linux_user="no"
;; ;;
--enable-user) user="yes" --enable-linux-user) linux_user="yes"
;;
--disable-darwin-user) darwin_user="no"
;;
--enable-darwin-user) darwin_user="yes"
;; ;;
--enable-uname-release=*) uname_release="$optarg" --enable-uname-release=*) uname_release="$optarg"
;; ;;
...@@ -287,8 +293,10 @@ echo " --enable-fmod enable FMOD audio driver" ...@@ -287,8 +293,10 @@ echo " --enable-fmod enable FMOD audio driver"
echo " --enabled-dsound enable DirectSound audio driver" echo " --enabled-dsound enable DirectSound audio driver"
echo " --enable-system enable all system emulation targets" echo " --enable-system enable all system emulation targets"
echo " --disable-system disable all system emulation targets" echo " --disable-system disable all system emulation targets"
echo " --enable-user enable all linux usermode emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets"
echo " --disable-user disable all linux usermode emulation targets" echo " --disable-linux-user disable all linux usermode emulation targets"
echo " --enable-darwin-user enable all darwin usermode emulation targets"
echo " --disable-darwin-user disable all darwin usermode emulation targets"
echo " --fmod-lib path to FMOD library" echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes" echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation" echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
...@@ -408,8 +416,12 @@ if test -z "$target_list" ; then ...@@ -408,8 +416,12 @@ if test -z "$target_list" ; then
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu" target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
fi fi
# the following are Linux specific # the following are Linux specific
if [ "$user" = "yes" ] ; then if [ "$linux_user" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user m68k-user $target_list" 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"
fi
# the following are Darwin specific
if [ "$darwin_user" = "yes" ] ; then
target_list="i386-darwin-user ppc-darwin-user $target_list"
fi fi
else else
target_list=`echo "$target_list" | sed -e 's/,/ /g'` target_list=`echo "$target_list" | sed -e 's/,/ /g'`
...@@ -787,6 +799,16 @@ if expr $target : '.*-user' > /dev/null ; then ...@@ -787,6 +799,16 @@ if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes" target_user_only="yes"
fi fi
target_linux_user="no"
if expr $target : '.*-linux-user' > /dev/null ; then
target_linux_user="yes"
fi
target_darwin_user="no"
if expr $target : '.*-darwin-user' > /dev/null ; then
target_darwin_user="yes"
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then -a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output" echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
...@@ -799,7 +821,7 @@ fi ...@@ -799,7 +821,7 @@ fi
mkdir -p $target_dir mkdir -p $target_dir
mkdir -p $target_dir/fpu mkdir -p $target_dir/fpu
if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
mkdir -p $target_dir/nwfpe mkdir -p $target_dir/nwfpe
fi fi
if test "$target_user_only" = "no" ; then if test "$target_user_only" = "no" ; then
...@@ -894,6 +916,14 @@ if test "$target_user_only" = "yes" ; then ...@@ -894,6 +916,14 @@ if test "$target_user_only" = "yes" ; then
echo "CONFIG_USER_ONLY=yes" >> $config_mak echo "CONFIG_USER_ONLY=yes" >> $config_mak
echo "#define CONFIG_USER_ONLY 1" >> $config_h echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi fi
if test "$target_linux_user" = "yes" ; then
echo "CONFIG_LINUX_USER=yes" >> $config_mak
echo "#define CONFIG_LINUX_USER 1" >> $config_h
fi
if test "$target_darwin_user" = "yes" ; then
echo "CONFIG_DARWIN_USER=yes" >> $config_mak
echo "#define CONFIG_DARWIN_USER 1" >> $config_h
fi
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
......
/*
* Commpage syscalls
*
* Copyright (c) 2006 Pierre d'Herbemont
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <mach/message.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <libkern/OSAtomic.h>
#include "qemu.h"
//#define DEBUG_COMMPAGE
#ifdef DEBUG_COMMPAGE
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
#else
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
#endif
/********************************************************************
* Commpage definitions
*/
#ifdef TARGET_I386
/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
#elif defined(TARGET_PPC)
/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
# define COMMPAGE_START (-8*4096)
# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
#endif
void do_compare_and_swap32(void *cpu_env, int num);
void do_compare_and_swap64(void *cpu_env, int num);
void do_add_atomic_word32(void *cpu_env, int num);
void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
void do_nanotime(void *cpu_env, int num);
void unimpl_commpage(void *cpu_env, int num);
typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
uint32_t arg8);
typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
uint32_t arg6, uint32_t arg7, uint32_t arg8);
#define HAS_PTR 0x10
#define NO_PTR 0x20
#define CALL_DIRECT 0x1
#define CALL_INDIRECT 0x2
#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
{ #name, offset, nargs, options, (commpage_8args_function_t)func }
struct commpage_entry {
char * name;
int offset;
int nargs;
char options;
commpage_8args_function_t function;
};
static inline int commpage_code_num(struct commpage_entry *entry)
{
if((entry->options & HAS_PTR))
return entry->offset + 4;
else
return entry->offset;
}
static inline int commpage_is_indirect(struct commpage_entry *entry)
{
return !(entry->options & CALL_DIRECT);
}
/********************************************************************
* Commpage entry
*/
static struct commpage_entry commpage_entries[] =
{
COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT),
COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT),
COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(gettimeofday, 1, 0x2c0, do_cgettimeofday, CALL_INDIRECT),
COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(pthread_self, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT),
#ifdef TARGET_I386
COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT),
#endif
COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT),
COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT),
COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT),
#ifdef TARGET_I386
COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT),
COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT),
#elif TARGET_PPC
COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT),
#endif
};
/********************************************************************
* Commpage backdoor
*/
static inline void print_commpage_entry(struct commpage_entry entry)
{
printf("@0x%x %s\n", entry.offset, entry.name);
}
static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
{
#ifdef TARGET_I386
char * commpage = (char*)(COMMPAGE_START+entry.offset);
int c = 0;
if(entry.options & HAS_PTR)
{
commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
}
commpage[c++] = 0xcd;
commpage[c++] = 0x79; /* int 0x79 */
commpage[c++] = 0xc3; /* ret */
#else
qerror("can't install the commpage on this arch\n");
#endif
}
/********************************************************************
* Commpage initialization
*/
void commpage_init(void)
{
#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC))
int i;
void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if((int)commpage != COMMPAGE_START)
qerror("can't allocate the commpage\n");
bzero(commpage, COMMPAGE_SIZE);
/* XXX: commpage data not handled */
for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++)
install_commpage_backdoor_for_entry(commpage_entries[i]);
#else
/* simply map our pages so they can be executed
XXX: we don't really want to do that since in the ppc on ppc situation we may
not able to run commpages host optimized instructions (like G5's on a G5),
hence this is sometimes a broken fix. */
page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
#endif
}
/********************************************************************
* Commpage implementation
*/
void do_compare_and_swap32(void *cpu_env, int num)
{
#ifdef TARGET_I386
uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
if(value && old == tswap32(*value))
{
uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
*value = tswap32(new);
/* set zf flag */
((CPUX86State*)cpu_env)->eflags |= 0x40;
}
else
{
((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
/* unset zf flag */
((CPUX86State*)cpu_env)->eflags &= ~0x40;
}
#else
qerror("do_compare_and_swap32 unimplemented");
#endif
}
void do_compare_and_swap64(void *cpu_env, int num)
{
#ifdef TARGET_I386
/* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
uint64_t old, new, swapped_val;
uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
swapped_val = tswap64(*value);
if(old == swapped_val)
{
new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
*value = tswap64(new);
/* set zf flag */
((CPUX86State*)cpu_env)->eflags |= 0x40;
}
else
{
((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
/* unset zf flag */
((CPUX86State*)cpu_env)->eflags &= ~0x40;
}
#else
qerror("do_compare_and_swap64 unimplemented");
#endif
}
void do_add_atomic_word32(void *cpu_env, int num)
{
#ifdef TARGET_I386
uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
uint32_t swapped_value = tswap32(*value);
DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
/* old value in EAX */
((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
*value = tswap32(swapped_value + amt);
#else
qerror("do_add_atomic_word32 unimplemented");
#endif
}
void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
{
#ifdef TARGET_I386
extern int __commpage_gettimeofday(struct timeval *);
DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
struct timeval *time = (struct timeval *)arg1;
int ret = __commpage_gettimeofday(time);
tswap32s((uint32_t*)&time->tv_sec);
tswap32s((uint32_t*)&time->tv_usec);
((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
#else
qerror("do_gettimeofday unimplemented");
#endif
}
void do_nanotime(void *cpu_env, int num)
{
#ifdef TARGET_I386
uint64_t t = mach_absolute_time();
((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
#else
qerror("do_nanotime unimplemented");
#endif
}
void unimpl_commpage(void *cpu_env, int num)
{
gemu_log("qemu: commpage function 0x%x not implemented\n", num);
}
/********************************************************************
* do_commpage - called by the main cpu loop
*/
void
do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
uint32_t arg8)
{
int i, found = 0;
arg1 = tswap32(arg1);
arg2 = tswap32(arg2);
arg3 = tswap32(arg3);
arg4 = tswap32(arg4);
arg5 = tswap32(arg5);
arg6 = tswap32(arg6);
arg7 = tswap32(arg7);
arg8 = tswap32(arg8);
num = num-COMMPAGE_START-2;
for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) {
if( num == commpage_code_num(&commpage_entries[i]) )
{
DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
found = 1;
if(commpage_is_indirect(&commpage_entries[i]))
{
commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
function(cpu_env, num, arg1, arg2, arg3,
arg4, arg5, arg6, arg7, arg8);
}
else
{
commpage_entries[i].function(arg1, arg2, arg3,
arg4, arg5, arg6, arg7, arg8);
}
break;
}
}
if(!found)
{
gemu_log("qemu: commpage function 0x%x not defined\n", num);
gdb_handlesig (cpu_env, SIGTRAP);
exit(-1);
}
}
/* emulated ioctl list */
IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)
\ No newline at end of file
此差异已折叠。
此差异已折叠。
/*
* mmap support for qemu
*
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "qemu.h"
//#define DEBUG_MMAP
/* NOTE: all the constants are the HOST ones */
int target_mprotect(unsigned long start, unsigned long len, int prot)
{
unsigned long end, host_start, host_end, addr;
int prot1, ret;
#ifdef DEBUG_MMAP
printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
#endif
if ((start & ~TARGET_PAGE_MASK) != 0)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return -EINVAL;
if (len == 0)
return 0;
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot1 = prot;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
if (host_end == host_start + qemu_host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
end = host_end;
}
ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_start += qemu_host_page_size;
}
if (end < host_end) {
prot1 = prot;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_end -= qemu_host_page_size;
}
/* handle the pages in the middle */
if (host_start < host_end) {
ret = mprotect((void *)host_start, host_end - host_start, prot);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, prot | PAGE_VALID);
return 0;
}
/* map an incomplete host page */
int mmap_frag(unsigned long host_start,
unsigned long start, unsigned long end,
int prot, int flags, int fd, unsigned long offset)
{
unsigned long host_end, ret, addr;
int prot1, prot_new;
host_end = host_start + qemu_host_page_size;
/* get the protection of the target pages outside the mapping */
prot1 = 0;
for(addr = host_start; addr < host_end; addr++) {
if (addr < start || addr >= end)
prot1 |= page_get_flags(addr);
}
if (prot1 == 0) {
/* no page was there, so we allocate one */
ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
flags | MAP_ANONYMOUS, -1, 0);
if (ret == -1)
return ret;
}
prot1 &= PAGE_BITS;
prot_new = prot | prot1;
if (!(flags & MAP_ANONYMOUS)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
#ifndef __APPLE__
if ((flags & MAP_TYPE) == MAP_SHARED &&
#else
if ((flags & MAP_SHARED) &&
#endif
(prot & PROT_WRITE))
return -EINVAL;
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
pread(fd, (void *)start, end - start, offset);
/* put final protection */
if (prot_new != (prot1 | PROT_WRITE))
mprotect((void *)host_start, qemu_host_page_size, prot_new);
} else {
/* just update the protection */
if (prot_new != prot1) {
mprotect((void *)host_start, qemu_host_page_size, prot_new);
}
}
return 0;
}
/* NOTE: all the constants are the HOST ones */
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset)
{
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
static unsigned long last_start = 0x40000000;
#endif
#ifdef DEBUG_MMAP
{
printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
if (flags & MAP_FIXED)
printf("MAP_FIXED ");
if (flags & MAP_ANONYMOUS)
printf("MAP_ANON ");
#ifndef MAP_TYPE
# define MAP_TYPE 0x3
#endif
switch(flags & MAP_TYPE) {
case MAP_PRIVATE:
printf("MAP_PRIVATE ");
break;
case MAP_SHARED:
printf("MAP_SHARED ");
break;
default:
printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
break;
}
printf("fd=%d offset=%lx\n", fd, offset);
}
#endif
if (offset & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return start;
host_start = start & qemu_host_page_mask;
if (!(flags & MAP_FIXED)) {
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
/* tell the kenel to search at the same place as i386 */
if (host_start == 0) {
host_start = last_start;
last_start += HOST_PAGE_ALIGN(len);
}
#endif
if (qemu_host_page_size != qemu_real_host_page_size) {
/* NOTE: this code is only for debugging with '-p' option */
/* reserve a memory area */
host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (host_start == -1)
return host_start;
host_end = host_start + host_len;
start = HOST_PAGE_ALIGN(host_start);
end = start + HOST_PAGE_ALIGN(len);
if (start > host_start)
munmap((void *)host_start, start - host_start);
if (end < host_end)
munmap((void *)end, host_end - end);
/* use it as a fixed mapping */
flags |= MAP_FIXED;
} else {
/* if not fixed, no need to do anything */
host_offset = offset & qemu_host_page_mask;
host_len = len + offset - host_offset;
start = (long)mmap((void *)host_start, host_len,
prot, flags, fd, host_offset);
if (start == -1)
return start;
/* update start so that it points to the file position at 'offset' */
if (!(flags & MAP_ANONYMOUS))
start += offset - host_offset;
goto the_end1;
}
}
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
end = start + len;
host_end = HOST_PAGE_ALIGN(end);
/* worst case: we cannot map the file because the offset is not
aligned, so we read it */
if (!(flags & MAP_ANONYMOUS) &&
(offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
#ifndef __APPLE__
if ((flags & MAP_TYPE) == MAP_SHARED &&
#else
if ((flags & MAP_SHARED) &&
#endif
(prot & PROT_WRITE))
return -EINVAL;
retaddr = target_mmap(start, len, prot | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (retaddr == -1)
return retaddr;
pread(fd, (void *)start, len, offset);
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
if (ret != 0)
return ret;
}
goto the_end;
}
/* handle the start of the mapping */
if (start > host_start) {
if (host_end == host_start + qemu_host_page_size) {
/* one single host page */
ret = mmap_frag(host_start, start, end,
prot, flags, fd, offset);
if (ret == -1)
return ret;
goto the_end1;
}
ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
prot, flags, fd, offset);
if (ret == -1)
return ret;
host_start += qemu_host_page_size;
}
/* handle the end of the mapping */
if (end < host_end) {
ret = mmap_frag(host_end - qemu_host_page_size,
host_end - qemu_host_page_size, host_end,
prot, flags, fd,
offset + host_end - qemu_host_page_size - start);
if (ret == -1)
return ret;
host_end -= qemu_host_page_size;
}
/* map the middle (easier) */
if (host_start < host_end) {
unsigned long offset1;
if (flags & MAP_ANONYMOUS)
offset1 = 0;
else
offset1 = offset + host_start - start;
ret = (long)mmap((void *)host_start, host_end - host_start,
prot, flags, fd, offset1);
if (ret == -1)
return ret;
}
the_end1:
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
printf("target_mmap: ret=0x%lx\n", (long)start);
page_dump(stdout);
printf("\n");
#endif
return start;
}
int target_munmap(unsigned long start, unsigned long len)
{
unsigned long end, host_start, host_end, addr;
int prot, ret;
#ifdef DEBUG_MMAP
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
#endif
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return -EINVAL;
end = start + len;
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot = 0;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (host_end == host_start + qemu_host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
end = host_end;
}
if (prot != 0)
host_start += qemu_host_page_size;
}
if (end < host_end) {
prot = 0;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (prot != 0)
host_end -= qemu_host_page_size;
}
/* unmap what we can */
if (host_start < host_end) {
ret = munmap((void *)host_start, host_end - host_start);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, 0);
return 0;
}
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
blocks which have been allocated starting on a host page */
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr)
{
#ifndef __APPLE__
/* XXX: use 5 args syscall */
new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
if (new_addr == -1)
return new_addr;
prot = page_get_flags(old_addr);
page_set_flags(old_addr, old_addr + old_size, 0);
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
return new_addr;
#else
qerror("target_mremap: unsupported\n");
#endif
}
int target_msync(unsigned long start, unsigned long len, int flags)
{
unsigned long end;
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (end == start)
return 0;
start &= qemu_host_page_mask;
return msync((void *)start, end - start, flags);
}
#ifndef GEMU_H
#define GEMU_H
#include "thunk.h"
#include <signal.h>
#include <string.h>
#include "cpu.h"
#include "gdbstub.h"
typedef siginfo_t target_siginfo_t;
#define target_sigaction sigaction
#ifdef TARGET_I386
struct target_pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
struct target_sigcontext {
int sc_onstack;
int sc_mask;
int sc_eax;
int sc_ebx;
int sc_ecx;
int sc_edx;
int sc_edi;
int sc_esi;
int sc_ebp;
int sc_esp;
int sc_ss;
int sc_eflags;
int sc_eip;
int sc_cs;
int sc_ds;
int sc_es;
int sc_fs;
int sc_gs;
};
#define __USER_CS (0x17)
#define __USER_DS (0x1F)
#elif defined(TARGET_PPC)
struct target_pt_regs {
unsigned long gpr[32];
unsigned long nip;
unsigned long msr;
unsigned long orig_gpr3; /* Used for restarting system calls */
unsigned long ctr;
unsigned long link;
unsigned long xer;
unsigned long ccr;
unsigned long mq; /* 601 only (not used at present) */
/* Used on APUS to hold IPL value. */
unsigned long trap; /* Reason for being here */
unsigned long dar; /* Fault registers */
unsigned long dsisr;
unsigned long result; /* Result of a system call */
};
struct target_sigcontext {
int sc_onstack; /* sigstack state to restore */
int sc_mask; /* signal mask to restore */
int sc_ir; /* pc */
int sc_psw; /* processor status word */
int sc_sp; /* stack pointer if sc_regs == NULL */
void *sc_regs; /* (kernel private) saved state */
};
#endif
typedef struct TaskState {
struct TaskState *next;
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
void syscall_init(void);
long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
long do_unix_syscall(void *cpu_env, int num);
int do_sigaction(int sig, const struct sigaction *act,
struct sigaction *oact);
int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
void qerror(const char *fmt, ...);
void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags);
extern CPUState *global_env;
void cpu_loop(CPUState *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
extern int loglevel;
extern FILE *logfile;
/* commpage.c */
void commpage_init();
void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
/* signal.c */
void process_pending_signals(void *cpu_env);
void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info);
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
long do_sigreturn(CPUState *env, int num);
/* machload.c */
int mach_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs);
/* mmap.c */
int target_mprotect(unsigned long start, unsigned long len, int prot);
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset);
int target_munmap(unsigned long start, unsigned long len);
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr);
int target_msync(unsigned long start, unsigned long len, int flags);
/* user access */
/* XXX: todo protect every memory access */
#define lock_user(x,y,z) (void*)(x)
#define unlock_user(x,y,z)
/* Mac OS X ABI arguments processing */
#ifdef TARGET_I386
static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env)
{
uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i);
*i+=4;
return tswap32(*args);
}
static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env)
{
uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i);
*i+=8;
return tswap64(*args);
}
#elif defined(TARGET_PPC)
static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env)
{
/* XXX: won't work when args goes on stack after gpr10 */
uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]);
*i+=4;
return tswap32(args);
}
static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env)
{
/* XXX: won't work when args goes on stack after gpr10 */
uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]);
*i+=(8 << 8) + 8;
return tswap64(args);
}
#endif
#endif
/*
* Emulation of Linux signals
*
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ucontext.h>
#ifdef __ia64__
#undef uc_mcontext
#undef uc_sigmask
#undef uc_stack
#undef uc_link
#endif
#include <signal.h>
#include "qemu.h"
#define DEBUG_SIGNAL
#define MAX_SIGQUEUE_SIZE 1024
struct sigqueue {
struct sigqueue *next;
target_siginfo_t info;
};
struct emulated_sigaction {
struct target_sigaction sa;
int pending; /* true if signal is pending */
struct sigqueue *first;
struct sigqueue info; /* in order to always have memory for the
first signal, we put it here */
};
struct sigaltstack target_sigaltstack_used = {
0, 0, SA_DISABLE
};
static struct emulated_sigaction sigact_table[NSIG];
static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
static struct sigqueue *first_free; /* first free siginfo queue entry */
static int signal_pending; /* non zero if a signal may be pending */
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
static inline int host_to_target_signal(int sig)
{
return sig;
}
static inline int target_to_host_signal(int sig)
{
return sig;
}
/* siginfo conversion */
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
{
}
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
{
}
void signal_init(void)
{
struct sigaction act;
int i;
/* set all host signal handlers. ALL signals are blocked during
the handlers to serialize them. */
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i < NSIG; i++) {
sigaction(i, &act, NULL);
}
memset(sigact_table, 0, sizeof(sigact_table));
first_free = &sigqueue_table[0];
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
sigqueue_table[i].next = &sigqueue_table[i + 1];
sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
}
/* signal queue handling */
static inline struct sigqueue *alloc_sigqueue(void)
{
struct sigqueue *q = first_free;
if (!q)
return NULL;
first_free = q->next;
return q;
}
static inline void free_sigqueue(struct sigqueue *q)
{
q->next = first_free;
first_free = q;
}
/* abort execution with signal */
void __attribute((noreturn)) force_sig(int sig)
{
int host_sig;
host_sig = target_to_host_signal(sig);
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig));
_exit(-host_sig);
}
/* queue a signal so that it will be send to the virtual CPU as soon
as possible */
int queue_signal(int sig, target_siginfo_t *info)
{
struct emulated_sigaction *k;
struct sigqueue *q, **pq;
target_ulong handler;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "queue_signal: sig=%d\n",
sig);
#endif
k = &sigact_table[sig - 1];
handler = (target_ulong)k->sa.sa_handler;
if (handler == SIG_DFL) {
/* default handler : ignore some signal. The other are fatal */
if (sig != SIGCHLD &&
sig != SIGURG &&
sig != SIGWINCH) {
force_sig(sig);
} else {
return 0; /* indicate ignored */
}
} else if (handler == host_to_target_signal(SIG_IGN)) {
/* ignore signal */
return 0;
} else if (handler == host_to_target_signal(SIG_ERR)) {
force_sig(sig);
} else {
pq = &k->first;
if (!k->pending) {
/* first signal */
q = &k->info;
} else {
q = alloc_sigqueue();
if (!q)
return -EAGAIN;
while (*pq != NULL)
pq = &(*pq)->next;
}
*pq = q;
q->info = *info;
q->next = NULL;
k->pending = 1;
/* signal that a new signal is pending */
signal_pending = 1;
return 1; /* indicates that the signal was queued */
}
}
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc)
{
int sig;
target_siginfo_t tinfo;
/* the CPU emulator uses some host signals to detect exceptions,
we we forward to it some signals */
if (host_signum == SIGSEGV || host_signum == SIGBUS
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|| host_signum == SIGFPE
#endif
) {
if (cpu_signal_handler(host_signum, (void*)info, puc))
return;
}
/* get target signal number */
sig = host_to_target_signal(host_signum);
if (sig < 1 || sig > NSIG)
return;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "qemu: got signal %d\n", sig);
#endif
if (queue_signal(sig, &tinfo) == 1) {
/* interrupt the virtual CPU as soon as possible */
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
}
}
int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
{
/* XXX: test errors */
if(oss)
{
oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
}
if(ss)
{
target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
}
return 0;
}
int do_sigaction(int sig, const struct sigaction *act,
struct sigaction *oact)
{
struct emulated_sigaction *k;
struct sigaction act1;
int host_sig;
if (sig < 1 || sig > NSIG)
return -EINVAL;
k = &sigact_table[sig - 1];
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
sig, (int)act, (int)oact);
#endif
if (oact) {
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
sig, (int)act, (int)oact);
#endif
oact->sa_handler = tswapl(k->sa.sa_handler);
oact->sa_flags = tswapl(k->sa.sa_flags);
oact->sa_mask = tswapl(k->sa.sa_mask);
}
if (act) {
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
act->sa_handler, act->sa_flags, act->sa_mask);
#endif
k->sa.sa_handler = tswapl(act->sa_handler);
k->sa.sa_flags = tswapl(act->sa_flags);
k->sa.sa_mask = tswapl(act->sa_mask);
/* we update the host signal state */
host_sig = target_to_host_signal(sig);
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction handler going to call sigaction\n",
act->sa_handler, act->sa_flags, act->sa_mask);
#endif
sigfillset(&act1.sa_mask);
act1.sa_flags = SA_SIGINFO;
if (k->sa.sa_flags & SA_RESTART)
act1.sa_flags |= SA_RESTART;
/* NOTE: it is important to update the host kernel signal
ignore state to avoid getting unexpected interrupted
syscalls */
if (k->sa.sa_handler == SIG_IGN) {
act1.sa_sigaction = (void *)SIG_IGN;
} else if (k->sa.sa_handler == SIG_DFL) {
act1.sa_sigaction = (void *)SIG_DFL;
} else {
act1.sa_sigaction = host_signal_handler;
}
sigaction(host_sig, &act1, NULL);
}
}
return 0;
}
#ifdef TARGET_I386
static inline void *
get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
{
/* XXX Fix that */
if(target_sigaltstack_used.ss_flags & SA_DISABLE)
{
int esp;
/* Default to using normal stack */
esp = env->regs[R_ESP];
return (void *)((esp - frame_size) & -8ul);
}
else
{
return target_sigaltstack_used.ss_sp;
}
}
static void setup_frame(int sig, struct emulated_sigaction *ka,
void *set, CPUState *env)
{
void *frame;
int i, err = 0;
fprintf(stderr, "setup_frame %d\n", sig);
frame = get_sigframe(ka, env, sizeof(*frame));
/* Set up registers for signal handler */
env->regs[R_ESP] = (unsigned long) frame;
env->eip = (unsigned long) ka->sa.sa_handler;
env->eflags &= ~TF_MASK;
return;
give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
force_sig(SIGSEGV /* , current */);
}
long do_sigreturn(CPUState *env, int num)
{
int i = 0;
struct target_sigcontext *scp = get_int_arg(&i, env);
/* XXX Get current signal number */
/* XXX Adjust accordin to sc_onstack, sc_mask */
if(tswapl(scp->sc_onstack) & 0x1)
target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
else
target_sigaltstack_used.ss_flags &= SA_DISABLE;
int set = tswapl(scp->sc_eax);
sigprocmask(SIG_SETMASK, &set, NULL);
fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
env->regs[R_EAX] = tswapl(scp->sc_eax);
env->regs[R_EBX] = tswapl(scp->sc_ebx);
env->regs[R_ECX] = tswapl(scp->sc_ecx);
env->regs[R_EDX] = tswapl(scp->sc_edx);
env->regs[R_EDI] = tswapl(scp->sc_edi);
env->regs[R_ESI] = tswapl(scp->sc_esi);
env->regs[R_EBP] = tswapl(scp->sc_ebp);
env->regs[R_ESP] = tswapl(scp->sc_esp);
env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
env->eflags = tswapl(scp->sc_eflags);
env->eip = tswapl(scp->sc_eip);
env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
/* Again, because our caller's caller will reset EAX */
return env->regs[R_EAX];
}
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,
void *set, CPUState *env)
{
fprintf(stderr, "setup_frame: not implemented\n");
}
long do_sigreturn(CPUState *env, int num)
{
int i = 0;
struct target_sigcontext *scp = get_int_arg(&i, env);
fprintf(stderr, "do_sigreturn: not implemented\n");
return -ENOSYS;
}
#endif
void process_pending_signals(void *cpu_env)
{
struct emulated_sigaction *k;
struct sigqueue *q;
target_ulong handler;
int sig;
if (!signal_pending)
return;
k = sigact_table;
for(sig = 1; sig <= NSIG; sig++) {
if (k->pending)
goto handle_signal;
k++;
}
/* if no signal is pending, just return */
signal_pending = 0;
return;
handle_signal:
#ifdef DEBUG_SIGNAL
fprintf(stderr, "qemu: process signal %d\n", sig);
#endif
/* dequeue signal */
q = k->first;
k->first = q->next;
if (!k->first)
k->pending = 0;
sig = gdb_handlesig (cpu_env, sig);
if (!sig) {
fprintf (stderr, "Lost signal\n");
abort();
}
handler = k->sa.sa_handler;
if (handler == SIG_DFL) {
/* default handler : ignore some signal. The other are fatal */
if (sig != SIGCHLD &&
sig != SIGURG &&
sig != SIGWINCH) {
force_sig(sig);
}
} else if (handler == SIG_IGN) {
/* ignore sig */
} else if (handler == SIG_ERR) {
force_sig(sig);
} else {
setup_frame(sig, k, 0, cpu_env);
if (k->sa.sa_flags & SA_RESETHAND)
k->sa.sa_handler = SIG_DFL;
}
if (q != &k->info)
free_sigqueue(q);
}
此差异已折叠。
此差异已折叠。
...@@ -810,7 +810,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) ...@@ -810,7 +810,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
goto breakpoint_error; goto breakpoint_error;
} }
break; break;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_LINUX_USER
case 'q': case 'q':
if (strncmp(p, "Offsets", 7) == 0) { if (strncmp(p, "Offsets", 7) == 0) {
TaskState *ts = env->opaque; TaskState *ts = env->opaque;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册