Compare commits

...

35 Commits

Author SHA1 Message Date
bellard
285dc330bd update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@417 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:58:04 +00:00
bellard
baf8ebf01a fixed virtual memory access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@416 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:57:40 +00:00
bellard
9d16dd550e make cpu test static
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@415 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:56:59 +00:00
bellard
78d6da976c license
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@414 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:55:20 +00:00
bellard
dd6ee15c37 fixed idt/gdt relocation bug - added support for Redhat kernels
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@413 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 23:36:59 +00:00
bellard
0db634747e qemu with softmmu is now the default executable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@412 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:37:46 +00:00
bellard
6e59c1db89 full soft mmu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@411 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:24:54 +00:00
bellard
61382a500a full softmmu support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@410 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:22:23 +00:00
bellard
3a51dee658 disabled signal hacks for softmmu version (qemu should be much more portable now...)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@409 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:18:35 +00:00
bellard
cc38b844d7 factorized debug code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@408 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:16:14 +00:00
bellard
c6105c0a04 added correct memory access code for system emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@407 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:13:58 +00:00
bellard
93a40ea926 fixed mmu fault priviledge logic
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@406 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:13:06 +00:00
bellard
db8d746688 comments
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@405 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:12:17 +00:00
bellard
997344f303 added i386 user only target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@404 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:10:39 +00:00
bellard
16e9b7de41 filename fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@403 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-27 21:09:52 +00:00
bellard
3486513433 log activation from gdb - gdb single step support for x86 - stop timer when cpu is being debugged
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@402 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-05 14:28:56 +00:00
bellard
0806e3f66f updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@401 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-01 00:15:32 +00:00
bellard
39b4da28b3 bios binary images
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@400 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-01 00:14:04 +00:00
bellard
5a67135a0b automatic man page generation - BIOS installation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@399 c046a42c-6fe2-441c-8c8c-71466251a162
2003-10-01 00:13:48 +00:00
bellard
42f1e0e49b tun-fd option support for external tundev config (Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@398 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 22:11:17 +00:00
bellard
27c3f2cb9b buffer overflow fix - handle case where stdin is closed (Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@397 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:40:47 +00:00
bellard
a07cf92aed multiscan/doublescan fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@396 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:29:03 +00:00
bellard
01e3b763a6 removed SIGIOT
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@395 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:10:14 +00:00
bellard
0ae04d7367 allow Ctrl-C to be pressed when using gdb stub and SDL
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@394 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:09:16 +00:00
bellard
ebc054881f added utime syscall - fixed nanosleep exact behaviour
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@393 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:08:41 +00:00
bellard
a20dd508aa simplified invocation - added automatic IDE disk geometry guessing to reuse old disk images directly
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@392 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:07:02 +00:00
bellard
6180a1818a new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@391 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 21:04:53 +00:00
bellard
d3eead2eec new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@390 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:59:51 +00:00
bellard
853d6f7a83 sparc support - hack to fix case where real_host_page_size < TARGET_PAGE_SIZE (typically sparc target case)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@389 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:58:32 +00:00
bellard
93ac68bca5 sparc emulation target (thanx to Thomas M. Ogrisegg)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@388 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:57:29 +00:00
bellard
1e43adfc89 new directory structure - changed naming of qemu and vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@387 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:54:24 +00:00
bellard
7a3f194486 sparc emulation target (thanx to Thomas M. Ogrisegg)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@386 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:36:07 +00:00
bellard
2c0262afa7 new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@385 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-30 20:34:21 +00:00
bellard
196ad10903 portable Linux test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@384 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-28 18:59:32 +00:00
bellard
b7dda06abf Redhat 9 fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@383 c046a42c-6fe2-441c-8c8c-71466251a162
2003-09-17 22:57:56 +00:00
65 changed files with 4669 additions and 1304 deletions

View File

@@ -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:

View File

@@ -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)

View 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
View File

@@ -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
--------------------

View File

@@ -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
View File

@@ -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

View File

@@ -1 +1 @@
0.4.4
0.5.0

34
configure vendored
View File

@@ -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
View File

@@ -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);

View File

@@ -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

View File

@@ -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
View File

@@ -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;

View File

@@ -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
View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
View 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 */

View File

@@ -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;

View 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)

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View 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];
};

View 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

View File

@@ -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);

View File

@@ -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
View 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

Binary file not shown.

BIN
pc-bios/vgabios.bin Normal file

Binary file not shown.

View File

@@ -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
View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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) */

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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, &reg_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
View 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
View 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
View 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)
{
}

View 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
View 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'));
}

View File

@@ -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
View 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;
}

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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
View 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/&/&amp;/g;
s/\@\{/&lbrace;/g;
s/\@\}/&rbrace;/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/</&lt;/g;
s/>/&gt;/g;
} else {
s/</&LT;/g;
s/>/&GT;/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\&LT;$1\&GT;\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)\{([^\},]*)\}/&lt;B<$1>&gt;/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/&LT;/</g;
s/&GT;/>/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/&lt;/E<lt>/g;
s/&gt;/E<gt>/g;
s/&lbrace;/\{/g;
s/&rbrace;/\}/g;
s/&at;/\@/g;
s/&amp;/&/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;
}
}

View File

@@ -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
View File

@@ -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);