Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
285dc330bd | ||
|
baf8ebf01a | ||
|
9d16dd550e | ||
|
78d6da976c | ||
|
dd6ee15c37 | ||
|
0db634747e | ||
|
6e59c1db89 | ||
|
61382a500a | ||
|
3a51dee658 | ||
|
cc38b844d7 | ||
|
c6105c0a04 | ||
|
93a40ea926 | ||
|
db8d746688 | ||
|
997344f303 | ||
|
16e9b7de41 | ||
|
3486513433 | ||
|
0806e3f66f | ||
|
39b4da28b3 | ||
|
5a67135a0b | ||
|
42f1e0e49b | ||
|
27c3f2cb9b | ||
|
a07cf92aed | ||
|
01e3b763a6 | ||
|
0ae04d7367 | ||
|
ebc054881f | ||
|
a20dd508aa | ||
|
6180a1818a | ||
|
d3eead2eec | ||
|
853d6f7a83 | ||
|
93ac68bca5 | ||
|
1e43adfc89 | ||
|
7a3f194486 | ||
|
2c0262afa7 | ||
|
196ad10903 | ||
|
b7dda06abf |
10
Changelog
10
Changelog
@@ -1,4 +1,4 @@
|
||||
version 0.4.4:
|
||||
version 0.5.0:
|
||||
|
||||
- full hardware level VGA emulation
|
||||
- graphical display with SDL
|
||||
@@ -6,13 +6,19 @@ version 0.4.4:
|
||||
- popw (%esp) fix
|
||||
- mov to/from segment data width fix
|
||||
- added real mode support
|
||||
- added Bochs BIOS and LGPL'ed VGA BIOS loader in vl
|
||||
- added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
|
||||
- m68k host port (Richard Zidlicky)
|
||||
- partial soft MMU support for memory mapped I/Os
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping thru string operations
|
||||
- preliminary SPARC target support (Thomas M. Ogrisegg)
|
||||
- tun-fd option (Rusty Russell)
|
||||
- automatic IDE geometry detection
|
||||
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
||||
- added man page
|
||||
- added full soft mmy mode to launch unpatched OSes.
|
||||
|
||||
version 0.4.3:
|
||||
|
||||
|
47
Makefile
47
Makefile
@@ -4,14 +4,14 @@ CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
TOOLS=vlmkcow
|
||||
TOOLS=qemu-mkcow
|
||||
|
||||
all: dyngen $(TOOLS) qemu-doc.html
|
||||
all: dyngen $(TOOLS) qemu-doc.html qemu.1
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
vlmkcow: vlmkcow.o
|
||||
qemu-mkcow: qemu-mkcow.o
|
||||
$(HOST_CC) -o $@ $^ $(LIBS)
|
||||
|
||||
dyngen: dyngen.o
|
||||
@@ -23,7 +23,7 @@ dyngen: dyngen.o
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.a $(TOOLS) dyngen TAGS
|
||||
rm -f *.o *.a $(TOOLS) dyngen TAGS qemu.pod
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
@@ -37,6 +37,10 @@ distclean: clean
|
||||
install: all
|
||||
mkdir -p $(prefix)/bin
|
||||
install -m 755 -s $(TOOLS) $(prefix)/bin
|
||||
mkdir -p $(sharedir)
|
||||
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin $(sharedir)
|
||||
mkdir -p $(mandir)/man1
|
||||
install qemu.1 $(mandir)/man1
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
@@ -52,39 +56,16 @@ TAGS:
|
||||
qemu-doc.html: qemu-doc.texi
|
||||
texi2html -monolithic -number $<
|
||||
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
configure Makefile Makefile.target \
|
||||
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
elf.h elfload.c main.c signal.c qemu.h \
|
||||
syscall.c syscall_defs.h vm86.c path.c mmap.c \
|
||||
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld m68k.ld \
|
||||
vl.c i386-vl.ld vl.h block.c vlmkcow.c vga.c vga_template.h sdl.c \
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h cpu-defs.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c gdbstub.c bswap.h \
|
||||
cpu-i386.h op-i386.c helper-i386.c helper2-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
|
||||
ops_mem.h softmmu_template.h softmmu_header.h \
|
||||
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
|
||||
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
|
||||
arm-dis.c \
|
||||
tests/Makefile \
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
|
||||
tests/hello-i386.c tests/hello-i386 \
|
||||
tests/hello-arm.c tests/hello-arm \
|
||||
tests/sha1.c \
|
||||
tests/testsig.c tests/testclone.c tests/testthread.c \
|
||||
tests/runcom.c tests/pi_10.com \
|
||||
tests/test_path.c \
|
||||
qemu-doc.texi qemu-doc.html
|
||||
qemu.1: qemu-doc.texi
|
||||
./texi2pod.pl $< qemu.pod
|
||||
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
|
||||
|
||||
FILE=qemu-$(VERSION)
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
tar:
|
||||
rm -rf /tmp/$(FILE)
|
||||
mkdir -p /tmp/$(FILE)
|
||||
cp -P $(FILES) /tmp/$(FILE)
|
||||
cp -r . /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
||||
rm -rf /tmp/$(FILE)
|
||||
|
||||
|
@@ -1,14 +1,30 @@
|
||||
include config.mak
|
||||
|
||||
VPATH=$(SRC_PATH)
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
|
||||
VPATH=$(SRC_PATH):$(TARGET_PATH)
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-I.
|
||||
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen
|
||||
ifndef CONFIG_SOFTMMU
|
||||
PROGS=qemu
|
||||
# user emulator name
|
||||
QEMU_USER=qemu-$(TARGET_ARCH)
|
||||
# system emulator name
|
||||
ifdef CONFIG_SOFTMMU
|
||||
QEMU_SYSTEM=qemu
|
||||
else
|
||||
QEMU_SYSTEM=qemu-fast
|
||||
endif
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
PROGS=$(QEMU_USER)
|
||||
else
|
||||
ifeq ($(ARCH),i386)
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
@@ -31,9 +47,6 @@ else
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
PROGS+=vl
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
@@ -108,13 +121,11 @@ SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
# cpu emulator library
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o
|
||||
LIBOBJS=thunk.o exec.o translate-all.o cpu-exec.o gdbstub.o \
|
||||
translate.o op.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o helper2-i386.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
LIBOBJS+=translate-arm.o op-arm.o
|
||||
LIBOBJS+=helper.o helper2.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
@@ -139,9 +150,9 @@ ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
endif
|
||||
|
||||
all: $(PROGS) qemu-doc.html
|
||||
all: $(PROGS)
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(QEMU_USER): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
@@ -153,17 +164,17 @@ endif
|
||||
VL_OBJS=vl.o block.o vga.o
|
||||
ifdef CONFIG_SDL
|
||||
VL_OBJS+=sdl.o
|
||||
SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl
|
||||
SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm
|
||||
endif
|
||||
|
||||
vl: $(VL_OBJS) libqemu.a
|
||||
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
|
||||
$(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS)
|
||||
|
||||
sdl.o: sdl.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
@@ -171,35 +182,45 @@ libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
translate.o: translate.c gen-op.h opc.h cpu.h
|
||||
|
||||
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
translate-all.o: translate-all.c op.h opc.h cpu.h
|
||||
|
||||
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN)
|
||||
op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -o $@ $<
|
||||
|
||||
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN)
|
||||
opc.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -c -o $@ $<
|
||||
|
||||
gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN)
|
||||
gen-op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -g -o $@ $<
|
||||
|
||||
op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
|
||||
op.o: op.c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
|
||||
helper.o: helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
|
||||
endif
|
||||
|
||||
op-arm.o: op-arm.c op-arm-template.h
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) \
|
||||
gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h op-$(TARGET_ARCH).h
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h
|
||||
|
||||
install: all
|
||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
|
26
README
26
README
@@ -6,35 +6,17 @@ INSTALLATION
|
||||
|
||||
Type
|
||||
|
||||
./configure --interp-prefix=/usr/local/qemu-i386
|
||||
./configure
|
||||
make
|
||||
|
||||
to build qemu and libqemu.a.
|
||||
to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various
|
||||
supported target CPUs).
|
||||
|
||||
Type
|
||||
|
||||
make install
|
||||
|
||||
to install QEMU in /usr/local/bin
|
||||
|
||||
* On x86 you should be able to launch any program by using the
|
||||
libraries installed on your PC. For example:
|
||||
|
||||
./qemu -L / /bin/ls
|
||||
|
||||
* On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
LD_LIBRARY_PATH is not set:
|
||||
|
||||
unset LD_LIBRARY_PATH
|
||||
|
||||
Then you can launch the precompiled 'ls' x86 executable:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
|
||||
You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
|
||||
automatically launched by the Linux kernel when you try to launch x86
|
||||
executables.
|
||||
to install QEMU in /usr/local
|
||||
|
||||
Tested tool versions
|
||||
--------------------
|
||||
|
@@ -6,11 +6,11 @@ x86 binary distribution:
|
||||
|
||||
* wine-20020411 tarball
|
||||
|
||||
./configure --prefix=/usr/local/qemu-i386/wine
|
||||
./configure --prefix=/usr/local/wine-i386
|
||||
|
||||
All exe and libs were stripped. Some compile time tools and the
|
||||
includes were deleted.
|
||||
|
||||
* ldconfig was launched to build the library links:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache
|
||||
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
|
||||
|
9
TODO
9
TODO
@@ -1,17 +1,20 @@
|
||||
- tests for each target CPU
|
||||
- ppc qemu test
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
||||
fix cr0.TS emulation
|
||||
- fix some 16 bit sp push/pop overflow
|
||||
- sysenter/sysexit emulation
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- fix CCOP optimisation
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- add IPC syscalls
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- sysenter/sysexit emulation
|
||||
- add IPC syscalls
|
||||
- SMP support
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- handle rare page fault cases (in particular if page fault in heplers or
|
||||
|
34
configure
vendored
34
configure
vendored
@@ -18,7 +18,7 @@ TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
interp_prefix="/usr/gnemul/qemu-i386"
|
||||
interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
@@ -27,7 +27,7 @@ ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
cpu=`uname -m`
|
||||
target_list="i386 i386-softmmu arm"
|
||||
target_list="i386-user i386 i386-softmmu arm-user sparc-user"
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="i386"
|
||||
@@ -193,7 +193,8 @@ EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
|
||||
echo " use %M for cpu name [$interp_prefix]"
|
||||
echo " --target-list=LIST set target list [$target_list]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
@@ -207,9 +208,14 @@ echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mandir="$prefix/share/man"
|
||||
sharedir="$prefix/share/qemu"
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "Manual directory $mandir"
|
||||
echo "BIOS directory $sharedir"
|
||||
echo "ELF interp prefix $interp_prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
@@ -231,6 +237,9 @@ echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
echo "prefix=$prefix" >> $config_mak
|
||||
echo "mandir=$mandir" >> $config_mak
|
||||
echo "sharedir=$sharedir" >> $config_mak
|
||||
echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h
|
||||
echo "MAKE=$make" >> $config_mak
|
||||
echo "CC=$cc" >> $config_mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
@@ -310,10 +319,15 @@ config_mak=$target_dir/config.mak
|
||||
config_h=$target_dir/config.h
|
||||
target_cpu=`echo $target | cut -d '-' -f 1`
|
||||
target_bigendian="no"
|
||||
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
fi
|
||||
target_user_only="no"
|
||||
if expr $target : '.*-user' > /dev/null ; then
|
||||
target_user_only="yes"
|
||||
fi
|
||||
|
||||
echo "Creating $config_mak, $config_h and $target_dir/Makefile"
|
||||
|
||||
@@ -326,7 +340,9 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
echo "include ../config-host.mak" >> $config_mak
|
||||
echo "#include \"../config-host.h\"" >> $config_h
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $config_h
|
||||
|
||||
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
|
||||
|
||||
if test "$target_cpu" = "i386" ; then
|
||||
echo "TARGET_ARCH=i386" >> $config_mak
|
||||
@@ -336,6 +352,10 @@ elif test "$target_cpu" = "arm" ; then
|
||||
echo "TARGET_ARCH=arm" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $config_h
|
||||
echo "#define TARGET_ARM 1" >> $config_h
|
||||
elif test "$target_cpu" = "sparc" ; then
|
||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||
echo "#define TARGET_SPARC 1" >> $config_h
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
@@ -348,6 +368,10 @@ if test "$target_softmmu" = "yes" ; then
|
||||
echo "CONFIG_SOFTMMU=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTMMU 1" >> $config_h
|
||||
fi
|
||||
if test "$target_user_only" = "yes" ; then
|
||||
echo "CONFIG_USER_ONLY=yes" >> $config_mak
|
||||
echo "#define CONFIG_USER_ONLY 1" >> $config_h
|
||||
fi
|
||||
|
||||
done # for target in $targets
|
||||
|
||||
|
182
cpu-all.h
182
cpu-all.h
@@ -20,18 +20,19 @@
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
/* CPU memory access without any memory or io remapping */
|
||||
|
||||
static inline int ldub_raw(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
static inline int ldsb_raw(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
static inline void stb_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
@@ -42,7 +43,7 @@ static inline void stb(void *ptr, int v)
|
||||
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -54,7 +55,7 @@ static inline int lduw(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -66,7 +67,7 @@ static inline int ldsw(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -78,16 +79,16 @@ static inline int ldl(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
v1 = ldl_raw(p);
|
||||
v2 = ldl_raw(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
@@ -98,7 +99,7 @@ static inline void stw(void *ptr, int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
@@ -111,143 +112,231 @@ static inline void stl(void *ptr, int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
stl_raw(p, (uint32_t)v);
|
||||
stl_raw(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
u.i = ldl_raw(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
stl_raw(ptr, u.i);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.tab[1] = ldl(ptr);
|
||||
u.tab[0] = ldl(ptr + 4);
|
||||
u.tab[1] = ldl_raw(ptr);
|
||||
u.tab[0] = ldl_raw(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.d = v;
|
||||
stl(ptr, u.tab[1]);
|
||||
stl(ptr + 4, u.tab[0]);
|
||||
stl_raw(ptr, u.tab[1]);
|
||||
stl_raw(ptr + 4, u.tab[0]);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
u.i = ldq_raw(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
stq_raw(ptr, u.i);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(TARGET_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)
|
||||
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return (b[0]<<8|b[1]);
|
||||
}
|
||||
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
int8_t *b = (int8_t *) ptr;
|
||||
return (b[0]<<8|b[1]);
|
||||
}
|
||||
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]);
|
||||
}
|
||||
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint32_t a,b;
|
||||
a = ldl (ptr);
|
||||
b = ldl (ptr+4);
|
||||
return (((uint64_t)a<<32)|b);
|
||||
}
|
||||
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
uint8_t *d = (uint8_t *) ptr;
|
||||
d[0] = v >> 8;
|
||||
d[1] = v;
|
||||
}
|
||||
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
uint8_t *d = (uint8_t *) ptr;
|
||||
d[0] = v >> 24;
|
||||
d[1] = v >> 16;
|
||||
d[2] = v >> 8;
|
||||
d[3] = v;
|
||||
}
|
||||
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
stl (ptr, v);
|
||||
stl (ptr+4, v >> 32);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MMU memory access macros */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* if user mode, no other memory access functions */
|
||||
#define ldub(p) ldub_raw(p)
|
||||
#define ldsb(p) ldsb_raw(p)
|
||||
#define lduw(p) lduw_raw(p)
|
||||
#define ldsw(p) ldsw_raw(p)
|
||||
#define ldl(p) ldl_raw(p)
|
||||
#define ldq(p) ldq_raw(p)
|
||||
#define ldfl(p) ldfl_raw(p)
|
||||
#define ldfq(p) ldfq_raw(p)
|
||||
#define stb(p, v) stb_raw(p, v)
|
||||
#define stw(p, v) stw_raw(p, v)
|
||||
#define stl(p, v) stl_raw(p, v)
|
||||
#define stq(p, v) stq_raw(p, v)
|
||||
#define stfl(p, v) stfl_raw(p, v)
|
||||
#define stfq(p, v) stfq_raw(p, v)
|
||||
|
||||
#define ldub_code(p) ldub_raw(p)
|
||||
#define ldsb_code(p) ldsb_raw(p)
|
||||
#define lduw_code(p) lduw_raw(p)
|
||||
#define ldsw_code(p) ldsw_raw(p)
|
||||
#define ldl_code(p) ldl_raw(p)
|
||||
|
||||
#define ldub_kernel(p) ldub_raw(p)
|
||||
#define ldsb_kernel(p) ldsb_raw(p)
|
||||
#define lduw_kernel(p) lduw_raw(p)
|
||||
#define ldsw_kernel(p) ldsw_raw(p)
|
||||
#define ldl_kernel(p) ldl_raw(p)
|
||||
#define stb_kernel(p, v) stb_raw(p, v)
|
||||
#define stw_kernel(p, v) stw_raw(p, v)
|
||||
#define stl_kernel(p, v) stl_raw(p, v)
|
||||
#define stq_kernel(p, v) stq_raw(p, v)
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
@@ -297,6 +386,15 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
#define cpu_interrupt cpu_arm_interrupt
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
#define CPUState CPUSPARCState
|
||||
#define cpu_init cpu_sparc_init
|
||||
#define cpu_exec cpu_sparc_exec
|
||||
#define cpu_gen_code cpu_sparc_gen_code
|
||||
#define cpu_interrupt cpu_sparc_interrupt
|
||||
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported target CPU
|
||||
@@ -318,6 +416,10 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
|
||||
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
|
||||
void cpu_single_step(CPUState *env, int enabled);
|
||||
|
||||
#define CPU_LOG_ALL 1
|
||||
void cpu_set_log(int log_flags);
|
||||
void cpu_set_log_filename(const char *filename);
|
||||
|
||||
/* memory API */
|
||||
|
||||
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
||||
|
11
cpu-defs.h
11
cpu-defs.h
@@ -32,8 +32,15 @@
|
||||
#define CPU_TLB_SIZE 256
|
||||
|
||||
typedef struct CPUTLBEntry {
|
||||
uint32_t address;
|
||||
uint32_t addend;
|
||||
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
|
||||
zone number
|
||||
bit 3 : indicates that the entry is invalid
|
||||
bit 2..0 : zero
|
||||
*/
|
||||
uint32_t address;
|
||||
/* addend to virtual address to get physical address */
|
||||
uint32_t addend;
|
||||
} CPUTLBEntry;
|
||||
|
||||
#endif
|
||||
|
32
cpu-exec.c
32
cpu-exec.c
@@ -18,19 +18,13 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "exec-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "exec-arm.h"
|
||||
#endif
|
||||
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
/* XXX: unify with i386 target */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
@@ -136,6 +130,7 @@ int cpu_exec(CPUState *env1)
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
env->cpsr = psr & ~0xf0000000;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -229,6 +224,8 @@ int cpu_exec(CPUState *env1)
|
||||
env->cpsr = compute_cpsr();
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
env->cpsr &= ~0xf0000000;
|
||||
#elif defined(TARGET_SPARC)
|
||||
cpu_sparc_dump_state (env, logfile, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -246,6 +243,14 @@ int cpu_exec(CPUState *env1)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->regs[15];
|
||||
#elif defined(TARGET_SPARC)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
if (env->npc) {
|
||||
env->pc = env->npc;
|
||||
env->npc = 0;
|
||||
}
|
||||
pc = (uint8_t *) env->pc;
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@@ -268,6 +273,7 @@ int cpu_exec(CPUState *env1)
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
/* XXX: an MMU exception can occur here */
|
||||
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
@@ -358,6 +364,7 @@ int cpu_exec(CPUState *env1)
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
env->cpsr = compute_cpsr();
|
||||
#elif defined(TARGET_SPARC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -450,7 +457,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
return 1;
|
||||
}
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
|
||||
((env->hflags & HF_CPL_MASK) == 3), 0);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
@@ -488,6 +496,12 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
/* XXX: do more */
|
||||
return 0;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
41
disas.c
41
disas.c
@@ -5,6 +5,9 @@
|
||||
#include "elf.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
unsigned int disas_num_syms;
|
||||
void *disas_symtab;
|
||||
@@ -19,14 +22,32 @@ buffer_read_memory (memaddr, myaddr, length, info)
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
static int
|
||||
target_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < length; i++) {
|
||||
myaddr[i] = ldub_code((void *)((long)memaddr + i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
@@ -103,6 +124,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!is_host) {
|
||||
disasm_info.read_memory_func = target_read_memory;
|
||||
}
|
||||
#endif
|
||||
|
||||
disasm_info.buffer = code;
|
||||
disasm_info.buffer_vma = (unsigned long)code;
|
||||
disasm_info.buffer_length = size;
|
||||
@@ -142,6 +169,8 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
|
@@ -79,6 +79,7 @@ void cpu_exec_init(void);
|
||||
int page_unprotect(unsigned long address);
|
||||
void page_unmap(void);
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr);
|
||||
void tlb_flush_page_write(CPUState *env, uint32_t addr);
|
||||
void tlb_flush(CPUState *env);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
@@ -415,3 +416,27 @@ static inline int spin_trylock(spinlock_t *lock)
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
|
||||
#define ACCESS_TYPE 3
|
||||
#define MEMSUFFIX _code
|
||||
#define env cpu_single_env
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
#undef env
|
||||
|
||||
#endif
|
137
exec.c
137
exec.c
@@ -27,13 +27,8 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DEBUG_TB_INVALIDATE
|
||||
//#define DEBUG_FLUSH
|
||||
@@ -83,6 +78,11 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||
static int io_mem_nb;
|
||||
|
||||
/* log support */
|
||||
char *logfilename = "/tmp/qemu.log";
|
||||
FILE *logfile;
|
||||
int loglevel;
|
||||
|
||||
static void page_init(void)
|
||||
{
|
||||
/* NOTE: we can always suppose that host_page_size >=
|
||||
@@ -444,16 +444,20 @@ static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
|
||||
prot = 0;
|
||||
for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
|
||||
prot |= page_get_flags(addr);
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
#endif
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* suppress soft TLB */
|
||||
/* XXX: must flush on all processor with same address space */
|
||||
tlb_flush_page_write(cpu_single_env, host_start);
|
||||
#endif
|
||||
#ifdef DEBUG_TB_INVALIDATE
|
||||
printf("protecting code page: 0x%08lx\n",
|
||||
host_start);
|
||||
#endif
|
||||
p->flags &= ~PAGE_WRITE;
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_page_check();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,6 +487,9 @@ void tb_link(TranslationBlock *tb)
|
||||
if (page_index2 != page_index1) {
|
||||
tb_alloc_page(tb, page_index2);
|
||||
}
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_page_check();
|
||||
#endif
|
||||
tb->jmp_first = (TranslationBlock *)((long)tb | 2);
|
||||
tb->jmp_next[0] = NULL;
|
||||
tb->jmp_next[1] = NULL;
|
||||
@@ -517,20 +524,23 @@ int page_unprotect(unsigned long address)
|
||||
/* if the page was really writable, then we change its
|
||||
protection back to writable */
|
||||
if (prot & PAGE_WRITE_ORG) {
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) | PAGE_WRITE);
|
||||
pindex = (address - host_start) >> TARGET_PAGE_BITS;
|
||||
p1[pindex].flags |= PAGE_WRITE;
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
tb_invalidate_page(address);
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_invalidate_check(address);
|
||||
if (!(p1[pindex].flags & PAGE_WRITE)) {
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) | PAGE_WRITE);
|
||||
#endif
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
p1[pindex].flags |= PAGE_WRITE;
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
tb_invalidate_page(address);
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_invalidate_check(address);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call this function when system calls directly modify a memory area */
|
||||
@@ -681,6 +691,24 @@ void cpu_single_step(CPUState *env, int enabled)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable or disable low levels log */
|
||||
void cpu_set_log(int log_flags)
|
||||
{
|
||||
loglevel = log_flags;
|
||||
if (loglevel && !logfile) {
|
||||
logfile = fopen(logfilename, "w");
|
||||
if (!logfile) {
|
||||
perror(logfilename);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_set_log_filename(const char *filename)
|
||||
{
|
||||
logfilename = strdup(filename);
|
||||
}
|
||||
|
||||
/* mask must never be zero */
|
||||
void cpu_interrupt(CPUState *env, int mask)
|
||||
@@ -716,13 +744,17 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
|
||||
/* unmap all maped pages and flush all associated code */
|
||||
void page_unmap(void)
|
||||
{
|
||||
PageDesc *p, *pmap;
|
||||
unsigned long addr;
|
||||
int i, j, ret, j1;
|
||||
PageDesc *pmap;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
pmap = l1_map[i];
|
||||
if (pmap) {
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
PageDesc *p;
|
||||
unsigned long addr;
|
||||
int j, ret, j1;
|
||||
|
||||
p = pmap;
|
||||
for(j = 0;j < L2_SIZE;) {
|
||||
if (p->flags & PAGE_VALID) {
|
||||
@@ -745,6 +777,7 @@ void page_unmap(void)
|
||||
j++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(pmap);
|
||||
l1_map[i] = NULL;
|
||||
}
|
||||
@@ -755,7 +788,7 @@ void page_unmap(void)
|
||||
|
||||
void tlb_flush(CPUState *env)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int i;
|
||||
for(i = 0; i < CPU_TLB_SIZE; i++) {
|
||||
env->tlb_read[0][i].address = -1;
|
||||
@@ -766,16 +799,38 @@ void tlb_flush(CPUState *env)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
|
||||
{
|
||||
if (addr == (tlb_entry->address &
|
||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)))
|
||||
tlb_entry->address = -1;
|
||||
}
|
||||
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int i;
|
||||
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
env->tlb_read[0][i].address = -1;
|
||||
env->tlb_write[0][i].address = -1;
|
||||
env->tlb_read[1][i].address = -1;
|
||||
env->tlb_write[1][i].address = -1;
|
||||
tlb_flush_entry(&env->tlb_read[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_write[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_read[1][i], addr);
|
||||
tlb_flush_entry(&env->tlb_write[1][i], addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* make all write to page 'addr' trigger a TLB exception to detect
|
||||
self modifying code */
|
||||
void tlb_flush_page_write(CPUState *env, uint32_t addr)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int i;
|
||||
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
tlb_flush_entry(&env->tlb_write[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_write[1][i], addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -882,3 +937,25 @@ int cpu_register_io_memory(int io_index,
|
||||
}
|
||||
return io_index << IO_MEM_SHIFT;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _cmmu
|
||||
#define GETPC() NULL
|
||||
#define env cpu_single_env
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#undef env
|
||||
|
||||
#endif
|
||||
|
26
gdbstub.c
26
gdbstub.c
@@ -28,14 +28,9 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "cpu.h"
|
||||
#include "thunk.h"
|
||||
#include "exec.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
@@ -442,7 +437,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
|
||||
goto breakpoint_error;
|
||||
}
|
||||
break;
|
||||
case 'Q':
|
||||
if (!strncmp(p, "Tinit", 5)) {
|
||||
/* init traces */
|
||||
put_packet("OK");
|
||||
} else if (!strncmp(p, "TStart", 6)) {
|
||||
/* start log (gdb 'tstart' command) */
|
||||
cpu_set_log(CPU_LOG_ALL);
|
||||
put_packet("OK");
|
||||
} else if (!strncmp(p, "TStop", 5)) {
|
||||
/* stop log (gdb 'tstop' command) */
|
||||
cpu_set_log(0);
|
||||
put_packet("OK");
|
||||
} else {
|
||||
goto unknown_command;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
unknown_command:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(buf);
|
||||
|
37
hw/vga.c
37
hw/vga.c
@@ -40,8 +40,8 @@
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
@@ -1109,7 +1109,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
|
||||
{
|
||||
int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
|
||||
int width, height, shift_control, line_offset, page0, page1, bwidth;
|
||||
int disp_width;
|
||||
int disp_width, multi_scan, multi_run;
|
||||
uint8_t *d;
|
||||
uint32_t v, addr1, addr;
|
||||
vga_draw_line_func *vga_draw_line;
|
||||
@@ -1124,10 +1124,13 @@ static void vga_draw_graphic(VGAState *s, int full_update)
|
||||
disp_width = width;
|
||||
|
||||
shift_control = (s->gr[0x05] >> 5) & 3;
|
||||
if (shift_control > 1)
|
||||
double_scan = ((s->cr[0x09] & 0x1f) != 0);
|
||||
else
|
||||
double_scan = (s->cr[0x09] & 0x80);
|
||||
double_scan = (s->cr[0x09] & 0x80);
|
||||
if (shift_control > 1) {
|
||||
multi_scan = (s->cr[0x09] & 0x1f);
|
||||
} else {
|
||||
multi_scan = 0;
|
||||
}
|
||||
multi_run = multi_scan;
|
||||
if (shift_control != s->shift_control ||
|
||||
double_scan != s->double_scan) {
|
||||
full_update = 1;
|
||||
@@ -1212,14 +1215,20 @@ static void vga_draw_graphic(VGAState *s, int full_update)
|
||||
y_start = -1;
|
||||
}
|
||||
}
|
||||
if (!double_scan || (y & 1) != 0) {
|
||||
if (y1 == s->line_compare) {
|
||||
addr1 = 0;
|
||||
} else {
|
||||
mask = (s->cr[0x17] & 3) ^ 3;
|
||||
if ((y1 & mask) == mask)
|
||||
addr1 += line_offset;
|
||||
if (!multi_run) {
|
||||
if (!double_scan || (y & 1) != 0) {
|
||||
if (y1 == s->line_compare) {
|
||||
addr1 = 0;
|
||||
} else {
|
||||
mask = (s->cr[0x17] & 3) ^ 3;
|
||||
if ((y1 & mask) == mask)
|
||||
addr1 += line_offset;
|
||||
}
|
||||
y1++;
|
||||
}
|
||||
multi_run = multi_scan;
|
||||
} else {
|
||||
multi_run--;
|
||||
y1++;
|
||||
}
|
||||
d += linesize;
|
||||
|
@@ -354,7 +354,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw((void *)s);
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
@@ -379,7 +379,7 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw((void *)s);
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
|
261
linux-user/arm/syscall_nr.h
Normal file
261
linux-user/arm/syscall_nr.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall ( 0)
|
||||
#define TARGET_NR_exit ( 1)
|
||||
#define TARGET_NR_fork ( 2)
|
||||
#define TARGET_NR_read ( 3)
|
||||
#define TARGET_NR_write ( 4)
|
||||
#define TARGET_NR_open ( 5)
|
||||
#define TARGET_NR_close ( 6)
|
||||
#define TARGET_NR_waitpid ( 7) /* removed */
|
||||
#define TARGET_NR_creat ( 8)
|
||||
#define TARGET_NR_link ( 9)
|
||||
#define TARGET_NR_unlink ( 10)
|
||||
#define TARGET_NR_execve ( 11)
|
||||
#define TARGET_NR_chdir ( 12)
|
||||
#define TARGET_NR_time ( 13)
|
||||
#define TARGET_NR_mknod ( 14)
|
||||
#define TARGET_NR_chmod ( 15)
|
||||
#define TARGET_NR_lchown ( 16)
|
||||
#define TARGET_NR_break ( 17) /* removed */
|
||||
/* 18 was sys_stat */
|
||||
#define TARGET_NR_lseek ( 19)
|
||||
#define TARGET_NR_getpid ( 20)
|
||||
#define TARGET_NR_mount ( 21)
|
||||
#define TARGET_NR_umount ( 22)
|
||||
#define TARGET_NR_setuid ( 23)
|
||||
#define TARGET_NR_getuid ( 24)
|
||||
#define TARGET_NR_stime ( 25)
|
||||
#define TARGET_NR_ptrace ( 26)
|
||||
#define TARGET_NR_alarm ( 27)
|
||||
|
||||
#define TARGET_NR_pause ( 29)
|
||||
#define TARGET_NR_utime ( 30)
|
||||
#define TARGET_NR_stty ( 31) /* removed */
|
||||
#define TARGET_NR_gtty ( 32) /* removed */
|
||||
#define TARGET_NR_access ( 33)
|
||||
#define TARGET_NR_nice ( 34)
|
||||
#define TARGET_NR_ftime ( 35) /* removed */
|
||||
#define TARGET_NR_sync ( 36)
|
||||
#define TARGET_NR_kill ( 37)
|
||||
#define TARGET_NR_rename ( 38)
|
||||
#define TARGET_NR_mkdir ( 39)
|
||||
#define TARGET_NR_rmdir ( 40)
|
||||
#define TARGET_NR_dup ( 41)
|
||||
#define TARGET_NR_pipe ( 42)
|
||||
#define TARGET_NR_times ( 43)
|
||||
#define TARGET_NR_prof ( 44) /* removed */
|
||||
#define TARGET_NR_brk ( 45)
|
||||
#define TARGET_NR_setgid ( 46)
|
||||
#define TARGET_NR_getgid ( 47)
|
||||
#define TARGET_NR_signal ( 48) /* removed */
|
||||
#define TARGET_NR_geteuid ( 49)
|
||||
#define TARGET_NR_getegid ( 50)
|
||||
#define TARGET_NR_acct ( 51)
|
||||
#define TARGET_NR_umount2 ( 52)
|
||||
#define TARGET_NR_lock ( 53) /* removed */
|
||||
#define TARGET_NR_ioctl ( 54)
|
||||
#define TARGET_NR_fcntl ( 55)
|
||||
#define TARGET_NR_mpx ( 56) /* removed */
|
||||
#define TARGET_NR_setpgid ( 57)
|
||||
#define TARGET_NR_ulimit ( 58) /* removed */
|
||||
/* 59 was sys_olduname */
|
||||
#define TARGET_NR_umask ( 60)
|
||||
#define TARGET_NR_chroot ( 61)
|
||||
#define TARGET_NR_ustat ( 62)
|
||||
#define TARGET_NR_dup2 ( 63)
|
||||
#define TARGET_NR_getppid ( 64)
|
||||
#define TARGET_NR_getpgrp ( 65)
|
||||
#define TARGET_NR_setsid ( 66)
|
||||
#define TARGET_NR_sigaction ( 67)
|
||||
#define TARGET_NR_sgetmask ( 68) /* removed */
|
||||
#define TARGET_NR_ssetmask ( 69) /* removed */
|
||||
#define TARGET_NR_setreuid ( 70)
|
||||
#define TARGET_NR_setregid ( 71)
|
||||
#define TARGET_NR_sigsuspend ( 72)
|
||||
#define TARGET_NR_sigpending ( 73)
|
||||
#define TARGET_NR_sethostname ( 74)
|
||||
#define TARGET_NR_setrlimit ( 75)
|
||||
#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */
|
||||
#define TARGET_NR_getrusage ( 77)
|
||||
#define TARGET_NR_gettimeofday ( 78)
|
||||
#define TARGET_NR_settimeofday ( 79)
|
||||
#define TARGET_NR_getgroups ( 80)
|
||||
#define TARGET_NR_setgroups ( 81)
|
||||
#define TARGET_NR_select ( 82)
|
||||
#define TARGET_NR_symlink ( 83)
|
||||
/* 84 was sys_lstat */
|
||||
#define TARGET_NR_readlink ( 85)
|
||||
#define TARGET_NR_uselib ( 86)
|
||||
#define TARGET_NR_swapon ( 87)
|
||||
#define TARGET_NR_reboot ( 88)
|
||||
#define TARGET_NR_readdir ( 89)
|
||||
#define TARGET_NR_mmap ( 90)
|
||||
#define TARGET_NR_munmap ( 91)
|
||||
#define TARGET_NR_truncate ( 92)
|
||||
#define TARGET_NR_ftruncate ( 93)
|
||||
#define TARGET_NR_fchmod ( 94)
|
||||
#define TARGET_NR_fchown ( 95)
|
||||
#define TARGET_NR_getpriority ( 96)
|
||||
#define TARGET_NR_setpriority ( 97)
|
||||
#define TARGET_NR_profil ( 98) /* removed */
|
||||
#define TARGET_NR_statfs ( 99)
|
||||
#define TARGET_NR_fstatfs (100)
|
||||
#define TARGET_NR_ioperm (101)
|
||||
#define TARGET_NR_socketcall (102)
|
||||
#define TARGET_NR_syslog (103)
|
||||
#define TARGET_NR_setitimer (104)
|
||||
#define TARGET_NR_getitimer (105)
|
||||
#define TARGET_NR_stat (106)
|
||||
#define TARGET_NR_lstat (107)
|
||||
#define TARGET_NR_fstat (108)
|
||||
/* 109 was sys_uname */
|
||||
/* 110 was sys_iopl */
|
||||
#define TARGET_NR_vhangup (111)
|
||||
#define TARGET_NR_idle (112)
|
||||
#define TARGET_NR_syscall (113) /* syscall to call a syscall! */
|
||||
#define TARGET_NR_wait4 (114)
|
||||
#define TARGET_NR_swapoff (115)
|
||||
#define TARGET_NR_sysinfo (116)
|
||||
#define TARGET_NR_ipc (117)
|
||||
#define TARGET_NR_fsync (118)
|
||||
#define TARGET_NR_sigreturn (119)
|
||||
#define TARGET_NR_clone (120)
|
||||
#define TARGET_NR_setdomainname (121)
|
||||
#define TARGET_NR_uname (122)
|
||||
#define TARGET_NR_modify_ldt (123)
|
||||
#define TARGET_NR_adjtimex (124)
|
||||
#define TARGET_NR_mprotect (125)
|
||||
#define TARGET_NR_sigprocmask (126)
|
||||
#define TARGET_NR_create_module (127) /* removed */
|
||||
#define TARGET_NR_init_module (128)
|
||||
#define TARGET_NR_delete_module (129)
|
||||
#define TARGET_NR_get_kernel_syms (130) /* removed */
|
||||
#define TARGET_NR_quotactl (131)
|
||||
#define TARGET_NR_getpgid (132)
|
||||
#define TARGET_NR_fchdir (133)
|
||||
#define TARGET_NR_bdflush (134)
|
||||
#define TARGET_NR_sysfs (135)
|
||||
#define TARGET_NR_personality (136)
|
||||
#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid (138)
|
||||
#define TARGET_NR_setfsgid (139)
|
||||
#define TARGET_NR__llseek (140)
|
||||
#define TARGET_NR_getdents (141)
|
||||
#define TARGET_NR__newselect (142)
|
||||
#define TARGET_NR_flock (143)
|
||||
#define TARGET_NR_msync (144)
|
||||
#define TARGET_NR_readv (145)
|
||||
#define TARGET_NR_writev (146)
|
||||
#define TARGET_NR_getsid (147)
|
||||
#define TARGET_NR_fdatasync (148)
|
||||
#define TARGET_NR__sysctl (149)
|
||||
#define TARGET_NR_mlock (150)
|
||||
#define TARGET_NR_munlock (151)
|
||||
#define TARGET_NR_mlockall (152)
|
||||
#define TARGET_NR_munlockall (153)
|
||||
#define TARGET_NR_sched_setparam (154)
|
||||
#define TARGET_NR_sched_getparam (155)
|
||||
#define TARGET_NR_sched_setscheduler (156)
|
||||
#define TARGET_NR_sched_getscheduler (157)
|
||||
#define TARGET_NR_sched_yield (158)
|
||||
#define TARGET_NR_sched_get_priority_max (159)
|
||||
#define TARGET_NR_sched_get_priority_min (160)
|
||||
#define TARGET_NR_sched_rr_get_interval (161)
|
||||
#define TARGET_NR_nanosleep (162)
|
||||
#define TARGET_NR_mremap (163)
|
||||
#define TARGET_NR_setresuid (164)
|
||||
#define TARGET_NR_getresuid (165)
|
||||
#define TARGET_NR_vm86 (166) /* removed */
|
||||
#define TARGET_NR_query_module (167) /* removed */
|
||||
#define TARGET_NR_poll (168)
|
||||
#define TARGET_NR_nfsservctl (169)
|
||||
#define TARGET_NR_setresgid (170)
|
||||
#define TARGET_NR_getresgid (171)
|
||||
#define TARGET_NR_prctl (172)
|
||||
#define TARGET_NR_rt_sigreturn (173)
|
||||
#define TARGET_NR_rt_sigaction (174)
|
||||
#define TARGET_NR_rt_sigprocmask (175)
|
||||
#define TARGET_NR_rt_sigpending (176)
|
||||
#define TARGET_NR_rt_sigtimedwait (177)
|
||||
#define TARGET_NR_rt_sigqueueinfo (178)
|
||||
#define TARGET_NR_rt_sigsuspend (179)
|
||||
#define TARGET_NR_pread (180)
|
||||
#define TARGET_NR_pwrite (181)
|
||||
#define TARGET_NR_chown (182)
|
||||
#define TARGET_NR_getcwd (183)
|
||||
#define TARGET_NR_capget (184)
|
||||
#define TARGET_NR_capset (185)
|
||||
#define TARGET_NR_sigaltstack (186)
|
||||
#define TARGET_NR_sendfile (187)
|
||||
/* 188 reserved */
|
||||
/* 189 reserved */
|
||||
#define TARGET_NR_vfork (190)
|
||||
#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 (192)
|
||||
#define TARGET_NR_truncate64 (193)
|
||||
#define TARGET_NR_ftruncate64 (194)
|
||||
#define TARGET_NR_stat64 (195)
|
||||
#define TARGET_NR_lstat64 (196)
|
||||
#define TARGET_NR_fstat64 (197)
|
||||
#define TARGET_NR_lchown32 (198)
|
||||
#define TARGET_NR_getuid32 (199)
|
||||
#define TARGET_NR_getgid32 (200)
|
||||
#define TARGET_NR_geteuid32 (201)
|
||||
#define TARGET_NR_getegid32 (202)
|
||||
#define TARGET_NR_setreuid32 (203)
|
||||
#define TARGET_NR_setregid32 (204)
|
||||
#define TARGET_NR_getgroups32 (205)
|
||||
#define TARGET_NR_setgroups32 (206)
|
||||
#define TARGET_NR_fchown32 (207)
|
||||
#define TARGET_NR_setresuid32 (208)
|
||||
#define TARGET_NR_getresuid32 (209)
|
||||
#define TARGET_NR_setresgid32 (210)
|
||||
#define TARGET_NR_getresgid32 (211)
|
||||
#define TARGET_NR_chown32 (212)
|
||||
#define TARGET_NR_setuid32 (213)
|
||||
#define TARGET_NR_setgid32 (214)
|
||||
#define TARGET_NR_setfsuid32 (215)
|
||||
#define TARGET_NR_setfsgid32 (216)
|
||||
#define TARGET_NR_getdents64 (217)
|
||||
#define TARGET_NR_pivot_root (218)
|
||||
#define TARGET_NR_mincore (219)
|
||||
#define TARGET_NR_madvise (220)
|
||||
#define TARGET_NR_fcntl64 (221)
|
||||
/* 222 for tux */
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid (224)
|
||||
#define TARGET_NR_readahead (225)
|
||||
#define TARGET_NR_setxattr (226)
|
||||
#define TARGET_NR_lsetxattr (227)
|
||||
#define TARGET_NR_fsetxattr (228)
|
||||
#define TARGET_NR_getxattr (229)
|
||||
#define TARGET_NR_lgetxattr (230)
|
||||
#define TARGET_NR_fgetxattr (231)
|
||||
#define TARGET_NR_listxattr (232)
|
||||
#define TARGET_NR_llistxattr (233)
|
||||
#define TARGET_NR_flistxattr (234)
|
||||
#define TARGET_NR_removexattr (235)
|
||||
#define TARGET_NR_lremovexattr (236)
|
||||
#define TARGET_NR_fremovexattr (237)
|
||||
#define TARGET_NR_tkill (238)
|
||||
#define TARGET_NR_sendfile64 (239)
|
||||
#define TARGET_NR_futex (240)
|
||||
#define TARGET_NR_sched_setaffinity (241)
|
||||
#define TARGET_NR_sched_getaffinity (242)
|
||||
#define TARGET_NR_io_setup (243)
|
||||
#define TARGET_NR_io_destroy (244)
|
||||
#define TARGET_NR_io_getevents (245)
|
||||
#define TARGET_NR_io_submit (246)
|
||||
#define TARGET_NR_io_cancel (247)
|
||||
#define TARGET_NR_exit_group (248)
|
||||
#define TARGET_NR_lookup_dcookie (249)
|
||||
#define TARGET_NR_epoll_create (250)
|
||||
#define TARGET_NR_epoll_ctl (251)
|
||||
#define TARGET_NR_epoll_wait (252)
|
||||
#define TARGET_NR_remap_file_pages (253)
|
||||
/* 254 for set_thread_area */
|
||||
/* 255 for get_thread_area */
|
||||
/* 256 for set_tid_address */
|
@@ -83,6 +83,27 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_SPARC )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->u_regs[0] = infop->entry;
|
||||
regs->u_regs[1] = infop->start_stack;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
/*
|
||||
@@ -456,18 +477,32 @@ static void set_brk(unsigned long start, unsigned long end)
|
||||
}
|
||||
|
||||
|
||||
/* We need to explicitly zero any fractional pages
|
||||
after the data section (i.e. bss). This would
|
||||
contain the junk from the file that should not
|
||||
be in memory */
|
||||
|
||||
|
||||
/* We need to explicitly zero any fractional pages after the data
|
||||
section (i.e. bss). This would contain the junk from the file that
|
||||
should not be in memory. */
|
||||
static void padzero(unsigned long elf_bss)
|
||||
{
|
||||
unsigned long nbyte;
|
||||
char * fpnt;
|
||||
|
||||
nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */
|
||||
/* XXX: this is really a hack : if the real host page size is
|
||||
smaller than the target page size, some pages after the end
|
||||
of the file may not be mapped. A better fix would be to
|
||||
patch target_mmap(), but it is more complicated as the file
|
||||
size must be known */
|
||||
if (real_host_page_size < host_page_size) {
|
||||
unsigned long end_addr, end_addr1;
|
||||
end_addr1 = (elf_bss + real_host_page_size - 1) &
|
||||
~(real_host_page_size - 1);
|
||||
end_addr = HOST_PAGE_ALIGN(elf_bss);
|
||||
if (end_addr1 < end_addr) {
|
||||
mmap((void *)end_addr1, end_addr - end_addr1,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
nbyte = elf_bss & (host_page_size-1);
|
||||
if (nbyte) {
|
||||
nbyte = host_page_size - nbyte;
|
||||
fpnt = (char *) elf_bss;
|
||||
|
273
linux-user/i386/syscall_nr.h
Normal file
273
linux-user/i386/syscall_nr.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* qemu main
|
||||
* qemu user main
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
|
||||
#ifdef __i386__
|
||||
@@ -38,7 +36,7 @@ static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
|
||||
/* for recent libc, we add these dummies symbol which are not declared
|
||||
/* for recent libc, we add these dummy symbols which are not declared
|
||||
when generating a linked object (bug in ld ?) */
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
long __init_array_start[0];
|
||||
@@ -299,10 +297,37 @@ void cpu_loop(CPUARMState *env)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
||||
void cpu_loop (CPUSPARCState *env)
|
||||
{
|
||||
int trapnr;
|
||||
|
||||
while (1) {
|
||||
trapnr = cpu_sparc_exec (env);
|
||||
|
||||
switch (trapnr) {
|
||||
case 0x8: case 0x10:
|
||||
env->regwptr[0] = do_syscall (env, env->gregs[1],
|
||||
env->regwptr[0], env->regwptr[1], env->regwptr[2],
|
||||
env->regwptr[3], env->regwptr[4], env->regwptr[13]);
|
||||
if (env->regwptr[0] >= 0xffffffe0)
|
||||
env->psr |= PSR_CARRY;
|
||||
break;
|
||||
default:
|
||||
printf ("Invalid trap: %d\n", trapnr);
|
||||
exit (1);
|
||||
}
|
||||
process_pending_signals (env);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu-" TARGET_ARCH " [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
@@ -340,7 +365,9 @@ int main(int argc, char **argv)
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
loglevel = 0;
|
||||
/* init debug */
|
||||
cpu_set_log_filename(DEBUG_LOGFILE);
|
||||
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
if (optind >= argc)
|
||||
@@ -353,7 +380,7 @@ int main(int argc, char **argv)
|
||||
if (!strcmp(r, "-")) {
|
||||
break;
|
||||
} else if (!strcmp(r, "d")) {
|
||||
loglevel = 1;
|
||||
cpu_set_log(CPU_LOG_ALL);
|
||||
} else if (!strcmp(r, "s")) {
|
||||
r = argv[optind++];
|
||||
x86_stack_size = strtol(r, (char **)&r, 0);
|
||||
@@ -380,16 +407,6 @@ int main(int argc, char **argv)
|
||||
usage();
|
||||
filename = argv[optind];
|
||||
|
||||
/* init debug */
|
||||
if (loglevel) {
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
/* Zero out regs */
|
||||
memset(regs, 0, sizeof(struct target_pt_regs));
|
||||
|
||||
@@ -497,6 +514,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
env->cpsr = regs->uregs[16];
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
env->pc = regs->u_regs[0];
|
||||
env->regwptr[6] = regs->u_regs[1]-0x40;
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
@@ -6,15 +6,8 @@
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#include "syscall-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#include "cpu.h"
|
||||
#include "syscall.h"
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
* Basically, it replicates in user space what would be certain
|
||||
|
@@ -67,7 +67,7 @@ static uint8_t host_to_target_signal_table[65] = {
|
||||
[SIGILL] = TARGET_SIGILL,
|
||||
[SIGTRAP] = TARGET_SIGTRAP,
|
||||
[SIGABRT] = TARGET_SIGABRT,
|
||||
[SIGIOT] = TARGET_SIGIOT,
|
||||
/* [SIGIOT] = TARGET_SIGIOT,*/
|
||||
[SIGBUS] = TARGET_SIGBUS,
|
||||
[SIGFPE] = TARGET_SIGFPE,
|
||||
[SIGKILL] = TARGET_SIGKILL,
|
||||
|
7
linux-user/sparc/syscall.h
Normal file
7
linux-user/sparc/syscall.h
Normal file
@@ -0,0 +1,7 @@
|
||||
struct target_pt_regs {
|
||||
target_ulong psr;
|
||||
target_ulong pc;
|
||||
target_ulong npc;
|
||||
target_ulong y;
|
||||
target_ulong u_regs[16];
|
||||
};
|
220
linux-user/sparc/syscall_nr.h
Normal file
220
linux-user/sparc/syscall_nr.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#define TARGET_NR_exit 1 /* Common */
|
||||
#define TARGET_NR_fork 2 /* Common */
|
||||
#define TARGET_NR_read 3 /* Common */
|
||||
#define TARGET_NR_write 4 /* Common */
|
||||
#define TARGET_NR_open 5 /* Common */
|
||||
#define TARGET_NR_close 6 /* Common */
|
||||
#define TARGET_NR_wait4 7 /* Common */
|
||||
#define TARGET_NR_creat 8 /* Common */
|
||||
#define TARGET_NR_link 9 /* Common */
|
||||
#define TARGET_NR_unlink 10 /* Common */
|
||||
#define TARGET_NR_execv 11 /* SunOS Specific */
|
||||
#define TARGET_NR_chdir 12 /* Common */
|
||||
#define TARGET_NR_chown 13 /* Common */
|
||||
#define TARGET_NR_mknod 14 /* Common */
|
||||
#define TARGET_NR_chmod 15 /* Common */
|
||||
#define TARGET_NR_lchown 16 /* Common */
|
||||
#define TARGET_NR_brk 17 /* Common */
|
||||
#define TARGET_NR_perfctr 18 /* Performance counter operations */
|
||||
#define TARGET_NR_lseek 19 /* Common */
|
||||
#define TARGET_NR_getpid 20 /* Common */
|
||||
#define TARGET_NR_capget 21 /* Linux Specific */
|
||||
#define TARGET_NR_capset 22 /* Linux Specific */
|
||||
#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */
|
||||
#define TARGET_NR_getuid 24 /* Common */
|
||||
#define TARGET_NR_ptrace 26 /* Common */
|
||||
#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */
|
||||
#define TARGET_NR_sigaltstack 28 /* Common */
|
||||
#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
|
||||
#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */
|
||||
#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_access 33 /* Common */
|
||||
#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */
|
||||
#define TARGET_NR_chown32 35 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_sync 36 /* Common */
|
||||
#define TARGET_NR_kill 37 /* Common */
|
||||
#define TARGET_NR_stat 38 /* Common */
|
||||
#define TARGET_NR_sendfile 39 /* Linux Specific */
|
||||
#define TARGET_NR_lstat 40 /* Common */
|
||||
#define TARGET_NR_dup 41 /* Common */
|
||||
#define TARGET_NR_pipe 42 /* Common */
|
||||
#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */
|
||||
#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_umount2 45 /* Linux Specific */
|
||||
#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */
|
||||
#define TARGET_NR_getgid 47 /* Common */
|
||||
#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */
|
||||
#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */
|
||||
#define TARGET_NR_getegid 50 /* SunOS calls getgid() */
|
||||
#define TARGET_NR_acct 51 /* Common */
|
||||
#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_ioctl 54 /* Common */
|
||||
#define TARGET_NR_reboot 55 /* Common */
|
||||
#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_symlink 57 /* Common */
|
||||
#define TARGET_NR_readlink 58 /* Common */
|
||||
#define TARGET_NR_execve 59 /* Common */
|
||||
#define TARGET_NR_umask 60 /* Common */
|
||||
#define TARGET_NR_chroot 61 /* Common */
|
||||
#define TARGET_NR_fstat 62 /* Common */
|
||||
#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_getpagesize 64 /* Common */
|
||||
#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */
|
||||
#define TARGET_NR_vfork 66 /* Common */
|
||||
#define TARGET_NR_pread 67 /* Linux Specific */
|
||||
#define TARGET_NR_pwrite 68 /* Linux Specific */
|
||||
#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
|
||||
#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
|
||||
#define TARGET_NR_mmap 71 /* Common */
|
||||
#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
|
||||
#define TARGET_NR_munmap 73 /* Common */
|
||||
#define TARGET_NR_mprotect 74 /* Common */
|
||||
#define TARGET_NR_madvise 75 /* Common */
|
||||
#define TARGET_NR_vhangup 76 /* Common */
|
||||
#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_mincore 78 /* Common */
|
||||
#define TARGET_NR_getgroups 79 /* Common */
|
||||
#define TARGET_NR_setgroups 80 /* Common */
|
||||
#define TARGET_NR_getpgrp 81 /* Common */
|
||||
#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
|
||||
#define TARGET_NR_setitimer 83 /* Common */
|
||||
#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_swapon 85 /* Common */
|
||||
#define TARGET_NR_getitimer 86 /* Common */
|
||||
#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
|
||||
#define TARGET_NR_sethostname 88 /* Common */
|
||||
#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
|
||||
#define TARGET_NR_dup2 90 /* Common */
|
||||
#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
|
||||
#define TARGET_NR_fcntl 92 /* Common */
|
||||
#define TARGET_NR_select 93 /* Common */
|
||||
#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
|
||||
#define TARGET_NR_fsync 95 /* Common */
|
||||
#define TARGET_NR_setpriority 96 /* Common */
|
||||
#define TARGET_NR_socket 97 /* Common */
|
||||
#define TARGET_NR_connect 98 /* Common */
|
||||
#define TARGET_NR_accept 99 /* Common */
|
||||
#define TARGET_NR_getpriority 100 /* Common */
|
||||
#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigaction 102 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigpending 104 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */
|
||||
#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
|
||||
#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
|
||||
#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
|
||||
#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
|
||||
#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
|
||||
#define TARGET_NR_recvmsg 113 /* Common */
|
||||
#define TARGET_NR_sendmsg 114 /* Common */
|
||||
#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
|
||||
#define TARGET_NR_gettimeofday 116 /* Common */
|
||||
#define TARGET_NR_getrusage 117 /* Common */
|
||||
#define TARGET_NR_getsockopt 118 /* Common */
|
||||
#define TARGET_NR_getcwd 119 /* Linux Specific */
|
||||
#define TARGET_NR_readv 120 /* Common */
|
||||
#define TARGET_NR_writev 121 /* Common */
|
||||
#define TARGET_NR_settimeofday 122 /* Common */
|
||||
#define TARGET_NR_fchown 123 /* Common */
|
||||
#define TARGET_NR_fchmod 124 /* Common */
|
||||
#define TARGET_NR_recvfrom 125 /* Common */
|
||||
#define TARGET_NR_setreuid 126 /* Common */
|
||||
#define TARGET_NR_setregid 127 /* Common */
|
||||
#define TARGET_NR_rename 128 /* Common */
|
||||
#define TARGET_NR_truncate 129 /* Common */
|
||||
#define TARGET_NR_ftruncate 130 /* Common */
|
||||
#define TARGET_NR_flock 131 /* Common */
|
||||
#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_sendto 133 /* Common */
|
||||
#define TARGET_NR_shutdown 134 /* Common */
|
||||
#define TARGET_NR_socketpair 135 /* Common */
|
||||
#define TARGET_NR_mkdir 136 /* Common */
|
||||
#define TARGET_NR_rmdir 137 /* Common */
|
||||
#define TARGET_NR_utimes 138 /* SunOS Specific */
|
||||
#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_getpeername 141 /* Common */
|
||||
#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_getrlimit 144 /* Common */
|
||||
#define TARGET_NR_setrlimit 145 /* Common */
|
||||
#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
|
||||
#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_getsockname 150 /* Common */
|
||||
#define TARGET_NR_poll 153 /* Common */
|
||||
#define TARGET_NR_getdents64 154 /* Linux specific */
|
||||
#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_statfs 157 /* Common */
|
||||
#define TARGET_NR_fstatfs 158 /* Common */
|
||||
#define TARGET_NR_umount 159 /* Common */
|
||||
#define TARGET_NR_getdomainname 162 /* SunOS Specific */
|
||||
#define TARGET_NR_setdomainname 163 /* Common */
|
||||
#define TARGET_NR_quotactl 165 /* Common */
|
||||
#define TARGET_NR_mount 167 /* Common */
|
||||
#define TARGET_NR_ustat 168 /* Common */
|
||||
#define TARGET_NR_getdents 174 /* Common */
|
||||
#define TARGET_NR_setsid 175 /* Common */
|
||||
#define TARGET_NR_fchdir 176 /* Common */
|
||||
#define TARGET_NR_sigpending 183 /* Common */
|
||||
#define TARGET_NR_query_module 184 /* Linux Specific */
|
||||
#define TARGET_NR_setpgid 185 /* Common */
|
||||
#define TARGET_NR_tkill 187 /* SunOS: fpathconf */
|
||||
#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
|
||||
#define TARGET_NR_uname 189 /* Linux Specific */
|
||||
#define TARGET_NR_init_module 190 /* Linux Specific */
|
||||
#define TARGET_NR_personality 191 /* Linux Specific */
|
||||
#define TARGET_NR_getppid 197 /* Linux Specific */
|
||||
#define TARGET_NR_sigaction 198 /* Linux Specific */
|
||||
#define TARGET_NR_sgetmask 199 /* Linux Specific */
|
||||
#define TARGET_NR_ssetmask 200 /* Linux Specific */
|
||||
#define TARGET_NR_sigsuspend 201 /* Linux Specific */
|
||||
#define TARGET_NR_oldlstat 202 /* Linux Specific */
|
||||
#define TARGET_NR_uselib 203 /* Linux Specific */
|
||||
#define TARGET_NR_readdir 204 /* Linux Specific */
|
||||
#define TARGET_NR_readahead 205 /* Linux Specific */
|
||||
#define TARGET_NR_socketcall 206 /* Linux Specific */
|
||||
#define TARGET_NR_syslog 207 /* Linux Specific */
|
||||
#define TARGET_NR_waitpid 212 /* Linux Specific */
|
||||
#define TARGET_NR_swapoff 213 /* Linux Specific */
|
||||
#define TARGET_NR_sysinfo 214 /* Linux Specific */
|
||||
#define TARGET_NR_ipc 215 /* Linux Specific */
|
||||
#define TARGET_NR_sigreturn 216 /* Linux Specific */
|
||||
#define TARGET_NR_clone 217 /* Linux Specific */
|
||||
#define TARGET_NR_adjtimex 219 /* Linux Specific */
|
||||
#define TARGET_NR_sigprocmask 220 /* Linux Specific */
|
||||
#define TARGET_NR_create_module 221 /* Linux Specific */
|
||||
#define TARGET_NR_delete_module 222 /* Linux Specific */
|
||||
#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */
|
||||
#define TARGET_NR_getpgid 224 /* Linux Specific */
|
||||
#define TARGET_NR_bdflush 225 /* Linux Specific */
|
||||
#define TARGET_NR_sysfs 226 /* Linux Specific */
|
||||
#define TARGET_NR_afs_syscall 227 /* Linux Specific */
|
||||
#define TARGET_NR_setfsuid 228 /* Linux Specific */
|
||||
#define TARGET_NR_setfsgid 229 /* Linux Specific */
|
||||
#define TARGET_NR__newselect 230 /* Linux Specific */
|
||||
#define TARGET_NR_time 231 /* Linux Specific */
|
||||
#define TARGET_NR_stime 233 /* Linux Specific */
|
||||
#define TARGET_NR__llseek 236 /* Linux Specific */
|
||||
#define TARGET_NR_mlock 237
|
||||
#define TARGET_NR_munlock 238
|
||||
#define TARGET_NR_mlockall 239
|
||||
#define TARGET_NR_munlockall 240
|
||||
#define TARGET_NR_sched_setparam 241
|
||||
#define TARGET_NR_sched_getparam 242
|
||||
#define TARGET_NR_sched_setscheduler 243
|
||||
#define TARGET_NR_sched_getscheduler 244
|
||||
#define TARGET_NR_sched_yield 245
|
||||
#define TARGET_NR_sched_get_priority_max 246
|
||||
#define TARGET_NR_sched_get_priority_min 247
|
||||
#define TARGET_NR_sched_rr_get_interval 248
|
||||
#define TARGET_NR_nanosleep 249
|
||||
#define TARGET_NR_mremap 250
|
||||
#define TARGET_NR__sysctl 251
|
||||
#define TARGET_NR_getsid 252
|
||||
#define TARGET_NR_fdatasync 253
|
||||
#define TARGET_NR_nfsservctl 254
|
||||
#define TARGET_NR_aplib 255
|
||||
#define TARGET_NR__exit TARGET_NR_exit
|
@@ -41,6 +41,7 @@
|
||||
#include <sys/uio.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/times.h>
|
||||
#include <utime.h>
|
||||
//#include <sys/user.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
@@ -1262,6 +1263,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
|
||||
newsp = env->regs[13];
|
||||
new_env->regs[13] = newsp;
|
||||
new_env->regs[0] = 0;
|
||||
#elif defined(TARGET_SPARC)
|
||||
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -1472,10 +1475,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_lchown:
|
||||
ret = get_errno(chown((const char *)arg1, arg2, arg3));
|
||||
break;
|
||||
#ifdef TARGET_NR_break
|
||||
case TARGET_NR_break:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_oldstat
|
||||
case TARGET_NR_oldstat:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_lseek:
|
||||
ret = get_errno(lseek(arg1, arg2, arg3));
|
||||
break;
|
||||
@@ -1507,25 +1514,40 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_alarm:
|
||||
ret = alarm(arg1);
|
||||
break;
|
||||
#ifdef TARGET_NR_oldfstat
|
||||
case TARGET_NR_oldfstat:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_pause:
|
||||
ret = get_errno(pause());
|
||||
break;
|
||||
case TARGET_NR_utime:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct utimbuf tbuf;
|
||||
struct target_utimbuf *target_tbuf = (void *)arg2;
|
||||
tbuf.actime = tswapl(target_tbuf->actime);
|
||||
tbuf.modtime = tswapl(target_tbuf->modtime);
|
||||
ret = get_errno(utime((const char *)arg1, &tbuf));
|
||||
}
|
||||
break;
|
||||
#ifdef TARGET_NR_stty
|
||||
case TARGET_NR_stty:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_gtty
|
||||
case TARGET_NR_gtty:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_access:
|
||||
ret = get_errno(access((const char *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_nice:
|
||||
ret = get_errno(nice(arg1));
|
||||
break;
|
||||
#ifdef TARGET_NR_ftime
|
||||
case TARGET_NR_ftime:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_sync:
|
||||
sync();
|
||||
ret = 0;
|
||||
@@ -1570,8 +1592,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
ret = host_to_target_clock_t(ret);
|
||||
}
|
||||
break;
|
||||
#ifdef TARGET_NR_prof
|
||||
case TARGET_NR_prof:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_setgid:
|
||||
ret = get_errno(setgid(low2highgid(arg1)));
|
||||
break;
|
||||
@@ -1591,23 +1615,31 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_umount2:
|
||||
ret = get_errno(umount2((const char *)arg1, arg2));
|
||||
break;
|
||||
#ifdef TARGET_NR_lock
|
||||
case TARGET_NR_lock:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_ioctl:
|
||||
ret = do_ioctl(arg1, arg2, arg3);
|
||||
break;
|
||||
case TARGET_NR_fcntl:
|
||||
ret = get_errno(do_fcntl(arg1, arg2, arg3));
|
||||
break;
|
||||
#ifdef TARGET_NR_mpx
|
||||
case TARGET_NR_mpx:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_setpgid:
|
||||
ret = get_errno(setpgid(arg1, arg2));
|
||||
break;
|
||||
#ifdef TARGET_NR_ulimit
|
||||
case TARGET_NR_ulimit:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_oldolduname
|
||||
case TARGET_NR_oldolduname:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_umask:
|
||||
ret = get_errno(umask(arg1));
|
||||
break;
|
||||
@@ -1917,8 +1949,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_symlink:
|
||||
ret = get_errno(symlink((const char *)arg1, (const char *)arg2));
|
||||
break;
|
||||
#ifdef TARGET_NR_oldlstat
|
||||
case TARGET_NR_oldlstat:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_readlink:
|
||||
ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3));
|
||||
break;
|
||||
@@ -2001,8 +2035,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_setpriority:
|
||||
ret = get_errno(setpriority(arg1, arg2, arg3));
|
||||
break;
|
||||
#ifdef TARGET_NR_profil
|
||||
case TARGET_NR_profil:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_statfs:
|
||||
stfs = (void *)arg2;
|
||||
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
|
||||
@@ -2024,8 +2060,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
stfs = (void *)arg2;
|
||||
ret = get_errno(sys_fstatfs(arg1, stfs));
|
||||
goto convert_statfs;
|
||||
#ifdef TARGET_NR_ioperm
|
||||
case TARGET_NR_ioperm:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_socketcall:
|
||||
ret = do_socketcall(arg1, (int32_t *)arg2);
|
||||
break;
|
||||
@@ -2097,15 +2135,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifdef TARGET_NR_olduname
|
||||
case TARGET_NR_olduname:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_iopl
|
||||
case TARGET_NR_iopl:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_vhangup:
|
||||
ret = get_errno(vhangup());
|
||||
break;
|
||||
#ifdef TARGET_NR_idle
|
||||
case TARGET_NR_idle:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_wait4:
|
||||
{
|
||||
int status;
|
||||
@@ -2415,17 +2459,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
req.tv_sec = tswapl(target_req->tv_sec);
|
||||
req.tv_nsec = tswapl(target_req->tv_nsec);
|
||||
ret = get_errno(nanosleep(&req, &rem));
|
||||
if (target_rem) {
|
||||
if (is_error(ret) && target_rem) {
|
||||
target_rem->tv_sec = tswapl(rem.tv_sec);
|
||||
target_rem->tv_nsec = tswapl(rem.tv_nsec);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifdef TARGET_NR_setresuid
|
||||
case TARGET_NR_setresuid:
|
||||
ret = get_errno(setresuid(low2highuid(arg1),
|
||||
low2highuid(arg2),
|
||||
low2highuid(arg3)));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresuid
|
||||
case TARGET_NR_getresuid:
|
||||
{
|
||||
int ruid, euid, suid;
|
||||
@@ -2437,11 +2484,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresgid
|
||||
case TARGET_NR_setresgid:
|
||||
ret = get_errno(setresgid(low2highgid(arg1),
|
||||
low2highgid(arg2),
|
||||
low2highgid(arg3)));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresgid
|
||||
case TARGET_NR_getresgid:
|
||||
{
|
||||
int rgid, egid, sgid;
|
||||
@@ -2453,6 +2504,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_query_module:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_nfsservctl:
|
||||
@@ -2480,13 +2532,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
goto unimplemented;
|
||||
case TARGET_NR_sendfile:
|
||||
goto unimplemented;
|
||||
#ifdef TARGET_NR_getpmsg
|
||||
case TARGET_NR_getpmsg:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_putpmsg
|
||||
case TARGET_NR_putpmsg:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_vfork:
|
||||
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
|
||||
break;
|
||||
#ifdef TARGET_NR_ugetrlimit
|
||||
case TARGET_NR_ugetrlimit:
|
||||
{
|
||||
struct rlimit rlim;
|
||||
@@ -2498,6 +2555,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TARGET_NR_truncate64:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_ftruncate64:
|
||||
@@ -2647,13 +2705,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef TARGET_NR_security
|
||||
case TARGET_NR_security:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_gettid:
|
||||
ret = get_errno(gettid());
|
||||
break;
|
||||
case TARGET_NR_readahead:
|
||||
goto unimplemented;
|
||||
#ifdef TARGET_NR_setxattr
|
||||
case TARGET_NR_setxattr:
|
||||
case TARGET_NR_lsetxattr:
|
||||
case TARGET_NR_fsetxattr:
|
||||
@@ -2667,9 +2728,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_lremovexattr:
|
||||
case TARGET_NR_fremovexattr:
|
||||
goto unimplemented_nowarn;
|
||||
#endif
|
||||
#ifdef TARGET_NR_set_thread_area
|
||||
case TARGET_NR_set_thread_area:
|
||||
case TARGET_NR_get_thread_area:
|
||||
goto unimplemented_nowarn;
|
||||
#endif
|
||||
default:
|
||||
unimplemented:
|
||||
gemu_log("qemu: Unsupported syscall: %d\n", num);
|
||||
|
@@ -4,284 +4,7 @@
|
||||
most of them stay the same, so we handle it by puting ifdefs if
|
||||
necessary */
|
||||
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
#define TARGET_NR_getdents64 217
|
||||
#define TARGET_NR_pivot_root 218
|
||||
#define TARGET_NR_mincore 219
|
||||
#define TARGET_NR_madvise 220
|
||||
#endif
|
||||
|
||||
#define TARGET_NR_fcntl64 221
|
||||
#define TARGET_NR_security 223 /* syscall for security modules */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
#include "syscall_nr.h"
|
||||
|
||||
#define SOCKOP_socket 1
|
||||
#define SOCKOP_bind 2
|
||||
@@ -321,7 +44,7 @@
|
||||
#define TARGET_IOC_WRITE 1U
|
||||
#define TARGET_IOC_READ 2U
|
||||
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC)
|
||||
|
||||
#define TARGET_IOC_SIZEBITS 13
|
||||
#define TARGET_IOC_DIRBITS 3
|
||||
@@ -392,6 +115,11 @@ struct target_tms {
|
||||
target_clock_t tms_cstime;
|
||||
};
|
||||
|
||||
struct target_utimbuf {
|
||||
target_long actime;
|
||||
target_long modtime;
|
||||
};
|
||||
|
||||
struct target_sel_arg_struct {
|
||||
target_long n;
|
||||
target_long inp, outp, exp;
|
||||
@@ -551,7 +279,7 @@ struct target_sigaction;
|
||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact);
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
@@ -936,7 +664,7 @@ struct target_pollfd {
|
||||
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
|
||||
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
|
||||
/* 0x54 is just a magic number to make these relatively unique ('T') */
|
||||
|
||||
|
4
pc-bios/README
Normal file
4
pc-bios/README
Normal file
@@ -0,0 +1,4 @@
|
||||
- The PC BIOS comes from the Bochs project
|
||||
(http://bochs.sourceforge.net/).
|
||||
- The VGA BIOS comes from the LGPL VGA bios project
|
||||
(http://www.nongnu.org/vgabios/).
|
BIN
pc-bios/bios.bin
Normal file
BIN
pc-bios/bios.bin
Normal file
Binary file not shown.
BIN
pc-bios/vgabios.bin
Normal file
BIN
pc-bios/vgabios.bin
Normal file
Binary file not shown.
259
qemu-doc.texi
259
qemu-doc.texi
@@ -1,11 +1,13 @@
|
||||
\input texinfo @c -*- texinfo -*-
|
||||
|
||||
@iftex
|
||||
@settitle QEMU CPU Emulator Reference Documentation
|
||||
@titlepage
|
||||
@sp 7
|
||||
@center @titlefont{QEMU CPU Emulator Reference Documentation}
|
||||
@sp 3
|
||||
@end titlepage
|
||||
@end iftex
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
@@ -16,14 +18,18 @@ achieves a reasonnable speed while being easy to port on new host
|
||||
CPUs.
|
||||
|
||||
QEMU has two operating modes:
|
||||
@itemize
|
||||
@item User mode emulation. In this mode, QEMU can launch Linux processes
|
||||
|
||||
@itemize @minus
|
||||
|
||||
@item
|
||||
User mode emulation. In this mode, QEMU can launch Linux processes
|
||||
compiled for one CPU on another CPU. Linux system calls are converted
|
||||
because of endianness and 32/64 bit mismatches. The Wine Windows API
|
||||
emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator
|
||||
(@url{www.dosemu.org}) are the main targets for QEMU.
|
||||
|
||||
@item Full system emulation. In this mode, QEMU emulates a full
|
||||
@item
|
||||
Full system emulation. In this mode, QEMU emulates a full
|
||||
system, including a processor and various peripherials. Currently, it
|
||||
is only used to launch an x86 Linux kernel on an x86 Linux system. It
|
||||
enables easier testing and debugging of system code. It can also be
|
||||
@@ -66,7 +72,7 @@ QEMU user mode emulation features:
|
||||
|
||||
QEMU full system emulation features:
|
||||
@itemize
|
||||
@item Using mmap() system calls to simulate the MMU
|
||||
@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU.
|
||||
@end itemize
|
||||
|
||||
@section x86 emulation
|
||||
@@ -104,14 +110,7 @@ memory access.
|
||||
10 byte @code{long double}s of x86 for floating point emulation to get
|
||||
maximum performances.
|
||||
|
||||
@item Full system emulation only works if no data are mapped above the virtual address
|
||||
0xc0000000 (yet).
|
||||
|
||||
@item Some priviledged instructions or behaviors are missing. Only the ones
|
||||
needed for proper Linux kernel operation are emulated.
|
||||
|
||||
@item No memory separation between the kernel and the user processes is done.
|
||||
It will be implemented very soon.
|
||||
@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet).
|
||||
|
||||
@end itemize
|
||||
|
||||
@@ -128,6 +127,10 @@ generic dynamic code generation architecture of QEMU.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section SPARC emulation
|
||||
|
||||
The SPARC emulation is currently in development.
|
||||
|
||||
@chapter QEMU User space emulator invocation
|
||||
|
||||
@section Quick Start
|
||||
@@ -144,7 +147,7 @@ itself and all the target (x86) dynamic libraries used by it.
|
||||
libraries:
|
||||
|
||||
@example
|
||||
qemu -L / /bin/ls
|
||||
qemu-i386 -L / /bin/ls
|
||||
@end example
|
||||
|
||||
@code{-L /} tells that the x86 dynamic linker must be searched with a
|
||||
@@ -153,7 +156,7 @@ qemu -L / /bin/ls
|
||||
@item Since QEMU is also a linux process, you can launch qemu with qemu:
|
||||
|
||||
@example
|
||||
qemu -L / qemu -L / /bin/ls
|
||||
qemu-i386 -L / qemu-i386 -L / /bin/ls
|
||||
@end example
|
||||
|
||||
@item On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
@@ -167,16 +170,16 @@ unset LD_LIBRARY_PATH
|
||||
Then you can launch the precompiled @file{ls} x86 executable:
|
||||
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
qemu-i386 tests/i386/ls
|
||||
@end example
|
||||
You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that
|
||||
You can look at @file{qemu-binfmt-conf.sh} so that
|
||||
QEMU is automatically launched by the Linux kernel when you try to
|
||||
launch x86 executables. It requires the @code{binfmt_misc} module in the
|
||||
Linux kernel.
|
||||
|
||||
@item The x86 version of QEMU is also included. You can try weird things such as:
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
@@ -190,7 +193,7 @@ distribution (see previous section). In order to verify it, you must be
|
||||
able to do:
|
||||
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@item Download the binary x86 Wine install
|
||||
@@ -203,7 +206,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
@item Then you can try the example @file{putty.exe}:
|
||||
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
|
||||
qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
@@ -211,7 +214,7 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil
|
||||
@section Command line options
|
||||
|
||||
@example
|
||||
usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]
|
||||
usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
|
||||
@end example
|
||||
|
||||
@table @option
|
||||
@@ -234,20 +237,80 @@ Act as if the host page size was 'pagesize' bytes
|
||||
|
||||
@chapter QEMU System emulator invocation
|
||||
|
||||
@section Introduction
|
||||
|
||||
@c man begin DESCRIPTION
|
||||
|
||||
The QEMU System emulator simulates a complete PC. It can either boot
|
||||
directly a Linux kernel (without any BIOS or boot loader) or boot like a
|
||||
real PC with the included BIOS.
|
||||
|
||||
In order to meet specific user needs, two versions of QEMU are
|
||||
available:
|
||||
|
||||
@enumerate
|
||||
|
||||
@item
|
||||
@code{qemu-fast} uses the host Memory Management Unit (MMU) to simulate
|
||||
the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB
|
||||
address space cannot be used and some memory mapped peripherials
|
||||
cannot be emulated accurately yet. Therefore, a specific Linux kernel
|
||||
must be used (@xref{linux_compile}).
|
||||
|
||||
@item
|
||||
@code{qemu} uses a software MMU. It is about @emph{two times
|
||||
slower} but gives a more accurate emulation.
|
||||
|
||||
@end enumerate
|
||||
|
||||
QEMU emulates the following PC peripherials:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
VGA (hardware level, including all non standard modes)
|
||||
@item
|
||||
PS/2 mouse and keyboard
|
||||
@item
|
||||
IDE disk interface (port=0x1f0, irq=14)
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
Serial port (port=0x3f8, irq=4)
|
||||
@item
|
||||
PIC (interrupt controler)
|
||||
@item
|
||||
PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@end itemize
|
||||
|
||||
@c man end
|
||||
|
||||
@section Quick Start
|
||||
|
||||
This section explains how to launch a Linux kernel inside QEMU.
|
||||
Download and uncompress the linux image (@file{linux.img}) and type:
|
||||
|
||||
@example
|
||||
qemu linux.img
|
||||
@end example
|
||||
|
||||
Linux should boot and give you a prompt.
|
||||
|
||||
@section Direct Linux Boot and Network emulation
|
||||
|
||||
This section explains how to launch a Linux kernel inside QEMU without
|
||||
having to make a full bootable image. It is very useful for fast Linux
|
||||
kernel testing. The QEMU network configuration is also explained.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image. The archive also contains a precompiled
|
||||
version of @file{vl}, the QEMU System emulator.
|
||||
Download the archive @file{linux-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image.
|
||||
|
||||
@item Optional: If you want network support (for example to launch X11 examples), you
|
||||
must copy the script @file{vl-ifup} in @file{/etc} and configure
|
||||
must copy the script @file{qemu-ifup} in @file{/etc} and configure
|
||||
properly @code{sudo} so that the command @code{ifconfig} contained in
|
||||
@file{vl-ifup} can be executed as root. You must verify that your host
|
||||
@file{qemu-ifup} can be executed as root. You must verify that your host
|
||||
kernel supports the TUN/TAP network interfaces: the device
|
||||
@file{/dev/net/tun} must be present.
|
||||
|
||||
@@ -256,10 +319,10 @@ the host kernel and the emulated kernel. The emulated kernel is seen
|
||||
from the host kernel at IP address 172.20.0.2 and the host kernel is
|
||||
seen from the emulated kernel at IP address 172.20.0.1.
|
||||
|
||||
@item Launch @code{vl.sh}. You should have the following output:
|
||||
@item Launch @code{qemu.sh}. You should have the following output:
|
||||
|
||||
@example
|
||||
> ./vl.sh
|
||||
> ./qemu.sh
|
||||
connected to host network interface: tun0
|
||||
Uncompressing Linux... Ok, booting the kernel.
|
||||
Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003
|
||||
@@ -349,11 +412,11 @@ a real Virtual Linux system !
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
A 2.5.74 kernel is also included in the vl-test archive. Just
|
||||
replace the bzImage in vl.sh to try it.
|
||||
A 2.5.74 kernel is also included in the archive. Just
|
||||
replace the bzImage in qemu.sh to try it.
|
||||
|
||||
@item
|
||||
vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the
|
||||
vl creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the
|
||||
default) containing all the simulated PC memory. If possible, try to use
|
||||
a temporary directory using the tmpfs filesystem to avoid too many
|
||||
unnecessary disk accesses.
|
||||
@@ -379,16 +442,19 @@ Lawton for the plex86 Project (@url{www.plex86.org}).
|
||||
@section Invocation
|
||||
|
||||
@example
|
||||
usage: vl [options] bzImage [kernel parameters...]
|
||||
@c man begin SYNOPSIS
|
||||
usage: qemu [options] [disk_image]
|
||||
@c man end
|
||||
@end example
|
||||
|
||||
@file{bzImage} is a Linux kernel image.
|
||||
@c man begin OPTIONS
|
||||
@var{disk_image} is a raw hard image image for IDE hard disk 0.
|
||||
|
||||
General options:
|
||||
@table @option
|
||||
@item -hda file
|
||||
@item -hdb file
|
||||
Use 'file' as hard disk 0 or 1 image (@xref{disk_images}).
|
||||
Use @var{file} as hard disk 0 or 1 image (@xref{disk_images}).
|
||||
|
||||
@item -snapshot
|
||||
|
||||
@@ -405,13 +471,41 @@ launched to configure the host network interface (usually tun0)
|
||||
corresponding to the virtual NE2000 card.
|
||||
|
||||
@item -initrd file
|
||||
Use 'file' as initial ram disk.
|
||||
Use @var{file} as initial ram disk.
|
||||
|
||||
@item -tun-fd fd
|
||||
Assumes @var{fd} talks to tap/tun and use it. Read
|
||||
@url{http://bellard.org/qemu/tetrinet.html} to have an example of its
|
||||
use.
|
||||
|
||||
@item -nographic
|
||||
|
||||
Normally, QEMU uses SDL to display the VGA output. With this option,
|
||||
you can totally disable graphical output so that QEMU is a simple
|
||||
command line application. The emulated serial port is redirected on
|
||||
the console. Therefore, you can still use QEMU to debug a Linux kernel
|
||||
with a serial console.
|
||||
|
||||
@end table
|
||||
|
||||
Linux boot specific (does not require a full PC boot with a BIOS):
|
||||
@table @option
|
||||
|
||||
@item -kernel bzImage
|
||||
Use @var{bzImage} as kernel image.
|
||||
|
||||
@item -append cmdline
|
||||
Use @var{cmdline} as kernel command line
|
||||
|
||||
@item -initrd file
|
||||
Use @var{file} as initial ram disk.
|
||||
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
@table @option
|
||||
@item -s
|
||||
Wait gdb connection to port 1234.
|
||||
Wait gdb connection to port 1234 (@xref{gdb_usage}).
|
||||
@item -p port
|
||||
Change gdb connection port.
|
||||
@item -d
|
||||
@@ -432,7 +526,25 @@ Send break (magic sysrq)
|
||||
@item C-a C-a
|
||||
Send C-a
|
||||
@end table
|
||||
@c man end
|
||||
|
||||
@ignore
|
||||
|
||||
@setfilename qemu
|
||||
@settitle QEMU System Emulator
|
||||
|
||||
@c man begin SEEALSO
|
||||
The HTML documentation of QEMU for more precise information and Linux
|
||||
user mode emulator invocation.
|
||||
@c man end
|
||||
|
||||
@c man begin AUTHOR
|
||||
Fabrice Bellard
|
||||
@c man end
|
||||
|
||||
@end ignore
|
||||
|
||||
@end ignore
|
||||
@node disk_images
|
||||
@section Disk Images
|
||||
|
||||
@@ -466,14 +578,14 @@ same disk image template for many users.
|
||||
To create a COW disk images, use the command:
|
||||
|
||||
@example
|
||||
vlmkcow -f myrawimage.bin mycowimage.cow
|
||||
qemu-mkcow -f myrawimage.bin mycowimage.cow
|
||||
@end example
|
||||
|
||||
@file{myrawimage.bin} is a raw image you want to use as original disk
|
||||
image. It will never be written to.
|
||||
|
||||
@file{mycowimage.cow} is the COW disk image which is created by
|
||||
@code{vlmkcow}. You can use it directly with the @option{-hdx}
|
||||
@code{qemu-mkcow}. You can use it directly with the @option{-hdx}
|
||||
options. You must not modify the original raw disk image if you use
|
||||
COW images, as COW images only store the modified sectors from the raw
|
||||
disk image. QEMU stores the original raw disk image name and its
|
||||
@@ -489,7 +601,7 @@ image. It is useful to have a big initial virtual disk image without
|
||||
using much disk space. Use:
|
||||
|
||||
@example
|
||||
vlmkcow mycowimage.cow 1024
|
||||
qemu-mkcow mycowimage.cow 1024
|
||||
@end example
|
||||
|
||||
to create a 1 gigabyte empty COW disk image.
|
||||
@@ -504,10 +616,13 @@ Since holes are used, the displayed size of the COW disk image is not
|
||||
the real one. To know it, use the @code{ls -ls} command.
|
||||
@end enumerate
|
||||
|
||||
@node linux_compile
|
||||
@section Linux Kernel Compilation
|
||||
|
||||
You should be able to use any kernel with QEMU provided you make the
|
||||
following changes (only 2.4.x and 2.5.x were tested):
|
||||
You can use any linux kernel with QEMU. However, if you want to use
|
||||
@code{qemu-fast} to get maximum performances, you should make the
|
||||
following changes to the Linux kernel (only 2.4.x and 2.5.x were
|
||||
tested):
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
@@ -573,31 +688,11 @@ As you would do to make a real kernel. Then you can use with QEMU
|
||||
exactly the same kernel as you would boot on your PC (in
|
||||
@file{arch/i386/boot/bzImage}).
|
||||
|
||||
@section PC Emulation
|
||||
|
||||
QEMU emulates the following PC peripherials:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
PIC (interrupt controler)
|
||||
@item
|
||||
PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@item
|
||||
Dumb VGA (to print the @code{Uncompressing Linux} message)
|
||||
@item
|
||||
Serial port (port=0x3f8, irq=4)
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
IDE disk interface (port=0x1f0, irq=14)
|
||||
@end itemize
|
||||
|
||||
@node gdb_usage
|
||||
@section GDB usage
|
||||
|
||||
QEMU has a primitive support to work with gdb, so that you can do
|
||||
'Ctrl-C' while the kernel is running and inspect its state.
|
||||
'Ctrl-C' while the virtual machine is running and inspect its state.
|
||||
|
||||
In order to use gdb, launch vl with the '-s' option. It will wait for a
|
||||
gdb connection:
|
||||
@@ -622,7 +717,17 @@ Then you can use gdb normally. For example, type 'c' to launch the kernel:
|
||||
(gdb) c
|
||||
@end example
|
||||
|
||||
WARNING: breakpoints and single stepping are not yet supported.
|
||||
Here are some useful tips in order to use gdb on system code:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Use @code{info reg} to display all the CPU registers.
|
||||
@item
|
||||
Use @code{x/10i $eip} to display the code at the PC position.
|
||||
@item
|
||||
Use @code{set architecture i8086} to dump 16 bit code. Then use
|
||||
@code{x/10i $cs*16+*eip} to dump the code at the PC position.
|
||||
@end enumerate
|
||||
|
||||
@chapter QEMU Internals
|
||||
|
||||
@@ -906,16 +1011,6 @@ The new Plex86 project.
|
||||
In the directory @file{tests/}, various interesting testing programs
|
||||
are available. There are used for regression testing.
|
||||
|
||||
@section @file{hello-i386}
|
||||
|
||||
Very simple statically linked x86 program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{hello-arm}
|
||||
|
||||
Very simple statically linked ARM program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{test-i386}
|
||||
|
||||
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||
@@ -931,6 +1026,22 @@ The Linux system call @code{vm86()} is used to test vm86 emulation.
|
||||
Various exceptions are raised to test most of the x86 user space
|
||||
exception reporting.
|
||||
|
||||
@section @file{linux-test}
|
||||
|
||||
This program tests various Linux system calls. It is used to verify
|
||||
that the system call parameters are correctly converted between target
|
||||
and host CPUs.
|
||||
|
||||
@section @file{hello-i386}
|
||||
|
||||
Very simple statically linked x86 program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{hello-arm}
|
||||
|
||||
Very simple statically linked ARM program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{sha1}
|
||||
|
||||
It is a simple benchmark. Care must be taken to interpret the results
|
||||
|
8
sdl.c
8
sdl.c
@@ -42,8 +42,8 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
@@ -264,6 +264,10 @@ void sdl_display_init(DisplayState *ds)
|
||||
fprintf(stderr, "Could not initialize SDL - exiting\n");
|
||||
exit(1);
|
||||
}
|
||||
/* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGQUIT, SIG_DFL);
|
||||
|
||||
ds->dpy_update = sdl_update;
|
||||
ds->dpy_resize = sdl_resize;
|
||||
ds->dpy_refresh = sdl_refresh;
|
||||
|
@@ -19,26 +19,48 @@
|
||||
*/
|
||||
#if DATA_SIZE == 8
|
||||
#define SUFFIX q
|
||||
#define USUFFIX q
|
||||
#define DATA_TYPE uint64_t
|
||||
#elif DATA_SIZE == 4
|
||||
#define SUFFIX l
|
||||
#define USUFFIX l
|
||||
#define DATA_TYPE uint32_t
|
||||
#elif DATA_SIZE == 2
|
||||
#define SUFFIX w
|
||||
#define USUFFIX uw
|
||||
#define DATA_TYPE uint16_t
|
||||
#define DATA_STYPE int16_t
|
||||
#elif DATA_SIZE == 1
|
||||
#define SUFFIX b
|
||||
#define USUFFIX ub
|
||||
#define DATA_TYPE uint8_t
|
||||
#define DATA_STYPE int8_t
|
||||
#else
|
||||
#error unsupported data size
|
||||
#endif
|
||||
|
||||
#if MEMUSER == 0
|
||||
#define MEMSUFFIX _kernel
|
||||
#if ACCESS_TYPE == 0
|
||||
|
||||
#define CPU_MEM_INDEX 0
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#elif ACCESS_TYPE == 1
|
||||
|
||||
#define CPU_MEM_INDEX 1
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#elif ACCESS_TYPE == 2
|
||||
|
||||
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#elif ACCESS_TYPE == 3
|
||||
|
||||
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
||||
#define MMUSUFFIX _cmmu
|
||||
|
||||
#else
|
||||
#define MEMSUFFIX _user
|
||||
#error invalid ACCESS_TYPE
|
||||
#endif
|
||||
|
||||
#if DATA_SIZE == 8
|
||||
@@ -48,24 +70,26 @@
|
||||
#endif
|
||||
|
||||
|
||||
#if MEMUSER == 0
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr);
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE v);
|
||||
#endif
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user);
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user);
|
||||
|
||||
static inline int glue(glue(ldu, SUFFIX), MEMSUFFIX)(void *ptr)
|
||||
static inline int glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr)
|
||||
{
|
||||
int index;
|
||||
RES_TYPE res;
|
||||
unsigned long addr, physaddr;
|
||||
int is_user;
|
||||
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
if (__builtin_expect(env->tlb_read[MEMUSER][index].address !=
|
||||
is_user = CPU_MEM_INDEX;
|
||||
if (__builtin_expect(env->tlb_read[is_user][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
res = glue(glue(__ld, SUFFIX), _mmu)(addr);
|
||||
res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_read[MEMUSER][index].addend;
|
||||
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -75,13 +99,16 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr)
|
||||
{
|
||||
int res, index;
|
||||
unsigned long addr, physaddr;
|
||||
int is_user;
|
||||
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
if (__builtin_expect(env->tlb_read[MEMUSER][index].address !=
|
||||
is_user = CPU_MEM_INDEX;
|
||||
if (__builtin_expect(env->tlb_read[is_user][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
res = (DATA_STYPE)glue(glue(__ld, SUFFIX), _mmu)(addr);
|
||||
res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_read[MEMUSER][index].addend;
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
return res;
|
||||
@@ -92,13 +119,16 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v)
|
||||
{
|
||||
int index;
|
||||
unsigned long addr, physaddr;
|
||||
int is_user;
|
||||
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
if (__builtin_expect(env->tlb_write[MEMUSER][index].address !=
|
||||
is_user = CPU_MEM_INDEX;
|
||||
if (__builtin_expect(env->tlb_write[is_user][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
glue(glue(__st, SUFFIX), _mmu)(addr, v);
|
||||
glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_write[MEMUSER][index].addend;
|
||||
physaddr = addr + env->tlb_write[is_user][index].addend;
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
|
||||
}
|
||||
}
|
||||
@@ -107,5 +137,7 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v)
|
||||
#undef DATA_TYPE
|
||||
#undef DATA_STYPE
|
||||
#undef SUFFIX
|
||||
#undef USUFFIX
|
||||
#undef DATA_SIZE
|
||||
#undef MEMSUFFIX
|
||||
#undef CPU_MEM_INDEX
|
||||
#undef MMUSUFFIX
|
||||
|
@@ -21,23 +21,31 @@
|
||||
|
||||
#if DATA_SIZE == 8
|
||||
#define SUFFIX q
|
||||
#define USUFFIX q
|
||||
#define DATA_TYPE uint64_t
|
||||
#elif DATA_SIZE == 4
|
||||
#define SUFFIX l
|
||||
#define USUFFIX l
|
||||
#define DATA_TYPE uint32_t
|
||||
#elif DATA_SIZE == 2
|
||||
#define SUFFIX w
|
||||
#define USUFFIX uw
|
||||
#define DATA_TYPE uint16_t
|
||||
#elif DATA_SIZE == 1
|
||||
#define SUFFIX b
|
||||
#define USUFFIX ub
|
||||
#define DATA_TYPE uint8_t
|
||||
#else
|
||||
#error unsupported data size
|
||||
#endif
|
||||
|
||||
static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr);
|
||||
static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
void *retaddr);
|
||||
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user,
|
||||
void *retaddr);
|
||||
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
DATA_TYPE val,
|
||||
int is_user,
|
||||
void *retaddr);
|
||||
|
||||
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
|
||||
unsigned long tlb_addr)
|
||||
@@ -81,16 +89,16 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
|
||||
}
|
||||
|
||||
/* handle all cases except unaligned access which span two pages */
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr)
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user)
|
||||
{
|
||||
DATA_TYPE res;
|
||||
int is_user, index;
|
||||
int index;
|
||||
unsigned long physaddr, tlb_addr;
|
||||
void *retaddr;
|
||||
|
||||
/* test if there is match for unaligned or IO access */
|
||||
/* XXX: could done more in memory macro in a non portable way */
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_read[is_user][index].address;
|
||||
@@ -104,29 +112,31 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr)
|
||||
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
|
||||
/* slow unaligned access (it spans two pages or IO) */
|
||||
do_unaligned_access:
|
||||
retaddr = __builtin_return_address(0);
|
||||
res = glue(slow_ld, SUFFIX)(addr, retaddr);
|
||||
retaddr = GETPC();
|
||||
res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
|
||||
is_user, retaddr);
|
||||
} else {
|
||||
/* unaligned access in the same page */
|
||||
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = __builtin_return_address(0);
|
||||
tlb_fill(addr, 0, retaddr);
|
||||
retaddr = GETPC();
|
||||
tlb_fill(addr, 0, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* handle all unaligned cases */
|
||||
static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr)
|
||||
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user,
|
||||
void *retaddr)
|
||||
{
|
||||
DATA_TYPE res, res1, res2;
|
||||
int is_user, index, shift;
|
||||
int index, shift;
|
||||
unsigned long physaddr, tlb_addr, addr1, addr2;
|
||||
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_read[is_user][index].address;
|
||||
@@ -142,8 +152,10 @@ static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr)
|
||||
/* slow unaligned access (it spans two pages) */
|
||||
addr1 = addr & ~(DATA_SIZE - 1);
|
||||
addr2 = addr1 + DATA_SIZE;
|
||||
res1 = glue(slow_ld, SUFFIX)(addr1, retaddr);
|
||||
res2 = glue(slow_ld, SUFFIX)(addr2, retaddr);
|
||||
res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
|
||||
is_user, retaddr);
|
||||
res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
|
||||
is_user, retaddr);
|
||||
shift = (addr & (DATA_SIZE - 1)) * 8;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
|
||||
@@ -152,24 +164,25 @@ static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr)
|
||||
#endif
|
||||
} else {
|
||||
/* unaligned/aligned access in the same page */
|
||||
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
tlb_fill(addr, 0, retaddr);
|
||||
tlb_fill(addr, 0, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val)
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
DATA_TYPE val,
|
||||
int is_user)
|
||||
{
|
||||
unsigned long physaddr, tlb_addr;
|
||||
void *retaddr;
|
||||
int is_user, index;
|
||||
int index;
|
||||
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_write[is_user][index].address;
|
||||
@@ -182,28 +195,30 @@ void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val
|
||||
glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
|
||||
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
|
||||
do_unaligned_access:
|
||||
retaddr = __builtin_return_address(0);
|
||||
glue(slow_st, SUFFIX)(addr, val, retaddr);
|
||||
retaddr = GETPC();
|
||||
glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
|
||||
is_user, retaddr);
|
||||
} else {
|
||||
/* aligned/unaligned access in the same page */
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = __builtin_return_address(0);
|
||||
tlb_fill(addr, 1, retaddr);
|
||||
retaddr = GETPC();
|
||||
tlb_fill(addr, 1, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
||||
/* handles all unaligned cases */
|
||||
static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
void *retaddr)
|
||||
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
DATA_TYPE val,
|
||||
int is_user,
|
||||
void *retaddr)
|
||||
{
|
||||
unsigned long physaddr, tlb_addr;
|
||||
int is_user, index, i;
|
||||
int index, i;
|
||||
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_write[is_user][index].address;
|
||||
@@ -219,9 +234,11 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
/* XXX: not efficient, but simple */
|
||||
for(i = 0;i < DATA_SIZE; i++) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
slow_stb(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), retaddr);
|
||||
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
|
||||
is_user, retaddr);
|
||||
#else
|
||||
slow_stb(addr + i, val >> (i * 8), retaddr);
|
||||
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
|
||||
is_user, retaddr);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
@@ -230,7 +247,7 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
tlb_fill(addr, 1, retaddr);
|
||||
tlb_fill(addr, 1, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
@@ -238,4 +255,5 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
#undef SHIFT
|
||||
#undef DATA_TYPE
|
||||
#undef SUFFIX
|
||||
#undef USUFFIX
|
||||
#undef DATA_SIZE
|
||||
|
@@ -24,8 +24,8 @@ register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
@@ -17,71 +17,71 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-arm.h"
|
||||
#include "exec.h"
|
||||
|
||||
#define REGNAME r0
|
||||
#define REG (env->regs[0])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r1
|
||||
#define REG (env->regs[1])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r2
|
||||
#define REG (env->regs[2])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r3
|
||||
#define REG (env->regs[3])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r4
|
||||
#define REG (env->regs[4])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r5
|
||||
#define REG (env->regs[5])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r6
|
||||
#define REG (env->regs[6])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r7
|
||||
#define REG (env->regs[7])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r8
|
||||
#define REG (env->regs[8])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r9
|
||||
#define REG (env->regs[9])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r10
|
||||
#define REG (env->regs[10])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r11
|
||||
#define REG (env->regs[11])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r12
|
||||
#define REG (env->regs[12])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r13
|
||||
#define REG (env->regs[13])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r14
|
||||
#define REG (env->regs[14])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r15
|
||||
#define REG (env->regs[15])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
@@ -23,8 +23,8 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* internal defines */
|
||||
@@ -44,12 +44,12 @@ extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc-arm.h"
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op-arm.h"
|
||||
#include "gen-op.h"
|
||||
|
||||
typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
@@ -112,8 +112,8 @@ extern int loglevel;
|
||||
#define FP_CONVERT (env->fp_convert)
|
||||
#endif
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
typedef struct CCTable {
|
||||
int (*compute_all)(void); /* return all the flags */
|
||||
@@ -137,8 +137,10 @@ void helper_invlpg(unsigned int addr);
|
||||
void cpu_x86_update_cr0(CPUX86State *env);
|
||||
void cpu_x86_update_cr3(CPUX86State *env);
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write);
|
||||
void tlb_fill(unsigned long addr, int is_write, void *retaddr);
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
|
||||
int is_write, int is_user, int is_softmmu);
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
void __hidden cpu_lock(void);
|
||||
void __hidden cpu_unlock(void);
|
||||
void do_interrupt(int intno, int is_int, int error_code,
|
||||
@@ -366,26 +368,14 @@ static inline void load_eflags(int eflags, int update_mask)
|
||||
(eflags & update_mask);
|
||||
}
|
||||
|
||||
/* memory access macros */
|
||||
/* XXX: move that to a generic header */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define ldul ldl
|
||||
#define lduq ldq
|
||||
#define ldul_user ldl_user
|
||||
#define ldul_kernel ldl_kernel
|
||||
|
||||
#define ldub_raw ldub
|
||||
#define ldsb_raw ldsb
|
||||
#define lduw_raw lduw
|
||||
#define ldsw_raw ldsw
|
||||
#define ldl_raw ldl
|
||||
#define ldq_raw ldq
|
||||
|
||||
#define stb_raw stb
|
||||
#define stw_raw stw
|
||||
#define stl_raw stl
|
||||
#define stq_raw stq
|
||||
|
||||
#define MEMUSER 0
|
||||
#define ACCESS_TYPE 0
|
||||
#define MEMSUFFIX _kernel
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
@@ -397,9 +387,11 @@ static inline void load_eflags(int eflags, int update_mask)
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#undef MEMUSER
|
||||
#define MEMUSER 1
|
||||
#define ACCESS_TYPE 1
|
||||
#define MEMSUFFIX _user
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
@@ -411,6 +403,76 @@ static inline void load_eflags(int eflags, int update_mask)
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#undef MEMUSER
|
||||
/* these access are slower, they must be as rare as possible */
|
||||
#define ACCESS_TYPE 2
|
||||
#define MEMSUFFIX _data
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define ldub(p) ldub_data(p)
|
||||
#define ldsb(p) ldsb_data(p)
|
||||
#define lduw(p) lduw_data(p)
|
||||
#define ldsw(p) ldsw_data(p)
|
||||
#define ldl(p) ldl_data(p)
|
||||
#define ldq(p) ldq_data(p)
|
||||
|
||||
#define stb(p, v) stb_data(p, v)
|
||||
#define stw(p, v) stw_data(p, v)
|
||||
#define stl(p, v) stl_data(p, v)
|
||||
#define stq(p, v) stq_data(p, v)
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
@@ -17,7 +17,7 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
const uint8_t parity_table[256] = {
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
@@ -153,11 +153,11 @@ static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
|
||||
if (index + (4 << shift) - 1 > env->tr.limit)
|
||||
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
|
||||
if (shift == 0) {
|
||||
*esp_ptr = lduw(env->tr.base + index);
|
||||
*ss_ptr = lduw(env->tr.base + index + 2);
|
||||
*esp_ptr = lduw_kernel(env->tr.base + index);
|
||||
*ss_ptr = lduw_kernel(env->tr.base + index + 2);
|
||||
} else {
|
||||
*esp_ptr = ldl(env->tr.base + index);
|
||||
*ss_ptr = lduw(env->tr.base + index + 4);
|
||||
*esp_ptr = ldl_kernel(env->tr.base + index);
|
||||
*ss_ptr = lduw_kernel(env->tr.base + index + 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,8 +177,8 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
|
||||
if ((index + 7) > dt->limit)
|
||||
return -1;
|
||||
ptr = dt->base + index;
|
||||
*e1_ptr = ldl(ptr);
|
||||
*e2_ptr = ldl(ptr + 4);
|
||||
*e1_ptr = ldl_kernel(ptr);
|
||||
*e2_ptr = ldl_kernel(ptr + 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -226,8 +226,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
|
||||
if (intno * 8 + 7 > dt->limit)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
ptr = dt->base + intno * 8;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
e1 = ldl_kernel(ptr);
|
||||
e2 = ldl_kernel(ptr + 4);
|
||||
/* check gate type */
|
||||
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
|
||||
switch(type) {
|
||||
@@ -344,47 +344,47 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
|
||||
int old_eflags;
|
||||
if (env->eflags & VM_MASK) {
|
||||
ssp -= 4;
|
||||
stl(ssp, env->segs[R_GS].selector);
|
||||
stl_kernel(ssp, env->segs[R_GS].selector);
|
||||
ssp -= 4;
|
||||
stl(ssp, env->segs[R_FS].selector);
|
||||
stl_kernel(ssp, env->segs[R_FS].selector);
|
||||
ssp -= 4;
|
||||
stl(ssp, env->segs[R_DS].selector);
|
||||
stl_kernel(ssp, env->segs[R_DS].selector);
|
||||
ssp -= 4;
|
||||
stl(ssp, env->segs[R_ES].selector);
|
||||
stl_kernel(ssp, env->segs[R_ES].selector);
|
||||
}
|
||||
if (new_stack) {
|
||||
ssp -= 4;
|
||||
stl(ssp, old_ss);
|
||||
stl_kernel(ssp, old_ss);
|
||||
ssp -= 4;
|
||||
stl(ssp, old_esp);
|
||||
stl_kernel(ssp, old_esp);
|
||||
}
|
||||
ssp -= 4;
|
||||
old_eflags = compute_eflags();
|
||||
stl(ssp, old_eflags);
|
||||
stl_kernel(ssp, old_eflags);
|
||||
ssp -= 4;
|
||||
stl(ssp, old_cs);
|
||||
stl_kernel(ssp, old_cs);
|
||||
ssp -= 4;
|
||||
stl(ssp, old_eip);
|
||||
stl_kernel(ssp, old_eip);
|
||||
if (has_error_code) {
|
||||
ssp -= 4;
|
||||
stl(ssp, error_code);
|
||||
stl_kernel(ssp, error_code);
|
||||
}
|
||||
} else {
|
||||
if (new_stack) {
|
||||
ssp -= 2;
|
||||
stw(ssp, old_ss);
|
||||
stw_kernel(ssp, old_ss);
|
||||
ssp -= 2;
|
||||
stw(ssp, old_esp);
|
||||
stw_kernel(ssp, old_esp);
|
||||
}
|
||||
ssp -= 2;
|
||||
stw(ssp, compute_eflags());
|
||||
stw_kernel(ssp, compute_eflags());
|
||||
ssp -= 2;
|
||||
stw(ssp, old_cs);
|
||||
stw_kernel(ssp, old_cs);
|
||||
ssp -= 2;
|
||||
stw(ssp, old_eip);
|
||||
stw_kernel(ssp, old_eip);
|
||||
if (has_error_code) {
|
||||
ssp -= 2;
|
||||
stw(ssp, error_code);
|
||||
stw_kernel(ssp, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,8 +410,8 @@ static void do_interrupt_real(int intno, int is_int, int error_code,
|
||||
if (intno * 4 + 3 > dt->limit)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
ptr = dt->base + intno * 4;
|
||||
offset = lduw(ptr);
|
||||
selector = lduw(ptr + 2);
|
||||
offset = lduw_kernel(ptr);
|
||||
selector = lduw_kernel(ptr + 2);
|
||||
esp = ESP;
|
||||
ssp = env->segs[R_SS].base;
|
||||
if (is_int)
|
||||
@@ -420,11 +420,11 @@ static void do_interrupt_real(int intno, int is_int, int error_code,
|
||||
old_eip = env->eip;
|
||||
old_cs = env->segs[R_CS].selector;
|
||||
esp -= 2;
|
||||
stw(ssp + (esp & 0xffff), compute_eflags());
|
||||
stw_kernel(ssp + (esp & 0xffff), compute_eflags());
|
||||
esp -= 2;
|
||||
stw(ssp + (esp & 0xffff), old_cs);
|
||||
stw_kernel(ssp + (esp & 0xffff), old_cs);
|
||||
esp -= 2;
|
||||
stw(ssp + (esp & 0xffff), old_eip);
|
||||
stw_kernel(ssp + (esp & 0xffff), old_eip);
|
||||
|
||||
/* update processor state */
|
||||
ESP = (ESP & ~0xffff) | (esp & 0xffff);
|
||||
@@ -445,7 +445,7 @@ void do_interrupt_user(int intno, int is_int, int error_code,
|
||||
|
||||
dt = &env->idt;
|
||||
ptr = dt->base + (intno * 8);
|
||||
e2 = ldl(ptr + 4);
|
||||
e2 = ldl_kernel(ptr + 4);
|
||||
|
||||
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||
cpl = env->hflags & HF_CPL_MASK;
|
||||
@@ -651,8 +651,8 @@ void helper_lldt_T0(void)
|
||||
if ((index + 7) > dt->limit)
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
ptr = dt->base + index;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
e1 = ldl_kernel(ptr);
|
||||
e2 = ldl_kernel(ptr + 4);
|
||||
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
if (!(e2 & DESC_P_MASK))
|
||||
@@ -684,8 +684,8 @@ void helper_ltr_T0(void)
|
||||
if ((index + 7) > dt->limit)
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
ptr = dt->base + index;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
e1 = ldl_kernel(ptr);
|
||||
e2 = ldl_kernel(ptr + 4);
|
||||
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
|
||||
if ((e2 & DESC_S_MASK) ||
|
||||
(type != 2 && type != 9))
|
||||
@@ -694,7 +694,7 @@ void helper_ltr_T0(void)
|
||||
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
|
||||
load_seg_cache_raw_dt(&env->tr, e1, e2);
|
||||
e2 |= 0x00000200; /* set the busy bit */
|
||||
stl(ptr + 4, e2);
|
||||
stl_kernel(ptr + 4, e2);
|
||||
}
|
||||
env->tr.selector = selector;
|
||||
}
|
||||
@@ -813,14 +813,14 @@ void helper_lcall_real_T0_T1(int shift, int next_eip)
|
||||
ssp = env->segs[R_SS].base;
|
||||
if (shift) {
|
||||
esp -= 4;
|
||||
stl(ssp + (esp & esp_mask), env->segs[R_CS].selector);
|
||||
stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector);
|
||||
esp -= 4;
|
||||
stl(ssp + (esp & esp_mask), next_eip);
|
||||
stl_kernel(ssp + (esp & esp_mask), next_eip);
|
||||
} else {
|
||||
esp -= 2;
|
||||
stw(ssp + (esp & esp_mask), env->segs[R_CS].selector);
|
||||
stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector);
|
||||
esp -= 2;
|
||||
stw(ssp + (esp & esp_mask), next_eip);
|
||||
stw_kernel(ssp + (esp & esp_mask), next_eip);
|
||||
}
|
||||
|
||||
if (!(env->segs[R_SS].flags & DESC_B_MASK))
|
||||
@@ -873,14 +873,14 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
|
||||
ssp = env->segs[R_SS].base + sp;
|
||||
if (shift) {
|
||||
ssp -= 4;
|
||||
stl(ssp, env->segs[R_CS].selector);
|
||||
stl_kernel(ssp, env->segs[R_CS].selector);
|
||||
ssp -= 4;
|
||||
stl(ssp, next_eip);
|
||||
stl_kernel(ssp, next_eip);
|
||||
} else {
|
||||
ssp -= 2;
|
||||
stw(ssp, env->segs[R_CS].selector);
|
||||
stw_kernel(ssp, env->segs[R_CS].selector);
|
||||
ssp -= 2;
|
||||
stw(ssp, next_eip);
|
||||
stw_kernel(ssp, next_eip);
|
||||
}
|
||||
sp -= (4 << shift);
|
||||
|
||||
@@ -975,23 +975,23 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
|
||||
ssp = env->segs[R_SS].base + sp;
|
||||
if (shift) {
|
||||
ssp -= 4;
|
||||
stl(ssp, old_ss);
|
||||
stl_kernel(ssp, old_ss);
|
||||
ssp -= 4;
|
||||
stl(ssp, old_esp);
|
||||
stl_kernel(ssp, old_esp);
|
||||
ssp -= 4 * param_count;
|
||||
for(i = 0; i < param_count; i++) {
|
||||
val = ldl(old_ssp + i * 4);
|
||||
stl(ssp + i * 4, val);
|
||||
val = ldl_kernel(old_ssp + i * 4);
|
||||
stl_kernel(ssp + i * 4, val);
|
||||
}
|
||||
} else {
|
||||
ssp -= 2;
|
||||
stw(ssp, old_ss);
|
||||
stw_kernel(ssp, old_ss);
|
||||
ssp -= 2;
|
||||
stw(ssp, old_esp);
|
||||
stw_kernel(ssp, old_esp);
|
||||
ssp -= 2 * param_count;
|
||||
for(i = 0; i < param_count; i++) {
|
||||
val = lduw(old_ssp + i * 2);
|
||||
stw(ssp + i * 2, val);
|
||||
val = lduw_kernel(old_ssp + i * 2);
|
||||
stw_kernel(ssp + i * 2, val);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1004,14 +1004,14 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
|
||||
|
||||
if (shift) {
|
||||
ssp -= 4;
|
||||
stl(ssp, env->segs[R_CS].selector);
|
||||
stl_kernel(ssp, env->segs[R_CS].selector);
|
||||
ssp -= 4;
|
||||
stl(ssp, next_eip);
|
||||
stl_kernel(ssp, next_eip);
|
||||
} else {
|
||||
ssp -= 2;
|
||||
stw(ssp, env->segs[R_CS].selector);
|
||||
stw_kernel(ssp, env->segs[R_CS].selector);
|
||||
ssp -= 2;
|
||||
stw(ssp, next_eip);
|
||||
stw_kernel(ssp, next_eip);
|
||||
}
|
||||
|
||||
sp -= push_size;
|
||||
@@ -1042,14 +1042,14 @@ void helper_iret_real(int shift)
|
||||
ssp = env->segs[R_SS].base + sp;
|
||||
if (shift == 1) {
|
||||
/* 32 bits */
|
||||
new_eflags = ldl(ssp + 8);
|
||||
new_cs = ldl(ssp + 4) & 0xffff;
|
||||
new_eip = ldl(ssp) & 0xffff;
|
||||
new_eflags = ldl_kernel(ssp + 8);
|
||||
new_cs = ldl_kernel(ssp + 4) & 0xffff;
|
||||
new_eip = ldl_kernel(ssp) & 0xffff;
|
||||
} else {
|
||||
/* 16 bits */
|
||||
new_eflags = lduw(ssp + 4);
|
||||
new_cs = lduw(ssp + 2);
|
||||
new_eip = lduw(ssp);
|
||||
new_eflags = lduw_kernel(ssp + 4);
|
||||
new_cs = lduw_kernel(ssp + 2);
|
||||
new_eip = lduw_kernel(ssp);
|
||||
}
|
||||
new_esp = sp + (6 << shift);
|
||||
ESP = (ESP & 0xffff0000) |
|
||||
@@ -1078,17 +1078,17 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
|
||||
if (shift == 1) {
|
||||
/* 32 bits */
|
||||
if (is_iret)
|
||||
new_eflags = ldl(ssp + 8);
|
||||
new_cs = ldl(ssp + 4) & 0xffff;
|
||||
new_eip = ldl(ssp);
|
||||
new_eflags = ldl_kernel(ssp + 8);
|
||||
new_cs = ldl_kernel(ssp + 4) & 0xffff;
|
||||
new_eip = ldl_kernel(ssp);
|
||||
if (is_iret && (new_eflags & VM_MASK))
|
||||
goto return_to_vm86;
|
||||
} else {
|
||||
/* 16 bits */
|
||||
if (is_iret)
|
||||
new_eflags = lduw(ssp + 4);
|
||||
new_cs = lduw(ssp + 2);
|
||||
new_eip = lduw(ssp);
|
||||
new_eflags = lduw_kernel(ssp + 4);
|
||||
new_cs = lduw_kernel(ssp + 2);
|
||||
new_eip = lduw_kernel(ssp);
|
||||
}
|
||||
if ((new_cs & 0xfffc) == 0)
|
||||
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
|
||||
@@ -1124,12 +1124,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
|
||||
ssp += (4 << shift) + ((2 * is_iret) << shift) + addend;
|
||||
if (shift == 1) {
|
||||
/* 32 bits */
|
||||
new_esp = ldl(ssp);
|
||||
new_ss = ldl(ssp + 4) & 0xffff;
|
||||
new_esp = ldl_kernel(ssp);
|
||||
new_ss = ldl_kernel(ssp + 4) & 0xffff;
|
||||
} else {
|
||||
/* 16 bits */
|
||||
new_esp = lduw(ssp);
|
||||
new_ss = lduw(ssp + 2);
|
||||
new_esp = lduw_kernel(ssp);
|
||||
new_ss = lduw_kernel(ssp + 2);
|
||||
}
|
||||
|
||||
if ((new_ss & 3) != rpl)
|
||||
@@ -1175,12 +1175,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
|
||||
return;
|
||||
|
||||
return_to_vm86:
|
||||
new_esp = ldl(ssp + 12);
|
||||
new_ss = ldl(ssp + 16);
|
||||
new_es = ldl(ssp + 20);
|
||||
new_ds = ldl(ssp + 24);
|
||||
new_fs = ldl(ssp + 28);
|
||||
new_gs = ldl(ssp + 32);
|
||||
new_esp = ldl_kernel(ssp + 12);
|
||||
new_ss = ldl_kernel(ssp + 16);
|
||||
new_es = ldl_kernel(ssp + 20);
|
||||
new_ds = ldl_kernel(ssp + 24);
|
||||
new_fs = ldl_kernel(ssp + 28);
|
||||
new_gs = ldl_kernel(ssp + 32);
|
||||
|
||||
/* modify processor state */
|
||||
load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
|
||||
@@ -1770,6 +1770,11 @@ void helper_frstor(uint8_t *ptr, int data32)
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
@@ -1782,22 +1787,41 @@ void helper_frstor(uint8_t *ptr, int data32)
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
/* try to fill the TLB and return an exception if error */
|
||||
void tlb_fill(unsigned long addr, int is_write, void *retaddr)
|
||||
#endif
|
||||
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
unsigned long pc;
|
||||
ret = cpu_x86_handle_mmu_fault(env, addr, is_write);
|
||||
CPUX86State *saved_env;
|
||||
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
if (is_write && page_unprotect(addr)) {
|
||||
/* nothing more to do: the page was write protected because
|
||||
there was code in it. page_unprotect() flushed the code. */
|
||||
}
|
||||
|
||||
ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (ret) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (unsigned long)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc);
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (unsigned long)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc);
|
||||
}
|
||||
}
|
||||
raise_exception_err(EXCP0E_PAGE, env->error_code);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
@@ -26,8 +26,8 @@
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DEBUG_MMU
|
||||
|
||||
@@ -210,7 +210,9 @@ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
|
||||
flags = page_get_flags(addr);
|
||||
if (flags & PAGE_VALID) {
|
||||
virt_addr = addr & ~0xfff;
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
munmap((void *)virt_addr, 4096);
|
||||
#endif
|
||||
page_set_flags(virt_addr, virt_addr + 4096, 0);
|
||||
}
|
||||
}
|
||||
@@ -221,16 +223,14 @@ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
|
||||
1 = generate PF fault
|
||||
2 = soft MMU activation required for this block
|
||||
*/
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
|
||||
int is_write, int is_user, int is_softmmu)
|
||||
{
|
||||
uint8_t *pde_ptr, *pte_ptr;
|
||||
uint32_t pde, pte, virt_addr;
|
||||
int cpl, error_code, is_dirty, is_user, prot, page_size, ret;
|
||||
int error_code, is_dirty, prot, page_size, ret;
|
||||
unsigned long pd;
|
||||
|
||||
cpl = env->hflags & HF_CPL_MASK;
|
||||
is_user = (cpl == 3);
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
|
||||
addr, is_write, is_user, env->eip);
|
||||
@@ -252,7 +252,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
|
||||
/* page directory entry */
|
||||
pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3));
|
||||
pde = ldl(pde_ptr);
|
||||
pde = ldl_raw(pde_ptr);
|
||||
if (!(pde & PG_PRESENT_MASK)) {
|
||||
error_code = 0;
|
||||
goto do_fault;
|
||||
@@ -274,7 +274,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
if (is_dirty)
|
||||
pde |= PG_DIRTY_MASK;
|
||||
stl(pde_ptr, pde);
|
||||
stl_raw(pde_ptr, pde);
|
||||
}
|
||||
|
||||
pte = pde & ~0x003ff000; /* align to 4MB */
|
||||
@@ -283,12 +283,12 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
} else {
|
||||
if (!(pde & PG_ACCESSED_MASK)) {
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
stl(pde_ptr, pde);
|
||||
stl_raw(pde_ptr, pde);
|
||||
}
|
||||
|
||||
/* page directory entry */
|
||||
pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc));
|
||||
pte = ldl(pte_ptr);
|
||||
pte = ldl_raw(pte_ptr);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
error_code = 0;
|
||||
goto do_fault;
|
||||
@@ -308,7 +308,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
pte |= PG_ACCESSED_MASK;
|
||||
if (is_dirty)
|
||||
pte |= PG_DIRTY_MASK;
|
||||
stl(pte_ptr, pte);
|
||||
stl_raw(pte_ptr, pte);
|
||||
}
|
||||
page_size = 4096;
|
||||
virt_addr = addr & ~0xfff;
|
||||
@@ -325,7 +325,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
}
|
||||
|
||||
do_mapping:
|
||||
if (env->hflags & HF_SOFTMMU_MASK) {
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
if (is_softmmu)
|
||||
#endif
|
||||
{
|
||||
unsigned long paddr, vaddr, address, addend, page_offset;
|
||||
int index;
|
||||
|
||||
@@ -352,32 +355,39 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
env->tlb_write[is_user][index].address = address;
|
||||
env->tlb_write[is_user][index].addend = addend;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
/* XXX: incorrect for 4MB pages */
|
||||
pd = physpage_find(pte & ~0xfff);
|
||||
if ((pd & 0xfff) != 0) {
|
||||
/* IO access: no mapping is done as it will be handled by the
|
||||
soft MMU */
|
||||
if (!(env->hflags & HF_SOFTMMU_MASK))
|
||||
ret = 2;
|
||||
} else {
|
||||
void *map_addr;
|
||||
map_addr = mmap((void *)virt_addr, page_size, prot,
|
||||
MAP_SHARED | MAP_FIXED, phys_ram_fd, pd);
|
||||
if (map_addr == MAP_FAILED) {
|
||||
fprintf(stderr,
|
||||
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
|
||||
pte & ~0xfff, virt_addr);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
|
||||
pte & ~0xfff, virt_addr, (page_size != 4096));
|
||||
#endif
|
||||
page_set_flags(virt_addr, virt_addr + page_size,
|
||||
page_set_flags(vaddr, vaddr + TARGET_PAGE_SIZE,
|
||||
PAGE_VALID | PAGE_EXEC | prot);
|
||||
ret = 0;
|
||||
}
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
else {
|
||||
ret = 0;
|
||||
/* XXX: incorrect for 4MB pages */
|
||||
pd = physpage_find(pte & ~0xfff);
|
||||
if ((pd & 0xfff) != 0) {
|
||||
/* IO access: no mapping is done as it will be handled by the
|
||||
soft MMU */
|
||||
if (!(env->hflags & HF_SOFTMMU_MASK))
|
||||
ret = 2;
|
||||
} else {
|
||||
void *map_addr;
|
||||
map_addr = mmap((void *)virt_addr, page_size, prot,
|
||||
MAP_SHARED | MAP_FIXED, phys_ram_fd, pd);
|
||||
if (map_addr == MAP_FAILED) {
|
||||
fprintf(stderr,
|
||||
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
|
||||
pte & ~0xfff, virt_addr);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
|
||||
pte & ~0xfff, virt_addr, (page_size != 4096));
|
||||
#endif
|
||||
page_set_flags(virt_addr, virt_addr + page_size,
|
||||
PAGE_VALID | PAGE_EXEC | prot);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
do_fault_protect:
|
||||
error_code = PG_ERROR_P_MASK;
|
@@ -17,7 +17,7 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
/* n must be a constant to be efficient */
|
||||
static inline int lshift(int x, int n)
|
||||
@@ -376,14 +376,16 @@ void OPPROTO op_andl_A0_ffff(void)
|
||||
|
||||
/* memory access */
|
||||
|
||||
#define MEMSUFFIX
|
||||
#define MEMSUFFIX _raw
|
||||
#include "ops_mem.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMSUFFIX _user
|
||||
#include "ops_mem.h"
|
||||
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "ops_mem.h"
|
||||
#endif
|
||||
|
||||
/* used for bit operations */
|
||||
|
@@ -26,8 +26,8 @@
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
@@ -60,6 +60,7 @@ typedef struct DisasContext {
|
||||
int cpl;
|
||||
int iopl;
|
||||
int tf; /* TF cpu flag */
|
||||
int singlestep_enabled; /* "hardware" single step enabled */
|
||||
int jmp_opt; /* use direct block chaining for direct jumps */
|
||||
int mem_index; /* select memory access functions */
|
||||
struct TranslationBlock *tb;
|
||||
@@ -95,12 +96,12 @@ enum {
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc-i386.h"
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op-i386.h"
|
||||
#include "gen-op.h"
|
||||
|
||||
/* operand size */
|
||||
enum {
|
||||
@@ -569,10 +570,10 @@ static GenOpFunc *gen_op_bsx_T0_cc[2][2] = {
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = {
|
||||
gen_op_ldsb_T0_A0,
|
||||
gen_op_ldsw_T0_A0,
|
||||
gen_op_ldsb_raw_T0_A0,
|
||||
gen_op_ldsw_raw_T0_A0,
|
||||
NULL,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
gen_op_ldsb_kernel_T0_A0,
|
||||
gen_op_ldsw_kernel_T0_A0,
|
||||
NULL,
|
||||
@@ -580,13 +581,15 @@ static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = {
|
||||
gen_op_ldsb_user_T0_A0,
|
||||
gen_op_ldsw_user_T0_A0,
|
||||
NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = {
|
||||
gen_op_ldub_T0_A0,
|
||||
gen_op_lduw_T0_A0,
|
||||
gen_op_ldub_raw_T0_A0,
|
||||
gen_op_lduw_raw_T0_A0,
|
||||
NULL,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
gen_op_ldub_kernel_T0_A0,
|
||||
gen_op_lduw_kernel_T0_A0,
|
||||
NULL,
|
||||
@@ -594,14 +597,16 @@ static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = {
|
||||
gen_op_ldub_user_T0_A0,
|
||||
gen_op_lduw_user_T0_A0,
|
||||
NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */
|
||||
static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = {
|
||||
gen_op_ldub_T0_A0,
|
||||
gen_op_lduw_T0_A0,
|
||||
gen_op_ldl_T0_A0,
|
||||
gen_op_ldub_raw_T0_A0,
|
||||
gen_op_lduw_raw_T0_A0,
|
||||
gen_op_ldl_raw_T0_A0,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
gen_op_ldub_kernel_T0_A0,
|
||||
gen_op_lduw_kernel_T0_A0,
|
||||
gen_op_ldl_kernel_T0_A0,
|
||||
@@ -609,13 +614,15 @@ static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = {
|
||||
gen_op_ldub_user_T0_A0,
|
||||
gen_op_lduw_user_T0_A0,
|
||||
gen_op_ldl_user_T0_A0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = {
|
||||
gen_op_ldub_T1_A0,
|
||||
gen_op_lduw_T1_A0,
|
||||
gen_op_ldl_T1_A0,
|
||||
gen_op_ldub_raw_T1_A0,
|
||||
gen_op_lduw_raw_T1_A0,
|
||||
gen_op_ldl_raw_T1_A0,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
gen_op_ldub_kernel_T1_A0,
|
||||
gen_op_lduw_kernel_T1_A0,
|
||||
gen_op_ldl_kernel_T1_A0,
|
||||
@@ -623,13 +630,15 @@ static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = {
|
||||
gen_op_ldub_user_T1_A0,
|
||||
gen_op_lduw_user_T1_A0,
|
||||
gen_op_ldl_user_T1_A0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_st_T0_A0[3 * 3] = {
|
||||
gen_op_stb_T0_A0,
|
||||
gen_op_stw_T0_A0,
|
||||
gen_op_stl_T0_A0,
|
||||
gen_op_stb_raw_T0_A0,
|
||||
gen_op_stw_raw_T0_A0,
|
||||
gen_op_stl_raw_T0_A0,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
gen_op_stb_kernel_T0_A0,
|
||||
gen_op_stw_kernel_T0_A0,
|
||||
gen_op_stl_kernel_T0_A0,
|
||||
@@ -637,6 +646,7 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = {
|
||||
gen_op_stb_user_T0_A0,
|
||||
gen_op_stw_user_T0_A0,
|
||||
gen_op_stl_user_T0_A0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void gen_string_movl_A0_ESI(DisasContext *s)
|
||||
@@ -1175,7 +1185,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
|
||||
|
||||
if (base == 4) {
|
||||
havesib = 1;
|
||||
code = ldub(s->pc++);
|
||||
code = ldub_code(s->pc++);
|
||||
scale = (code >> 6) & 3;
|
||||
index = (code >> 3) & 7;
|
||||
base = code & 7;
|
||||
@@ -1185,18 +1195,18 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
|
||||
case 0:
|
||||
if (base == 5) {
|
||||
base = -1;
|
||||
disp = ldl(s->pc);
|
||||
disp = ldl_code(s->pc);
|
||||
s->pc += 4;
|
||||
} else {
|
||||
disp = 0;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
disp = (int8_t)ldub(s->pc++);
|
||||
disp = (int8_t)ldub_code(s->pc++);
|
||||
break;
|
||||
default:
|
||||
case 2:
|
||||
disp = ldl(s->pc);
|
||||
disp = ldl_code(s->pc);
|
||||
s->pc += 4;
|
||||
break;
|
||||
}
|
||||
@@ -1228,7 +1238,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
|
||||
switch (mod) {
|
||||
case 0:
|
||||
if (rm == 6) {
|
||||
disp = lduw(s->pc);
|
||||
disp = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
gen_op_movl_A0_im(disp);
|
||||
rm = 0; /* avoid SS override */
|
||||
@@ -1238,11 +1248,11 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
disp = (int8_t)ldub(s->pc++);
|
||||
disp = (int8_t)ldub_code(s->pc++);
|
||||
break;
|
||||
default:
|
||||
case 2:
|
||||
disp = lduw(s->pc);
|
||||
disp = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
break;
|
||||
}
|
||||
@@ -1336,16 +1346,16 @@ static inline uint32_t insn_get(DisasContext *s, int ot)
|
||||
|
||||
switch(ot) {
|
||||
case OT_BYTE:
|
||||
ret = ldub(s->pc);
|
||||
ret = ldub_code(s->pc);
|
||||
s->pc++;
|
||||
break;
|
||||
case OT_WORD:
|
||||
ret = lduw(s->pc);
|
||||
ret = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
break;
|
||||
default:
|
||||
case OT_LONG:
|
||||
ret = ldl(s->pc);
|
||||
ret = ldl_code(s->pc);
|
||||
s->pc += 4;
|
||||
break;
|
||||
}
|
||||
@@ -1712,7 +1722,9 @@ static void gen_eob(DisasContext *s)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
if (s->tf) {
|
||||
if (s->singlestep_enabled) {
|
||||
gen_op_debug();
|
||||
} else if (s->tf) {
|
||||
gen_op_raise_exception(EXCP01_SSTP);
|
||||
} else {
|
||||
gen_op_movl_T0_0();
|
||||
@@ -1753,7 +1765,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
dflag = s->code32;
|
||||
s->override = -1;
|
||||
next_byte:
|
||||
b = ldub(s->pc);
|
||||
b = ldub_code(s->pc);
|
||||
s->pc++;
|
||||
/* check prefixes */
|
||||
switch (b) {
|
||||
@@ -1811,7 +1823,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0x0f:
|
||||
/**************************/
|
||||
/* extended op code */
|
||||
b = ldub(s->pc++) | 0x100;
|
||||
b = ldub_code(s->pc++) | 0x100;
|
||||
goto reswitch;
|
||||
|
||||
/**************************/
|
||||
@@ -1836,7 +1848,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
|
||||
switch(f) {
|
||||
case 0: /* OP Ev, Gv */
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = ((modrm >> 3) & 7);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
@@ -1858,7 +1870,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op(s, op, ot, opreg);
|
||||
break;
|
||||
case 1: /* OP Gv, Ev */
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
reg = ((modrm >> 3) & 7);
|
||||
rm = modrm & 7;
|
||||
@@ -1892,7 +1904,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
op = (modrm >> 3) & 7;
|
||||
@@ -1936,7 +1948,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
op = (modrm >> 3) & 7;
|
||||
@@ -2042,7 +2054,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
op = (modrm >> 3) & 7;
|
||||
@@ -2082,10 +2094,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_push_T0(s);
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 3: /*< lcall Ev */
|
||||
case 3: /* lcall Ev */
|
||||
gen_op_ld_T1_A0[ot + s->mem_index]();
|
||||
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
|
||||
gen_op_ld_T0_A0[OT_WORD + s->mem_index]();
|
||||
gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
|
||||
do_lcall:
|
||||
if (s->pe && !s->vm86) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
@@ -2106,7 +2118,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 5: /* ljmp Ev */
|
||||
gen_op_ld_T1_A0[ot + s->mem_index]();
|
||||
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
|
||||
gen_op_lduw_T0_A0();
|
||||
gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
|
||||
do_ljmp:
|
||||
if (s->pe && !s->vm86) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
@@ -2135,7 +2147,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
reg = (modrm >> 3) & 7;
|
||||
@@ -2176,7 +2188,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0x69: /* imul Gv, Ev, I */
|
||||
case 0x6b:
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = ((modrm >> 3) & 7) + OR_EAX;
|
||||
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
|
||||
if (b == 0x69) {
|
||||
@@ -2203,7 +2215,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (mod == 3) {
|
||||
@@ -2230,7 +2242,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
gen_op_mov_TN_reg[ot][1][reg]();
|
||||
@@ -2247,7 +2259,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
s->cc_op = CC_OP_SUBB + ot;
|
||||
break;
|
||||
case 0x1c7: /* cmpxchg8b */
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (mod == 3)
|
||||
goto illegal_op;
|
||||
@@ -2288,7 +2300,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
break;
|
||||
case 0x8f: /* pop Ev */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
gen_pop_T0(s);
|
||||
s->popl_esp_hack = 2 << dflag;
|
||||
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
|
||||
@@ -2298,9 +2310,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0xc8: /* enter */
|
||||
{
|
||||
int level;
|
||||
val = lduw(s->pc);
|
||||
val = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
level = ldub(s->pc++);
|
||||
level = ldub_code(s->pc++);
|
||||
gen_enter(s, val, level);
|
||||
}
|
||||
break;
|
||||
@@ -2366,7 +2378,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
|
||||
/* generate a generic store */
|
||||
@@ -2378,7 +2390,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (mod != 3)
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
@@ -2395,14 +2407,14 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
|
||||
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
|
||||
gen_op_mov_reg_T0[ot][reg]();
|
||||
break;
|
||||
case 0x8e: /* mov seg, Gv */
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
if (reg >= 6 || reg == R_CS)
|
||||
goto illegal_op;
|
||||
@@ -2419,7 +2431,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
break;
|
||||
case 0x8c: /* mov Gv, seg */
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (reg >= 6)
|
||||
@@ -2441,7 +2453,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
d_ot = dflag + OT_WORD;
|
||||
/* ot is the size of source */
|
||||
ot = (b & 1) + OT_BYTE;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = ((modrm >> 3) & 7) + OR_EAX;
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
@@ -2478,7 +2490,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
|
||||
case 0x8d: /* lea */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
/* we must ensure that no segment is added */
|
||||
s->override = -1;
|
||||
@@ -2571,7 +2583,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (mod == 3) {
|
||||
@@ -2610,7 +2622,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
op = R_GS;
|
||||
do_lxx:
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (mod == 3)
|
||||
@@ -2619,7 +2631,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_ld_T1_A0[ot + s->mem_index]();
|
||||
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
|
||||
/* load the segment first to handle exceptions properly */
|
||||
gen_op_lduw_T0_A0();
|
||||
gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
|
||||
gen_movl_seg_T0(s, op, pc_start - s->cs_base);
|
||||
/* then put the data */
|
||||
gen_op_mov_reg_T1[ot][reg]();
|
||||
@@ -2642,7 +2654,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
op = (modrm >> 3) & 7;
|
||||
@@ -2659,7 +2671,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_shift(s, op, ot, opreg, OR_ECX);
|
||||
} else {
|
||||
if (shift == 2) {
|
||||
shift = ldub(s->pc++);
|
||||
shift = ldub_code(s->pc++);
|
||||
}
|
||||
gen_shifti(s, op, ot, opreg, shift);
|
||||
}
|
||||
@@ -2693,7 +2705,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
shift = 0;
|
||||
do_shiftd:
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
reg = (modrm >> 3) & 7;
|
||||
@@ -2707,7 +2719,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_mov_TN_reg[ot][1][reg]();
|
||||
|
||||
if (shift) {
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
val &= 0x1f;
|
||||
if (val) {
|
||||
if (mod == 3)
|
||||
@@ -2736,7 +2748,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
/************************/
|
||||
/* floats */
|
||||
case 0xd8 ... 0xdf:
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
op = ((b & 7) << 3) | ((modrm >> 3) & 7);
|
||||
@@ -3253,7 +3265,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
gen_op_movl_T0_im(val);
|
||||
gen_op_in[ot]();
|
||||
gen_op_mov_reg_T1[ot][R_EAX]();
|
||||
@@ -3268,7 +3280,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
ot = OT_BYTE;
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
gen_op_movl_T0_im(val);
|
||||
gen_op_mov_TN_reg[ot][1][R_EAX]();
|
||||
gen_op_out[ot]();
|
||||
@@ -3306,7 +3318,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
/************************/
|
||||
/* control */
|
||||
case 0xc2: /* ret im */
|
||||
val = ldsw(s->pc);
|
||||
val = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
gen_pop_T0(s);
|
||||
gen_stack_update(s, val + (2 << s->dflag));
|
||||
@@ -3324,7 +3336,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 0xca: /* lret im */
|
||||
val = ldsw(s->pc);
|
||||
val = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
do_lret:
|
||||
if (s->pe && !s->vm86) {
|
||||
@@ -3440,13 +3452,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
break;
|
||||
|
||||
case 0x190 ... 0x19f: /* setcc Gv */
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
gen_setcc(s, b);
|
||||
gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
|
||||
break;
|
||||
case 0x140 ... 0x14f: /* cmov Gv, Ev */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
gen_setcc(s, b);
|
||||
@@ -3539,7 +3551,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
/* bit operations */
|
||||
case 0x1ba: /* bt/bts/btr/btc Gv, im */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
op = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
@@ -3550,7 +3562,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_mov_TN_reg[ot][0][rm]();
|
||||
}
|
||||
/* load shift */
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
gen_op_movl_T1_im(val);
|
||||
if (op < 4)
|
||||
goto illegal_op;
|
||||
@@ -3578,7 +3590,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
op = 3;
|
||||
do_btx:
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
@@ -3607,7 +3619,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0x1bc: /* bsf */
|
||||
case 0x1bd: /* bsr */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
|
||||
gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
|
||||
@@ -3643,12 +3655,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
break;
|
||||
case 0xd4: /* aam */
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
gen_op_aam(val);
|
||||
s->cc_op = CC_OP_LOGICB;
|
||||
break;
|
||||
case 0xd5: /* aad */
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
gen_op_aad(val);
|
||||
s->cc_op = CC_OP_LOGICB;
|
||||
break;
|
||||
@@ -3662,7 +3674,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
|
||||
break;
|
||||
case 0xcd: /* int N */
|
||||
val = ldub(s->pc++);
|
||||
val = ldub_code(s->pc++);
|
||||
/* XXX: add error code for vm86 GPF */
|
||||
if (!s->vm86)
|
||||
gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
|
||||
@@ -3715,7 +3727,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
break;
|
||||
case 0x62: /* bound */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
mod = (modrm >> 6) & 3;
|
||||
if (mod == 3)
|
||||
@@ -3782,7 +3794,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
break;
|
||||
case 0x100:
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
op = (modrm >> 3) & 7;
|
||||
switch(op) {
|
||||
@@ -3825,7 +3837,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
break;
|
||||
case 0x101:
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
op = (modrm >> 3) & 7;
|
||||
switch(op) {
|
||||
@@ -3901,7 +3913,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (!s->pe || s->vm86)
|
||||
goto illegal_op;
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
reg = (modrm >> 3) & 7;
|
||||
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
|
||||
gen_op_mov_TN_reg[ot][1][reg]();
|
||||
@@ -3915,7 +3927,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_mov_reg_T1[ot][reg]();
|
||||
break;
|
||||
case 0x118:
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
op = (modrm >> 3) & 7;
|
||||
switch(op) {
|
||||
@@ -3937,7 +3949,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (s->cpl != 0) {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
} else {
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
if ((modrm & 0xc0) != 0xc0)
|
||||
goto illegal_op;
|
||||
rm = modrm & 7;
|
||||
@@ -3967,7 +3979,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (s->cpl != 0) {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
} else {
|
||||
modrm = ldub(s->pc++);
|
||||
modrm = ldub_code(s->pc++);
|
||||
if ((modrm & 0xc0) != 0xc0)
|
||||
goto illegal_op;
|
||||
rm = modrm & 7;
|
||||
@@ -4368,6 +4380,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
|
||||
dc->iopl = (flags >> IOPL_SHIFT) & 3;
|
||||
dc->tf = (flags >> TF_SHIFT) & 1;
|
||||
dc->singlestep_enabled = env->singlestep_enabled;
|
||||
dc->cc_op = CC_OP_DYNAMIC;
|
||||
dc->cs_base = cs_base;
|
||||
dc->tb = tb;
|
||||
@@ -4425,7 +4438,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
break;
|
||||
/* if single step mode, we generate only one instruction and
|
||||
generate an exception */
|
||||
if (dc->tf) {
|
||||
if (dc->tf || dc->singlestep_enabled) {
|
||||
gen_op_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
46
target-sparc/cpu.h
Normal file
46
target-sparc/cpu.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef CPU_SPARC_H
|
||||
#define CPU_SPARC_H
|
||||
|
||||
#include <setjmp.h>
|
||||
#include "config.h"
|
||||
#include "cpu-defs.h"
|
||||
|
||||
/*#define EXCP_INTERRUPT 0x100*/
|
||||
|
||||
|
||||
#define PSR_NEG (1<<23)
|
||||
#define PSR_ZERO (1<<22)
|
||||
#define PSR_OVF (1<<21)
|
||||
#define PSR_CARRY (1<<20)
|
||||
|
||||
typedef struct CPUSPARCState {
|
||||
uint32_t gregs[8]; /* general registers */
|
||||
uint32_t *regwptr; /* pointer to current register window */
|
||||
double *regfptr; /* floating point registers */
|
||||
uint32_t pc; /* program counter */
|
||||
uint32_t npc; /* next program counter */
|
||||
uint32_t sp; /* stack pointer */
|
||||
uint32_t y; /* multiply/divide register */
|
||||
uint32_t psr; /* processor state register */
|
||||
uint32_t T2;
|
||||
jmp_buf jmp_env;
|
||||
int user_mode_only;
|
||||
int exception_index;
|
||||
int interrupt_index;
|
||||
int interrupt_request;
|
||||
struct TranslationBlock *current_tb;
|
||||
void *opaque;
|
||||
} CPUSPARCState;
|
||||
|
||||
CPUSPARCState *cpu_sparc_init(void);
|
||||
int cpu_sparc_exec(CPUSPARCState *s);
|
||||
int cpu_sparc_close(CPUSPARCState *s);
|
||||
|
||||
struct siginfo;
|
||||
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
|
||||
void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags);
|
||||
|
||||
#define TARGET_PAGE_BITS 13
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif
|
16
target-sparc/exec.h
Normal file
16
target-sparc/exec.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef EXEC_SPARC_H
|
||||
#define EXEC_SPARC_H 1
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
register struct CPUSPARCState *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void cpu_loop_exit(void);
|
||||
#endif
|
500
target-sparc/op.c
Normal file
500
target-sparc/op.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
SPARC micro operations
|
||||
|
||||
Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
/*XXX*/
|
||||
#define REGNAME g0
|
||||
#define REG (env->gregs[0])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g1
|
||||
#define REG (env->gregs[1])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g2
|
||||
#define REG (env->gregs[2])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g3
|
||||
#define REG (env->gregs[3])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g4
|
||||
#define REG (env->gregs[4])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g5
|
||||
#define REG (env->gregs[5])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g6
|
||||
#define REG (env->gregs[6])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g7
|
||||
#define REG (env->gregs[7])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i0
|
||||
#define REG (env->regwptr[16])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i1
|
||||
#define REG (env->regwptr[17])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i2
|
||||
#define REG (env->regwptr[18])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i3
|
||||
#define REG (env->regwptr[19])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i4
|
||||
#define REG (env->regwptr[20])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i5
|
||||
#define REG (env->regwptr[21])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i6
|
||||
#define REG (env->regwptr[22])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i7
|
||||
#define REG (env->regwptr[23])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l0
|
||||
#define REG (env->regwptr[8])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l1
|
||||
#define REG (env->regwptr[9])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l2
|
||||
#define REG (env->regwptr[10])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l3
|
||||
#define REG (env->regwptr[11])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l4
|
||||
#define REG (env->regwptr[12])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l5
|
||||
#define REG (env->regwptr[13])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l6
|
||||
#define REG (env->regwptr[14])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l7
|
||||
#define REG (env->regwptr[15])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o0
|
||||
#define REG (env->regwptr[0])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o1
|
||||
#define REG (env->regwptr[1])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o2
|
||||
#define REG (env->regwptr[2])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o3
|
||||
#define REG (env->regwptr[3])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o4
|
||||
#define REG (env->regwptr[4])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o5
|
||||
#define REG (env->regwptr[5])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o6
|
||||
#define REG (env->regwptr[6])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o7
|
||||
#define REG (env->regwptr[7])
|
||||
#include "op_template.h"
|
||||
|
||||
#define EIP (env->pc)
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_1(void)
|
||||
{
|
||||
T0 = 1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_im(void)
|
||||
{
|
||||
T0 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T1_im(void)
|
||||
{
|
||||
T1 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T2_im(void)
|
||||
{
|
||||
T2 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_im(void)
|
||||
{
|
||||
T1 += PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_T2(void)
|
||||
{
|
||||
T1 += T2;
|
||||
}
|
||||
|
||||
void OPPROTO op_subl_T1_T2(void)
|
||||
{
|
||||
T1 -= T2;
|
||||
}
|
||||
|
||||
void OPPROTO op_add_T1_T0 (void)
|
||||
{
|
||||
T0 += T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_and_T1_T0 (void)
|
||||
{
|
||||
T0 &= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_or_T1_T0 (void)
|
||||
{
|
||||
T0 |= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xor_T1_T0 (void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sub_T1_T0 (void)
|
||||
{
|
||||
T0 -= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_andn_T1_T0 (void)
|
||||
{
|
||||
T0 &= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_orn_T1_T0 (void)
|
||||
{
|
||||
T0 |= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xnor_T1_T0 (void)
|
||||
{
|
||||
T0 ^= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addx_T1_T0 (void)
|
||||
{
|
||||
T0 += T1+((env->psr & PSR_CARRY)?1:0);
|
||||
}
|
||||
|
||||
void OPPROTO op_umul_T1_T0 (void)
|
||||
{
|
||||
unsigned long long res = T0*T1;
|
||||
T0 = res & 0xffffffff;
|
||||
env->y = res >> 32;
|
||||
}
|
||||
|
||||
void OPPROTO op_smul_T1_T0 (void)
|
||||
{
|
||||
long long res = T0*T1;
|
||||
T0 = res & 0xffffffff;
|
||||
env->y = res >> 32;
|
||||
}
|
||||
|
||||
void OPPROTO op_udiv_T1_T0 (void)
|
||||
{
|
||||
unsigned long long x0 = T0 * env->y;
|
||||
unsigned int x1 = T1;
|
||||
T0 = x0 / x1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sdiv_T1_T0 (void)
|
||||
{
|
||||
long long x0 = T0 * env->y;
|
||||
int x1 = T1;
|
||||
T0 = x0 / x1;
|
||||
}
|
||||
|
||||
void OPPROTO op_subx_T1_T0 (void)
|
||||
{
|
||||
T0 -= T1+((env->psr & PSR_CARRY)?1:0);
|
||||
}
|
||||
|
||||
void OPPROTO op_set_flags (void)
|
||||
{
|
||||
env->psr = 0;
|
||||
if (!T0) env->psr |= PSR_ZERO;
|
||||
if ((unsigned int) T0 < (unsigned int) T1) env->psr |= PSR_CARRY;
|
||||
if ((int) T0 < (int) T1) env->psr |= PSR_OVF;
|
||||
if ((int) T0 < 0) env->psr |= PSR_NEG;
|
||||
}
|
||||
|
||||
void OPPROTO op_sll (void)
|
||||
{
|
||||
T0 <<= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_srl (void)
|
||||
{
|
||||
T0 >>= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sra (void)
|
||||
{
|
||||
int x = T0 >> T1;
|
||||
T0 = x;
|
||||
}
|
||||
|
||||
void OPPROTO op_st (void)
|
||||
{
|
||||
stl ((void *) T0, T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_stb (void)
|
||||
{
|
||||
stb ((void *) T0, T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_sth (void)
|
||||
{
|
||||
stw ((void *) T0, T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ld (void)
|
||||
{
|
||||
T1 = ldl ((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldub (void)
|
||||
{
|
||||
T1 = ldub ((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_lduh (void)
|
||||
{
|
||||
T1 = lduw ((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsb (void)
|
||||
{
|
||||
T1 = ldsb ((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsh (void)
|
||||
{
|
||||
T1 = ldsw ((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldstub (void)
|
||||
{
|
||||
T1 = ldub ((void *) T0);
|
||||
stb ((void *) T0, 0xff); /* XXX: Should be Atomically */
|
||||
}
|
||||
|
||||
void OPPROTO op_swap (void)
|
||||
{
|
||||
unsigned int tmp = ldl ((void *) T0);
|
||||
stl ((void *) T0, T1); /* XXX: Should be Atomically */
|
||||
T1 = tmp;
|
||||
}
|
||||
|
||||
void OPPROTO op_ldd (void)
|
||||
{
|
||||
T1 = ldl ((void *) T0);
|
||||
T0 = ldl ((void *) T0+4);
|
||||
}
|
||||
|
||||
void OPPROTO op_wry (void)
|
||||
{
|
||||
env->y = T0^T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rdy (void)
|
||||
{
|
||||
T0 = env->y;
|
||||
}
|
||||
|
||||
#define regwptr (env->regwptr)
|
||||
|
||||
void OPPROTO op_save (void)
|
||||
{
|
||||
regwptr -= 16;
|
||||
}
|
||||
|
||||
void OPPROTO op_restore (void)
|
||||
{
|
||||
regwptr += 16;
|
||||
}
|
||||
|
||||
void OPPROTO op_trap (void)
|
||||
{
|
||||
env->exception_index = PARAM1;
|
||||
cpu_loop_exit ();
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb (void)
|
||||
{
|
||||
EXIT_TB ();
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_be (void)
|
||||
{
|
||||
T0 = (env->psr & PSR_ZERO);
|
||||
}
|
||||
|
||||
#define FLAG_SET(x) (env->psr&x)?1:0
|
||||
#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY)
|
||||
|
||||
void OPPROTO op_eval_ble (void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T0 = Z | (N^V);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bl (void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T0 = N^V;
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bleu (void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T0 = C|Z;
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bcs (void)
|
||||
{
|
||||
T0 = (env->psr & PSR_CARRY);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bvs (void)
|
||||
{
|
||||
T0 = (env->psr & PSR_OVF);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bneg (void)
|
||||
{
|
||||
T0 = (env->psr & PSR_NEG);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bne (void)
|
||||
{
|
||||
T0 = !(env->psr & PSR_ZERO);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bg (void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T0 = !(Z | (N^V));
|
||||
}
|
||||
|
||||
/*XXX: This seems to be documented wrong in the SPARC V8 Manual
|
||||
The manual states: !(N^V)
|
||||
but I assume Z | !(N^V) to be correct */
|
||||
void OPPROTO op_eval_bge (void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T0 = Z | !(N^V);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bgu (void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T0 = !(C | Z);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bcc (void)
|
||||
{
|
||||
T0 = !(env->psr & PSR_CARRY);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bpos (void)
|
||||
{
|
||||
T0 = !(env->psr & PSR_NEG);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bvc (void)
|
||||
{
|
||||
T0 = !(env->psr & PSR_OVF);
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp_im (void)
|
||||
{
|
||||
env->pc = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_call (void)
|
||||
{
|
||||
regwptr[7] = PARAM1-4;
|
||||
env->pc = PARAM1+PARAM2;
|
||||
}
|
||||
|
||||
void OPPROTO op_jmpl (void)
|
||||
{
|
||||
env->npc = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_generic_jmp_1 (void)
|
||||
{
|
||||
T1 = PARAM1;
|
||||
env->pc = PARAM1+PARAM2;
|
||||
}
|
||||
|
||||
void OPPROTO op_generic_jmp_2 (void)
|
||||
{
|
||||
T1 = PARAM1;
|
||||
env->pc = env->npc;
|
||||
}
|
||||
|
||||
unsigned long old_T0;
|
||||
|
||||
void OPPROTO op_save_T0 (void)
|
||||
{
|
||||
old_T0 = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_restore_T0 (void)
|
||||
{
|
||||
T0 = old_T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_generic_branch (void)
|
||||
{
|
||||
if (T0)
|
||||
JUMP_TB (__func__, PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB (__func__, PARAM1, 1, PARAM3);
|
||||
FORCE_RET ();
|
||||
}
|
||||
|
||||
void OPPROTO op_generic_branch_a (void)
|
||||
{
|
||||
if (T0)
|
||||
env->npc = PARAM3;
|
||||
else
|
||||
JUMP_TB (__func__, PARAM1, 0, PARAM2);
|
||||
FORCE_RET ();
|
||||
}
|
||||
|
||||
void OPPROTO op_noop (void)
|
||||
{
|
||||
}
|
48
target-sparc/op_template.h
Normal file
48
target-sparc/op_template.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPARC micro operations (templates for various register related
|
||||
* operations)
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
void OPPROTO glue(op_movl_T0_, REGNAME)(void)
|
||||
{
|
||||
T0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T1_, REGNAME)(void)
|
||||
{
|
||||
T1 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T2_, REGNAME)(void)
|
||||
{
|
||||
T2 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
|
||||
{
|
||||
REG = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
|
||||
{
|
||||
REG = T1;
|
||||
}
|
||||
|
||||
#undef REG
|
||||
#undef REGNAME
|
744
target-sparc/translate.c
Normal file
744
target-sparc/translate.c
Normal file
@@ -0,0 +1,744 @@
|
||||
/*
|
||||
SPARC translation
|
||||
|
||||
Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
SPARC has two pitfalls: Delay slots and (a)nullification.
|
||||
This is currently solved as follows:
|
||||
|
||||
'call' instructions simply execute the delay slot before the actual
|
||||
control transfer instructions.
|
||||
|
||||
'jmpl' instructions execute calculate the destination, then execute
|
||||
the delay slot and then do the control transfer.
|
||||
|
||||
(conditional) branch instructions are the most difficult ones, as the
|
||||
delay slot may be nullified (ie. not executed). This happens when a
|
||||
conditional branch is not executed (thus no control transfer happens)
|
||||
and the 'anull' bit in the branch instruction opcode is set. This is
|
||||
currently solved by doing a jump after the delay slot instruction.
|
||||
|
||||
There is also one big (currently unsolved) bug in the branch code:
|
||||
If a delay slot modifies the condition codes then the new condition
|
||||
codes, instead of the old ones will be used.
|
||||
|
||||
TODO-list:
|
||||
|
||||
FPU-Instructions
|
||||
Coprocessor-Instructions
|
||||
Fix above bug
|
||||
Check signedness issues
|
||||
Privileged instructions
|
||||
Register window overflow/underflow check
|
||||
Optimize synthetic instructions
|
||||
Optional alignment and privileged instruction check
|
||||
|
||||
-- TMO, 09/03/03
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
#define DEBUG_DISAS
|
||||
|
||||
typedef struct DisasContext {
|
||||
uint8_t *pc;
|
||||
uint8_t *npc;
|
||||
void (*branch) (struct DisasContext *, uint32_t, uint32_t);
|
||||
unsigned int delay_slot:2;
|
||||
uint32_t insn;
|
||||
uint32_t target;
|
||||
int is_br;
|
||||
struct TranslationBlock *tb;
|
||||
} DisasContext;
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s,n,copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS
|
||||
};
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
#define GET_FIELD(X, FROM, TO) \
|
||||
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
|
||||
|
||||
#define IS_IMM (insn & (1<<13))
|
||||
|
||||
static void disas_sparc_insn (DisasContext *dc);
|
||||
|
||||
typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
||||
typedef void (GenOpFunc2)(long, long);
|
||||
typedef void (GenOpFunc3)(long, long, long);
|
||||
|
||||
static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
|
||||
{
|
||||
gen_op_movl_g0_T0,
|
||||
gen_op_movl_g1_T0,
|
||||
gen_op_movl_g2_T0,
|
||||
gen_op_movl_g3_T0,
|
||||
gen_op_movl_g4_T0,
|
||||
gen_op_movl_g5_T0,
|
||||
gen_op_movl_g6_T0,
|
||||
gen_op_movl_g7_T0,
|
||||
gen_op_movl_o0_T0,
|
||||
gen_op_movl_o1_T0,
|
||||
gen_op_movl_o2_T0,
|
||||
gen_op_movl_o3_T0,
|
||||
gen_op_movl_o4_T0,
|
||||
gen_op_movl_o5_T0,
|
||||
gen_op_movl_o6_T0,
|
||||
gen_op_movl_o7_T0,
|
||||
gen_op_movl_l0_T0,
|
||||
gen_op_movl_l1_T0,
|
||||
gen_op_movl_l2_T0,
|
||||
gen_op_movl_l3_T0,
|
||||
gen_op_movl_l4_T0,
|
||||
gen_op_movl_l5_T0,
|
||||
gen_op_movl_l6_T0,
|
||||
gen_op_movl_l7_T0,
|
||||
gen_op_movl_i0_T0,
|
||||
gen_op_movl_i1_T0,
|
||||
gen_op_movl_i2_T0,
|
||||
gen_op_movl_i3_T0,
|
||||
gen_op_movl_i4_T0,
|
||||
gen_op_movl_i5_T0,
|
||||
gen_op_movl_i6_T0,
|
||||
gen_op_movl_i7_T0,
|
||||
},
|
||||
{
|
||||
gen_op_movl_g0_T1,
|
||||
gen_op_movl_g1_T1,
|
||||
gen_op_movl_g2_T1,
|
||||
gen_op_movl_g3_T1,
|
||||
gen_op_movl_g4_T1,
|
||||
gen_op_movl_g5_T1,
|
||||
gen_op_movl_g6_T1,
|
||||
gen_op_movl_g7_T1,
|
||||
gen_op_movl_o0_T1,
|
||||
gen_op_movl_o1_T1,
|
||||
gen_op_movl_o2_T1,
|
||||
gen_op_movl_o3_T1,
|
||||
gen_op_movl_o4_T1,
|
||||
gen_op_movl_o5_T1,
|
||||
gen_op_movl_o6_T1,
|
||||
gen_op_movl_o7_T1,
|
||||
gen_op_movl_l0_T1,
|
||||
gen_op_movl_l1_T1,
|
||||
gen_op_movl_l2_T1,
|
||||
gen_op_movl_l3_T1,
|
||||
gen_op_movl_l4_T1,
|
||||
gen_op_movl_l5_T1,
|
||||
gen_op_movl_l6_T1,
|
||||
gen_op_movl_l7_T1,
|
||||
gen_op_movl_i0_T1,
|
||||
gen_op_movl_i1_T1,
|
||||
gen_op_movl_i2_T1,
|
||||
gen_op_movl_i3_T1,
|
||||
gen_op_movl_i4_T1,
|
||||
gen_op_movl_i5_T1,
|
||||
gen_op_movl_i6_T1,
|
||||
gen_op_movl_i7_T1,
|
||||
}
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
|
||||
{
|
||||
gen_op_movl_T0_g0,
|
||||
gen_op_movl_T0_g1,
|
||||
gen_op_movl_T0_g2,
|
||||
gen_op_movl_T0_g3,
|
||||
gen_op_movl_T0_g4,
|
||||
gen_op_movl_T0_g5,
|
||||
gen_op_movl_T0_g6,
|
||||
gen_op_movl_T0_g7,
|
||||
gen_op_movl_T0_o0,
|
||||
gen_op_movl_T0_o1,
|
||||
gen_op_movl_T0_o2,
|
||||
gen_op_movl_T0_o3,
|
||||
gen_op_movl_T0_o4,
|
||||
gen_op_movl_T0_o5,
|
||||
gen_op_movl_T0_o6,
|
||||
gen_op_movl_T0_o7,
|
||||
gen_op_movl_T0_l0,
|
||||
gen_op_movl_T0_l1,
|
||||
gen_op_movl_T0_l2,
|
||||
gen_op_movl_T0_l3,
|
||||
gen_op_movl_T0_l4,
|
||||
gen_op_movl_T0_l5,
|
||||
gen_op_movl_T0_l6,
|
||||
gen_op_movl_T0_l7,
|
||||
gen_op_movl_T0_i0,
|
||||
gen_op_movl_T0_i1,
|
||||
gen_op_movl_T0_i2,
|
||||
gen_op_movl_T0_i3,
|
||||
gen_op_movl_T0_i4,
|
||||
gen_op_movl_T0_i5,
|
||||
gen_op_movl_T0_i6,
|
||||
gen_op_movl_T0_i7,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T1_g0,
|
||||
gen_op_movl_T1_g1,
|
||||
gen_op_movl_T1_g2,
|
||||
gen_op_movl_T1_g3,
|
||||
gen_op_movl_T1_g4,
|
||||
gen_op_movl_T1_g5,
|
||||
gen_op_movl_T1_g6,
|
||||
gen_op_movl_T1_g7,
|
||||
gen_op_movl_T1_o0,
|
||||
gen_op_movl_T1_o1,
|
||||
gen_op_movl_T1_o2,
|
||||
gen_op_movl_T1_o3,
|
||||
gen_op_movl_T1_o4,
|
||||
gen_op_movl_T1_o5,
|
||||
gen_op_movl_T1_o6,
|
||||
gen_op_movl_T1_o7,
|
||||
gen_op_movl_T1_l0,
|
||||
gen_op_movl_T1_l1,
|
||||
gen_op_movl_T1_l2,
|
||||
gen_op_movl_T1_l3,
|
||||
gen_op_movl_T1_l4,
|
||||
gen_op_movl_T1_l5,
|
||||
gen_op_movl_T1_l6,
|
||||
gen_op_movl_T1_l7,
|
||||
gen_op_movl_T1_i0,
|
||||
gen_op_movl_T1_i1,
|
||||
gen_op_movl_T1_i2,
|
||||
gen_op_movl_T1_i3,
|
||||
gen_op_movl_T1_i4,
|
||||
gen_op_movl_T1_i5,
|
||||
gen_op_movl_T1_i6,
|
||||
gen_op_movl_T1_i7,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T2_g0,
|
||||
gen_op_movl_T2_g1,
|
||||
gen_op_movl_T2_g2,
|
||||
gen_op_movl_T2_g3,
|
||||
gen_op_movl_T2_g4,
|
||||
gen_op_movl_T2_g5,
|
||||
gen_op_movl_T2_g6,
|
||||
gen_op_movl_T2_g7,
|
||||
gen_op_movl_T2_o0,
|
||||
gen_op_movl_T2_o1,
|
||||
gen_op_movl_T2_o2,
|
||||
gen_op_movl_T2_o3,
|
||||
gen_op_movl_T2_o4,
|
||||
gen_op_movl_T2_o5,
|
||||
gen_op_movl_T2_o6,
|
||||
gen_op_movl_T2_o7,
|
||||
gen_op_movl_T2_l0,
|
||||
gen_op_movl_T2_l1,
|
||||
gen_op_movl_T2_l2,
|
||||
gen_op_movl_T2_l3,
|
||||
gen_op_movl_T2_l4,
|
||||
gen_op_movl_T2_l5,
|
||||
gen_op_movl_T2_l6,
|
||||
gen_op_movl_T2_l7,
|
||||
gen_op_movl_T2_i0,
|
||||
gen_op_movl_T2_i1,
|
||||
gen_op_movl_T2_i2,
|
||||
gen_op_movl_T2_i3,
|
||||
gen_op_movl_T2_i4,
|
||||
gen_op_movl_T2_i5,
|
||||
gen_op_movl_T2_i6,
|
||||
gen_op_movl_T2_i7,
|
||||
}
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
|
||||
gen_op_movl_T0_im,
|
||||
gen_op_movl_T1_im,
|
||||
gen_op_movl_T2_im
|
||||
};
|
||||
|
||||
static inline void gen_movl_imm_TN (int reg, int imm)
|
||||
{
|
||||
gen_op_movl_TN_im[reg](imm);
|
||||
}
|
||||
|
||||
static inline void gen_movl_imm_T1 (int val)
|
||||
{
|
||||
gen_movl_imm_TN (1, val);
|
||||
}
|
||||
|
||||
static inline void gen_movl_imm_T0 (int val)
|
||||
{
|
||||
gen_movl_imm_TN (0, val);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_TN (int reg, int t)
|
||||
{
|
||||
if (reg) gen_op_movl_reg_TN[t][reg]();
|
||||
else gen_movl_imm_TN (t, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T0 (int reg)
|
||||
{
|
||||
gen_movl_reg_TN (reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T1 (int reg)
|
||||
{
|
||||
gen_movl_reg_TN (reg, 1);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T2 (int reg)
|
||||
{
|
||||
gen_movl_reg_TN (reg, 2);
|
||||
}
|
||||
|
||||
static inline void gen_movl_TN_reg (int reg, int t)
|
||||
{
|
||||
if (reg) gen_op_movl_TN_reg[t][reg]();
|
||||
}
|
||||
|
||||
static inline void gen_movl_T0_reg (int reg)
|
||||
{
|
||||
gen_movl_TN_reg (reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_T1_reg (int reg)
|
||||
{
|
||||
gen_movl_TN_reg (reg, 1);
|
||||
}
|
||||
|
||||
static void do_branch (DisasContext *dc, uint32_t target, uint32_t insn)
|
||||
{
|
||||
unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0;
|
||||
target += (uint32_t) dc->pc-4;
|
||||
if (!a) disas_sparc_insn (dc);
|
||||
switch (cond) {
|
||||
case 0x0: gen_op_movl_T0_0 (); break;
|
||||
case 0x1: gen_op_eval_be (); break;
|
||||
case 0x2: gen_op_eval_ble (); break;
|
||||
case 0x3: gen_op_eval_bl (); break;
|
||||
case 0x4: gen_op_eval_bleu (); break;
|
||||
case 0x5: gen_op_eval_bcs (); break;
|
||||
case 0x6: gen_op_eval_bneg (); break;
|
||||
case 0x7: gen_op_eval_bvs (); break;
|
||||
case 0x8: gen_op_movl_T0_1 (); break;
|
||||
case 0x9: gen_op_eval_bne (); break;
|
||||
case 0xa: gen_op_eval_bg (); break;
|
||||
case 0xb: gen_op_eval_bge (); break;
|
||||
case 0xc: gen_op_eval_bgu (); break;
|
||||
case 0xd: gen_op_eval_bcc (); break;
|
||||
case 0xe: gen_op_eval_bpos (); break;
|
||||
case 0xf: gen_op_eval_bvc (); break;
|
||||
}
|
||||
if (a && ((cond|0x8) != 0x8)) {
|
||||
gen_op_generic_branch_a ((uint32_t) dc->tb,
|
||||
(uint32_t) dc->pc+4, target);
|
||||
disas_sparc_insn (dc);
|
||||
ib = 1;
|
||||
}
|
||||
else
|
||||
if (cond && !a) {
|
||||
gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target,
|
||||
(uint32_t) dc->pc);
|
||||
ib = 1;
|
||||
}
|
||||
if (ib) dc->is_br = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* target == 0x1 means CALL- else JMPL-instruction */
|
||||
static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd)
|
||||
{
|
||||
uint32_t orig_pc = (uint32_t) dc->pc-8;
|
||||
if (target != 0x1)
|
||||
gen_op_generic_jmp_1 (orig_pc, target);
|
||||
else
|
||||
gen_op_generic_jmp_2 (orig_pc);
|
||||
gen_movl_T1_reg (rd);
|
||||
dc->is_br = DISAS_JUMP;
|
||||
gen_op_movl_T0_0 ();
|
||||
}
|
||||
|
||||
#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a)
|
||||
|
||||
static int
|
||||
sign_extend (x, len)
|
||||
int x, len;
|
||||
{
|
||||
int signbit = (1 << (len - 1));
|
||||
int mask = (signbit << 1) - 1;
|
||||
return ((x & mask) ^ signbit) - signbit;
|
||||
}
|
||||
|
||||
static void disas_sparc_insn (DisasContext *dc)
|
||||
{
|
||||
unsigned int insn, opc, rs1, rs2, rd;
|
||||
|
||||
if (dc->delay_slot == 1) {
|
||||
insn = dc->insn;
|
||||
} else {
|
||||
if (dc->delay_slot) dc->delay_slot--;
|
||||
insn = htonl (*(unsigned int *) (dc->pc));
|
||||
dc->pc += 4;
|
||||
}
|
||||
|
||||
opc = GET_FIELD (insn, 0, 1);
|
||||
|
||||
rd = GET_FIELD (insn, 2, 6);
|
||||
switch (opc) {
|
||||
case 0: /* branches/sethi */
|
||||
{
|
||||
unsigned int xop = GET_FIELD (insn, 7, 9);
|
||||
int target;
|
||||
target = GET_FIELD (insn, 10, 31);
|
||||
switch (xop) {
|
||||
case 0x0: case 0x1: /* UNIMPL */
|
||||
printf ("UNIMPLEMENTED: %p\n", dc->pc-4);
|
||||
exit (23);
|
||||
break;
|
||||
case 0x2: /* BN+x */
|
||||
{
|
||||
target <<= 2;
|
||||
target = sign_extend (target, 22);
|
||||
do_branch (dc, target, insn);
|
||||
break;
|
||||
}
|
||||
case 0x3: /* FBN+x */
|
||||
break;
|
||||
case 0x4: /* SETHI */
|
||||
gen_movl_imm_T0 (target<<10);
|
||||
gen_movl_T0_reg (rd);
|
||||
break;
|
||||
case 0x5: /*CBN+x*/
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: /*CALL*/
|
||||
{
|
||||
unsigned int target = GET_FIELDs (insn, 2, 31) << 2;
|
||||
if (dc->delay_slot) {
|
||||
do_jump (dc, target, 15);
|
||||
dc->delay_slot = 0;
|
||||
} else {
|
||||
dc->insn = insn;
|
||||
dc->delay_slot = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: /* FPU & Logical Operations */
|
||||
{
|
||||
unsigned int xop = GET_FIELD (insn, 7, 12);
|
||||
if (xop == 58) { /* generate trap */
|
||||
dc->is_br = DISAS_JUMP;
|
||||
gen_op_jmp_im ((uint32_t) dc->pc);
|
||||
if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31));
|
||||
/* else XXX*/
|
||||
gen_op_movl_T0_0 ();
|
||||
break;
|
||||
}
|
||||
if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
|
||||
exit (33);
|
||||
}
|
||||
rs1 = GET_FIELD (insn, 13, 17);
|
||||
gen_movl_reg_T0 (rs1);
|
||||
if (IS_IMM) { /* immediate */
|
||||
rs2 = GET_FIELDs (insn, 20, 31);
|
||||
gen_movl_imm_T1 (rs2);
|
||||
} else { /* register */
|
||||
rs2 = GET_FIELD (insn, 27, 31);
|
||||
gen_movl_reg_T1 (rs2);
|
||||
}
|
||||
if (xop < 0x20) {
|
||||
switch (xop &~ 0x10) {
|
||||
case 0x0:
|
||||
gen_op_add_T1_T0 ();
|
||||
break;
|
||||
case 0x1:
|
||||
gen_op_and_T1_T0 ();
|
||||
break;
|
||||
case 0x2:
|
||||
gen_op_or_T1_T0 ();
|
||||
break;
|
||||
case 0x3:
|
||||
gen_op_xor_T1_T0 ();
|
||||
break;
|
||||
case 0x4:
|
||||
gen_op_sub_T1_T0 ();
|
||||
break;
|
||||
case 0x5:
|
||||
gen_op_andn_T1_T0 ();
|
||||
break;
|
||||
case 0x6:
|
||||
gen_op_orn_T1_T0 ();
|
||||
break;
|
||||
case 0x7:
|
||||
gen_op_xnor_T1_T0 ();
|
||||
break;
|
||||
case 0x8:
|
||||
gen_op_addx_T1_T0 ();
|
||||
break;
|
||||
case 0xa:
|
||||
gen_op_umul_T1_T0 ();
|
||||
break;
|
||||
case 0xb:
|
||||
gen_op_smul_T1_T0 ();
|
||||
break;
|
||||
case 0xc:
|
||||
gen_op_subx_T1_T0 ();
|
||||
break;
|
||||
case 0xe:
|
||||
gen_op_udiv_T1_T0 ();
|
||||
break;
|
||||
case 0xf:
|
||||
gen_op_sdiv_T1_T0 ();
|
||||
break;
|
||||
default:
|
||||
exit (17);
|
||||
break;
|
||||
}
|
||||
gen_movl_T0_reg (rd);
|
||||
if (xop & 0x10) {
|
||||
gen_op_set_flags ();
|
||||
}
|
||||
} else {
|
||||
switch (xop) {
|
||||
case 0x25: /* SLL */
|
||||
gen_op_sll ();
|
||||
break;
|
||||
case 0x26:
|
||||
gen_op_srl ();
|
||||
break;
|
||||
case 0x27:
|
||||
gen_op_sra ();
|
||||
break;
|
||||
case 0x28: case 0x30:
|
||||
{
|
||||
unsigned int rdi = GET_FIELD (insn, 13, 17);
|
||||
if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry());
|
||||
/* else gen_op_su_trap (); */
|
||||
break;
|
||||
}
|
||||
/* Problem with jmpl: if restore is executed in the delay
|
||||
slot, then the wrong registers are beeing used */
|
||||
case 0x38: /* jmpl */
|
||||
{
|
||||
if (dc->delay_slot) {
|
||||
gen_op_add_T1_T0 ();
|
||||
do_jump (dc, 1, rd);
|
||||
dc->delay_slot = 0;
|
||||
} else {
|
||||
gen_op_add_T1_T0 ();
|
||||
gen_op_jmpl ();
|
||||
dc->insn = insn;
|
||||
dc->delay_slot = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x3c: /* save */
|
||||
gen_op_add_T1_T0 ();
|
||||
gen_op_save ();
|
||||
gen_movl_T0_reg (rd);
|
||||
break;
|
||||
case 0x3d: /* restore */
|
||||
gen_op_add_T1_T0 ();
|
||||
gen_op_restore ();
|
||||
gen_movl_T0_reg (rd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: /* load/store instructions */
|
||||
{
|
||||
unsigned int xop = GET_FIELD (insn, 7, 12);
|
||||
rs1 = GET_FIELD (insn, 13, 17);
|
||||
gen_movl_reg_T0 (rs1);
|
||||
if (IS_IMM) { /* immediate */
|
||||
rs2 = GET_FIELDs (insn, 20, 31);
|
||||
gen_movl_imm_T1 (rs2);
|
||||
} else { /* register */
|
||||
rs2 = GET_FIELD (insn, 27, 31);
|
||||
gen_movl_reg_T1 (rs2);
|
||||
}
|
||||
gen_op_add_T1_T0 ();
|
||||
if (xop < 4 || xop > 7) {
|
||||
switch (xop) {
|
||||
case 0x0: /* load word */
|
||||
gen_op_ld ();
|
||||
break;
|
||||
case 0x1: /* load unsigned byte */
|
||||
gen_op_ldub ();
|
||||
break;
|
||||
case 0x2: /* load unsigned halfword */
|
||||
gen_op_lduh ();
|
||||
break;
|
||||
case 0x3: /* load double word */
|
||||
gen_op_ldd ();
|
||||
gen_movl_T0_reg (rd+1);
|
||||
break;
|
||||
case 0x9: /* load signed byte */
|
||||
gen_op_ldsb ();
|
||||
break;
|
||||
case 0xa: /* load signed halfword */
|
||||
gen_op_ldsh ();
|
||||
break;
|
||||
case 0xd: /* ldstub -- XXX: should be atomically */
|
||||
gen_op_ldstub ();
|
||||
break;
|
||||
case 0x0f: /* swap register with memory. Also atomically */
|
||||
gen_op_swap ();
|
||||
break;
|
||||
}
|
||||
gen_movl_T1_reg (rd);
|
||||
} else if (xop < 8) {
|
||||
gen_movl_reg_T1 (rd);
|
||||
switch (xop) {
|
||||
case 0x4:
|
||||
gen_op_st ();
|
||||
break;
|
||||
case 0x5:
|
||||
gen_op_stb ();
|
||||
break;
|
||||
case 0x6:
|
||||
gen_op_sth ();
|
||||
break;
|
||||
case 0x7:
|
||||
gen_op_st ();
|
||||
gen_movl_reg_T1 (rd+1);
|
||||
gen_op_st ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc)
|
||||
{
|
||||
uint8_t *pc_start = (uint8_t *) tb->pc;
|
||||
uint16_t *gen_opc_end;
|
||||
DisasContext dc;
|
||||
|
||||
memset (&dc, 0, sizeof (dc));
|
||||
if (spc) {
|
||||
printf ("SearchPC not yet supported\n");
|
||||
exit (0);
|
||||
}
|
||||
dc.tb = tb;
|
||||
dc.pc = pc_start;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
do {
|
||||
disas_sparc_insn (&dc);
|
||||
} while (!dc.is_br && (gen_opc_ptr < gen_opc_end) &&
|
||||
(dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
|
||||
switch (dc.is_br) {
|
||||
case DISAS_JUMP:
|
||||
case DISAS_TB_JUMP:
|
||||
gen_op_exit_tb ();
|
||||
break;
|
||||
}
|
||||
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf (logfile, "--------------\n");
|
||||
fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start));
|
||||
disas(logfile, pc_start, dc.pc - pc_start, 0, 0);
|
||||
fprintf(logfile, "\n");
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen_intermediate_code (CPUSPARCState *env, TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 0);
|
||||
}
|
||||
|
||||
int gen_intermediate_code_pc (CPUSPARCState *env, TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 1);
|
||||
}
|
||||
|
||||
void *mycpu;
|
||||
|
||||
CPUSPARCState *cpu_sparc_init (void)
|
||||
{
|
||||
CPUSPARCState *env;
|
||||
|
||||
cpu_exec_init ();
|
||||
|
||||
if (!(env = malloc (sizeof(CPUSPARCState))))
|
||||
return (NULL);
|
||||
memset (env, 0, sizeof (*env));
|
||||
if (!(env->regwptr = malloc (0x2000)))
|
||||
return (NULL);
|
||||
memset (env->regwptr, 0, 0x2000);
|
||||
env->regwptr += 127;
|
||||
env->user_mode_only = 1;
|
||||
mycpu = env;
|
||||
return (env);
|
||||
}
|
||||
|
||||
#define GET_FLAG(a,b) ((env->psr & a)?b:'-')
|
||||
|
||||
void cpu_sparc_dump_state (CPUSPARCState *env, FILE *f, int flags)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
fprintf (f, "@PC: %p\n", (void *) env->pc);
|
||||
fprintf (f, "General Registers:\n");
|
||||
for (i=0;i<4;i++)
|
||||
fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
|
||||
fprintf (f, "\n");
|
||||
for (;i<8;i++)
|
||||
fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
|
||||
fprintf (f, "\nCurrent Register Window:\n");
|
||||
for (x=0;x<3;x++) {
|
||||
for (i=0;i<4;i++)
|
||||
fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':(x==1?'l':'i')), i, env->regwptr[i+x*8]);
|
||||
fprintf (f, "\n");
|
||||
for (;i<8;i++)
|
||||
fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr,
|
||||
GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
|
||||
GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'));
|
||||
}
|
@@ -4,11 +4,12 @@ CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
||||
TESTS=linux-test testthread sha1-i386 test-i386 runcom
|
||||
endif
|
||||
TESTS+=sha1 test_path
|
||||
TESTS+=sha1# test_path
|
||||
#TESTS+=test_path
|
||||
|
||||
QEMU=../i386/qemu
|
||||
QEMU=../i386/qemu-i386
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
@@ -16,12 +17,6 @@ hello-i386: hello-i386.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
strip $@
|
||||
|
||||
testclone: testclone.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
testsig: testsig.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
testthread: testthread.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
||||
|
||||
@@ -32,7 +27,7 @@ test_path: test_path.c
|
||||
# i386 emulation test (test various opcodes) */
|
||||
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
|
||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c \
|
||||
test-i386-code16.S test-i386-vm86.S -lm
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
@@ -44,6 +39,10 @@ endif
|
||||
$(QEMU) test-i386 > test-i386.out
|
||||
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
|
||||
|
||||
# generic Linux and CPU test
|
||||
linux-test: linux-test.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm
|
||||
|
||||
# speed test
|
||||
sha1-i386: sha1.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
509
tests/linux-test.c
Normal file
509
tests/linux-test.c
Normal file
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* linux and CPU test
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <utime.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sched.h>
|
||||
#include <dirent.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define TESTPATH "/tmp/linux-test.tmp"
|
||||
#define TESTPORT 7654
|
||||
#define STACK_SIZE 16384
|
||||
|
||||
void error1(const char *filename, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "%s:%d: ", filename, line);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int __chk_error(const char *filename, int line, int ret)
|
||||
{
|
||||
if (ret < 0) {
|
||||
error1(filename, line, "%m (ret=%d, errno=%d)",
|
||||
ret, errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define error(fmt, args...) error1(__FILE__, __LINE__, fmt, ##args)
|
||||
|
||||
#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret))
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
#define FILE_BUF_SIZE 300
|
||||
|
||||
void test_file(void)
|
||||
{
|
||||
int fd, i, len, ret;
|
||||
uint8_t buf[FILE_BUF_SIZE];
|
||||
uint8_t buf2[FILE_BUF_SIZE];
|
||||
uint8_t buf3[FILE_BUF_SIZE];
|
||||
char cur_dir[1024];
|
||||
struct stat st;
|
||||
struct utimbuf tbuf;
|
||||
struct iovec vecs[2];
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
|
||||
/* clean up, just in case */
|
||||
unlink(TESTPATH "/file1");
|
||||
unlink(TESTPATH "/file2");
|
||||
unlink(TESTPATH "/file3");
|
||||
rmdir(TESTPATH);
|
||||
|
||||
if (getcwd(cur_dir, sizeof(cur_dir)) == NULL)
|
||||
error("getcwd");
|
||||
|
||||
chk_error(mkdir(TESTPATH, 0755));
|
||||
|
||||
chk_error(chdir(TESTPATH));
|
||||
|
||||
/* open/read/write/close/readv/writev/lseek */
|
||||
|
||||
fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
||||
for(i=0;i < FILE_BUF_SIZE; i++)
|
||||
buf[i] = i;
|
||||
len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2));
|
||||
if (len != (FILE_BUF_SIZE / 2))
|
||||
error("write");
|
||||
vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2);
|
||||
vecs[0].iov_len = 16;
|
||||
vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16;
|
||||
vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16;
|
||||
len = chk_error(writev(fd, vecs, 2));
|
||||
if (len != (FILE_BUF_SIZE / 2))
|
||||
error("writev");
|
||||
chk_error(close(fd));
|
||||
|
||||
chk_error(rename("file1", "file2"));
|
||||
|
||||
fd = chk_error(open("file2", O_RDONLY));
|
||||
|
||||
len = chk_error(read(fd, buf2, FILE_BUF_SIZE));
|
||||
if (len != FILE_BUF_SIZE)
|
||||
error("read");
|
||||
if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0)
|
||||
error("memcmp");
|
||||
|
||||
#define FOFFSET 16
|
||||
ret = chk_error(lseek(fd, FOFFSET, SEEK_SET));
|
||||
if (ret != 16)
|
||||
error("lseek");
|
||||
vecs[0].iov_base = buf3;
|
||||
vecs[0].iov_len = 32;
|
||||
vecs[1].iov_base = buf3 + 32;
|
||||
vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32;
|
||||
len = chk_error(readv(fd, vecs, 2));
|
||||
if (len != FILE_BUF_SIZE - FOFFSET)
|
||||
error("readv");
|
||||
if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0)
|
||||
error("memcmp");
|
||||
|
||||
chk_error(close(fd));
|
||||
|
||||
/* access */
|
||||
chk_error(access("file2", R_OK));
|
||||
|
||||
/* stat/chmod/utime/truncate */
|
||||
|
||||
chk_error(chmod("file2", 0600));
|
||||
tbuf.actime = 1001;
|
||||
tbuf.modtime = 1000;
|
||||
chk_error(truncate("file2", 100));
|
||||
chk_error(utime("file2", &tbuf));
|
||||
chk_error(stat("file2", &st));
|
||||
if (st.st_size != 100)
|
||||
error("stat size");
|
||||
if (!S_ISREG(st.st_mode))
|
||||
error("stat mode");
|
||||
if ((st.st_mode & 0777) != 0600)
|
||||
error("stat mode2");
|
||||
if (st.st_atime != 1001 ||
|
||||
st.st_mtime != 1000)
|
||||
error("stat time");
|
||||
|
||||
chk_error(stat(TESTPATH, &st));
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
error("stat mode");
|
||||
|
||||
/* fstat */
|
||||
fd = chk_error(open("file2", O_RDWR));
|
||||
chk_error(ftruncate(fd, 50));
|
||||
chk_error(fstat(fd, &st));
|
||||
chk_error(close(fd));
|
||||
|
||||
if (st.st_size != 50)
|
||||
error("stat size");
|
||||
if (!S_ISREG(st.st_mode))
|
||||
error("stat mode");
|
||||
|
||||
/* symlink/lstat */
|
||||
chk_error(symlink("file2", "file3"));
|
||||
chk_error(lstat("file3", &st));
|
||||
if (!S_ISLNK(st.st_mode))
|
||||
error("stat mode");
|
||||
|
||||
/* getdents */
|
||||
dir = opendir(TESTPATH);
|
||||
if (!dir)
|
||||
error("opendir");
|
||||
len = 0;
|
||||
for(;;) {
|
||||
de = readdir(dir);
|
||||
if (!de)
|
||||
break;
|
||||
if (strcmp(de->d_name, ".") != 0 &&
|
||||
strcmp(de->d_name, "..") != 0 &&
|
||||
strcmp(de->d_name, "file2") != 0 &&
|
||||
strcmp(de->d_name, "file3") != 0)
|
||||
error("readdir");
|
||||
len++;
|
||||
}
|
||||
closedir(dir);
|
||||
if (len != 4)
|
||||
error("readdir");
|
||||
|
||||
chk_error(unlink("file3"));
|
||||
chk_error(unlink("file2"));
|
||||
chk_error(chdir(cur_dir));
|
||||
chk_error(rmdir(TESTPATH));
|
||||
}
|
||||
|
||||
void test_fork(void)
|
||||
{
|
||||
int pid, status;
|
||||
|
||||
pid = chk_error(fork());
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
exit(2);
|
||||
}
|
||||
chk_error(waitpid(pid, &status, 0));
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 2)
|
||||
error("waitpid status=0x%x", status);
|
||||
}
|
||||
|
||||
void test_time(void)
|
||||
{
|
||||
struct timeval tv, tv2;
|
||||
struct timespec ts, rem;
|
||||
struct rusage rusg1, rusg2;
|
||||
int ti, i;
|
||||
|
||||
chk_error(gettimeofday(&tv, NULL));
|
||||
rem.tv_sec = 1;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 20 * 1000000;
|
||||
chk_error(nanosleep(&ts, &rem));
|
||||
if (rem.tv_sec != 1)
|
||||
error("nanosleep");
|
||||
chk_error(gettimeofday(&tv2, NULL));
|
||||
ti = tv2.tv_sec - tv.tv_sec;
|
||||
if (ti >= 2)
|
||||
error("gettimeofday");
|
||||
|
||||
chk_error(getrusage(RUSAGE_SELF, &rusg1));
|
||||
for(i = 0;i < 10000; i++);
|
||||
chk_error(getrusage(RUSAGE_SELF, &rusg2));
|
||||
if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 ||
|
||||
(rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0)
|
||||
error("getrusage");
|
||||
}
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int server_socket(void)
|
||||
{
|
||||
int val, fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
|
||||
/* server socket */
|
||||
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
|
||||
|
||||
val = 1;
|
||||
chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(TESTPORT);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
|
||||
chk_error(listen(fd, 0));
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
int client_socket(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
|
||||
/* server socket */
|
||||
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(TESTPORT);
|
||||
inet_aton("127.0.0.1", &sockaddr.sin_addr);
|
||||
chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
|
||||
return fd;
|
||||
}
|
||||
|
||||
const char socket_msg[] = "hello socket\n";
|
||||
|
||||
void test_socket(void)
|
||||
{
|
||||
int server_fd, client_fd, fd, pid, ret;
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
char buf[512];
|
||||
|
||||
server_fd = server_socket();
|
||||
pid = chk_error(fork());
|
||||
if (pid == 0) {
|
||||
client_fd = client_socket();
|
||||
send(client_fd, socket_msg, sizeof(socket_msg), 0);
|
||||
close(client_fd);
|
||||
exit(0);
|
||||
}
|
||||
len = sizeof(sockaddr);
|
||||
fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len));
|
||||
|
||||
ret = chk_error(recv(fd, buf, sizeof(buf), 0));
|
||||
if (ret != sizeof(socket_msg))
|
||||
error("recv");
|
||||
if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0)
|
||||
error("socket_msg");
|
||||
chk_error(close(fd));
|
||||
chk_error(close(server_fd));
|
||||
}
|
||||
|
||||
#define WCOUNT_MAX 512
|
||||
|
||||
void test_pipe(void)
|
||||
{
|
||||
fd_set rfds, wfds;
|
||||
int fds[2], fd_max, ret;
|
||||
uint8_t ch;
|
||||
int wcount, rcount;
|
||||
|
||||
chk_error(pipe(fds));
|
||||
chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK));
|
||||
chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK));
|
||||
wcount = 0;
|
||||
rcount = 0;
|
||||
for(;;) {
|
||||
FD_ZERO(&rfds);
|
||||
fd_max = fds[0];
|
||||
FD_SET(fds[0], &rfds);
|
||||
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(fds[1], &wfds);
|
||||
if (fds[1] > fd_max)
|
||||
fd_max = fds[1];
|
||||
|
||||
ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL));
|
||||
if (ret > 0) {
|
||||
if (FD_ISSET(fds[0], &rfds)) {
|
||||
chk_error(read(fds[0], &ch, 1));
|
||||
rcount++;
|
||||
if (rcount >= WCOUNT_MAX)
|
||||
break;
|
||||
}
|
||||
if (FD_ISSET(fds[1], &wfds)) {
|
||||
ch = 'a';
|
||||
chk_error(write(fds[0], &ch, 1));
|
||||
wcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
chk_error(close(fds[0]));
|
||||
chk_error(close(fds[1]));
|
||||
}
|
||||
|
||||
int thread1_res;
|
||||
int thread2_res;
|
||||
|
||||
int thread1_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<5;i++) {
|
||||
thread1_res++;
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread2_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<6;i++) {
|
||||
thread2_res++;
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_clone(void)
|
||||
{
|
||||
uint8_t *stack1, *stack2;
|
||||
int pid1, pid2, status1, status2;
|
||||
|
||||
stack1 = malloc(STACK_SIZE);
|
||||
pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"));
|
||||
|
||||
stack2 = malloc(STACK_SIZE);
|
||||
pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"));
|
||||
|
||||
while (waitpid(pid1, &status1, 0) != pid1);
|
||||
while (waitpid(pid2, &status2, 0) != pid2);
|
||||
if (thread1_res != 5 ||
|
||||
thread2_res != 6)
|
||||
error("clone");
|
||||
}
|
||||
|
||||
/***********************************/
|
||||
|
||||
volatile int alarm_count;
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void sig_alarm(int sig)
|
||||
{
|
||||
if (sig != SIGALRM)
|
||||
error("signal");
|
||||
alarm_count++;
|
||||
}
|
||||
|
||||
void sig_segv(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
if (sig != SIGSEGV)
|
||||
error("signal");
|
||||
longjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
void test_signal(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
struct itimerval it, oit;
|
||||
|
||||
/* timer test */
|
||||
|
||||
alarm_count = 0;
|
||||
|
||||
act.sa_handler = sig_alarm;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
chk_error(sigaction(SIGALRM, &act, NULL));
|
||||
|
||||
it.it_interval.tv_sec = 0;
|
||||
it.it_interval.tv_usec = 10 * 1000;
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = 10 * 1000;
|
||||
chk_error(setitimer(ITIMER_REAL, &it, NULL));
|
||||
chk_error(getitimer(ITIMER_REAL, &oit));
|
||||
if (oit.it_value.tv_sec != it.it_value.tv_sec ||
|
||||
oit.it_value.tv_usec != it.it_value.tv_usec)
|
||||
error("itimer");
|
||||
|
||||
while (alarm_count < 5) {
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
|
||||
it.it_interval.tv_sec = 0;
|
||||
it.it_interval.tv_usec = 0;
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = 0;
|
||||
memset(&oit, 0xff, sizeof(oit));
|
||||
chk_error(setitimer(ITIMER_REAL, &it, &oit));
|
||||
if (oit.it_value.tv_sec != 0 ||
|
||||
oit.it_value.tv_usec != 10 * 1000)
|
||||
error("setitimer");
|
||||
|
||||
/* SIGSEGV test */
|
||||
act.sa_sigaction = sig_segv;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
chk_error(sigaction(SIGSEGV, &act, NULL));
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
*(uint8_t *)0 = 0;
|
||||
}
|
||||
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
chk_error(sigaction(SIGSEGV, &act, NULL));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_file();
|
||||
test_fork();
|
||||
test_time();
|
||||
test_socket();
|
||||
test_clone();
|
||||
test_signal();
|
||||
return 0;
|
||||
}
|
@@ -1,3 +1,22 @@
|
||||
/*
|
||||
* x86 CPU test
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@@ -1,62 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sched.h>
|
||||
|
||||
int thread1_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
|
||||
for(i=0;i<10;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread2_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
for(i=0;i<20;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(120 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STACK_SIZE 16384
|
||||
|
||||
void test_clone(void)
|
||||
{
|
||||
uint8_t *stack1, *stack2;
|
||||
int pid1, pid2, status1, status2;
|
||||
|
||||
stack1 = malloc(STACK_SIZE);
|
||||
pid1 = clone(thread1_func, stack1 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
|
||||
|
||||
stack2 = malloc(STACK_SIZE);
|
||||
pid2 = clone(thread2_func, stack2 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
|
||||
|
||||
while (waitpid(pid1, &status1, 0) != pid1);
|
||||
while (waitpid(pid2, &status2, 0) != pid2);
|
||||
printf("status1=0x%x\n", status1);
|
||||
printf("status2=0x%x\n", status2);
|
||||
printf("End of clone test.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_clone();
|
||||
return 0;
|
||||
}
|
194
tests/testsig.c
194
tests/testsig.c
@@ -1,194 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void alarm_handler(int sig)
|
||||
{
|
||||
printf("alarm signal=%d\n", sig);
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
#ifndef REG_EAX
|
||||
#define REG_EAX EAX
|
||||
#define REG_EBX EBX
|
||||
#define REG_ECX ECX
|
||||
#define REG_EDX EDX
|
||||
#define REG_ESI ESI
|
||||
#define REG_EDI EDI
|
||||
#define REG_EBP EBP
|
||||
#define REG_ESP ESP
|
||||
#define REG_EIP EIP
|
||||
#define REG_EFL EFL
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#define REG_ERR ERR
|
||||
#endif
|
||||
|
||||
void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x trapno=%02x err=%08x\n",
|
||||
uc->uc_mcontext.gregs[REG_EAX],
|
||||
uc->uc_mcontext.gregs[REG_EBX],
|
||||
uc->uc_mcontext.gregs[REG_ECX],
|
||||
uc->uc_mcontext.gregs[REG_EDX],
|
||||
uc->uc_mcontext.gregs[REG_ESI],
|
||||
uc->uc_mcontext.gregs[REG_EDI],
|
||||
uc->uc_mcontext.gregs[REG_EBP],
|
||||
uc->uc_mcontext.gregs[REG_ESP],
|
||||
uc->uc_mcontext.gregs[REG_EFL],
|
||||
uc->uc_mcontext.gregs[REG_EIP],
|
||||
uc->uc_mcontext.gregs[REG_TRAPNO],
|
||||
uc->uc_mcontext.gregs[REG_ERR]);
|
||||
}
|
||||
|
||||
void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
|
||||
printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n",
|
||||
strsignal(info->si_signo),
|
||||
info->si_signo, info->si_errno, info->si_code,
|
||||
(unsigned long)info->si_addr);
|
||||
dump_regs(uc);
|
||||
longjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
int v1;
|
||||
int tab[2];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act;
|
||||
volatile int val;
|
||||
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGTRAP, &act, NULL);
|
||||
|
||||
/* test division by zero reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now divide by zero */
|
||||
v1 = 0;
|
||||
v1 = 2 / v1;
|
||||
}
|
||||
|
||||
/* test illegal instruction reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now execute an invalid instruction */
|
||||
asm volatile("ud2");
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now store in an invalid address */
|
||||
*(char *)0x1234 = 1;
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* read from an invalid address */
|
||||
v1 = *(char *)0x1234;
|
||||
}
|
||||
|
||||
printf("segment GPF exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* load an invalid segment */
|
||||
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0));
|
||||
}
|
||||
|
||||
printf("INT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0xfd");
|
||||
}
|
||||
|
||||
printf("INT3 exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int3");
|
||||
}
|
||||
|
||||
printf("CLI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("STI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("INTO exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* overflow exception */
|
||||
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
|
||||
}
|
||||
|
||||
printf("BOUND exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* bound exception */
|
||||
tab[0] = 1;
|
||||
tab[1] = 10;
|
||||
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
|
||||
}
|
||||
|
||||
printf("OUTB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
|
||||
}
|
||||
|
||||
printf("INB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
|
||||
}
|
||||
|
||||
printf("REP OUTSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("REP INSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("HLT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
|
||||
printf("single step exception:\n");
|
||||
val = 0;
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("pushf\n"
|
||||
"orl $0x00100, (%%esp)\n"
|
||||
"popf\n"
|
||||
"movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory");
|
||||
}
|
||||
printf("val=0x%x\n", val);
|
||||
|
||||
#if 1
|
||||
{
|
||||
int i;
|
||||
act.sa_handler = alarm_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
alarm(1);
|
||||
for(i = 0;i < 2; i++) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
428
texi2pod.pl
Executable file
428
texi2pod.pl
Executable file
@@ -0,0 +1,428 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU CC.
|
||||
|
||||
# GNU CC 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, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GNU CC 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 GNU CC; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
# Boston MA 02111-1307, USA.
|
||||
|
||||
# This does trivial (and I mean _trivial_) conversion of Texinfo
|
||||
# markup to Perl POD format. It's intended to be used to extract
|
||||
# something suitable for a manpage from a Texinfo document.
|
||||
|
||||
$output = 0;
|
||||
$skipping = 0;
|
||||
%sects = ();
|
||||
$section = "";
|
||||
@icstack = ();
|
||||
@endwstack = ();
|
||||
@skstack = ();
|
||||
@instack = ();
|
||||
$shift = "";
|
||||
%defs = ();
|
||||
$fnno = 1;
|
||||
$inf = "";
|
||||
$ibase = "";
|
||||
|
||||
while ($_ = shift) {
|
||||
if (/^-D(.*)$/) {
|
||||
if ($1 ne "") {
|
||||
$flag = $1;
|
||||
} else {
|
||||
$flag = shift;
|
||||
}
|
||||
$value = "";
|
||||
($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
|
||||
die "no flag specified for -D\n"
|
||||
unless $flag ne "";
|
||||
die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
|
||||
unless $flag =~ /^[a-zA-Z0-9_-]+$/;
|
||||
$defs{$flag} = $value;
|
||||
} elsif (/^-/) {
|
||||
usage();
|
||||
} else {
|
||||
$in = $_, next unless defined $in;
|
||||
$out = $_, next unless defined $out;
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $in) {
|
||||
$inf = gensym();
|
||||
open($inf, "<$in") or die "opening \"$in\": $!\n";
|
||||
$ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
|
||||
} else {
|
||||
$inf = \*STDIN;
|
||||
}
|
||||
|
||||
if (defined $out) {
|
||||
open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
|
||||
}
|
||||
|
||||
while(defined $inf) {
|
||||
while(<$inf>) {
|
||||
# Certain commands are discarded without further processing.
|
||||
/^\@(?:
|
||||
[a-z]+index # @*index: useful only in complete manual
|
||||
|need # @need: useful only in printed manual
|
||||
|(?:end\s+)?group # @group .. @end group: ditto
|
||||
|page # @page: ditto
|
||||
|node # @node: useful only in .info file
|
||||
|(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents
|
||||
)\b/x and next;
|
||||
|
||||
chomp;
|
||||
|
||||
# Look for filename and title markers.
|
||||
/^\@setfilename\s+([^.]+)/ and $fn = $1, next;
|
||||
/^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
|
||||
|
||||
# Identify a man title but keep only the one we are interested in.
|
||||
/^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
|
||||
if (exists $defs{$1}) {
|
||||
$fn = $1;
|
||||
$tl = postprocess($2);
|
||||
}
|
||||
next;
|
||||
};
|
||||
|
||||
# Look for blocks surrounded by @c man begin SECTION ... @c man end.
|
||||
# This really oughta be @ifman ... @end ifman and the like, but such
|
||||
# would require rev'ing all other Texinfo translators.
|
||||
/^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
|
||||
$output = 1 if exists $defs{$2};
|
||||
$sect = $1;
|
||||
next;
|
||||
};
|
||||
/^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
|
||||
/^\@c\s+man\s+end/ and do {
|
||||
$sects{$sect} = "" unless exists $sects{$sect};
|
||||
$sects{$sect} .= postprocess($section);
|
||||
$section = "";
|
||||
$output = 0;
|
||||
next;
|
||||
};
|
||||
|
||||
# handle variables
|
||||
/^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
|
||||
$defs{$1} = $2;
|
||||
next;
|
||||
};
|
||||
/^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
delete $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
next unless $output;
|
||||
|
||||
# Discard comments. (Can't do it above, because then we'd never see
|
||||
# @c man lines.)
|
||||
/^\@c\b/ and next;
|
||||
|
||||
# End-block handler goes up here because it needs to operate even
|
||||
# if we are skipping.
|
||||
/^\@end\s+([a-z]+)/ and do {
|
||||
# Ignore @end foo, where foo is not an operation which may
|
||||
# cause us to skip, if we are presently skipping.
|
||||
my $ended = $1;
|
||||
next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/;
|
||||
|
||||
die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
|
||||
die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
|
||||
|
||||
$endw = pop @endwstack;
|
||||
|
||||
if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
|
||||
$skipping = pop @skstack;
|
||||
next;
|
||||
} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
|
||||
$shift = "";
|
||||
$_ = ""; # need a paragraph break
|
||||
} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
|
||||
$_ = "\n=back\n";
|
||||
$ic = pop @icstack;
|
||||
} else {
|
||||
die "unknown command \@end $ended at line $.\n";
|
||||
}
|
||||
};
|
||||
|
||||
# We must handle commands which can cause skipping even while we
|
||||
# are skipping, otherwise we will not process nested conditionals
|
||||
# correctly.
|
||||
/^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = "ifset";
|
||||
$skipping = 1 unless exists $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = "ifclear";
|
||||
$skipping = 1 if exists $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@(ignore|menu|iftex)\b/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = $1;
|
||||
$skipping = 1;
|
||||
next;
|
||||
};
|
||||
|
||||
next if $skipping;
|
||||
|
||||
# Character entities. First the ones that can be replaced by raw text
|
||||
# or discarded outright:
|
||||
s/\@copyright\{\}/(c)/g;
|
||||
s/\@dots\{\}/.../g;
|
||||
s/\@enddots\{\}/..../g;
|
||||
s/\@([.!? ])/$1/g;
|
||||
s/\@[:-]//g;
|
||||
s/\@bullet(?:\{\})?/*/g;
|
||||
s/\@TeX\{\}/TeX/g;
|
||||
s/\@pounds\{\}/\#/g;
|
||||
s/\@minus(?:\{\})?/-/g;
|
||||
s/\\,/,/g;
|
||||
|
||||
# Now the ones that have to be replaced by special escapes
|
||||
# (which will be turned back into text by unmunge())
|
||||
s/&/&/g;
|
||||
s/\@\{/{/g;
|
||||
s/\@\}/}/g;
|
||||
s/\@\@/&at;/g;
|
||||
|
||||
# Inside a verbatim block, handle @var specially.
|
||||
if ($shift ne "") {
|
||||
s/\@var\{([^\}]*)\}/<$1>/g;
|
||||
}
|
||||
|
||||
# POD doesn't interpret E<> inside a verbatim block.
|
||||
if ($shift eq "") {
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
} else {
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
}
|
||||
|
||||
# Single line command handlers.
|
||||
|
||||
/^\@include\s+(.+)$/ and do {
|
||||
push @instack, $inf;
|
||||
$inf = gensym();
|
||||
|
||||
# Try cwd and $ibase.
|
||||
open($inf, "<" . $1)
|
||||
or open($inf, "<" . $ibase . "/" . $1)
|
||||
or die "cannot open $1 or $ibase/$1: $!\n";
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
|
||||
and $_ = "\n=head2 $1\n";
|
||||
/^\@subsection\s+(.+)$/
|
||||
and $_ = "\n=head3 $1\n";
|
||||
|
||||
# Block command handlers:
|
||||
/^\@itemize\s+(\@[a-z]+|\*|-)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
$ic = $1;
|
||||
$_ = "\n=over 4\n";
|
||||
$endw = "itemize";
|
||||
};
|
||||
|
||||
/^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
if (defined $1) {
|
||||
$ic = $1 . ".";
|
||||
} else {
|
||||
$ic = "1.";
|
||||
}
|
||||
$_ = "\n=over 4\n";
|
||||
$endw = "enumerate";
|
||||
};
|
||||
|
||||
/^\@([fv]?table)\s+(\@[a-z]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
$endw = $1;
|
||||
$ic = $2;
|
||||
$ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
|
||||
$ic =~ s/\@(?:code|kbd)/C/;
|
||||
$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
|
||||
$ic =~ s/\@(?:file)/F/;
|
||||
$_ = "\n=over 4\n";
|
||||
};
|
||||
|
||||
/^\@((?:small)?example|display)/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = $1;
|
||||
$shift = "\t";
|
||||
$_ = ""; # need a paragraph break
|
||||
};
|
||||
|
||||
/^\@itemx?\s*(.+)?$/ and do {
|
||||
if (defined $1) {
|
||||
# Entity escapes prevent munging by the <> processing below.
|
||||
# print "$ic\n";
|
||||
$_ = "\n=item $ic\<$1\>\n";
|
||||
} else {
|
||||
$_ = "\n=item $ic\n";
|
||||
$ic =~ y/A-Ya-y/B-Zb-z/;
|
||||
$ic =~ s/(\d+)/$1 + 1/eg;
|
||||
}
|
||||
};
|
||||
|
||||
$section .= $shift.$_."\n";
|
||||
}
|
||||
# End of current file.
|
||||
close($inf);
|
||||
$inf = pop @instack;
|
||||
}
|
||||
|
||||
die "No filename or title\n" unless defined $fn && defined $tl;
|
||||
|
||||
$sects{NAME} = "$fn \- $tl\n";
|
||||
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
|
||||
|
||||
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
|
||||
BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
|
||||
if(exists $sects{$sect}) {
|
||||
$head = $sect;
|
||||
$head =~ s/SEEALSO/SEE ALSO/;
|
||||
print "=head1 $head\n\n";
|
||||
print scalar unmunge ($sects{$sect});
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die "usage: $0 [-D toggle...] [infile [outfile]]\n";
|
||||
}
|
||||
|
||||
sub postprocess
|
||||
{
|
||||
local $_ = $_[0];
|
||||
|
||||
# @value{foo} is replaced by whatever 'foo' is defined as.
|
||||
while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
|
||||
if (! exists $defs{$2}) {
|
||||
print STDERR "Option $2 not defined\n";
|
||||
s/\Q$1\E//;
|
||||
} else {
|
||||
$value = $defs{$2};
|
||||
s/\Q$1\E/$value/;
|
||||
}
|
||||
}
|
||||
|
||||
# Formatting commands.
|
||||
# Temporary escape for @r.
|
||||
s/\@r\{([^\}]*)\}/R<$1>/g;
|
||||
s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
|
||||
s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
|
||||
s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
|
||||
s/\@sc\{([^\}]*)\}/\U$1/g;
|
||||
s/\@file\{([^\}]*)\}/F<$1>/g;
|
||||
s/\@w\{([^\}]*)\}/S<$1>/g;
|
||||
s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
|
||||
|
||||
# Cross references are thrown away, as are @noindent and @refill.
|
||||
# (@noindent is impossible in .pod, and @refill is unnecessary.)
|
||||
# @* is also impossible in .pod; we discard it and any newline that
|
||||
# follows it. Similarly, our macro @gol must be discarded.
|
||||
|
||||
s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
|
||||
s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
|
||||
s/;\s+\@pxref\{(?:[^\}]*)\}//g;
|
||||
s/\@noindent\s*//g;
|
||||
s/\@refill//g;
|
||||
s/\@gol//g;
|
||||
s/\@\*\s*\n?//g;
|
||||
|
||||
# @uref can take one, two, or three arguments, with different
|
||||
# semantics each time. @url and @email are just like @uref with
|
||||
# one argument, for our purposes.
|
||||
s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g;
|
||||
s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
|
||||
s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
|
||||
|
||||
# Turn B<blah I<blah> blah> into B<blah> I<blah> B<blah> to
|
||||
# match Texinfo semantics of @emph inside @samp. Also handle @r
|
||||
# inside bold.
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B</g;
|
||||
1 while (s/B<([^<>]*)I<([^>]+)>/B<$1>I<$2>B</g);
|
||||
1 while (s/I<([^<>]*)B<([^>]+)>/I<$1>B<$2>I</g);
|
||||
s/[BI]<>//g;
|
||||
s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
|
||||
s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
|
||||
|
||||
# Extract footnotes. This has to be done after all other
|
||||
# processing because otherwise the regexp will choke on formatting
|
||||
# inside @footnote.
|
||||
while (/\@footnote/g) {
|
||||
s/\@footnote\{([^\}]+)\}/[$fnno]/;
|
||||
add_footnote($1, $fnno);
|
||||
$fnno++;
|
||||
}
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub unmunge
|
||||
{
|
||||
# Replace escaped symbols with their equivalents.
|
||||
local $_ = $_[0];
|
||||
|
||||
s/</E<lt>/g;
|
||||
s/>/E<gt>/g;
|
||||
s/{/\{/g;
|
||||
s/}/\}/g;
|
||||
s/&at;/\@/g;
|
||||
s/&/&/g;
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub add_footnote
|
||||
{
|
||||
unless (exists $sects{FOOTNOTES}) {
|
||||
$sects{FOOTNOTES} = "\n=over 4\n\n";
|
||||
}
|
||||
|
||||
$sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
|
||||
$sects{FOOTNOTES} .= $_[0];
|
||||
$sects{FOOTNOTES} .= "\n\n";
|
||||
}
|
||||
|
||||
# stolen from Symbol.pm
|
||||
{
|
||||
my $genseq = 0;
|
||||
sub gensym
|
||||
{
|
||||
my $name = "GEN" . $genseq++;
|
||||
my $ref = \*{$name};
|
||||
delete $::{$name};
|
||||
return $ref;
|
||||
}
|
||||
}
|
@@ -26,34 +26,19 @@
|
||||
#include "config.h"
|
||||
|
||||
#define IN_OP_I386
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#define OPC_CPU_H "opc-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#define OPC_CPU_H "opc-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "dyngen.h"
|
||||
#if defined(TARGET_I386)
|
||||
#include "op-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "op-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#include "op.h"
|
||||
|
||||
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
@@ -66,13 +51,13 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
@@ -146,7 +131,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb,
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
@@ -204,6 +189,8 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
env->regs[15] = gen_opc_pc[j];
|
||||
#elif defined(TARGET_SPARC)
|
||||
env->pc = gen_opc_pc[j];
|
||||
#endif
|
||||
return 0;
|
||||
}
|
370
vl.c
370
vl.c
@@ -44,14 +44,13 @@
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "cpu.h"
|
||||
#include "disas.h"
|
||||
#include "thunk.h"
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/vl.log"
|
||||
#define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup"
|
||||
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
|
||||
#define BIOS_FILENAME "bios.bin"
|
||||
#define VGABIOS_FILENAME "vgabios.bin"
|
||||
|
||||
@@ -205,18 +204,16 @@ struct __attribute__ ((packed)) linux_params {
|
||||
|
||||
#define MAX_IOPORTS 4096
|
||||
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
static const char *bios_dir = CONFIG_QEMU_SHAREDIR;
|
||||
char phys_ram_file[1024];
|
||||
CPUX86State *global_env;
|
||||
CPUX86State *cpu_single_env;
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
|
||||
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
|
||||
BlockDriverState *bs_table[MAX_DISKS];
|
||||
int vga_ram_size;
|
||||
static DisplayState display_state;
|
||||
int nodisp;
|
||||
int nographic;
|
||||
int term_inited;
|
||||
int64_t ticks_per_sec;
|
||||
|
||||
@@ -832,6 +829,69 @@ int speaker_data_on;
|
||||
int dummy_refresh_clock;
|
||||
int pit_min_timer_count = 0;
|
||||
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
static inline uint32_t get_tbl(void)
|
||||
{
|
||||
uint32_t tbl;
|
||||
asm volatile("mftb %0" : "=r" (tbl));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
static inline uint32_t get_tbu(void)
|
||||
{
|
||||
uint32_t tbl;
|
||||
asm volatile("mftbu %0" : "=r" (tbl));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t l, h, h1;
|
||||
/* NOTE: we test if wrapping has occurred */
|
||||
do {
|
||||
h = get_tbu();
|
||||
l = get_tbl();
|
||||
h1 = get_tbu();
|
||||
} while (h != h1);
|
||||
return ((int64_t)h << 32) | l;
|
||||
}
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
static int64_t cpu_ticks_offset;
|
||||
static int64_t cpu_ticks_last;
|
||||
|
||||
int64_t cpu_get_ticks(void)
|
||||
{
|
||||
return cpu_get_real_ticks() + cpu_ticks_offset;
|
||||
}
|
||||
|
||||
/* enable cpu_get_ticks() */
|
||||
void cpu_enable_ticks(void)
|
||||
{
|
||||
cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks();
|
||||
}
|
||||
|
||||
/* disable cpu_get_ticks() : the clock is stopped. You must not call
|
||||
cpu_get_ticks() after that. */
|
||||
void cpu_disable_ticks(void)
|
||||
{
|
||||
cpu_ticks_last = cpu_get_ticks();
|
||||
}
|
||||
|
||||
int64_t get_clock(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
@@ -839,13 +899,6 @@ int64_t get_clock(void)
|
||||
return tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||
}
|
||||
|
||||
int64_t cpu_get_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
void cpu_calibrate_ticks(void)
|
||||
{
|
||||
int64_t usec, ticks;
|
||||
@@ -2014,40 +2067,40 @@ static void ide_identify(IDEState *s)
|
||||
|
||||
memset(s->io_buffer, 0, 512);
|
||||
p = (uint16_t *)s->io_buffer;
|
||||
stw(p + 0, 0x0040);
|
||||
stw(p + 1, s->cylinders);
|
||||
stw(p + 3, s->heads);
|
||||
stw(p + 4, 512 * s->sectors); /* sectors */
|
||||
stw(p + 5, 512); /* sector size */
|
||||
stw(p + 6, s->sectors);
|
||||
stw(p + 20, 3); /* buffer type */
|
||||
stw(p + 21, 512); /* cache size in sectors */
|
||||
stw(p + 22, 4); /* ecc bytes */
|
||||
stw_raw(p + 0, 0x0040);
|
||||
stw_raw(p + 1, s->cylinders);
|
||||
stw_raw(p + 3, s->heads);
|
||||
stw_raw(p + 4, 512 * s->sectors); /* sectors */
|
||||
stw_raw(p + 5, 512); /* sector size */
|
||||
stw_raw(p + 6, s->sectors);
|
||||
stw_raw(p + 20, 3); /* buffer type */
|
||||
stw_raw(p + 21, 512); /* cache size in sectors */
|
||||
stw_raw(p + 22, 4); /* ecc bytes */
|
||||
padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40);
|
||||
#if MAX_MULT_SECTORS > 1
|
||||
stw(p + 47, MAX_MULT_SECTORS);
|
||||
stw_raw(p + 47, MAX_MULT_SECTORS);
|
||||
#endif
|
||||
stw(p + 48, 1); /* dword I/O */
|
||||
stw(p + 49, 1 << 9); /* LBA supported, no DMA */
|
||||
stw(p + 51, 0x200); /* PIO transfer cycle */
|
||||
stw(p + 52, 0x200); /* DMA transfer cycle */
|
||||
stw(p + 54, s->cylinders);
|
||||
stw(p + 55, s->heads);
|
||||
stw(p + 56, s->sectors);
|
||||
stw_raw(p + 48, 1); /* dword I/O */
|
||||
stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */
|
||||
stw_raw(p + 51, 0x200); /* PIO transfer cycle */
|
||||
stw_raw(p + 52, 0x200); /* DMA transfer cycle */
|
||||
stw_raw(p + 54, s->cylinders);
|
||||
stw_raw(p + 55, s->heads);
|
||||
stw_raw(p + 56, s->sectors);
|
||||
oldsize = s->cylinders * s->heads * s->sectors;
|
||||
stw(p + 57, oldsize);
|
||||
stw(p + 58, oldsize >> 16);
|
||||
stw_raw(p + 57, oldsize);
|
||||
stw_raw(p + 58, oldsize >> 16);
|
||||
if (s->mult_sectors)
|
||||
stw(p + 59, 0x100 | s->mult_sectors);
|
||||
stw(p + 60, s->nb_sectors);
|
||||
stw(p + 61, s->nb_sectors >> 16);
|
||||
stw(p + 80, (1 << 1) | (1 << 2));
|
||||
stw(p + 82, (1 << 14));
|
||||
stw(p + 83, (1 << 14));
|
||||
stw(p + 84, (1 << 14));
|
||||
stw(p + 85, (1 << 14));
|
||||
stw(p + 86, 0);
|
||||
stw(p + 87, (1 << 14));
|
||||
stw_raw(p + 59, 0x100 | s->mult_sectors);
|
||||
stw_raw(p + 60, s->nb_sectors);
|
||||
stw_raw(p + 61, s->nb_sectors >> 16);
|
||||
stw_raw(p + 80, (1 << 1) | (1 << 2));
|
||||
stw_raw(p + 82, (1 << 14));
|
||||
stw_raw(p + 83, (1 << 14));
|
||||
stw_raw(p + 84, (1 << 14));
|
||||
stw_raw(p + 85, (1 << 14));
|
||||
stw_raw(p + 86, 0);
|
||||
stw_raw(p + 87, (1 << 14));
|
||||
}
|
||||
|
||||
static inline void ide_abort_command(IDEState *s)
|
||||
@@ -2434,6 +2487,52 @@ void ide_reset(IDEState *s)
|
||||
s->select = 0xa0;
|
||||
}
|
||||
|
||||
struct partition {
|
||||
uint8_t boot_ind; /* 0x80 - active */
|
||||
uint8_t head; /* starting head */
|
||||
uint8_t sector; /* starting sector */
|
||||
uint8_t cyl; /* starting cylinder */
|
||||
uint8_t sys_ind; /* What partition type */
|
||||
uint8_t end_head; /* end head */
|
||||
uint8_t end_sector; /* end sector */
|
||||
uint8_t end_cyl; /* end cylinder */
|
||||
uint32_t start_sect; /* starting sector counting from 0 */
|
||||
uint32_t nr_sects; /* nr of sectors in partition */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* try to guess the IDE geometry from the MSDOS partition table */
|
||||
void ide_guess_geometry(IDEState *s)
|
||||
{
|
||||
uint8_t buf[512];
|
||||
int ret, i;
|
||||
struct partition *p;
|
||||
uint32_t nr_sects;
|
||||
|
||||
if (s->cylinders != 0)
|
||||
return;
|
||||
ret = bdrv_read(s->bs, 0, buf, 1);
|
||||
if (ret < 0)
|
||||
return;
|
||||
/* test msdos magic */
|
||||
if (buf[510] != 0x55 || buf[511] != 0xaa)
|
||||
return;
|
||||
for(i = 0; i < 4; i++) {
|
||||
p = ((struct partition *)(buf + 0x1be)) + i;
|
||||
nr_sects = tswap32(p->nr_sects);
|
||||
if (nr_sects && p->end_head) {
|
||||
/* We make the assumption that the partition terminates on
|
||||
a cylinder boundary */
|
||||
s->heads = p->end_head + 1;
|
||||
s->sectors = p->end_sector & 63;
|
||||
s->cylinders = s->nb_sectors / (s->heads * s->sectors);
|
||||
#if 0
|
||||
printf("guessed partition: CHS=%d %d %d\n",
|
||||
s->cylinders, s->heads, s->sectors);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ide_init(void)
|
||||
{
|
||||
IDEState *s;
|
||||
@@ -2445,6 +2544,8 @@ void ide_init(void)
|
||||
s->bs = bs_table[i];
|
||||
if (s->bs) {
|
||||
bdrv_get_geometry(s->bs, &nb_sectors);
|
||||
s->nb_sectors = nb_sectors;
|
||||
ide_guess_geometry(s);
|
||||
if (s->cylinders == 0) {
|
||||
/* if no geometry, use a LBA compatible one */
|
||||
cylinders = nb_sectors / (16 * 63);
|
||||
@@ -2456,7 +2557,6 @@ void ide_init(void)
|
||||
s->heads = 16;
|
||||
s->sectors = 63;
|
||||
}
|
||||
s->nb_sectors = nb_sectors;
|
||||
}
|
||||
s->irq = 14;
|
||||
ide_reset(s);
|
||||
@@ -3136,7 +3236,10 @@ static void term_init(void)
|
||||
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|
||||
|INLCR|IGNCR|ICRNL|IXON);
|
||||
tty.c_oflag |= OPOST;
|
||||
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
|
||||
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
|
||||
/* if graphical mode, we allow Ctrl-C handling */
|
||||
if (nographic)
|
||||
tty.c_lflag &= ~ISIG;
|
||||
tty.c_cflag &= ~(CSIZE|PARENB);
|
||||
tty.c_cflag |= CS8;
|
||||
tty.c_cc[VMIN] = 1;
|
||||
@@ -3172,6 +3275,7 @@ void dumb_display_init(DisplayState *ds)
|
||||
ds->dpy_refresh = dumb_refresh;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
/***********************************************************/
|
||||
/* cpu signal handler */
|
||||
static void host_segv_handler(int host_signum, siginfo_t *info,
|
||||
@@ -3182,6 +3286,7 @@ static void host_segv_handler(int host_signum, siginfo_t *info,
|
||||
term_exit();
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int timer_irq_pending;
|
||||
static int timer_irq_count;
|
||||
@@ -3233,12 +3338,12 @@ CPUState *cpu_gdbstub_get_env(void *opaque)
|
||||
|
||||
int main_loop(void *opaque)
|
||||
{
|
||||
struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd;
|
||||
int ret, n, timeout;
|
||||
struct pollfd ufds[3], *pf, *serial_ufd, *net_ufd, *gdb_ufd;
|
||||
int ret, n, timeout, serial_ok;
|
||||
uint8_t ch;
|
||||
CPUState *env = global_env;
|
||||
|
||||
if (nodisp && !term_inited) {
|
||||
if (!term_inited) {
|
||||
/* initialize terminal only there so that the user has a
|
||||
chance to stop QEMU with Ctrl-C before the gdb connection
|
||||
is launched */
|
||||
@@ -3246,12 +3351,18 @@ int main_loop(void *opaque)
|
||||
term_init();
|
||||
}
|
||||
|
||||
serial_ok = 1;
|
||||
cpu_enable_ticks();
|
||||
for(;;) {
|
||||
ret = cpu_x86_exec(env);
|
||||
if (reset_requested)
|
||||
if (reset_requested) {
|
||||
ret = EXCP_INTERRUPT;
|
||||
break;
|
||||
if (ret == EXCP_DEBUG)
|
||||
return EXCP_DEBUG;
|
||||
}
|
||||
if (ret == EXCP_DEBUG) {
|
||||
ret = EXCP_DEBUG;
|
||||
break;
|
||||
}
|
||||
/* if hlt instruction, we wait until the next IRQ */
|
||||
if (ret == EXCP_HLT)
|
||||
timeout = 10;
|
||||
@@ -3260,7 +3371,7 @@ int main_loop(void *opaque)
|
||||
/* poll any events */
|
||||
serial_ufd = NULL;
|
||||
pf = ufds;
|
||||
if (!(serial_ports[0].lsr & UART_LSR_DR)) {
|
||||
if (serial_ok && !(serial_ports[0].lsr & UART_LSR_DR)) {
|
||||
serial_ufd = pf;
|
||||
pf->fd = 0;
|
||||
pf->events = POLLIN;
|
||||
@@ -3287,6 +3398,9 @@ int main_loop(void *opaque)
|
||||
n = read(0, &ch, 1);
|
||||
if (n == 1) {
|
||||
serial_received_byte(&serial_ports[0], ch);
|
||||
} else {
|
||||
/* Closed, stop polling. */
|
||||
serial_ok = 0;
|
||||
}
|
||||
}
|
||||
if (net_ufd && (net_ufd->revents & POLLIN)) {
|
||||
@@ -3305,8 +3419,10 @@ int main_loop(void *opaque)
|
||||
uint8_t buf[1];
|
||||
/* stop emulation if requested by gdb */
|
||||
n = read(gdbstub_fd, buf, 1);
|
||||
if (n == 1)
|
||||
if (n == 1) {
|
||||
ret = EXCP_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3323,35 +3439,53 @@ int main_loop(void *opaque)
|
||||
gui_refresh_pending = 0;
|
||||
}
|
||||
}
|
||||
return EXCP_INTERRUPT;
|
||||
cpu_disable_ticks();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: vl [options] [bzImage [kernel parameters...]]\n"
|
||||
printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: %s [options] [disk_image]\n"
|
||||
"\n"
|
||||
"'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n"
|
||||
"to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n"
|
||||
"'disk_image' is a raw hard image image for IDE hard disk 0\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
"-initrd file use 'file' as initial ram disk\n"
|
||||
"-hda file use 'file' as hard disk 0 image\n"
|
||||
"-hdb file use 'file' as hard disk 1 image\n"
|
||||
"-snapshot write to temporary files instead of disk image files\n"
|
||||
"-m megs set virtual RAM size to megs MB\n"
|
||||
"-n script set network init script [default=%s]\n"
|
||||
"Standard options:\n"
|
||||
"-hda file use 'file' as IDE hard disk 0 image\n"
|
||||
"-hdb file use 'file' as IDE hard disk 1 image\n"
|
||||
"-snapshot write to temporary files instead of disk image files\n"
|
||||
"-m megs set virtual RAM size to megs MB\n"
|
||||
"-n script set network init script [default=%s]\n"
|
||||
"-tun-fd fd this fd talks to tap/tun, use it.\n"
|
||||
"-nographic disable graphical output\n"
|
||||
"\n"
|
||||
"Linux boot specific (does not require PC BIOS):\n"
|
||||
"-kernel bzImage use 'bzImage' as kernel image\n"
|
||||
"-append cmdline use 'cmdline' as kernel command line\n"
|
||||
"-initrd file use 'file' as initial ram disk\n"
|
||||
"\n"
|
||||
"Debug/Expert options:\n"
|
||||
"-s wait gdb connection to port %d\n"
|
||||
"-p port change gdb connection port\n"
|
||||
"-d output log in /tmp/vl.log\n"
|
||||
"-hdachs c,h,s force hard disk 0 geometry for non LBA disk images\n"
|
||||
"-L path set the directory for the BIOS and VGA BIOS\n"
|
||||
"-s wait gdb connection to port %d\n"
|
||||
"-p port change gdb connection port\n"
|
||||
"-d output log in /tmp/vl.log\n"
|
||||
"-hdachs c,h,s force hard disk 0 geometry (usually qemu can guess it)\n"
|
||||
"-L path set the directory for the BIOS and VGA BIOS\n"
|
||||
"\n"
|
||||
"During emulation, use C-a h to get terminal commands:\n",
|
||||
DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT);
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
"qemu",
|
||||
#else
|
||||
"qemu-fast",
|
||||
#endif
|
||||
DEFAULT_NETWORK_SCRIPT,
|
||||
DEFAULT_GDBSTUB_PORT);
|
||||
term_print_help();
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
printf("\n"
|
||||
"NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n"
|
||||
"work. Please use the 'qemu' executable to have a more accurate (but slower)\n"
|
||||
"PC emulation.\n");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -3361,10 +3495,25 @@ struct option long_options[] = {
|
||||
{ "hdb", 1, NULL, 0, },
|
||||
{ "snapshot", 0, NULL, 0, },
|
||||
{ "hdachs", 1, NULL, 0, },
|
||||
{ "nodisp", 0, NULL, 0, },
|
||||
{ "nographic", 0, NULL, 0, },
|
||||
{ "kernel", 1, NULL, 0, },
|
||||
{ "append", 1, NULL, 0, },
|
||||
{ "tun-fd", 1, NULL, 0, },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SDL
|
||||
/* SDL use the pthreads and they modify sigaction. We don't
|
||||
want that. */
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
extern void __libc_sigaction();
|
||||
#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact)
|
||||
#else
|
||||
extern void __sigaction();
|
||||
#define sigaction(sig, act, oact) __sigaction(sig, act, oact)
|
||||
#endif
|
||||
#endif /* CONFIG_SDL */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index;
|
||||
@@ -3375,6 +3524,7 @@ int main(int argc, char **argv)
|
||||
CPUX86State *env;
|
||||
const char *tmpdir, *initrd_filename;
|
||||
const char *hd_filename[MAX_DISKS];
|
||||
const char *kernel_filename, *kernel_cmdline;
|
||||
DisplayState *ds = &display_state;
|
||||
|
||||
/* we never want that malloc() uses mmap() */
|
||||
@@ -3388,8 +3538,9 @@ int main(int argc, char **argv)
|
||||
use_gdbstub = 0;
|
||||
gdbstub_port = DEFAULT_GDBSTUB_PORT;
|
||||
snapshot = 0;
|
||||
linux_boot = 0;
|
||||
nodisp = 0;
|
||||
nographic = 0;
|
||||
kernel_filename = NULL;
|
||||
kernel_cmdline = "";
|
||||
for(;;) {
|
||||
c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index);
|
||||
if (c == -1)
|
||||
@@ -3432,8 +3583,17 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
nodisp = 1;
|
||||
nographic = 1;
|
||||
break;
|
||||
case 6:
|
||||
kernel_filename = optarg;
|
||||
break;
|
||||
case 7:
|
||||
kernel_cmdline = optarg;
|
||||
break;
|
||||
case 8:
|
||||
net_fd = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
@@ -3450,7 +3610,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
loglevel = 1;
|
||||
cpu_set_log(CPU_LOG_ALL);
|
||||
break;
|
||||
case 'n':
|
||||
pstrcpy(network_script, sizeof(network_script), optarg);
|
||||
@@ -3462,32 +3622,29 @@ int main(int argc, char **argv)
|
||||
gdbstub_port = atoi(optarg);
|
||||
break;
|
||||
case 'L':
|
||||
interp_prefix = optarg;
|
||||
bios_dir = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
linux_boot = (optind < argc);
|
||||
if (optind < argc) {
|
||||
hd_filename[0] = argv[optind++];
|
||||
}
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
if (!linux_boot && hd_filename[0] == '\0')
|
||||
help();
|
||||
|
||||
/* init debug */
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
if (loglevel) {
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
/* init network tun interface */
|
||||
net_init();
|
||||
if (net_fd < 0)
|
||||
net_init();
|
||||
|
||||
/* init the memory */
|
||||
tmpdir = getenv("VLTMPDIR");
|
||||
tmpdir = getenv("QEMU_TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir);
|
||||
@@ -3538,9 +3695,10 @@ int main(int argc, char **argv)
|
||||
|
||||
if (linux_boot) {
|
||||
/* now we can load the kernel */
|
||||
ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
ret = load_kernel(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]);
|
||||
fprintf(stderr, "vl: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -3562,11 +3720,7 @@ int main(int argc, char **argv)
|
||||
params->cl_magic = 0xA33F;
|
||||
params->cl_offset = params->commandline - (uint8_t *)params;
|
||||
params->alt_mem_k = (phys_ram_size / 1024) - 1024;
|
||||
for(i = optind + 1; i < argc; i++) {
|
||||
if (i != optind + 1)
|
||||
pstrcat(params->commandline, sizeof(params->commandline), " ");
|
||||
pstrcat(params->commandline, sizeof(params->commandline), argv[i]);
|
||||
}
|
||||
pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline);
|
||||
params->loader_type = 0x01;
|
||||
if (initrd_size > 0) {
|
||||
params->initrd_start = INITRD_LOAD_ADDR;
|
||||
@@ -3583,10 +3737,13 @@ int main(int argc, char **argv)
|
||||
|
||||
params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */
|
||||
params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */
|
||||
/* for newer kernels (2.6.0) CS/DS are at different addresses */
|
||||
params->gdt_table[12] = 0x00cf9a000000ffffLL; /* KERNEL_CS */
|
||||
params->gdt_table[13] = 0x00cf92000000ffffLL; /* KERNEL_DS */
|
||||
|
||||
env->idt.base = (void *)params->idt_table;
|
||||
env->idt.base = (void *)((uint8_t *)params->idt_table - phys_ram_base);
|
||||
env->idt.limit = sizeof(params->idt_table) - 1;
|
||||
env->gdt.base = (void *)params->gdt_table;
|
||||
env->gdt.base = (void *)((uint8_t *)params->gdt_table - phys_ram_base);
|
||||
env->gdt.limit = sizeof(params->gdt_table) - 1;
|
||||
|
||||
cpu_x86_load_seg_cache(env, R_CS, KERNEL_CS, NULL, 0xffffffff, 0x00cf9a00);
|
||||
@@ -3602,19 +3759,19 @@ int main(int argc, char **argv)
|
||||
|
||||
} else {
|
||||
char buf[1024];
|
||||
|
||||
|
||||
/* RAW PC boot */
|
||||
|
||||
/* BIOS load */
|
||||
snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, BIOS_FILENAME);
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
|
||||
ret = load_image(buf, phys_ram_base + 0x000f0000);
|
||||
if (ret != 0x10000) {
|
||||
fprintf(stderr, "vl: could not load PC bios '%s'\n", BIOS_FILENAME);
|
||||
fprintf(stderr, "vl: could not load PC bios '%s'\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* VGA BIOS load */
|
||||
snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, VGABIOS_FILENAME);
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
|
||||
ret = load_image(buf, phys_ram_base + 0x000c0000);
|
||||
|
||||
/* setup basic memory access */
|
||||
@@ -3642,18 +3799,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* terminal init */
|
||||
if (nodisp) {
|
||||
if (nographic) {
|
||||
dumb_display_init(ds);
|
||||
} else {
|
||||
#ifdef CONFIG_SDL
|
||||
sdl_display_init(ds);
|
||||
/* SDL use the pthreads and they modify sigaction. We don't
|
||||
want that. */
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
#define sigaction __libc_sigaction
|
||||
#else
|
||||
#define sigaction __sigaction
|
||||
#endif
|
||||
#else
|
||||
dumb_display_init(ds);
|
||||
#endif
|
||||
@@ -3674,9 +3824,11 @@ int main(int argc, char **argv)
|
||||
/* setup cpu signal handlers for MMU / self modifying code handling */
|
||||
sigfillset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
act.sa_sigaction = host_segv_handler;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGBUS, &act, NULL);
|
||||
#endif
|
||||
|
||||
act.sa_sigaction = host_alarm_handler;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
|
Reference in New Issue
Block a user