Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de83cd02e0 | ||
|
|
6380ab5e26 | ||
|
|
b346ff468e | ||
|
|
5a9fdfec7e | ||
|
|
d19893dab5 | ||
|
|
2521d69883 | ||
|
|
2ab83ea784 | ||
|
|
2437490100 | ||
|
|
e4533c7a8c | ||
|
|
1e5ffbedde | ||
|
|
79638566e5 | ||
|
|
03daf0e361 | ||
|
|
d219f7e7ed | ||
|
|
95cbfc643d | ||
|
|
5898e81684 | ||
|
|
394411ac74 | ||
|
|
ea76864009 | ||
|
|
43ce4dfe9e | ||
|
|
ebc06f87ca | ||
|
|
5bbe92995c | ||
|
|
411bffc41c | ||
|
|
ff1f20a3ee | ||
|
|
9c5d1246c7 | ||
|
|
8dd7cb0621 | ||
|
|
d30329297b | ||
|
|
a95c67907c | ||
|
|
0f533160c7 | ||
|
|
e163bca720 | ||
|
|
8c6939c0b0 | ||
|
|
2d0e9143e2 | ||
|
|
87f4827e1d | ||
|
|
4a585ccb2f | ||
|
|
aa0aa4fa31 | ||
|
|
84fa15d854 | ||
|
|
4add45b4f6 | ||
|
|
4f101ad7ff | ||
|
|
c1db2eb8c3 | ||
|
|
82d19dafe4 | ||
|
|
5286db75a8 | ||
|
|
917f95fd4d | ||
|
|
fe31975692 | ||
|
|
95f7652d65 | ||
|
|
3ec9c4fcc6 | ||
|
|
2f87c60799 | ||
|
|
03bfca946a | ||
|
|
ed2dcdf68e | ||
|
|
4304763ba2 | ||
|
|
c1e42a1397 | ||
|
|
d0a1ffc957 |
No files matched your search
@@ -1,3 +1,13 @@
|
||||
version 0.3:
|
||||
|
||||
- initial support for ARM emulation
|
||||
- added fnsave, frstor, fnstenv, fldenv FPU instructions
|
||||
- added FPU register save in signal emulation
|
||||
- ARM port
|
||||
- Sparc and Alpha ports work on the regression test
|
||||
- generic ioctl number conversion
|
||||
- fixed ioctl type conversion
|
||||
|
||||
version 0.2:
|
||||
|
||||
- PowerPC disassembly and ELF symbols output (Rusty Russel)
|
||||
|
||||
@@ -4,6 +4,11 @@ CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-DHAVE_BYTESWAP_H
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
@@ -37,6 +42,8 @@ ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
|
||||
LDFLAGS+=-Wl,-T,sparc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
@@ -50,7 +57,7 @@ ifeq ($(ARCH),alpha)
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data -msmall-text
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,alpha.ld
|
||||
endif
|
||||
|
||||
@@ -58,6 +65,11 @@ ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
|
||||
LDFLAGS+=-Wl,-T,arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
@@ -74,20 +86,40 @@ LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
OBJS+= vm86.o
|
||||
endif
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o
|
||||
# cpu emulator library
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
LIBOBJS+=translate-arm.o op-arm.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=disas.o i386-dis.o dis-buf.o
|
||||
ifeq ($(ARCH),alpha)
|
||||
LIBOBJS+=disas.o
|
||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
||||
LIBOBJS+=i386-dis.o
|
||||
endif
|
||||
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(ARCH),ppc)
|
||||
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
|
||||
LIBOBJS+=sparc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
|
||||
LIBOBJS+=arm-dis.o
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OBJS += ia64-syscall.o
|
||||
@@ -115,17 +147,29 @@ libqemu.a: $(LIBOBJS)
|
||||
dyngen: dyngen.c
|
||||
$(HOST_CC) -O2 -Wall -g $< -o $@
|
||||
|
||||
translate-i386.o: translate-i386.c op-i386.h opc-i386.h cpu-i386.h
|
||||
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-i386.h: op-i386.o dyngen
|
||||
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -o $@ $<
|
||||
|
||||
opc-i386.h: op-i386.o dyngen
|
||||
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h
|
||||
gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -g -o $@ $<
|
||||
|
||||
op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h
|
||||
|
||||
op-arm.o: op-arm.c op-arm-template.h
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
@@ -152,17 +196,24 @@ qemu-doc.html: qemu-doc.texi
|
||||
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
|
||||
Makefile elf.h thunk.c\
|
||||
elfload.c main.c signal.c thunk.h exec.h\
|
||||
cpu-i386.h qemu.h op-i386.c syscall-i386.h translate-i386.c\
|
||||
syscall.c opreg_template.h syscall_defs.h vm86.c\
|
||||
dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\
|
||||
ppc.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \
|
||||
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/hello.c tests/hello tests/sha1.c \
|
||||
configure \
|
||||
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
Makefile elf.h elfload.c main.c signal.c qemu.h \
|
||||
syscall.c syscall_defs.h vm86.c path.c mmap.c \
|
||||
ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c\
|
||||
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h op_string.h opreg_template.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.c tests/hello \
|
||||
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 \
|
||||
|
||||
@@ -36,6 +36,32 @@ 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.
|
||||
|
||||
Tested tool versions
|
||||
--------------------
|
||||
|
||||
In order to compile QEMU succesfully, it is very important that you
|
||||
have the right tools. The most important one is gcc. I cannot guaranty
|
||||
that QEMU works if you do not use a tested gcc version. Look at
|
||||
'configure' and 'Makefile' if you want to make a different gcc
|
||||
version work.
|
||||
|
||||
host gcc binutils glibc linux
|
||||
-------------------------------------------------------
|
||||
x86 2.95.2 2.13.2 2.1.3 2.4.18
|
||||
|
||||
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2
|
||||
|
||||
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2]
|
||||
|
||||
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18
|
||||
|
||||
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9-ac10-rmk2-np1-cerf2
|
||||
|
||||
[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
|
||||
for gcc version >= 3.3.
|
||||
[2] Linux >= 2.4.20 is necessary for precise exception support
|
||||
(untested).
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
|
||||
- fix iret/lret/fpush not before mem load restarting
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- fix CCOP optimisation
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically)
|
||||
- fpush not before mem load restarting
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- handle fp87 state in signals
|
||||
- add gcc 2.96 test configure (some gcc3 flags are needed)
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically)
|
||||
- add IPC syscalls
|
||||
- submit a patch to fix DOSEMU coopthreads
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- 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
|
||||
in syscall emulation code).
|
||||
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
|
||||
|
||||
-13
@@ -248,19 +248,6 @@ enum bfd_reloc_code_real {
|
||||
BFD_RELOC_ALPHA_HINT
|
||||
};
|
||||
|
||||
bfd_vma
|
||||
bfd_getl32 (addr)
|
||||
register const bfd_byte *addr;
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0];
|
||||
v |= (unsigned long) addr[1] << 8;
|
||||
v |= (unsigned long) addr[2] << 16;
|
||||
v |= (unsigned long) addr[3] << 24;
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
/* This file holds the Alpha AXP opcode table. The opcode table includes
|
||||
almost all of the extended instruction mnemonics. This permits the
|
||||
disassembler to use them, and simplifies the assembler logic, at the
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
|
||||
"elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -20,6 +20,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
interp_prefix="/usr/gnemul/qemu-i386"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
@@ -27,6 +28,7 @@ ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
target_cpu="x86"
|
||||
target_bigendian="default"
|
||||
cpu=`uname -m`
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
@@ -102,8 +104,16 @@ for opt do
|
||||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--target-big-endian) target_bigendian="yes"
|
||||
;;
|
||||
--target-little-endian) target_bigendian="no"
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--static) static="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -159,6 +169,16 @@ if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="3"
|
||||
fi
|
||||
|
||||
if test "$target_bigendian" = "default" ; then
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
target_bigendian="no"
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
target_bigendian="no"
|
||||
else
|
||||
target_bigendian="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
cat << EOF
|
||||
|
||||
@@ -170,25 +190,30 @@ 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 " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo " --static enable static build [$static]"
|
||||
echo ""
|
||||
echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
echo "Big Endian $bigendian"
|
||||
echo "target CPU $target_cpu"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "ELF interp prefix $interp_prefix"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
echo "host big endian $bigendian"
|
||||
echo "target CPU $target_cpu"
|
||||
echo "target big endian $target_bigendian"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "static build $static"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
|
||||
@@ -240,10 +265,31 @@ if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
|
||||
fi
|
||||
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
echo "TARGET_ARCH=i386" >> config.mak
|
||||
echo "#define TARGET_ARCH \"i386\"" >> $TMPH
|
||||
echo "#define TARGET_I386 1" >> $TMPH
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
echo "TARGET_ARCH=arm" >> config.mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $TMPH
|
||||
echo "#define TARGET_ARM 1" >> $TMPH
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$target_bigendian" = "yes" ; then
|
||||
echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH
|
||||
fi
|
||||
|
||||
if test "$gprof" = "yes" ; then
|
||||
echo "TARGET_GPROF=yes" >> config.mak
|
||||
echo "#define HAVE_GPROF 1" >> $TMPH
|
||||
fi
|
||||
if test "$static" = "yes" ; then
|
||||
echo "CONFIG_STATIC=yes" >> config.mak
|
||||
fi
|
||||
echo -n "VERSION=" >>config.mak
|
||||
head $source_path/VERSION >>config.mak
|
||||
echo "" >>config.mak
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
* defines common to all virtual CPUs
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
||||
kernel handles unaligned load/stores may give better results, but
|
||||
it is a system wide setting : bad */
|
||||
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return (int16_t)(p[0] | (p[1] << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.tab[1] = ldl(ptr);
|
||||
u.tab[0] = ldl(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(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]);
|
||||
}
|
||||
|
||||
#else
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
||||
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
|
||||
|
||||
extern unsigned long real_host_page_size;
|
||||
extern unsigned long host_page_bits;
|
||||
extern unsigned long host_page_size;
|
||||
extern unsigned long host_page_mask;
|
||||
|
||||
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
#define PAGE_WRITE 0x0002
|
||||
#define PAGE_EXEC 0x0004
|
||||
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
|
||||
#define PAGE_VALID 0x0008
|
||||
/* original state of the write flag (used when tracking self-modifying
|
||||
code */
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
|
||||
void page_dump(FILE *f);
|
||||
int page_get_flags(unsigned long address);
|
||||
void page_set_flags(unsigned long start, unsigned long end, int flags);
|
||||
void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
|
||||
#define SINGLE_CPU_DEFINES
|
||||
#ifdef SINGLE_CPU_DEFINES
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define CPUState CPUX86State
|
||||
#define cpu_init cpu_x86_init
|
||||
#define cpu_exec cpu_x86_exec
|
||||
#define cpu_gen_code cpu_x86_gen_code
|
||||
#define cpu_interrupt cpu_x86_interrupt
|
||||
#define cpu_signal_handler cpu_x86_signal_handler
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
#define CPUState CPUARMState
|
||||
#define cpu_init cpu_arm_init
|
||||
#define cpu_exec cpu_arm_exec
|
||||
#define cpu_gen_code cpu_arm_gen_code
|
||||
#define cpu_interrupt cpu_arm_interrupt
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported target CPU
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ARM virtual CPU header
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifndef CPU_ARM_H
|
||||
#define CPU_ARM_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#define EXCP_UDEF 1 /* undefined instruction */
|
||||
#define EXCP_SWI 2 /* software interrupt */
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
|
||||
typedef struct CPUARMState {
|
||||
uint32_t regs[16];
|
||||
uint32_t cpsr;
|
||||
|
||||
/* cpsr flag cache for faster execution */
|
||||
uint32_t CF; /* 0 or 1 */
|
||||
uint32_t VF; /* V is the bit 31. All other bits are undefined */
|
||||
uint32_t NZF; /* N is bit 31. Z is computed from NZF */
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
} CPUARMState;
|
||||
|
||||
CPUARMState *cpu_arm_init(void);
|
||||
int cpu_arm_exec(CPUARMState *s);
|
||||
void cpu_arm_interrupt(CPUARMState *s);
|
||||
void cpu_arm_close(CPUARMState *s);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
struct siginfo;
|
||||
int cpu_arm_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags);
|
||||
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif
|
||||
+213
-68
@@ -17,70 +17,33 @@
|
||||
* 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 "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "exec-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "exec-arm.h"
|
||||
#endif
|
||||
|
||||
#include "disas.h"
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
/* thread support */
|
||||
|
||||
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
spin_lock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
spin_unlock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
/* XXX: unify with i386 target */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
/* NOTE: the register at this point must be saved by hand because
|
||||
longjmp restore them */
|
||||
#ifdef __sparc__
|
||||
/* We have to stay in the same register window as our caller,
|
||||
* thus this trick.
|
||||
*/
|
||||
__asm__ __volatile__("restore\n\t"
|
||||
"mov\t%o0, %i0");
|
||||
#endif
|
||||
#ifdef reg_EAX
|
||||
env->regs[R_EAX] = EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
env->regs[R_ECX] = ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
env->regs[R_EDX] = EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
env->regs[R_EBX] = EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
env->regs[R_ESP] = ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
env->regs[R_EBP] = EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
env->regs[R_ESI] = ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
env->regs[R_EDI] = EDI;
|
||||
#endif
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpu_x86_exec(CPUX86State *env1)
|
||||
/* main execution loop */
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
int saved_T0, saved_T1, saved_A0;
|
||||
CPUX86State *saved_env;
|
||||
int saved_T0, saved_T1, saved_T2;
|
||||
CPUState *saved_env;
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
@@ -104,19 +67,28 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
int saved_i7, tmp_T0;
|
||||
#endif
|
||||
int code_gen_size, ret;
|
||||
void (*gen_func)(void);
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
unsigned int flags;
|
||||
|
||||
|
||||
/* first we save global registers */
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
saved_A0 = A0;
|
||||
saved_T2 = T2;
|
||||
saved_env = env;
|
||||
env = env1;
|
||||
#ifdef __sparc__
|
||||
/* we also save i7 because longjmp may not restore it */
|
||||
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#ifdef reg_EAX
|
||||
saved_EAX = EAX;
|
||||
EAX = env->regs[R_EAX];
|
||||
@@ -155,19 +127,35 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
unsigned int psr;
|
||||
psr = env->cpsr;
|
||||
env->CF = (psr >> 29) & 1;
|
||||
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
env->cpsr = psr & ~0xf0000000;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
env->interrupt_request = 0;
|
||||
|
||||
/* prepare setjmp context for exception handling */
|
||||
if (setjmp(env->jmp_env) == 0) {
|
||||
T0 = 0; /* force lookup of first TB */
|
||||
for(;;) {
|
||||
#ifdef __sparc__
|
||||
/* g1 can be modified by some libc? functions */
|
||||
tmp_T0 = T0;
|
||||
#endif
|
||||
if (env->interrupt_request) {
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
/* XXX: save all volatile state in cpu state */
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->regs[R_EAX] = EAX;
|
||||
env->regs[R_EBX] = EBX;
|
||||
@@ -180,10 +168,16 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
cpu_x86_dump_state(env, logfile, 0);
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
#if defined(TARGET_I386)
|
||||
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
|
||||
flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
|
||||
flags |= (((unsigned long)env->seg_cache[R_DS].base |
|
||||
@@ -200,6 +194,13 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
|
||||
cs_base = env->seg_cache[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
#elif defined(TARGET_ARM)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->regs[15];
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||
flags);
|
||||
if (!tb) {
|
||||
@@ -219,7 +220,9 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
#if defined(TARGET_I386)
|
||||
/* XXX: suppress that, this is incorrect */
|
||||
/* if invalid instruction, signal it */
|
||||
if (ret != 0) {
|
||||
/* NOTE: the tb is allocated but not linked, so we
|
||||
@@ -227,6 +230,7 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
spin_unlock(&tb_lock);
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
}
|
||||
#endif
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
tb_link(tb);
|
||||
@@ -240,23 +244,36 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
lookup_symbol((void *)tb->pc));
|
||||
}
|
||||
#endif
|
||||
/* see if we can patch the calling TB */
|
||||
if (T0 != 0 && !(env->eflags & TF_MASK)) {
|
||||
#ifdef __sparc__
|
||||
T0 = tmp_T0;
|
||||
#endif
|
||||
/* see if we can patch the calling TB. XXX: remove TF test */
|
||||
if (T0 != 0
|
||||
#if defined(TARGET_I386)
|
||||
&& !(env->eflags & TF_MASK)
|
||||
#endif
|
||||
) {
|
||||
spin_lock(&tb_lock);
|
||||
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
|
||||
tc_ptr = tb->tc_ptr;
|
||||
|
||||
/* execute the generated code */
|
||||
gen_func = (void *)tc_ptr;
|
||||
#ifdef __sparc__
|
||||
#if defined(__sparc__)
|
||||
__asm__ __volatile__("call %0\n\t"
|
||||
" mov %%o7,%%i0"
|
||||
"mov %%o7,%%i0"
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "i0", "i1", "i2", "i3", "i4", "i5");
|
||||
#elif defined(__arm__)
|
||||
asm volatile ("mov pc, %0\n\t"
|
||||
".global exec_loop\n\t"
|
||||
"exec_loop:\n\t"
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
|
||||
#else
|
||||
gen_func();
|
||||
#endif
|
||||
@@ -264,6 +281,7 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
}
|
||||
ret = env->exception_index;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
|
||||
@@ -291,20 +309,35 @@ int cpu_x86_exec(CPUX86State *env1)
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
EDI = saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
|
||||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
A0 = saved_A0;
|
||||
T2 = saved_T2;
|
||||
env = saved_env;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cpu_x86_interrupt(CPUX86State *s)
|
||||
void cpu_interrupt(CPUState *s)
|
||||
{
|
||||
s->interrupt_request = 1;
|
||||
}
|
||||
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
@@ -327,6 +360,32 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
|
||||
helper_fsave(ptr, data32);
|
||||
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
|
||||
{
|
||||
CPUX86State *saved_env;
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
|
||||
helper_frstor(ptr, data32);
|
||||
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
#endif /* TARGET_I386 */
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
@@ -362,15 +421,22 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
ret = cpu_x86_search_pc(tb, &found_pc, pc);
|
||||
ret = cpu_search_pc(tb, &found_pc, pc);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
#if defined(TARGET_I386)
|
||||
env->eip = found_pc - tb->cs_base;
|
||||
env->cr2 = address;
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
|
||||
#elif defined(TARGET_ARM)
|
||||
env->regs[15] = found_pc;
|
||||
/* XXX: do more */
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
/* never comes here */
|
||||
return 1;
|
||||
} else {
|
||||
@@ -380,8 +446,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
@@ -401,8 +467,8 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
|
||||
#elif defined(__powerpc)
|
||||
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
struct pt_regs *regs = uc->uc_mcontext.regs;
|
||||
@@ -423,6 +489,85 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__alpha__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
uint32_t *pc = uc->uc_mcontext.sc_pc;
|
||||
uint32_t insn = *pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
switch (insn >> 26) {
|
||||
case 0x0d: // stw
|
||||
case 0x0e: // stb
|
||||
case 0x0f: // stq_u
|
||||
case 0x24: // stf
|
||||
case 0x25: // stg
|
||||
case 0x26: // sts
|
||||
case 0x27: // stt
|
||||
case 0x2c: // stl
|
||||
case 0x2d: // stq
|
||||
case 0x2e: // stl_c
|
||||
case 0x2f: // stq_c
|
||||
is_write = 1;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, &uc->uc_sigmask);
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
uint32_t *regs = (uint32_t *)(info + 1);
|
||||
void *sigmask = (regs + 20);
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
uint32_t insn;
|
||||
|
||||
/* XXX: is there a standard glibc define ? */
|
||||
pc = regs[1];
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
is_write = 0;
|
||||
insn = *(uint32_t *)pc;
|
||||
if ((insn >> 30) == 3) {
|
||||
switch((insn >> 19) & 0x3f) {
|
||||
case 0x05: // stb
|
||||
case 0x06: // sth
|
||||
case 0x04: // st
|
||||
case 0x07: // std
|
||||
case 0x24: // stf
|
||||
case 0x27: // stdf
|
||||
case 0x25: // stfsr
|
||||
is_write = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write, sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = uc->uc_mcontext.gregs[R15];
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error CPU specific signal handler needed
|
||||
+5
-223
@@ -222,203 +222,6 @@ typedef struct CPUX86State {
|
||||
void *opaque;
|
||||
} CPUX86State;
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return (int16_t)val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return (int16_t)(p[0] | (p[1] << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
|
||||
return val;
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
#else
|
||||
uint8_t *p = ptr;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef IN_OP_I386
|
||||
void cpu_x86_outb(CPUX86State *env, int addr, int val);
|
||||
void cpu_x86_outw(CPUX86State *env, int addr, int val);
|
||||
@@ -436,6 +239,10 @@ void cpu_x86_close(CPUX86State *s);
|
||||
/* needed to load some predefinied segment registers */
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
|
||||
|
||||
/* simulate fsave/frstor */
|
||||
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
|
||||
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
|
||||
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
@@ -448,32 +255,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
|
||||
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
|
||||
|
||||
/* page related stuff */
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
|
||||
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
|
||||
|
||||
extern unsigned long real_host_page_size;
|
||||
extern unsigned long host_page_bits;
|
||||
extern unsigned long host_page_size;
|
||||
extern unsigned long host_page_mask;
|
||||
|
||||
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
#define PAGE_WRITE 0x0002
|
||||
#define PAGE_EXEC 0x0004
|
||||
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
|
||||
#define PAGE_VALID 0x0008
|
||||
/* original state of the write flag (used when tracking self-modifying
|
||||
code */
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
|
||||
void page_dump(FILE *f);
|
||||
int page_get_flags(unsigned long address);
|
||||
void page_set_flags(unsigned long start, unsigned long end, int flags);
|
||||
void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif /* CPU_I386_H */
|
||||
@@ -73,16 +73,20 @@ enum bfd_architecture
|
||||
bfd_arch_a29k, /* AMD 29000 */
|
||||
bfd_arch_sparc, /* SPARC */
|
||||
#define bfd_mach_sparc 1
|
||||
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
|
||||
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
|
||||
#define bfd_mach_sparc_sparclet 2
|
||||
#define bfd_mach_sparc_sparclite 3
|
||||
#define bfd_mach_sparc_v8plus 4
|
||||
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */
|
||||
#define bfd_mach_sparc_v9 6
|
||||
#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */
|
||||
/* Nonzero if MACH has the v9 instruction set. */
|
||||
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
|
||||
#define bfd_mach_sparc_sparclite_le 6
|
||||
#define bfd_mach_sparc_v9 7
|
||||
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
|
||||
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
|
||||
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
|
||||
/* Nonzero if MACH has the v9 instruction set. */
|
||||
#define bfd_mach_sparc_v9_p(mach) \
|
||||
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a)
|
||||
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
|
||||
&& (mach) != bfd_mach_sparc_sparclite_le)
|
||||
bfd_arch_mips, /* MIPS Rxxxx */
|
||||
#define bfd_mach_mips3000 3000
|
||||
#define bfd_mach_mips3900 3900
|
||||
@@ -279,6 +283,9 @@ typedef struct disassemble_info {
|
||||
zero if unknown. */
|
||||
bfd_vma target2; /* Second target address for dref2 */
|
||||
|
||||
/* Command line options specific to the target disassembler. */
|
||||
char * disassembler_options;
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
|
||||
@@ -299,8 +306,7 @@ extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
|
||||
extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
|
||||
@@ -381,6 +387,15 @@ extern int generic_symbol_at_address
|
||||
(INFO).bytes_per_line = 0, \
|
||||
(INFO).bytes_per_chunk = 0, \
|
||||
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
|
||||
(INFO).disassembler_options = NULL, \
|
||||
(INFO).insn_info_valid = 0
|
||||
|
||||
#define _(x) x
|
||||
|
||||
/* from libbfd */
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr);
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr);
|
||||
typedef enum bfd_boolean {false, true} boolean;
|
||||
|
||||
#endif /* ! defined (DIS_ASM_H) */
|
||||
@@ -1,79 +0,0 @@
|
||||
/* Disassemble from a buffer, for GNU.
|
||||
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "dis-asm.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
int
|
||||
buffer_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
perror_memory (status, memaddr, info)
|
||||
int status;
|
||||
bfd_vma memaddr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (status != EIO)
|
||||
/* Can't happen. */
|
||||
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
|
||||
else
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%x is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
|
||||
void
|
||||
generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%x", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
||||
int
|
||||
generic_symbol_at_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info * info;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -1,15 +1,100 @@
|
||||
/* General "disassemble this chunk" code. Used for debugging. */
|
||||
#include "config.h"
|
||||
#include "dis-asm.h"
|
||||
#include "disas.h"
|
||||
#include "elf.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
unsigned int disas_num_syms;
|
||||
void *disas_symtab;
|
||||
const char *disas_strtab;
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
int
|
||||
buffer_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
perror_memory (status, memaddr, info)
|
||||
int status;
|
||||
bfd_vma memaddr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (status != EIO)
|
||||
/* Can't happen. */
|
||||
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
|
||||
else
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%x is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
though both GDB and objdump provide their own (to print symbolic
|
||||
addresses). */
|
||||
|
||||
void
|
||||
generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%x", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
||||
int
|
||||
generic_symbol_at_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info * info;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0];
|
||||
v |= (unsigned long) addr[1] << 8;
|
||||
v |= (unsigned long) addr[2] << 16;
|
||||
v |= (unsigned long) addr[3] << 24;
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0] << 24;
|
||||
v |= (unsigned long) addr[1] << 16;
|
||||
v |= (unsigned long) addr[2] << 8;
|
||||
v |= (unsigned long) addr[3];
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
/* Disassemble this for me please... (debugging). 'flags' is only used
|
||||
for i386: non zero means 16 bit code */
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
{
|
||||
uint8_t *pc;
|
||||
int count;
|
||||
@@ -22,7 +107,7 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
|
||||
disasm_info.buffer_vma = (unsigned long)code;
|
||||
disasm_info.buffer_length = size;
|
||||
|
||||
if (type == DISAS_TARGET) {
|
||||
if (is_host) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
@@ -35,22 +120,43 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(__alpha__)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
} else {
|
||||
/* Currently only source supported in x86. */
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
if (type == DISAS_I386_I386)
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (!flags)
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
|
||||
fprintf(out, "0x%08lx: ", (long)pc);
|
||||
#ifdef __arm__
|
||||
/* since data are included in the code, it is better to
|
||||
display code data too */
|
||||
if (is_host) {
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
}
|
||||
#endif
|
||||
count = print_insn((unsigned long)pc, &disasm_info);
|
||||
fprintf(out, "\n");
|
||||
if (count < 0)
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
#ifndef _QEMU_DISAS_H
|
||||
#define _QEMU_DISAS_H
|
||||
|
||||
enum disas_type {
|
||||
DISAS_I386_I386,
|
||||
DISAS_I386_I8086,
|
||||
DISAS_TARGET, /* whatever host is. */
|
||||
};
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size, enum disas_type type);
|
||||
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(void *orig_addr);
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* dyngen defines for micro operation code
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
|
||||
typedef struct FILE FILE;
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int printf(const char *, ...);
|
||||
#define NULL 0
|
||||
#include <fenv.h>
|
||||
|
||||
#ifdef __i386__
|
||||
#define AREG0 "ebp"
|
||||
#define AREG1 "ebx"
|
||||
#define AREG2 "esi"
|
||||
#define AREG3 "edi"
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
#define AREG4 "r16"
|
||||
#define AREG5 "r17"
|
||||
#define AREG6 "r18"
|
||||
#define AREG7 "r19"
|
||||
#define AREG8 "r20"
|
||||
#define AREG9 "r21"
|
||||
#define AREG10 "r22"
|
||||
#define AREG11 "r23"
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define AREG0 "r7"
|
||||
#define AREG1 "r4"
|
||||
#define AREG2 "r5"
|
||||
#define AREG3 "r6"
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
#define AREG0 "s3"
|
||||
#define AREG1 "s0"
|
||||
#define AREG2 "s1"
|
||||
#define AREG3 "s2"
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define AREG0 "g6"
|
||||
#define AREG1 "g1"
|
||||
#define AREG2 "g2"
|
||||
#define AREG3 "g3"
|
||||
#define AREG4 "l0"
|
||||
#define AREG5 "l1"
|
||||
#define AREG6 "l2"
|
||||
#define AREG7 "l3"
|
||||
#define AREG8 "l4"
|
||||
#define AREG9 "l5"
|
||||
#define AREG10 "l6"
|
||||
#define AREG11 "l7"
|
||||
#define USE_FP_CONVERT
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define AREG0 "r10"
|
||||
#define AREG1 "r7"
|
||||
#define AREG2 "r8"
|
||||
#define AREG3 "r9"
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
/* Note $15 is the frame pointer, so anything in op-i386.c that would
|
||||
require a frame pointer, like alloca, would probably loose. */
|
||||
#define AREG0 "$15"
|
||||
#define AREG1 "$9"
|
||||
#define AREG2 "$10"
|
||||
#define AREG3 "$11"
|
||||
#define AREG4 "$12"
|
||||
#define AREG5 "$13"
|
||||
#define AREG6 "$14"
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
#endif
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
|
||||
#ifdef __alpha__
|
||||
/* the symbols are considered non exported so a br immediate is generated */
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define __hidden
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
/* Suggested by Richard Henderson. This will result in code like
|
||||
ldah $0,__op_param1($29) !gprelhigh
|
||||
lda $0,__op_param1($0) !gprellow
|
||||
We can then conveniently change $29 to $31 and adapt the offsets to
|
||||
emit the appropriate constant. */
|
||||
extern int __op_param1 __hidden;
|
||||
extern int __op_param2 __hidden;
|
||||
extern int __op_param3 __hidden;
|
||||
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
|
||||
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
|
||||
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
|
||||
#else
|
||||
extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM1 ((long)(&__op_param1))
|
||||
#define PARAM2 ((long)(&__op_param2))
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
#endif
|
||||
|
||||
extern int __op_jmp0, __op_jmp1;
|
||||
@@ -79,6 +79,13 @@
|
||||
#define elf_check_arch(x) ((x) == EM_SPARCV9)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#elif defined(HOST_ARM)
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_ARCH EM_ARM
|
||||
#define elf_check_arch(x) ((x) == EM_ARM)
|
||||
#define ELF_USES_RELOC
|
||||
|
||||
#else
|
||||
#error unsupported CPU - please update the code
|
||||
#endif
|
||||
@@ -95,8 +102,20 @@ typedef uint64_t host_ulong;
|
||||
#define swabls(x) swab64s(x)
|
||||
#endif
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
#define SHT_RELOC SHT_RELA
|
||||
#else
|
||||
#define SHT_RELOC SHT_REL
|
||||
#endif
|
||||
|
||||
#include "thunk.h"
|
||||
|
||||
enum {
|
||||
OUT_GEN_OP,
|
||||
OUT_CODE,
|
||||
OUT_INDEX_OP,
|
||||
};
|
||||
|
||||
/* all dynamically generated functions begin with this code */
|
||||
#define OP_PREFIX "op_"
|
||||
|
||||
@@ -170,16 +189,24 @@ void elf_swap_phdr(struct elf_phdr *h)
|
||||
swabls(&h->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
void elf_swap_rel(ELF_RELOC *rel)
|
||||
{
|
||||
swabls(&rel->r_offset);
|
||||
swabls(&rel->r_info);
|
||||
#ifdef ELF_USES_RELOCA
|
||||
swabls(&rel->r_addend);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ELF file info */
|
||||
int do_swap;
|
||||
struct elf_shdr *shdr;
|
||||
uint8_t **sdata;
|
||||
struct elfhdr ehdr;
|
||||
ElfW(Sym) *symtab;
|
||||
int nb_syms;
|
||||
char *strtab;
|
||||
/* data section */
|
||||
uint8_t *data_data;
|
||||
int data_shndx;
|
||||
int text_shndx;
|
||||
|
||||
uint16_t get16(uint16_t *p)
|
||||
{
|
||||
@@ -243,6 +270,19 @@ struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int find_reloc(int sh_index)
|
||||
{
|
||||
struct elf_shdr *sec;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *load_data(int fd, long offset, unsigned int size)
|
||||
{
|
||||
char *data;
|
||||
@@ -274,11 +314,111 @@ int strstart(const char *str, const char *val, const char **ptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HOST_ARM
|
||||
|
||||
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
|
||||
FILE *outfile, uint8_t *p_start, uint8_t *p_end,
|
||||
ELF_RELOC *relocs, int nb_relocs)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint32_t insn;
|
||||
int offset, min_offset, pc_offset, data_size;
|
||||
uint8_t data_allocated[1024];
|
||||
unsigned int data_index;
|
||||
|
||||
memset(data_allocated, 0, sizeof(data_allocated));
|
||||
|
||||
p = p_start;
|
||||
min_offset = p_end - p_start;
|
||||
while (p < p_start + min_offset) {
|
||||
insn = get32((uint32_t *)p);
|
||||
if ((insn & 0x0d5f0000) == 0x051f0000) {
|
||||
/* ldr reg, [pc, #im] */
|
||||
offset = insn & 0xfff;
|
||||
if (!(insn & 0x00800000))
|
||||
offset = -offset;
|
||||
if ((offset & 3) !=0)
|
||||
error("%s:%04x: ldr pc offset must be 32 bit aligned",
|
||||
name, start_offset + p - p_start);
|
||||
pc_offset = p - p_start + offset + 8;
|
||||
if (pc_offset <= (p - p_start) ||
|
||||
pc_offset >= (p_end - p_start))
|
||||
error("%s:%04x: ldr pc offset must point inside the function code",
|
||||
name, start_offset + p - p_start);
|
||||
if (pc_offset < min_offset)
|
||||
min_offset = pc_offset;
|
||||
if (outfile) {
|
||||
/* ldr position */
|
||||
fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
|
||||
p - p_start);
|
||||
/* ldr data index */
|
||||
data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
|
||||
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
|
||||
data_index);
|
||||
fprintf(outfile, " arm_ldr_ptr++;\n");
|
||||
if (data_index >= sizeof(data_allocated))
|
||||
error("%s: too many data", name);
|
||||
if (!data_allocated[data_index]) {
|
||||
ELF_RELOC *rel;
|
||||
int i, addend, type;
|
||||
const char *sym_name, *p;
|
||||
char relname[1024];
|
||||
|
||||
data_allocated[data_index] = 1;
|
||||
|
||||
/* data value */
|
||||
addend = get32((uint32_t *)(p_start + pc_offset));
|
||||
relname[0] = '\0';
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset == (pc_offset + start_offset)) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
/* the compiler leave some unnecessary references to the code */
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(relname, sizeof(relname), "param%s", p);
|
||||
} else {
|
||||
snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
if (type != R_ARM_ABS32)
|
||||
error("%s: unsupported data relocation", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
|
||||
data_index, addend);
|
||||
if (relname[0] != '\0')
|
||||
fprintf(outfile, " + %s", relname);
|
||||
fprintf(outfile, ";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
p += 4;
|
||||
}
|
||||
data_size = (p_end - p_start) - min_offset;
|
||||
if (data_size > 0 && outfile) {
|
||||
fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2);
|
||||
}
|
||||
|
||||
/* the last instruction must be a mov pc, lr */
|
||||
if (p == p_start)
|
||||
goto arm_ret_error;
|
||||
p -= 4;
|
||||
insn = get32((uint32_t *)p);
|
||||
if ((insn & 0xffff0000) != 0xe91b0000) {
|
||||
arm_ret_error:
|
||||
if (!outfile)
|
||||
printf("%s: invalid epilog\n", name);
|
||||
}
|
||||
return p - p_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_ARGS 3
|
||||
|
||||
/* generate op code */
|
||||
void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type,
|
||||
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs,
|
||||
int gen_switch)
|
||||
{
|
||||
int copy_size = 0;
|
||||
@@ -361,7 +501,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
{
|
||||
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
|
||||
uint32_t start_insn, end_insn1, end_insn2;
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 8);
|
||||
if (p <= p_start)
|
||||
@@ -379,14 +519,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
} else {
|
||||
error("No save at the beginning of %s", name);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Skip a preceeding nop, if present. */
|
||||
if (p > p_start) {
|
||||
skip_insn = get32((uint32_t *)(p - 0x4));
|
||||
if (skip_insn == 0x01000000)
|
||||
p -= 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
@@ -421,6 +561,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
#ifdef HOST_ARM
|
||||
case EM_ARM:
|
||||
if ((p_end - p_start) <= 16)
|
||||
error("%s: function too small", name);
|
||||
if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
|
||||
(get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
|
||||
get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
|
||||
error("%s: invalid prolog", name);
|
||||
p_start += 12;
|
||||
start_offset += 12;
|
||||
copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
|
||||
relocs, nb_relocs);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
@@ -431,7 +585,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
rel->r_offset < start_offset + (p_end - p_start)) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
n = strtoul(p, NULL, 10);
|
||||
@@ -469,7 +623,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
rel->r_offset < start_offset + (p_end - p_start)) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (*sym_name &&
|
||||
!strstart(sym_name, "__op_param", NULL) &&
|
||||
@@ -499,11 +653,40 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
sym_name = strtab + sym->st_name;
|
||||
if (strstart(sym_name, "__op_label", &p)) {
|
||||
uint8_t *ptr;
|
||||
int addend;
|
||||
unsigned long offset;
|
||||
|
||||
/* test if the variable refers to a label inside
|
||||
the code we are generating */
|
||||
if (sym->st_shndx != data_shndx)
|
||||
error("__op_labelN symbols must be in .data or .sdata section");
|
||||
val = *(target_ulong *)(data_data + sym->st_value);
|
||||
ptr = sdata[sym->st_shndx];
|
||||
if (!ptr)
|
||||
error("__op_labelN in invalid section");
|
||||
offset = sym->st_value;
|
||||
addend = 0;
|
||||
#ifdef ELF_USES_RELOCA
|
||||
{
|
||||
int reloc_shndx, nb_relocs1, j;
|
||||
|
||||
/* try to find a matching relocation */
|
||||
reloc_shndx = find_reloc(sym->st_shndx);
|
||||
if (reloc_shndx) {
|
||||
nb_relocs1 = shdr[reloc_shndx].sh_size /
|
||||
shdr[reloc_shndx].sh_entsize;
|
||||
rel = (ELF_RELOC *)sdata[reloc_shndx];
|
||||
for(j = 0; j < nb_relocs1; j++) {
|
||||
if (rel->r_offset == offset) {
|
||||
addend = rel->r_addend;
|
||||
break;
|
||||
}
|
||||
rel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
val = *(target_ulong *)(ptr + offset);
|
||||
val += addend;
|
||||
|
||||
if (val >= start_offset && val < start_offset + copy_size) {
|
||||
n = strtol(p, NULL, 10);
|
||||
fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
|
||||
@@ -685,7 +868,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
case R_ALPHA_BRSGP:
|
||||
/* PC-relative jump. Tweak offset to skip the two instructions that try to
|
||||
set up the gp from the pv. */
|
||||
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n",
|
||||
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
|
||||
rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
|
||||
break;
|
||||
default:
|
||||
@@ -844,6 +1027,44 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_ARM)
|
||||
{
|
||||
char name[256];
|
||||
int type;
|
||||
int addend;
|
||||
|
||||
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
|
||||
relocs, nb_relocs);
|
||||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
/* the compiler leave some unnecessary references to the code */
|
||||
if (sym_name[0] == '\0')
|
||||
continue;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = get32((uint32_t *)(text + rel->r_offset));
|
||||
switch(type) {
|
||||
case R_ARM_ABS32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_ARM_PC24:
|
||||
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
|
||||
rel->r_offset - start_offset, addend, name);
|
||||
break;
|
||||
default:
|
||||
error("unsupported arm relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@@ -872,16 +1093,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
|
||||
/* load an elf object file */
|
||||
int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
int load_elf(const char *filename, FILE *outfile, int out_type)
|
||||
{
|
||||
int fd;
|
||||
struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
|
||||
int i, j;
|
||||
ElfW(Sym) *sym;
|
||||
char *shstr, *data_name;
|
||||
char *shstr;
|
||||
uint8_t *text;
|
||||
void *relocs;
|
||||
int nb_relocs, reloc_sh_type;
|
||||
ELF_RELOC *relocs;
|
||||
int nb_relocs;
|
||||
ELF_RELOC *rel;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
@@ -920,56 +1142,45 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
}
|
||||
}
|
||||
|
||||
sec = &shdr[ehdr.e_shstrndx];
|
||||
shstr = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
/* read all section data */
|
||||
sdata = malloc(sizeof(void *) * ehdr.e_shnum);
|
||||
memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
|
||||
|
||||
for(i = 0;i < ehdr.e_shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
if (sec->sh_type != SHT_NOBITS)
|
||||
sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
}
|
||||
|
||||
sec = &shdr[ehdr.e_shstrndx];
|
||||
shstr = sdata[ehdr.e_shstrndx];
|
||||
|
||||
/* swap relocations */
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
if (sec->sh_type == SHT_RELOC) {
|
||||
nb_relocs = sec->sh_size / sec->sh_entsize;
|
||||
if (do_swap) {
|
||||
for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
|
||||
elf_swap_rel(rel);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* text section */
|
||||
|
||||
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
|
||||
if (!text_sec)
|
||||
error("could not find .text section");
|
||||
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
|
||||
text_shndx = text_sec - shdr;
|
||||
text = sdata[text_shndx];
|
||||
|
||||
#if defined(HOST_PPC)
|
||||
data_name = ".sdata";
|
||||
#else
|
||||
data_name = ".data";
|
||||
#endif
|
||||
sec = find_elf_section(shdr, ehdr.e_shnum, shstr, data_name);
|
||||
if (!sec)
|
||||
error("could not find %s section", data_name);
|
||||
data_shndx = sec - shdr;
|
||||
data_data = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
|
||||
/* find text relocations, if any */
|
||||
nb_relocs = 0;
|
||||
relocs = NULL;
|
||||
reloc_sh_type = 0;
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
sec = &shdr[i];
|
||||
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) &&
|
||||
sec->sh_info == (text_sec - shdr)) {
|
||||
reloc_sh_type = sec->sh_type;
|
||||
relocs = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||
nb_relocs = sec->sh_size / sec->sh_entsize;
|
||||
if (do_swap) {
|
||||
if (sec->sh_type == SHT_REL) {
|
||||
ElfW(Rel) *rel = relocs;
|
||||
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
|
||||
swabls(&rel->r_offset);
|
||||
swabls(&rel->r_info);
|
||||
}
|
||||
} else {
|
||||
ElfW(Rela) *rel = relocs;
|
||||
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
|
||||
swabls(&rel->r_offset);
|
||||
swabls(&rel->r_info);
|
||||
swabls(&rel->r_addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
nb_relocs = 0;
|
||||
i = find_reloc(text_shndx);
|
||||
if (i != 0) {
|
||||
relocs = (ELF_RELOC *)sdata[i];
|
||||
nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
|
||||
}
|
||||
|
||||
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
|
||||
@@ -977,8 +1188,8 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
error("could not find .symtab section");
|
||||
strtab_sec = &shdr[symtab_sec->sh_link];
|
||||
|
||||
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
|
||||
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
|
||||
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
|
||||
strtab = sdata[symtab_sec->sh_link];
|
||||
|
||||
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
|
||||
if (do_swap) {
|
||||
@@ -990,38 +1201,32 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||
}
|
||||
}
|
||||
|
||||
if (do_print_enum) {
|
||||
if (out_type == OUT_INDEX_OP) {
|
||||
fprintf(outfile, "DEF(end, 0, 0)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name, *p;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, &p)) {
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, 2);
|
||||
text, relocs, nb_relocs, 2);
|
||||
}
|
||||
}
|
||||
} else if (out_type == OUT_GEN_OP) {
|
||||
/* generate gen_xxx functions */
|
||||
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, NULL)) {
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* generate big code generation switch */
|
||||
#ifdef HOST_ALPHA
|
||||
fprintf(outfile,
|
||||
"register int gp asm(\"$29\");\n"
|
||||
"static inline void immediate_ldah(void *p, int val) {\n"
|
||||
" uint32_t *dest = p;\n"
|
||||
" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n"
|
||||
"\n"
|
||||
" *dest &= ~0xffff;\n"
|
||||
" *dest |= high;\n"
|
||||
" *dest |= 31 << 16;\n"
|
||||
"}\n"
|
||||
"static inline void immediate_lda(void *dest, int val) {\n"
|
||||
" *(uint16_t *) dest = val;\n"
|
||||
"}\n"
|
||||
"void fix_bsr(void *p, int offset) {\n"
|
||||
" uint32_t *dest = p;\n"
|
||||
" *dest &= ~((1 << 21) - 1);\n"
|
||||
" *dest |= (offset >> 2) & ((1 << 21) - 1);\n"
|
||||
"}\n");
|
||||
#endif
|
||||
fprintf(outfile,
|
||||
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
||||
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
|
||||
@@ -1029,23 +1234,22 @@ fprintf(outfile,
|
||||
"{\n"
|
||||
" uint8_t *gen_code_ptr;\n"
|
||||
" const uint16_t *opc_ptr;\n"
|
||||
" const uint32_t *opparam_ptr;\n"
|
||||
" const uint32_t *opparam_ptr;\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
fprintf(outfile,
|
||||
" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
|
||||
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" uint32_t *arm_data_ptr = arm_data_table;\n");
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
"\n"
|
||||
" gen_code_ptr = gen_code_buf;\n"
|
||||
" opc_ptr = opc_buf;\n"
|
||||
" opparam_ptr = opparam_buf;\n");
|
||||
|
||||
/* Generate prologue, if needed. */
|
||||
switch(ELF_ARCH) {
|
||||
case EM_SPARC:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n");
|
||||
break;
|
||||
|
||||
case EM_SPARCV9:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n");
|
||||
break;
|
||||
};
|
||||
|
||||
fprintf(outfile,
|
||||
" for(;;) {\n"
|
||||
@@ -1063,14 +1267,28 @@ fprintf(outfile,
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, 1);
|
||||
text, relocs, nb_relocs, 1);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outfile,
|
||||
" default:\n"
|
||||
" goto the_end;\n"
|
||||
" }\n"
|
||||
" }\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
/* generate constant table if needed */
|
||||
fprintf(outfile,
|
||||
" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
|
||||
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
|
||||
" last_gen_code_ptr = gen_code_ptr;\n"
|
||||
" arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" arm_data_ptr = arm_data_table;\n"
|
||||
" }\n");
|
||||
#endif
|
||||
|
||||
|
||||
fprintf(outfile,
|
||||
" }\n"
|
||||
" the_end:\n"
|
||||
);
|
||||
@@ -1094,33 +1312,25 @@ fprintf(outfile,
|
||||
break;
|
||||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n");
|
||||
break;
|
||||
case EM_SPARCV9:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n");
|
||||
break;
|
||||
case EM_ARM:
|
||||
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
|
||||
break;
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
|
||||
/* flush instruction cache */
|
||||
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
|
||||
|
||||
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
|
||||
fprintf(outfile, "}\n\n");
|
||||
|
||||
/* generate gen_xxx functions */
|
||||
/* XXX: suppress the use of these functions to simplify code */
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = strtab + sym->st_name;
|
||||
if (strstart(name, OP_PREFIX, NULL)) {
|
||||
if (sym->st_shndx != (text_sec - shdr))
|
||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||
text, relocs, nb_relocs, reloc_sh_type, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -1133,20 +1343,21 @@ void usage(void)
|
||||
"usage: dyngen [-o outfile] [-c] objfile\n"
|
||||
"Generate a dynamic code generator from an object file\n"
|
||||
"-c output enum of operations\n"
|
||||
"-g output gen_op_xx() functions\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, do_print_enum;
|
||||
int c, out_type;
|
||||
const char *filename, *outfilename;
|
||||
FILE *outfile;
|
||||
|
||||
outfilename = "out.c";
|
||||
do_print_enum = 0;
|
||||
out_type = OUT_CODE;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "ho:c");
|
||||
c = getopt(argc, argv, "ho:cg");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
@@ -1157,7 +1368,10 @@ int main(int argc, char **argv)
|
||||
outfilename = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
do_print_enum = 1;
|
||||
out_type = OUT_INDEX_OP;
|
||||
break;
|
||||
case 'g':
|
||||
out_type = OUT_GEN_OP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1167,7 +1381,7 @@ int main(int argc, char **argv)
|
||||
outfile = fopen(outfilename, "w");
|
||||
if (!outfile)
|
||||
error("could not open '%s'", outfilename);
|
||||
load_elf(filename, outfile, do_print_enum);
|
||||
load_elf(filename, outfile, out_type);
|
||||
fclose(outfile);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* dyngen helpers
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
int __op_jmp0, __op_jmp1;
|
||||
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(8UL - 1UL);
|
||||
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
|
||||
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
register unsigned long _beg __asm ("a1") = start;
|
||||
register unsigned long _end __asm ("a2") = stop;
|
||||
register unsigned long _flg __asm ("a3") = 0;
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
static inline void immediate_ldah(void *p, int val) {
|
||||
uint32_t *dest = p;
|
||||
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
|
||||
|
||||
*dest &= ~0xffff;
|
||||
*dest |= high;
|
||||
*dest |= 31 << 16;
|
||||
}
|
||||
static inline void immediate_lda(void *dest, int val) {
|
||||
*(uint16_t *) dest = val;
|
||||
}
|
||||
void fix_bsr(void *p, int offset) {
|
||||
uint32_t *dest = p;
|
||||
*dest &= ~((1 << 21) - 1);
|
||||
*dest |= (offset >> 2) & ((1 << 21) - 1);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define MAX_OP_SIZE (128 * 4) /* in bytes */
|
||||
/* max size of the code that can be generated without calling arm_flush_ldr */
|
||||
#define MAX_FRAG_SIZE (1024 * 4)
|
||||
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[1024];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
{
|
||||
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
uint32_t *ptr;
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
|
||||
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
|
||||
|
||||
if (!gen_jmp) {
|
||||
/* b exec_loop */
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop));
|
||||
gen_code_ptr += 4;
|
||||
} else {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
target = (long)gen_code_ptr + data_size + 4;
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
insn = *ptr & ~(0xfff | 0x00800000);
|
||||
if (offset < 0) {
|
||||
offset = - offset;
|
||||
} else {
|
||||
insn |= 0x00800000;
|
||||
}
|
||||
if (offset > 0xfff) {
|
||||
fprintf(stderr, "Error ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
insn |= offset;
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ARM execution defines
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
register struct CPUARMState *env asm(AREG0);
|
||||
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"
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void cpu_loop_exit(void);
|
||||
+241
-145
@@ -17,134 +17,59 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
/* at least 4 register variables are defines */
|
||||
register struct CPUX86State *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
||||
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
||||
})
|
||||
#define A0 T2
|
||||
|
||||
#define NULL 0
|
||||
#include <fenv.h>
|
||||
/* if more registers are available, we define some registers too */
|
||||
#ifdef AREG4
|
||||
register uint32_t EAX asm(AREG4);
|
||||
#define reg_EAX
|
||||
#endif
|
||||
|
||||
#ifdef AREG5
|
||||
register uint32_t ESP asm(AREG5);
|
||||
#define reg_ESP
|
||||
#endif
|
||||
|
||||
#ifdef AREG6
|
||||
register uint32_t EBP asm(AREG6);
|
||||
#define reg_EBP
|
||||
#endif
|
||||
|
||||
#ifdef AREG7
|
||||
register uint32_t ECX asm(AREG7);
|
||||
#define reg_ECX
|
||||
#endif
|
||||
|
||||
#ifdef AREG8
|
||||
register uint32_t EDX asm(AREG8);
|
||||
#define reg_EDX
|
||||
#endif
|
||||
|
||||
#ifdef AREG9
|
||||
register uint32_t EBX asm(AREG9);
|
||||
#define reg_EBX
|
||||
#endif
|
||||
|
||||
#ifdef AREG10
|
||||
register uint32_t ESI asm(AREG10);
|
||||
#define reg_ESI
|
||||
#endif
|
||||
|
||||
#ifdef AREG11
|
||||
register uint32_t EDI asm(AREG11);
|
||||
#define reg_EDI
|
||||
#endif
|
||||
|
||||
typedef struct FILE FILE;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
#ifdef __i386__
|
||||
register unsigned int T0 asm("ebx");
|
||||
register unsigned int T1 asm("esi");
|
||||
register unsigned int A0 asm("edi");
|
||||
register struct CPUX86State *env asm("ebp");
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
register unsigned int EAX asm("r16");
|
||||
register unsigned int ECX asm("r17");
|
||||
register unsigned int EDX asm("r18");
|
||||
register unsigned int EBX asm("r19");
|
||||
register unsigned int ESP asm("r20");
|
||||
register unsigned int EBP asm("r21");
|
||||
register unsigned int ESI asm("r22");
|
||||
register unsigned int EDI asm("r23");
|
||||
register unsigned int T0 asm("r24");
|
||||
register unsigned int T1 asm("r25");
|
||||
register unsigned int A0 asm("r26");
|
||||
register struct CPUX86State *env asm("r27");
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#define reg_EAX
|
||||
#define reg_ECX
|
||||
#define reg_EDX
|
||||
#define reg_EBX
|
||||
#define reg_ESP
|
||||
#define reg_EBP
|
||||
#define reg_ESI
|
||||
#define reg_EDI
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
register unsigned int T0 asm("r4");
|
||||
register unsigned int T1 asm("r5");
|
||||
register unsigned int A0 asm("r6");
|
||||
register struct CPUX86State *env asm("r7");
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
register unsigned int T0 asm("s0");
|
||||
register unsigned int T1 asm("s1");
|
||||
register unsigned int A0 asm("s2");
|
||||
register struct CPUX86State *env asm("s3");
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
register unsigned int EAX asm("l0");
|
||||
register unsigned int ECX asm("l1");
|
||||
register unsigned int EDX asm("l2");
|
||||
register unsigned int EBX asm("l3");
|
||||
register unsigned int ESP asm("l4");
|
||||
register unsigned int EBP asm("l5");
|
||||
register unsigned int ESI asm("l6");
|
||||
register unsigned int EDI asm("l7");
|
||||
register unsigned int T0 asm("g1");
|
||||
register unsigned int T1 asm("g2");
|
||||
register unsigned int A0 asm("g3");
|
||||
register struct CPUX86State *env asm("g6");
|
||||
#define USE_FP_CONVERT
|
||||
#define reg_EAX
|
||||
#define reg_ECX
|
||||
#define reg_EDX
|
||||
#define reg_EBX
|
||||
#define reg_ESP
|
||||
#define reg_EBP
|
||||
#define reg_ESI
|
||||
#define reg_EDI
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
register unsigned int T0 asm("r7");
|
||||
register unsigned int T1 asm("r8");
|
||||
register unsigned int A0 asm("r9");
|
||||
register struct CPUX86State *env asm("r10");
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
register unsigned int T0 asm("$9");
|
||||
register unsigned int T1 asm("$10");
|
||||
register unsigned int A0 asm("$11");
|
||||
register unsigned int EAX asm("$12");
|
||||
register unsigned int ESP asm("$13");
|
||||
register unsigned int EBP asm("$14");
|
||||
register struct CPUX86State *env asm("$15");
|
||||
#define reg_EAX
|
||||
#define reg_ESP
|
||||
#define reg_EBP
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
register unsigned int T0 asm("r24");
|
||||
register unsigned int T1 asm("r25");
|
||||
register unsigned int A0 asm("r26");
|
||||
register struct CPUX86State *env asm("r27");
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
#endif
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
|
||||
#ifndef reg_EAX
|
||||
#define EAX (env->regs[R_EAX])
|
||||
@@ -187,26 +112,6 @@ register struct CPUX86State *env asm("r27");
|
||||
#define FP_CONVERT (env->fp_convert)
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
/* Suggested by Richard Henderson. This will result in code like
|
||||
ldah $0,__op_param1($29) !gprelhigh
|
||||
lda $0,__op_param1($0) !gprellow
|
||||
We can then conveniently change $29 to $31 and adapt the offsets to
|
||||
emit the appropriate constant. */
|
||||
extern int __op_param1 __attribute__((visibility("hidden")));
|
||||
extern int __op_param2 __attribute__((visibility("hidden")));
|
||||
extern int __op_param3 __attribute__((visibility("hidden")));
|
||||
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
|
||||
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
|
||||
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
|
||||
#else
|
||||
extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM1 ((long)(&__op_param1))
|
||||
#define PARAM2 ((long)(&__op_param2))
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
#endif
|
||||
extern int __op_jmp0, __op_jmp1;
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
@@ -218,13 +123,204 @@ typedef struct CCTable {
|
||||
extern CCTable cc_table[];
|
||||
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip);
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void __hidden cpu_lock(void);
|
||||
void __hidden cpu_unlock(void);
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
void raise_exception_err(int exception_index, int error_code);
|
||||
void raise_exception(int exception_index);
|
||||
void cpu_loop_exit(void);
|
||||
void __hidden cpu_loop_exit(void);
|
||||
void helper_fsave(uint8_t *ptr, int data32);
|
||||
void helper_frstor(uint8_t *ptr, int data32);
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void);
|
||||
void OPPROTO op_movl_T0_eflags(void);
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
void raise_exception_err(int exception_index, int error_code);
|
||||
void raise_exception(int exception_index);
|
||||
void helper_divl_EAX_T0(uint32_t eip);
|
||||
void helper_idivl_EAX_T0(uint32_t eip);
|
||||
void helper_cmpxchg8b(void);
|
||||
void helper_cpuid(void);
|
||||
void helper_rdtsc(void);
|
||||
void helper_lsl(void);
|
||||
void helper_lar(void);
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
/* use long double functions */
|
||||
#define lrint lrintl
|
||||
#define llrint llrintl
|
||||
#define fabs fabsl
|
||||
#define sin sinl
|
||||
#define cos cosl
|
||||
#define sqrt sqrtl
|
||||
#define pow powl
|
||||
#define log logl
|
||||
#define tan tanl
|
||||
#define atan2 atan2l
|
||||
#define floor floorl
|
||||
#define ceil ceill
|
||||
#define rint rintl
|
||||
#endif
|
||||
|
||||
extern int lrint(CPU86_LDouble x);
|
||||
extern int64_t llrint(CPU86_LDouble x);
|
||||
extern CPU86_LDouble fabs(CPU86_LDouble x);
|
||||
extern CPU86_LDouble sin(CPU86_LDouble x);
|
||||
extern CPU86_LDouble cos(CPU86_LDouble x);
|
||||
extern CPU86_LDouble sqrt(CPU86_LDouble x);
|
||||
extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble);
|
||||
extern CPU86_LDouble log(CPU86_LDouble x);
|
||||
extern CPU86_LDouble tan(CPU86_LDouble x);
|
||||
extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble);
|
||||
extern CPU86_LDouble floor(CPU86_LDouble x);
|
||||
extern CPU86_LDouble ceil(CPU86_LDouble x);
|
||||
extern CPU86_LDouble rint(CPU86_LDouble x);
|
||||
|
||||
#define RC_MASK 0xc00
|
||||
#define RC_NEAR 0x000
|
||||
#define RC_DOWN 0x400
|
||||
#define RC_UP 0x800
|
||||
#define RC_CHOP 0xc00
|
||||
|
||||
#define MAXTAN 9223372036854775808.0
|
||||
|
||||
#ifdef __arm__
|
||||
/* we have no way to do correct rounding - a FPU emulator is needed */
|
||||
#define FE_DOWNWARD FE_TONEAREST
|
||||
#define FE_UPWARD FE_TONEAREST
|
||||
#define FE_TOWARDZERO FE_TONEAREST
|
||||
#endif
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
|
||||
/* only for x86 */
|
||||
typedef union {
|
||||
long double d;
|
||||
struct {
|
||||
unsigned long long lower;
|
||||
unsigned short upper;
|
||||
} l;
|
||||
} CPU86_LDoubleU;
|
||||
|
||||
/* the following deal with x86 long double-precision numbers */
|
||||
#define MAXEXPD 0x7fff
|
||||
#define EXPBIAS 16383
|
||||
#define EXPD(fp) (fp.l.upper & 0x7fff)
|
||||
#define SIGND(fp) ((fp.l.upper) & 0x8000)
|
||||
#define MANTD(fp) (fp.l.lower)
|
||||
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
|
||||
|
||||
#else
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
typedef union {
|
||||
double d;
|
||||
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
|
||||
struct {
|
||||
uint32_t lower;
|
||||
int32_t upper;
|
||||
} l;
|
||||
#else
|
||||
struct {
|
||||
int32_t upper;
|
||||
uint32_t lower;
|
||||
} l;
|
||||
#endif
|
||||
#ifndef __arm__
|
||||
int64_t ll;
|
||||
#endif
|
||||
} CPU86_LDoubleU;
|
||||
|
||||
/* the following deal with IEEE double-precision numbers */
|
||||
#define MAXEXPD 0x7ff
|
||||
#define EXPBIAS 1023
|
||||
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
|
||||
#define SIGND(fp) ((fp.l.upper) & 0x80000000)
|
||||
#ifdef __arm__
|
||||
#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
|
||||
#else
|
||||
#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
|
||||
#endif
|
||||
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
|
||||
#endif
|
||||
|
||||
static inline void fpush(void)
|
||||
{
|
||||
env->fpstt = (env->fpstt - 1) & 7;
|
||||
env->fptags[env->fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
static inline void fpop(void)
|
||||
{
|
||||
env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
|
||||
env->fpstt = (env->fpstt + 1) & 7;
|
||||
}
|
||||
|
||||
#ifndef USE_X86LDOUBLE
|
||||
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
int upper, e;
|
||||
uint64_t ll;
|
||||
|
||||
/* mantissa */
|
||||
upper = lduw(ptr + 8);
|
||||
/* XXX: handle overflow ? */
|
||||
e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
|
||||
e |= (upper >> 4) & 0x800; /* sign */
|
||||
ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
|
||||
#ifdef __arm__
|
||||
temp.l.upper = (e << 20) | (ll >> 32);
|
||||
temp.l.lower = ll;
|
||||
#else
|
||||
temp.ll = ll | ((uint64_t)e << 52);
|
||||
#endif
|
||||
return temp.d;
|
||||
}
|
||||
|
||||
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
int e;
|
||||
|
||||
temp.d = f;
|
||||
/* mantissa */
|
||||
stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
|
||||
/* exponent + sign */
|
||||
e = EXPD(temp) - EXPBIAS + 16383;
|
||||
e |= SIGND(temp) >> 16;
|
||||
stw(ptr + 8, e);
|
||||
}
|
||||
#endif
|
||||
|
||||
const CPU86_LDouble f15rk[7];
|
||||
|
||||
void helper_fldt_ST0_A0(void);
|
||||
void helper_fstt_ST0_A0(void);
|
||||
void helper_fbld_ST0_A0(void);
|
||||
void helper_fbst_ST0_A0(void);
|
||||
void helper_f2xm1(void);
|
||||
void helper_fyl2x(void);
|
||||
void helper_fptan(void);
|
||||
void helper_fpatan(void);
|
||||
void helper_fxtract(void);
|
||||
void helper_fprem1(void);
|
||||
void helper_fprem(void);
|
||||
void helper_fyl2xp1(void);
|
||||
void helper_fsqrt(void);
|
||||
void helper_fsincos(void);
|
||||
void helper_frndint(void);
|
||||
void helper_fscale(void);
|
||||
void helper_fsin(void);
|
||||
void helper_fcos(void);
|
||||
void helper_fxam_ST0(void);
|
||||
void helper_fstenv(uint8_t *ptr, int data32);
|
||||
void helper_fldenv(uint8_t *ptr, int data32);
|
||||
void helper_fsave(uint8_t *ptr, int data32);
|
||||
void helper_frstor(uint8_t *ptr, int data32);
|
||||
|
||||
const uint8_t parity_table[256];
|
||||
const uint8_t rclw_table[32];
|
||||
const uint8_t rclb_table[32];
|
||||
@@ -70,7 +70,7 @@ unsigned long host_page_mask;
|
||||
|
||||
static PageDesc *l1_map[L1_SIZE];
|
||||
|
||||
void page_init(void)
|
||||
static void page_init(void)
|
||||
{
|
||||
/* NOTE: we can always suppose that host_page_size >=
|
||||
TARGET_PAGE_SIZE */
|
||||
@@ -190,10 +190,11 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
|
||||
void cpu_x86_tblocks_init(void)
|
||||
void cpu_exec_init(void)
|
||||
{
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
page_init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,31 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
|
||||
|
||||
struct TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 32
|
||||
#define OPC_BUF_SIZE 512
|
||||
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define GEN_FLAG_CODE32_SHIFT 0
|
||||
#define GEN_FLAG_ADDSEG_SHIFT 1
|
||||
#define GEN_FLAG_SS32_SHIFT 2
|
||||
@@ -27,13 +52,18 @@
|
||||
#define GEN_FLAG_CPL_SHIFT 9
|
||||
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
|
||||
|
||||
struct TranslationBlock;
|
||||
int cpu_x86_gen_code(struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_x86_search_pc(struct TranslationBlock *tb,
|
||||
uint32_t *found_pc, unsigned long searched_pc);
|
||||
void cpu_x86_tblocks_init(void);
|
||||
void page_init(void);
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(struct TranslationBlock *tb, int search_pc);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
int cpu_gen_code(struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_search_pc(struct TranslationBlock *tb,
|
||||
uint32_t *found_pc, unsigned long searched_pc);
|
||||
void cpu_exec_init(void);
|
||||
int page_unprotect(unsigned long address);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
@@ -65,7 +95,7 @@ typedef struct TranslationBlock {
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
|
||||
#else
|
||||
uint8_t *tb_next[2]; /* address of jump generated code */
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
/* list of TBs jumping to this one. This is a circular list using
|
||||
the two least significant bits of the pointers to tell what is
|
||||
@@ -142,7 +172,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
tb->tb_next[n] = (void *)addr;
|
||||
tb->tb_next[n] = addr;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -167,6 +197,33 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
/* on PowerPC we patch the jump instruction directly */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
/* jump to next block operations (more portable code, does not need
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
@@ -214,7 +271,7 @@ static inline int testandset (int *p)
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
int testandset (int *p)
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
unsigned long one;
|
||||
@@ -246,6 +303,18 @@ static inline int testandset (int *p)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline int testandset (int *spinlock)
|
||||
{
|
||||
register unsigned int ret;
|
||||
__asm__ __volatile__("swp %0, %1, [%2]"
|
||||
: "=r"(ret)
|
||||
: "0"(1), "r"(spinlock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
+958
@@ -0,0 +1,958 @@
|
||||
/*
|
||||
* i386 helpers
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
|
||||
const uint8_t parity_table[256] = {
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
||||
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
||||
};
|
||||
|
||||
/* modulo 17 table */
|
||||
const uint8_t rclw_table[32] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9,10,11,12,13,14,15,
|
||||
16, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9,10,11,12,13,14,
|
||||
};
|
||||
|
||||
/* modulo 9 table */
|
||||
const uint8_t rclb_table[32] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 0, 1, 2, 3, 4, 5,
|
||||
6, 7, 8, 0, 1, 2, 3, 4,
|
||||
};
|
||||
|
||||
const CPU86_LDouble f15rk[7] =
|
||||
{
|
||||
0.00000000000000000000L,
|
||||
1.00000000000000000000L,
|
||||
3.14159265358979323851L, /*pi*/
|
||||
0.30102999566398119523L, /*lg2*/
|
||||
0.69314718055994530943L, /*ln2*/
|
||||
1.44269504088896340739L, /*l2e*/
|
||||
3.32192809488736234781L, /*l2t*/
|
||||
};
|
||||
|
||||
/* thread support */
|
||||
|
||||
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
spin_lock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
spin_unlock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
/* NOTE: the register at this point must be saved by hand because
|
||||
longjmp restore them */
|
||||
#ifdef reg_EAX
|
||||
env->regs[R_EAX] = EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
env->regs[R_ECX] = ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
env->regs[R_EDX] = EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
env->regs[R_EBX] = EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
env->regs[R_ESP] = ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
env->regs[R_EBP] = EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
env->regs[R_ESI] = ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
env->regs[R_EDI] = EDI;
|
||||
#endif
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* full interrupt support (only useful for real CPU emulation, not
|
||||
finished) - I won't do it any time soon, finish it if you want ! */
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip)
|
||||
{
|
||||
SegmentDescriptorTable *dt;
|
||||
uint8_t *ptr;
|
||||
int type, dpl, cpl;
|
||||
uint32_t e1, e2;
|
||||
|
||||
dt = &env->idt;
|
||||
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);
|
||||
/* check gate type */
|
||||
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
|
||||
switch(type) {
|
||||
case 5: /* task gate */
|
||||
case 6: /* 286 interrupt gate */
|
||||
case 7: /* 286 trap gate */
|
||||
case 14: /* 386 interrupt gate */
|
||||
case 15: /* 386 trap gate */
|
||||
break;
|
||||
default:
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
break;
|
||||
}
|
||||
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||
cpl = env->segs[R_CS] & 3;
|
||||
/* check privledge if software int */
|
||||
if (is_int && dpl < cpl)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
/* check valid bit */
|
||||
if (!(e2 & DESC_P_MASK))
|
||||
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* is_int is TRUE if coming from the int instruction. next_eip is the
|
||||
* EIP value AFTER the interrupt instruction. It is only relevant if
|
||||
* is_int is TRUE.
|
||||
*/
|
||||
void raise_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip)
|
||||
{
|
||||
SegmentDescriptorTable *dt;
|
||||
uint8_t *ptr;
|
||||
int dpl, cpl;
|
||||
uint32_t e2;
|
||||
|
||||
dt = &env->idt;
|
||||
ptr = dt->base + (intno * 8);
|
||||
e2 = ldl(ptr + 4);
|
||||
|
||||
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
|
||||
cpl = 3;
|
||||
/* check privledge if software int */
|
||||
if (is_int && dpl < cpl)
|
||||
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
|
||||
|
||||
/* Since we emulate only user space, we cannot do more than
|
||||
exiting the emulation with the suitable exception and error
|
||||
code */
|
||||
if (is_int)
|
||||
EIP = next_eip;
|
||||
env->exception_index = intno;
|
||||
env->error_code = error_code;
|
||||
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* shortcuts to generate exceptions */
|
||||
void raise_exception_err(int exception_index, int error_code)
|
||||
{
|
||||
raise_interrupt(exception_index, 0, error_code, 0);
|
||||
}
|
||||
|
||||
void raise_exception(int exception_index)
|
||||
{
|
||||
raise_interrupt(exception_index, 0, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
|
||||
call it from another function */
|
||||
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
|
||||
{
|
||||
*q_ptr = num / den;
|
||||
return num % den;
|
||||
}
|
||||
|
||||
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
|
||||
{
|
||||
*q_ptr = num / den;
|
||||
return num % den;
|
||||
}
|
||||
#endif
|
||||
|
||||
void helper_divl_EAX_T0(uint32_t eip)
|
||||
{
|
||||
unsigned int den, q, r;
|
||||
uint64_t num;
|
||||
|
||||
num = EAX | ((uint64_t)EDX << 32);
|
||||
den = T0;
|
||||
if (den == 0) {
|
||||
EIP = eip;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
r = div64(&q, num, den);
|
||||
#else
|
||||
q = (num / den);
|
||||
r = (num % den);
|
||||
#endif
|
||||
EAX = q;
|
||||
EDX = r;
|
||||
}
|
||||
|
||||
void helper_idivl_EAX_T0(uint32_t eip)
|
||||
{
|
||||
int den, q, r;
|
||||
int64_t num;
|
||||
|
||||
num = EAX | ((uint64_t)EDX << 32);
|
||||
den = T0;
|
||||
if (den == 0) {
|
||||
EIP = eip;
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
r = idiv64(&q, num, den);
|
||||
#else
|
||||
q = (num / den);
|
||||
r = (num % den);
|
||||
#endif
|
||||
EAX = q;
|
||||
EDX = r;
|
||||
}
|
||||
|
||||
void helper_cmpxchg8b(void)
|
||||
{
|
||||
uint64_t d;
|
||||
int eflags;
|
||||
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
d = ldq((uint8_t *)A0);
|
||||
if (d == (((uint64_t)EDX << 32) | EAX)) {
|
||||
stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
|
||||
eflags |= CC_Z;
|
||||
} else {
|
||||
EDX = d >> 32;
|
||||
EAX = d;
|
||||
eflags &= ~CC_Z;
|
||||
}
|
||||
CC_SRC = eflags;
|
||||
}
|
||||
|
||||
/* We simulate a pre-MMX pentium as in valgrind */
|
||||
#define CPUID_FP87 (1 << 0)
|
||||
#define CPUID_VME (1 << 1)
|
||||
#define CPUID_DE (1 << 2)
|
||||
#define CPUID_PSE (1 << 3)
|
||||
#define CPUID_TSC (1 << 4)
|
||||
#define CPUID_MSR (1 << 5)
|
||||
#define CPUID_PAE (1 << 6)
|
||||
#define CPUID_MCE (1 << 7)
|
||||
#define CPUID_CX8 (1 << 8)
|
||||
#define CPUID_APIC (1 << 9)
|
||||
#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
|
||||
#define CPUID_MTRR (1 << 12)
|
||||
#define CPUID_PGE (1 << 13)
|
||||
#define CPUID_MCA (1 << 14)
|
||||
#define CPUID_CMOV (1 << 15)
|
||||
/* ... */
|
||||
#define CPUID_MMX (1 << 23)
|
||||
#define CPUID_FXSR (1 << 24)
|
||||
#define CPUID_SSE (1 << 25)
|
||||
#define CPUID_SSE2 (1 << 26)
|
||||
|
||||
void helper_cpuid(void)
|
||||
{
|
||||
if (EAX == 0) {
|
||||
EAX = 1; /* max EAX index supported */
|
||||
EBX = 0x756e6547;
|
||||
ECX = 0x6c65746e;
|
||||
EDX = 0x49656e69;
|
||||
} else if (EAX == 1) {
|
||||
/* EAX = 1 info */
|
||||
EAX = 0x52b;
|
||||
EBX = 0;
|
||||
ECX = 0;
|
||||
EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
|
||||
CPUID_TSC | CPUID_MSR | CPUID_MCE |
|
||||
CPUID_CX8;
|
||||
}
|
||||
}
|
||||
|
||||
/* only works if protected mode and not VM86 */
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip)
|
||||
{
|
||||
SegmentCache *sc;
|
||||
SegmentDescriptorTable *dt;
|
||||
int index;
|
||||
uint32_t e1, e2;
|
||||
uint8_t *ptr;
|
||||
|
||||
sc = &env->seg_cache[seg_reg];
|
||||
if ((selector & 0xfffc) == 0) {
|
||||
/* null selector case */
|
||||
if (seg_reg == R_SS) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
} else {
|
||||
/* XXX: each access should trigger an exception */
|
||||
sc->base = NULL;
|
||||
sc->limit = 0;
|
||||
sc->seg_32bit = 1;
|
||||
}
|
||||
} else {
|
||||
if (selector & 0x4)
|
||||
dt = &env->ldt;
|
||||
else
|
||||
dt = &env->gdt;
|
||||
index = selector & ~7;
|
||||
if ((index + 7) > dt->limit) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
ptr = dt->base + index;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
if (!(e2 & DESC_S_MASK) ||
|
||||
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
|
||||
if (seg_reg == R_SS) {
|
||||
if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
} else {
|
||||
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
|
||||
EIP = cur_eip;
|
||||
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(e2 & DESC_P_MASK)) {
|
||||
EIP = cur_eip;
|
||||
if (seg_reg == R_SS)
|
||||
raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
|
||||
else
|
||||
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
|
||||
}
|
||||
|
||||
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
|
||||
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
|
||||
if (e2 & (1 << 23))
|
||||
sc->limit = (sc->limit << 12) | 0xfff;
|
||||
sc->seg_32bit = (e2 >> 22) & 1;
|
||||
#if 0
|
||||
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n",
|
||||
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
|
||||
#endif
|
||||
}
|
||||
env->segs[seg_reg] = selector;
|
||||
}
|
||||
|
||||
/* rdtsc */
|
||||
#ifndef __i386__
|
||||
uint64_t emu_time;
|
||||
#endif
|
||||
|
||||
void helper_rdtsc(void)
|
||||
{
|
||||
uint64_t val;
|
||||
#ifdef __i386__
|
||||
asm("rdtsc" : "=A" (val));
|
||||
#else
|
||||
/* better than nothing: the time increases */
|
||||
val = emu_time++;
|
||||
#endif
|
||||
EAX = val;
|
||||
EDX = val >> 32;
|
||||
}
|
||||
|
||||
void helper_lsl(void)
|
||||
{
|
||||
unsigned int selector, limit;
|
||||
SegmentDescriptorTable *dt;
|
||||
int index;
|
||||
uint32_t e1, e2;
|
||||
uint8_t *ptr;
|
||||
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||
selector = T0 & 0xffff;
|
||||
if (selector & 0x4)
|
||||
dt = &env->ldt;
|
||||
else
|
||||
dt = &env->gdt;
|
||||
index = selector & ~7;
|
||||
if ((index + 7) > dt->limit)
|
||||
return;
|
||||
ptr = dt->base + index;
|
||||
e1 = ldl(ptr);
|
||||
e2 = ldl(ptr + 4);
|
||||
limit = (e1 & 0xffff) | (e2 & 0x000f0000);
|
||||
if (e2 & (1 << 23))
|
||||
limit = (limit << 12) | 0xfff;
|
||||
T1 = limit;
|
||||
CC_SRC |= CC_Z;
|
||||
}
|
||||
|
||||
void helper_lar(void)
|
||||
{
|
||||
unsigned int selector;
|
||||
SegmentDescriptorTable *dt;
|
||||
int index;
|
||||
uint32_t e2;
|
||||
uint8_t *ptr;
|
||||
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
|
||||
selector = T0 & 0xffff;
|
||||
if (selector & 0x4)
|
||||
dt = &env->ldt;
|
||||
else
|
||||
dt = &env->gdt;
|
||||
index = selector & ~7;
|
||||
if ((index + 7) > dt->limit)
|
||||
return;
|
||||
ptr = dt->base + index;
|
||||
e2 = ldl(ptr + 4);
|
||||
T1 = e2 & 0x00f0ff00;
|
||||
CC_SRC |= CC_Z;
|
||||
}
|
||||
|
||||
/* FPU helpers */
|
||||
|
||||
#ifndef USE_X86LDOUBLE
|
||||
void helper_fldt_ST0_A0(void)
|
||||
{
|
||||
ST0 = helper_fldt((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void helper_fstt_ST0_A0(void)
|
||||
{
|
||||
helper_fstt(ST0, (uint8_t *)A0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* BCD ops */
|
||||
|
||||
#define MUL10(iv) ( iv + iv + (iv << 3) )
|
||||
|
||||
void helper_fbld_ST0_A0(void)
|
||||
{
|
||||
uint8_t *seg;
|
||||
CPU86_LDouble fpsrcop;
|
||||
int m32i;
|
||||
unsigned int v;
|
||||
|
||||
/* in this code, seg/m32i will be used as temporary ptr/int */
|
||||
seg = (uint8_t *)A0 + 8;
|
||||
v = ldub(seg--);
|
||||
/* XXX: raise exception */
|
||||
if (v != 0)
|
||||
return;
|
||||
v = ldub(seg--);
|
||||
/* XXX: raise exception */
|
||||
if ((v & 0xf0) != 0)
|
||||
return;
|
||||
m32i = v; /* <-- d14 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */
|
||||
fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0;
|
||||
|
||||
v = ldub(seg--);
|
||||
m32i = (v >> 4); /* <-- d7 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */
|
||||
v = ldub(seg);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */
|
||||
fpsrcop += ((CPU86_LDouble)m32i);
|
||||
if ( ldub(seg+9) & 0x80 )
|
||||
fpsrcop = -fpsrcop;
|
||||
ST0 = fpsrcop;
|
||||
}
|
||||
|
||||
void helper_fbst_ST0_A0(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
CPU86_LDouble fpsrcop;
|
||||
int v;
|
||||
uint8_t *mem_ref, *mem_end;
|
||||
|
||||
fpsrcop = rint(ST0);
|
||||
mem_ref = (uint8_t *)A0;
|
||||
mem_end = mem_ref + 8;
|
||||
if ( fpsrcop < 0.0 ) {
|
||||
stw(mem_end, 0x8000);
|
||||
fpsrcop = -fpsrcop;
|
||||
} else {
|
||||
stw(mem_end, 0x0000);
|
||||
}
|
||||
while (mem_ref < mem_end) {
|
||||
if (fpsrcop == 0.0)
|
||||
break;
|
||||
fptemp = floor(fpsrcop/10.0);
|
||||
v = ((int)(fpsrcop - fptemp*10.0));
|
||||
if (fptemp == 0.0) {
|
||||
stb(mem_ref++, v);
|
||||
break;
|
||||
}
|
||||
fpsrcop = fptemp;
|
||||
fptemp = floor(fpsrcop/10.0);
|
||||
v |= (((int)(fpsrcop - fptemp*10.0)) << 4);
|
||||
stb(mem_ref++, v);
|
||||
fpsrcop = fptemp;
|
||||
}
|
||||
while (mem_ref < mem_end) {
|
||||
stb(mem_ref++, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_f2xm1(void)
|
||||
{
|
||||
ST0 = pow(2.0,ST0) - 1.0;
|
||||
}
|
||||
|
||||
void helper_fyl2x(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if (fptemp>0.0){
|
||||
fptemp = log(fptemp)/log(2.0); /* log2(ST) */
|
||||
ST1 *= fptemp;
|
||||
fpop();
|
||||
} else {
|
||||
env->fpus &= (~0x4700);
|
||||
env->fpus |= 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fptan(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
||||
env->fpus |= 0x400;
|
||||
} else {
|
||||
ST0 = tan(fptemp);
|
||||
fpush();
|
||||
ST0 = 1.0;
|
||||
env->fpus &= (~0x400); /* C2 <-- 0 */
|
||||
/* the above code is for |arg| < 2**52 only */
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fpatan(void)
|
||||
{
|
||||
CPU86_LDouble fptemp, fpsrcop;
|
||||
|
||||
fpsrcop = ST1;
|
||||
fptemp = ST0;
|
||||
ST1 = atan2(fpsrcop,fptemp);
|
||||
fpop();
|
||||
}
|
||||
|
||||
void helper_fxtract(void)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
unsigned int expdif;
|
||||
|
||||
temp.d = ST0;
|
||||
expdif = EXPD(temp) - EXPBIAS;
|
||||
/*DP exponent bias*/
|
||||
ST0 = expdif;
|
||||
fpush();
|
||||
BIASEXPONENT(temp);
|
||||
ST0 = temp.d;
|
||||
}
|
||||
|
||||
void helper_fprem1(void)
|
||||
{
|
||||
CPU86_LDouble dblq, fpsrcop, fptemp;
|
||||
CPU86_LDoubleU fpsrcop1, fptemp1;
|
||||
int expdif;
|
||||
int q;
|
||||
|
||||
fpsrcop = ST0;
|
||||
fptemp = ST1;
|
||||
fpsrcop1.d = fpsrcop;
|
||||
fptemp1.d = fptemp;
|
||||
expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
|
||||
if (expdif < 53) {
|
||||
dblq = fpsrcop / fptemp;
|
||||
dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
|
||||
ST0 = fpsrcop - fptemp*dblq;
|
||||
q = (int)dblq; /* cutting off top bits is assumed here */
|
||||
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
||||
/* (C0,C1,C3) <-- (q2,q1,q0) */
|
||||
env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
|
||||
env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
|
||||
env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
|
||||
} else {
|
||||
env->fpus |= 0x400; /* C2 <-- 1 */
|
||||
fptemp = pow(2.0, expdif-50);
|
||||
fpsrcop = (ST0 / ST1) / fptemp;
|
||||
/* fpsrcop = integer obtained by rounding to the nearest */
|
||||
fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
|
||||
floor(fpsrcop): ceil(fpsrcop);
|
||||
ST0 -= (ST1 * fpsrcop * fptemp);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fprem(void)
|
||||
{
|
||||
CPU86_LDouble dblq, fpsrcop, fptemp;
|
||||
CPU86_LDoubleU fpsrcop1, fptemp1;
|
||||
int expdif;
|
||||
int q;
|
||||
|
||||
fpsrcop = ST0;
|
||||
fptemp = ST1;
|
||||
fpsrcop1.d = fpsrcop;
|
||||
fptemp1.d = fptemp;
|
||||
expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
|
||||
if ( expdif < 53 ) {
|
||||
dblq = fpsrcop / fptemp;
|
||||
dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
|
||||
ST0 = fpsrcop - fptemp*dblq;
|
||||
q = (int)dblq; /* cutting off top bits is assumed here */
|
||||
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
||||
/* (C0,C1,C3) <-- (q2,q1,q0) */
|
||||
env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
|
||||
env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
|
||||
env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
|
||||
} else {
|
||||
env->fpus |= 0x400; /* C2 <-- 1 */
|
||||
fptemp = pow(2.0, expdif-50);
|
||||
fpsrcop = (ST0 / ST1) / fptemp;
|
||||
/* fpsrcop = integer obtained by chopping */
|
||||
fpsrcop = (fpsrcop < 0.0)?
|
||||
-(floor(fabs(fpsrcop))): floor(fpsrcop);
|
||||
ST0 -= (ST1 * fpsrcop * fptemp);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fyl2xp1(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if ((fptemp+1.0)>0.0) {
|
||||
fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
|
||||
ST1 *= fptemp;
|
||||
fpop();
|
||||
} else {
|
||||
env->fpus &= (~0x4700);
|
||||
env->fpus |= 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fsqrt(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if (fptemp<0.0) {
|
||||
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
||||
env->fpus |= 0x400;
|
||||
}
|
||||
ST0 = sqrt(fptemp);
|
||||
}
|
||||
|
||||
void helper_fsincos(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
||||
env->fpus |= 0x400;
|
||||
} else {
|
||||
ST0 = sin(fptemp);
|
||||
fpush();
|
||||
ST0 = cos(fptemp);
|
||||
env->fpus &= (~0x400); /* C2 <-- 0 */
|
||||
/* the above code is for |arg| < 2**63 only */
|
||||
}
|
||||
}
|
||||
|
||||
void helper_frndint(void)
|
||||
{
|
||||
CPU86_LDouble a;
|
||||
|
||||
a = ST0;
|
||||
#ifdef __arm__
|
||||
switch(env->fpuc & RC_MASK) {
|
||||
default:
|
||||
case RC_NEAR:
|
||||
asm("rndd %0, %1" : "=f" (a) : "f"(a));
|
||||
break;
|
||||
case RC_DOWN:
|
||||
asm("rnddm %0, %1" : "=f" (a) : "f"(a));
|
||||
break;
|
||||
case RC_UP:
|
||||
asm("rnddp %0, %1" : "=f" (a) : "f"(a));
|
||||
break;
|
||||
case RC_CHOP:
|
||||
asm("rnddz %0, %1" : "=f" (a) : "f"(a));
|
||||
break;
|
||||
}
|
||||
#else
|
||||
a = rint(a);
|
||||
#endif
|
||||
ST0 = a;
|
||||
}
|
||||
|
||||
void helper_fscale(void)
|
||||
{
|
||||
CPU86_LDouble fpsrcop, fptemp;
|
||||
|
||||
fpsrcop = 2.0;
|
||||
fptemp = pow(fpsrcop,ST1);
|
||||
ST0 *= fptemp;
|
||||
}
|
||||
|
||||
void helper_fsin(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
||||
env->fpus |= 0x400;
|
||||
} else {
|
||||
ST0 = sin(fptemp);
|
||||
env->fpus &= (~0x400); /* C2 <-- 0 */
|
||||
/* the above code is for |arg| < 2**53 only */
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fcos(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
|
||||
fptemp = ST0;
|
||||
if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
||||
env->fpus |= 0x400;
|
||||
} else {
|
||||
ST0 = cos(fptemp);
|
||||
env->fpus &= (~0x400); /* C2 <-- 0 */
|
||||
/* the above code is for |arg5 < 2**63 only */
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fxam_ST0(void)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
int expdif;
|
||||
|
||||
temp.d = ST0;
|
||||
|
||||
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
||||
if (SIGND(temp))
|
||||
env->fpus |= 0x200; /* C1 <-- 1 */
|
||||
|
||||
expdif = EXPD(temp);
|
||||
if (expdif == MAXEXPD) {
|
||||
if (MANTD(temp) == 0)
|
||||
env->fpus |= 0x500 /*Infinity*/;
|
||||
else
|
||||
env->fpus |= 0x100 /*NaN*/;
|
||||
} else if (expdif == 0) {
|
||||
if (MANTD(temp) == 0)
|
||||
env->fpus |= 0x4000 /*Zero*/;
|
||||
else
|
||||
env->fpus |= 0x4400 /*Denormal*/;
|
||||
} else {
|
||||
env->fpus |= 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fstenv(uint8_t *ptr, int data32)
|
||||
{
|
||||
int fpus, fptag, exp, i;
|
||||
uint64_t mant;
|
||||
CPU86_LDoubleU tmp;
|
||||
|
||||
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
|
||||
fptag = 0;
|
||||
for (i=7; i>=0; i--) {
|
||||
fptag <<= 2;
|
||||
if (env->fptags[i]) {
|
||||
fptag |= 3;
|
||||
} else {
|
||||
tmp.d = env->fpregs[i];
|
||||
exp = EXPD(tmp);
|
||||
mant = MANTD(tmp);
|
||||
if (exp == 0 && mant == 0) {
|
||||
/* zero */
|
||||
fptag |= 1;
|
||||
} else if (exp == 0 || exp == MAXEXPD
|
||||
#ifdef USE_X86LDOUBLE
|
||||
|| (mant & (1LL << 63)) == 0
|
||||
#endif
|
||||
) {
|
||||
/* NaNs, infinity, denormal */
|
||||
fptag |= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data32) {
|
||||
/* 32 bit */
|
||||
stl(ptr, env->fpuc);
|
||||
stl(ptr + 4, fpus);
|
||||
stl(ptr + 8, fptag);
|
||||
stl(ptr + 12, 0);
|
||||
stl(ptr + 16, 0);
|
||||
stl(ptr + 20, 0);
|
||||
stl(ptr + 24, 0);
|
||||
} else {
|
||||
/* 16 bit */
|
||||
stw(ptr, env->fpuc);
|
||||
stw(ptr + 2, fpus);
|
||||
stw(ptr + 4, fptag);
|
||||
stw(ptr + 6, 0);
|
||||
stw(ptr + 8, 0);
|
||||
stw(ptr + 10, 0);
|
||||
stw(ptr + 12, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fldenv(uint8_t *ptr, int data32)
|
||||
{
|
||||
int i, fpus, fptag;
|
||||
|
||||
if (data32) {
|
||||
env->fpuc = lduw(ptr);
|
||||
fpus = lduw(ptr + 4);
|
||||
fptag = lduw(ptr + 8);
|
||||
}
|
||||
else {
|
||||
env->fpuc = lduw(ptr);
|
||||
fpus = lduw(ptr + 2);
|
||||
fptag = lduw(ptr + 4);
|
||||
}
|
||||
env->fpstt = (fpus >> 11) & 7;
|
||||
env->fpus = fpus & ~0x3800;
|
||||
for(i = 0;i < 7; i++) {
|
||||
env->fptags[i] = ((fptag & 3) == 3);
|
||||
fptag >>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_fsave(uint8_t *ptr, int data32)
|
||||
{
|
||||
CPU86_LDouble tmp;
|
||||
int i;
|
||||
|
||||
helper_fstenv(ptr, data32);
|
||||
|
||||
ptr += (14 << data32);
|
||||
for(i = 0;i < 8; i++) {
|
||||
tmp = ST(i);
|
||||
#ifdef USE_X86LDOUBLE
|
||||
*(long double *)ptr = tmp;
|
||||
#else
|
||||
helper_fstt(tmp, ptr);
|
||||
#endif
|
||||
ptr += 10;
|
||||
}
|
||||
|
||||
/* fninit */
|
||||
env->fpus = 0;
|
||||
env->fpstt = 0;
|
||||
env->fpuc = 0x37f;
|
||||
env->fptags[0] = 1;
|
||||
env->fptags[1] = 1;
|
||||
env->fptags[2] = 1;
|
||||
env->fptags[3] = 1;
|
||||
env->fptags[4] = 1;
|
||||
env->fptags[5] = 1;
|
||||
env->fptags[6] = 1;
|
||||
env->fptags[7] = 1;
|
||||
}
|
||||
|
||||
void helper_frstor(uint8_t *ptr, int data32)
|
||||
{
|
||||
CPU86_LDouble tmp;
|
||||
int i;
|
||||
|
||||
helper_fldenv(ptr, data32);
|
||||
ptr += (14 << data32);
|
||||
|
||||
for(i = 0;i < 8; i++) {
|
||||
#ifdef USE_X86LDOUBLE
|
||||
tmp = *(long double *)ptr;
|
||||
#else
|
||||
tmp = helper_fldt(ptr);
|
||||
#endif
|
||||
ST(i) = tmp;
|
||||
ptr += 10;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1164,8 +1164,8 @@ int
|
||||
print_insn_x86 (pc, info, aflag, dflag)
|
||||
bfd_vma pc;
|
||||
disassemble_info *info;
|
||||
int aflag;
|
||||
int dflag;
|
||||
int volatile aflag;
|
||||
int volatile dflag;
|
||||
{
|
||||
struct dis386 *dp;
|
||||
int i;
|
||||
|
||||
+40
-10
@@ -17,13 +17,6 @@
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
typedef uint32_t elf_greg_t;
|
||||
|
||||
#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
typedef struct user_i387_struct elf_fpregset_t;
|
||||
|
||||
/*
|
||||
* This is used to ensure we don't load something for the wrong architecture.
|
||||
*/
|
||||
@@ -45,6 +38,45 @@ typedef struct user_i387_struct elf_fpregset_t;
|
||||
A value of 0 tells we have no such handler. */
|
||||
#define ELF_PLAT_INIT(_r) _r->edx = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->esp = infop->start_stack;
|
||||
regs->eip = infop->entry;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_ARM )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
target_long *stack = (void *)infop->start_stack;
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->ARM_cpsr = 0x10;
|
||||
regs->ARM_pc = infop->entry;
|
||||
regs->ARM_sp = infop->start_stack;
|
||||
regs->ARM_r2 = tswapl(stack[2]); /* envp */
|
||||
regs->ARM_r1 = tswapl(stack[1]); /* argv */
|
||||
regs->ARM_r0 = tswapl(stack[0]); /* argc */
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
@@ -758,7 +790,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
}
|
||||
|
||||
/* Now read in all of the header information */
|
||||
|
||||
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
|
||||
if (elf_phdata == NULL) {
|
||||
return -ENOMEM;
|
||||
@@ -1156,8 +1187,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
}
|
||||
if(retval>=0) {
|
||||
/* success. Initialize important registers */
|
||||
regs->esp = infop->start_stack;
|
||||
regs->eip = infop->entry;
|
||||
init_thread(regs, infop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -150,6 +150,7 @@
|
||||
IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL)
|
||||
IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT)
|
||||
|
||||
#if 0
|
||||
IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
@@ -160,14 +161,15 @@
|
||||
IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT))
|
||||
#endif
|
||||
IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
|
||||
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
|
||||
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
|
||||
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
|
||||
IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
|
||||
@@ -183,6 +185,7 @@
|
||||
IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL)
|
||||
#if 0
|
||||
IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT))
|
||||
@@ -222,6 +225,7 @@
|
||||
IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT))
|
||||
#endif
|
||||
IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT))
|
||||
IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID)
|
||||
IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT))
|
||||
|
||||
+77
-10
@@ -38,6 +38,7 @@ static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||
object ! */
|
||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
|
||||
/* for recent libc, we add these dummies symbol which are not declared
|
||||
when generating a linked object (bug in ld ?) */
|
||||
@@ -48,8 +49,6 @@ long __fini_array_start[0];
|
||||
long __fini_array_end[0];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
@@ -64,6 +63,7 @@ void gemu_log(const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
@@ -239,20 +239,76 @@ void cpu_loop(CPUX86State *env)
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
unsigned int n, insn;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_arm_exec(env);
|
||||
switch(trapnr) {
|
||||
case EXCP_UDEF:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->regs[15];
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
{
|
||||
/* system call */
|
||||
insn = ldl((void *)(env->regs[15] - 4));
|
||||
n = insn & 0xffffff;
|
||||
if (n >= ARM_SYSCALL_BASE) {
|
||||
/* linux syscall */
|
||||
n -= ARM_SYSCALL_BASE;
|
||||
env->regs[0] = do_syscall(env,
|
||||
n,
|
||||
env->regs[0],
|
||||
env->regs[1],
|
||||
env->regs[2],
|
||||
env->regs[3],
|
||||
env->regs[4],
|
||||
0);
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
cpu_arm_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
}
|
||||
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"
|
||||
"Linux x86 emulator\n"
|
||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
"-L path set the x86 elf interpreter prefix (default=%s)\n"
|
||||
"-s size set the x86 stack size in bytes (default=%ld)\n"
|
||||
"-L path set the elf interpreter prefix (default=%s)\n"
|
||||
"-s size set the stack size in bytes (default=%ld)\n"
|
||||
"\n"
|
||||
"debug options:\n"
|
||||
"-d activate log (logfile=%s)\n"
|
||||
"-p pagesize set the host page size to 'pagesize'\n",
|
||||
TARGET_ARCH,
|
||||
interp_prefix,
|
||||
x86_stack_size,
|
||||
DEBUG_LOGFILE);
|
||||
@@ -260,7 +316,7 @@ void usage(void)
|
||||
}
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
CPUX86State *global_env;
|
||||
CPUState *global_env;
|
||||
/* used to free thread contexts */
|
||||
TaskState *first_task_state;
|
||||
|
||||
@@ -270,7 +326,7 @@ int main(int argc, char **argv)
|
||||
struct target_pt_regs regs1, *regs = ®s1;
|
||||
struct image_info info1, *info = &info1;
|
||||
TaskState ts1, *ts = &ts1;
|
||||
CPUX86State *env;
|
||||
CPUState *env;
|
||||
int optind;
|
||||
const char *r;
|
||||
|
||||
@@ -338,7 +394,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* NOTE: we need to init the CPU at this stage to get the
|
||||
host_page_size */
|
||||
env = cpu_x86_init();
|
||||
env = cpu_init();
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
@@ -354,8 +410,7 @@ int main(int argc, char **argv)
|
||||
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
|
||||
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
|
||||
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
|
||||
fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
|
||||
fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
|
||||
fprintf(logfile, "entry 0x%08lx\n" , info->entry);
|
||||
}
|
||||
|
||||
target_set_brk((char *)info->brk);
|
||||
@@ -369,6 +424,7 @@ int main(int argc, char **argv)
|
||||
env->opaque = ts;
|
||||
ts->used = 1;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
/* linux register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
env->regs[R_EBX] = regs->ebx;
|
||||
@@ -420,6 +476,17 @@ int main(int argc, char **argv)
|
||||
cpu_x86_load_seg(env, R_SS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_FS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_GS, __USER_DS);
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 16; i++) {
|
||||
env->regs[i] = regs->uregs[i];
|
||||
}
|
||||
env->cpsr = regs->uregs[16];
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
|
||||
+12
-1
@@ -188,6 +188,11 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
host_start = start & host_page_mask;
|
||||
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
#if defined(__alpha__) || defined(__sparc__)
|
||||
/* tell the kenel to search at the same place as i386 */
|
||||
if (host_start == 0)
|
||||
host_start = 0x40000000;
|
||||
#endif
|
||||
if (host_page_size != real_host_page_size) {
|
||||
/* NOTE: this code is only for debugging with '-p' option */
|
||||
/* reserve a memory area */
|
||||
@@ -277,8 +282,13 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
|
||||
/* map the middle (easier) */
|
||||
if (host_start < host_end) {
|
||||
unsigned long offset1;
|
||||
if (flags & MAP_ANONYMOUS)
|
||||
offset1 = 0;
|
||||
else
|
||||
offset1 = offset + host_start - start;
|
||||
ret = (long)mmap((void *)host_start, host_end - host_start,
|
||||
prot, flags, fd, offset + host_start - start);
|
||||
prot, flags, fd, offset1);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
}
|
||||
@@ -286,6 +296,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||
the_end:
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("ret=0x%lx\n", (long)start);
|
||||
page_dump(stdout);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
+19
-9
@@ -6,10 +6,8 @@
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#endif
|
||||
#include "cpu-" TARGET_ARCH ".h"
|
||||
#include "syscall-" TARGET_ARCH ".h"
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
* Basically, it replicates in user space what would be certain
|
||||
@@ -33,6 +31,7 @@ struct image_info {
|
||||
int personality;
|
||||
};
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* Information about the current linux thread */
|
||||
struct vm86_saved_state {
|
||||
uint32_t eax; /* return code */
|
||||
@@ -47,16 +46,19 @@ struct vm86_saved_state {
|
||||
uint32_t eip;
|
||||
uint16_t cs, ss, ds, es, fs, gs;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* NOTE: we force a big alignment so that the stack stored after is
|
||||
aligned too */
|
||||
typedef struct TaskState {
|
||||
struct TaskState *next;
|
||||
#ifdef TARGET_I386
|
||||
struct target_vm86plus_struct *target_v86;
|
||||
struct vm86_saved_state vm86_saved_regs;
|
||||
struct target_vm86plus_struct vm86plus;
|
||||
uint32_t v86flags;
|
||||
uint32_t v86mask;
|
||||
#endif
|
||||
int used; /* non zero if used */
|
||||
uint8_t stack[0];
|
||||
} __attribute__((aligned(16))) TaskState;
|
||||
@@ -71,23 +73,31 @@ void syscall_init(void);
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6);
|
||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
extern CPUX86State *global_env;
|
||||
void cpu_loop(CPUX86State *env);
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
int queue_signal(int sig, target_siginfo_t *info);
|
||||
extern CPUState *global_env;
|
||||
void cpu_loop(CPUState *env);
|
||||
void init_paths(const char *prefix);
|
||||
const char *path(const char *pathname);
|
||||
|
||||
extern int loglevel;
|
||||
extern FILE *logfile;
|
||||
|
||||
/* signal.c */
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
int queue_signal(int sig, target_siginfo_t *info);
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUState *env);
|
||||
long do_rt_sigreturn(CPUState *env);
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* vm86.c */
|
||||
void save_v86_state(CPUX86State *env);
|
||||
void handle_vm86_trap(CPUX86State *env, int trapno);
|
||||
void handle_vm86_fault(CPUX86State *env);
|
||||
int do_vm86(CPUX86State *env, long subfunction,
|
||||
struct target_vm86plus_struct * target_v86);
|
||||
#endif
|
||||
|
||||
/* mmap.c */
|
||||
int target_mprotect(unsigned long start, unsigned long len, int prot);
|
||||
|
||||
+40
-34
@@ -318,7 +318,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we we forward to it some signals */
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
|
||||
if (cpu_x86_signal_handler(host_signum, info, puc))
|
||||
if (cpu_signal_handler(host_signum, info, puc))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
cpu_x86_interrupt(global_env);
|
||||
cpu_interrupt(global_env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,15 +536,12 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
err |= __put_user(env->eflags, &sc->eflags);
|
||||
err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
|
||||
err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss);
|
||||
#if 0
|
||||
tmp = save_i387(fpstate);
|
||||
if (tmp < 0)
|
||||
err = 1;
|
||||
else
|
||||
err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
|
||||
#else
|
||||
err |= __put_user(0, &sc->fpstate);
|
||||
#endif
|
||||
|
||||
cpu_x86_fsave(env, (void *)fpstate, 1);
|
||||
fpstate->status = fpstate->sw;
|
||||
err |= __put_user(0xffff, &fpstate->magic);
|
||||
err |= __put_user(fpstate, &sc->fpstate);
|
||||
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __put_user(env->cr2, &sc->cr2);
|
||||
@@ -721,25 +718,6 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
{
|
||||
unsigned int err = 0;
|
||||
|
||||
|
||||
|
||||
#define COPY(x) err |= __get_user(regs->x, &sc->x)
|
||||
|
||||
#define COPY_SEG(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
regs->x##seg = tmp; }
|
||||
|
||||
#define COPY_SEG_STRICT(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
regs->x##seg = tmp|3; }
|
||||
|
||||
#define GET_SEG(seg) \
|
||||
{ unsigned short tmp; \
|
||||
err |= __get_user(tmp, &sc->seg); \
|
||||
loadsegment(seg,tmp); }
|
||||
|
||||
cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
|
||||
cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
|
||||
cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
|
||||
@@ -764,17 +742,18 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
// regs->orig_eax = -1; /* disable syscall checks */
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
struct _fpstate * buf;
|
||||
err |= __get_user(buf, &sc->fpstate);
|
||||
buf = (void *)ldl(&sc->fpstate);
|
||||
if (buf) {
|
||||
#if 0
|
||||
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
|
||||
goto badframe;
|
||||
err |= restore_i387(buf);
|
||||
#endif
|
||||
cpu_x86_frstor(env, (void *)buf, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*peax = ldl(&sc->eax);
|
||||
return err;
|
||||
#if 0
|
||||
@@ -845,6 +824,33 @@ badframe:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "setup_frame: not implemented\n");
|
||||
}
|
||||
|
||||
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "setup_rt_frame: not implemented\n");
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "do_sigreturn: not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "do_rt_sigreturn: not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void process_pending_signals(void *cpu_env)
|
||||
|
||||
+114
-21
@@ -68,11 +68,6 @@
|
||||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
|
||||
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
|
||||
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUX86State *env);
|
||||
long do_rt_sigreturn(CPUX86State *env);
|
||||
|
||||
#define __NR_sys_uname __NR_uname
|
||||
#define __NR_sys_getcwd1 __NR_getcwd
|
||||
#define __NR_sys_statfs __NR_statfs
|
||||
@@ -702,8 +697,8 @@ enum {
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
typedef struct IOCTLEntry {
|
||||
int target_cmd;
|
||||
int host_cmd;
|
||||
unsigned int target_cmd;
|
||||
unsigned int host_cmd;
|
||||
const char *name;
|
||||
int access;
|
||||
const argtype arg_type[5];
|
||||
@@ -715,7 +710,7 @@ typedef struct IOCTLEntry {
|
||||
|
||||
#define MAX_STRUCT_SIZE 4096
|
||||
|
||||
const IOCTLEntry ioctl_entries[] = {
|
||||
IOCTLEntry ioctl_entries[] = {
|
||||
#define IOCTL(cmd, access, types...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, { types } },
|
||||
#include "ioctls.h"
|
||||
@@ -958,7 +953,19 @@ StructEntry struct_termios_def = {
|
||||
.align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
|
||||
};
|
||||
|
||||
#ifdef TARGET_I386
|
||||
static bitmask_transtbl mmap_flags_tbl[] = {
|
||||
{ TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
|
||||
{ TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
|
||||
{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
|
||||
{ TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
|
||||
{ TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
|
||||
{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
|
||||
{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
|
||||
{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
/* NOTE: there is really one LDT for all the threads */
|
||||
uint8_t *ldt_table;
|
||||
@@ -1075,28 +1082,28 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* defined(TARGET_I386) */
|
||||
|
||||
/* this stack is the equivalent of the kernel stack associated with a
|
||||
thread/process */
|
||||
#define NEW_STACK_SIZE 8192
|
||||
|
||||
static int clone_func(void *arg)
|
||||
{
|
||||
CPUX86State *env = arg;
|
||||
CPUState *env = arg;
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
|
||||
{
|
||||
int ret;
|
||||
TaskState *ts;
|
||||
uint8_t *new_stack;
|
||||
CPUX86State *new_env;
|
||||
CPUState *new_env;
|
||||
|
||||
if (flags & CLONE_VM) {
|
||||
if (!newsp)
|
||||
newsp = env->regs[R_ESP];
|
||||
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
new_stack = ts->stack;
|
||||
@@ -1105,10 +1112,21 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
ts->next = first_task_state;
|
||||
first_task_state = ts;
|
||||
/* we create a new CPU instance. */
|
||||
new_env = cpu_x86_init();
|
||||
memcpy(new_env, env, sizeof(CPUX86State));
|
||||
new_env = cpu_init();
|
||||
memcpy(new_env, env, sizeof(CPUState));
|
||||
#if defined(TARGET_I386)
|
||||
if (!newsp)
|
||||
newsp = env->regs[R_ESP];
|
||||
new_env->regs[R_ESP] = newsp;
|
||||
new_env->regs[R_EAX] = 0;
|
||||
#elif defined(TARGET_ARM)
|
||||
if (!newsp)
|
||||
newsp = env->regs[13];
|
||||
new_env->regs[13] = newsp;
|
||||
new_env->regs[0] = 0;
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
new_env->opaque = ts;
|
||||
#ifdef __ia64__
|
||||
ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
|
||||
@@ -1124,8 +1142,6 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static long do_fcntl(int fd, int cmd, unsigned long arg)
|
||||
{
|
||||
struct flock fl;
|
||||
@@ -1176,11 +1192,43 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
|
||||
|
||||
void syscall_init(void)
|
||||
{
|
||||
IOCTLEntry *ie;
|
||||
const argtype *arg_type;
|
||||
int size;
|
||||
|
||||
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
|
||||
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
|
||||
#include "syscall_types.h"
|
||||
#undef STRUCT
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
/* we patch the ioctl size if necessary. We rely on the fact that
|
||||
no ioctl has all the bits at '1' in the size field */
|
||||
ie = ioctl_entries;
|
||||
while (ie->target_cmd != 0) {
|
||||
if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
|
||||
TARGET_IOC_SIZEMASK) {
|
||||
arg_type = ie->arg_type;
|
||||
if (arg_type[0] != TYPE_PTR) {
|
||||
fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
|
||||
ie->target_cmd);
|
||||
exit(1);
|
||||
}
|
||||
arg_type++;
|
||||
size = thunk_type_size(arg_type, 0);
|
||||
ie->target_cmd = (ie->target_cmd &
|
||||
~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
|
||||
(size << TARGET_IOC_SIZESHIFT);
|
||||
}
|
||||
/* automatic consistency check if same arch */
|
||||
#if defined(__i386__) && defined(TARGET_I386)
|
||||
if (ie->target_cmd != ie->host_cmd) {
|
||||
fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
|
||||
ie->target_cmd, ie->host_cmd);
|
||||
}
|
||||
#endif
|
||||
ie++;
|
||||
}
|
||||
}
|
||||
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
@@ -1744,7 +1792,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
v4 = tswap32(vptr[3]);
|
||||
v5 = tswap32(vptr[4]);
|
||||
v6 = tswap32(vptr[5]);
|
||||
ret = get_errno(target_mmap(v1, v2, v3, v4, v5, v6));
|
||||
ret = get_errno(target_mmap(v1, v2, v3,
|
||||
target_to_host_bitmask(v4, mmap_flags_tbl),
|
||||
v5, v6));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -1753,7 +1803,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
#else
|
||||
case TARGET_NR_mmap:
|
||||
#endif
|
||||
ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5,
|
||||
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
||||
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
||||
arg5,
|
||||
arg6 << TARGET_PAGE_BITS));
|
||||
break;
|
||||
case TARGET_NR_munmap:
|
||||
@@ -1999,7 +2051,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_getdents:
|
||||
#if TARGET_LONG_SIZE != 4
|
||||
#error not supported
|
||||
#endif
|
||||
#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8
|
||||
{
|
||||
struct target_dirent *target_dirp = (void *)arg2;
|
||||
struct dirent *dirp;
|
||||
long count = arg3;
|
||||
|
||||
dirp = malloc(count);
|
||||
if (!dirp)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = get_errno(sys_getdents(arg1, dirp, count));
|
||||
if (!is_error(ret)) {
|
||||
struct dirent *de;
|
||||
struct target_dirent *tde;
|
||||
int len = ret;
|
||||
int reclen, treclen;
|
||||
int count1, tnamelen;
|
||||
|
||||
count1 = 0;
|
||||
de = dirp;
|
||||
tde = target_dirp;
|
||||
while (len > 0) {
|
||||
reclen = de->d_reclen;
|
||||
treclen = reclen - (2 * (sizeof(long) - sizeof(target_long)));
|
||||
tde->d_reclen = tswap16(treclen);
|
||||
tde->d_ino = tswapl(de->d_ino);
|
||||
tde->d_off = tswapl(de->d_off);
|
||||
tnamelen = treclen - (2 * sizeof(target_long) + 2);
|
||||
if (tnamelen > 256)
|
||||
tnamelen = 256;
|
||||
strncpy(tde->d_name, de->d_name, tnamelen);
|
||||
de = (struct dirent *)((char *)de + reclen);
|
||||
len -= reclen;
|
||||
tde = (struct dirent *)((char *)tde + treclen);
|
||||
count1 += treclen;
|
||||
}
|
||||
ret = count1;
|
||||
}
|
||||
free(dirp);
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct dirent *dirp = (void *)arg2;
|
||||
long count = arg3;
|
||||
@@ -2022,6 +2114,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case TARGET_NR_getdents64:
|
||||
{
|
||||
|
||||
+985
-2
File diff suppressed because it is too large.
Load diff
@@ -67,3 +67,12 @@ STRUCT(dirent,
|
||||
|
||||
STRUCT(kbentry,
|
||||
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
|
||||
|
||||
STRUCT(audio_buf_info,
|
||||
TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT)
|
||||
|
||||
STRUCT(count_info,
|
||||
TYPE_INT, TYPE_INT, TYPE_INT)
|
||||
|
||||
STRUCT(mixer_info,
|
||||
MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))
|
||||
+4
-4
@@ -41,22 +41,22 @@ static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
|
||||
|
||||
static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val)
|
||||
{
|
||||
*(uint16_t *)(segptr + (reg16 & 0xffff)) = tswap16(val);
|
||||
stw(segptr + (reg16 & 0xffff), val);
|
||||
}
|
||||
|
||||
static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
|
||||
{
|
||||
*(uint32_t *)(segptr + (reg16 & 0xffff)) = tswap32(val);
|
||||
stl(segptr + (reg16 & 0xffff), val);
|
||||
}
|
||||
|
||||
static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
|
||||
{
|
||||
return tswap16(*(uint16_t *)(segptr + (reg16 & 0xffff)));
|
||||
return lduw(segptr + (reg16 & 0xffff));
|
||||
}
|
||||
|
||||
static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
|
||||
{
|
||||
return tswap32(*(uint32_t *)(segptr + (reg16 & 0xffff)));
|
||||
return ldl(segptr + (reg16 & 0xffff));
|
||||
}
|
||||
|
||||
void save_v86_state(CPUX86State *env)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* ARM 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
|
||||
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
* ARM micro 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
|
||||
*/
|
||||
#include "exec-arm.h"
|
||||
|
||||
#define REGNAME r0
|
||||
#define REG (env->regs[0])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r1
|
||||
#define REG (env->regs[1])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r2
|
||||
#define REG (env->regs[2])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r3
|
||||
#define REG (env->regs[3])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r4
|
||||
#define REG (env->regs[4])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r5
|
||||
#define REG (env->regs[5])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r6
|
||||
#define REG (env->regs[6])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r7
|
||||
#define REG (env->regs[7])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r8
|
||||
#define REG (env->regs[8])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r9
|
||||
#define REG (env->regs[9])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r10
|
||||
#define REG (env->regs[10])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r11
|
||||
#define REG (env->regs[11])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r12
|
||||
#define REG (env->regs[12])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r13
|
||||
#define REG (env->regs[13])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r14
|
||||
#define REG (env->regs[14])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
#define REGNAME r15
|
||||
#define REG (env->regs[15])
|
||||
#include "op-arm-template.h"
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
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_addl_T0_T1(void)
|
||||
{
|
||||
T0 += T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T0_T1_cc(void)
|
||||
{
|
||||
unsigned int src1;
|
||||
src1 = T0;
|
||||
T0 += T1;
|
||||
env->NZF = T0;
|
||||
env->CF = T0 < src1;
|
||||
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_adcl_T0_T1(void)
|
||||
{
|
||||
T0 += T1 + env->CF;
|
||||
}
|
||||
|
||||
void OPPROTO op_adcl_T0_T1_cc(void)
|
||||
{
|
||||
unsigned int src1;
|
||||
src1 = T0;
|
||||
if (!env->CF) {
|
||||
T0 += T1;
|
||||
env->CF = T0 < src1;
|
||||
} else {
|
||||
T0 += T1 + 1;
|
||||
env->CF = T0 <= src1;
|
||||
}
|
||||
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
|
||||
env->NZF = T0;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#define OPSUB(sub, sbc, T0, T1) \
|
||||
\
|
||||
void OPPROTO op_ ## sub ## l_T0_T1(void) \
|
||||
{ \
|
||||
T0 -= T1; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
|
||||
{ \
|
||||
unsigned int src1; \
|
||||
src1 = T0; \
|
||||
T0 -= T1; \
|
||||
env->NZF = T0; \
|
||||
env->CF = src1 < T1; \
|
||||
env->VF = (src1 ^ T1) & (src1 ^ T0); \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
|
||||
{ \
|
||||
T0 = T0 - T1 + env->CF - 1; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
|
||||
{ \
|
||||
unsigned int src1; \
|
||||
src1 = T0; \
|
||||
if (!env->CF) { \
|
||||
T0 = T0 - T1 - 1; \
|
||||
T0 += T1; \
|
||||
env->CF = src1 < T1; \
|
||||
} else { \
|
||||
T0 = T0 - T1; \
|
||||
env->CF = src1 <= T1; \
|
||||
} \
|
||||
env->VF = (src1 ^ T1) & (src1 ^ T0); \
|
||||
env->NZF = T0; \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
OPSUB(sub, sbc, T0, T1)
|
||||
|
||||
OPSUB(rsb, rsc, T1, T0)
|
||||
|
||||
void OPPROTO op_andl_T0_T1(void)
|
||||
{
|
||||
T0 &= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xorl_T0_T1(void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_orl_T0_T1(void)
|
||||
{
|
||||
T0 |= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_bicl_T0_T1(void)
|
||||
{
|
||||
T0 &= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_notl_T1(void)
|
||||
{
|
||||
T1 = ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_logic_cc(void)
|
||||
{
|
||||
env->NZF = T0;
|
||||
}
|
||||
|
||||
#define EIP (env->regs[15])
|
||||
|
||||
void OPPROTO op_test_eq(void)
|
||||
{
|
||||
if (env->NZF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ne(void)
|
||||
{
|
||||
if (env->NZF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_cs(void)
|
||||
{
|
||||
if (env->CF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_cc(void)
|
||||
{
|
||||
if (env->CF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_mi(void)
|
||||
{
|
||||
if ((env->NZF & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_pl(void)
|
||||
{
|
||||
if ((env->NZF & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_vs(void)
|
||||
{
|
||||
if ((env->VF & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_vc(void)
|
||||
{
|
||||
if ((env->VF & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_hi(void)
|
||||
{
|
||||
if (env->CF != 0 && env->NZF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ls(void)
|
||||
{
|
||||
if (env->CF == 0 || env->NZF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ge(void)
|
||||
{
|
||||
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_lt(void)
|
||||
{
|
||||
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_gt(void)
|
||||
{
|
||||
if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_le(void)
|
||||
{
|
||||
if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp(void)
|
||||
{
|
||||
JUMP_TB(PARAM1, 1, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_psr(void)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
|
||||
}
|
||||
|
||||
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
|
||||
void OPPROTO op_movl_psr_T0(void)
|
||||
{
|
||||
unsigned int psr;
|
||||
psr = T0;
|
||||
env->CF = (psr >> 29) & 1;
|
||||
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
/* for user mode we do not update other state info */
|
||||
}
|
||||
|
||||
void OPPROTO op_mul_T0_T1(void)
|
||||
{
|
||||
T0 = T0 * T1;
|
||||
}
|
||||
|
||||
/* 64 bit unsigned mul */
|
||||
void OPPROTO op_mull_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = T0 * T1;
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
|
||||
/* 64 bit signed mul */
|
||||
void OPPROTO op_imull_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = (int32_t)T0 * (int32_t)T1;
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
|
||||
void OPPROTO op_addq_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = ((uint64_t)T1 << 32) | T0;
|
||||
res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
|
||||
void OPPROTO op_logicq_cc(void)
|
||||
{
|
||||
env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
|
||||
}
|
||||
|
||||
/* memory access */
|
||||
|
||||
void OPPROTO op_ldub_T0_T1(void)
|
||||
{
|
||||
T0 = ldub((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsb_T0_T1(void)
|
||||
{
|
||||
T0 = ldsb((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_lduw_T0_T1(void)
|
||||
{
|
||||
T0 = lduw((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsw_T0_T1(void)
|
||||
{
|
||||
T0 = ldsw((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldl_T0_T1(void)
|
||||
{
|
||||
T0 = ldl((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_stb_T0_T1(void)
|
||||
{
|
||||
stb((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stw_T0_T1(void)
|
||||
{
|
||||
stw((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stl_T0_T1(void)
|
||||
{
|
||||
stl((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_swpb_T0_T1(void)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
cpu_lock();
|
||||
tmp = ldub((void *)T1);
|
||||
stb((void *)T1, T0);
|
||||
T0 = tmp;
|
||||
cpu_unlock();
|
||||
}
|
||||
|
||||
void OPPROTO op_swpl_T0_T1(void)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
cpu_lock();
|
||||
tmp = ldl((void *)T1);
|
||||
stl((void *)T1, T0);
|
||||
T0 = tmp;
|
||||
cpu_unlock();
|
||||
}
|
||||
|
||||
/* shifts */
|
||||
|
||||
/* T1 based */
|
||||
void OPPROTO op_shll_T1_im(void)
|
||||
{
|
||||
T1 = T1 << PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_im(void)
|
||||
{
|
||||
T1 = (uint32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_im(void)
|
||||
{
|
||||
T1 = (int32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_im(void)
|
||||
{
|
||||
int shift;
|
||||
shift = PARAM1;
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
|
||||
/* T1 based, set C flag */
|
||||
void OPPROTO op_shll_T1_im_cc(void)
|
||||
{
|
||||
env->CF = (T1 >> (32 - PARAM1)) & 1;
|
||||
T1 = T1 << PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_im_cc(void)
|
||||
{
|
||||
env->CF = (T1 >> (PARAM1 - 1)) & 1;
|
||||
T1 = (uint32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_im_cc(void)
|
||||
{
|
||||
env->CF = (T1 >> (PARAM1 - 1)) & 1;
|
||||
T1 = (int32_t)T1 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_im_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = PARAM1;
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
|
||||
/* T2 based */
|
||||
void OPPROTO op_shll_T2_im(void)
|
||||
{
|
||||
T2 = T2 << PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T2_im(void)
|
||||
{
|
||||
T2 = (uint32_t)T2 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T2_im(void)
|
||||
{
|
||||
T2 = (int32_t)T2 >> PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T2_im(void)
|
||||
{
|
||||
int shift;
|
||||
shift = PARAM1;
|
||||
T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift));
|
||||
}
|
||||
|
||||
/* T1 based, use T0 as shift count */
|
||||
|
||||
void OPPROTO op_shll_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32)
|
||||
T1 = 0;
|
||||
else
|
||||
T1 = T1 << shift;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32)
|
||||
T1 = 0;
|
||||
else
|
||||
T1 = (uint32_t)T1 >> shift;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32)
|
||||
shift = 31;
|
||||
T1 = (int32_t)T1 >> shift;
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_T0(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0x1f;
|
||||
if (shift) {
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* T1 based, use T0 as shift count and compute CF */
|
||||
|
||||
void OPPROTO op_shll_T1_T0_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32) {
|
||||
if (shift == 32)
|
||||
env->CF = T1 & 1;
|
||||
else
|
||||
env->CF = 0;
|
||||
T1 = 0;
|
||||
} else if (shift != 0) {
|
||||
env->CF = (T1 >> (32 - shift)) & 1;
|
||||
T1 = T1 << shift;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_shrl_T1_T0_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32) {
|
||||
if (shift == 32)
|
||||
env->CF = (T1 >> 31) & 1;
|
||||
else
|
||||
env->CF = 0;
|
||||
T1 = 0;
|
||||
} else if (shift != 0) {
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = (uint32_t)T1 >> shift;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sarl_T1_T0_cc(void)
|
||||
{
|
||||
int shift;
|
||||
shift = T0 & 0xff;
|
||||
if (shift >= 32) {
|
||||
env->CF = (T1 >> 31) & 1;
|
||||
T1 = (int32_t)T1 >> 31;
|
||||
} else {
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = (int32_t)T1 >> shift;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_rorl_T1_T0_cc(void)
|
||||
{
|
||||
int shift1, shift;
|
||||
shift1 = T0 & 0xff;
|
||||
shift = shift1 & 0x1f;
|
||||
if (shift == 0) {
|
||||
if (shift1 != 0)
|
||||
env->CF = (T1 >> 31) & 1;
|
||||
} else {
|
||||
env->CF = (T1 >> (shift - 1)) & 1;
|
||||
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* exceptions */
|
||||
|
||||
void OPPROTO op_swi(void)
|
||||
{
|
||||
env->exception_index = EXCP_SWI;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_undef_insn(void)
|
||||
{
|
||||
env->exception_index = EXCP_UDEF;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
/* thread support */
|
||||
|
||||
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
void cpu_lock(void)
|
||||
{
|
||||
spin_lock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
void cpu_unlock(void)
|
||||
{
|
||||
spin_unlock(&global_cpu_lock);
|
||||
}
|
||||
|
||||
+3214
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,128 @@
|
||||
OUTPUT_FORMAT("elf32-sparc", "elf32-sparc",
|
||||
"elf32-sparc")
|
||||
OUTPUT_ARCH(sparc)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x60000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.text :
|
||||
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
||||
.rel.data :
|
||||
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
||||
.rel.rodata :
|
||||
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} =0x47ff041f
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(0x100000) + (. & (0x100000 - 1));
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
*(.dtors)
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss : { *(.sbss) *(.scommon) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
/* this struct defines the way the registers are stored on the
|
||||
stack during a system call. */
|
||||
|
||||
struct target_pt_regs {
|
||||
target_long uregs[18];
|
||||
};
|
||||
|
||||
#define ARM_cpsr uregs[16]
|
||||
#define ARM_pc uregs[15]
|
||||
#define ARM_lr uregs[14]
|
||||
#define ARM_sp uregs[13]
|
||||
#define ARM_ip uregs[12]
|
||||
#define ARM_fp uregs[11]
|
||||
#define ARM_r10 uregs[10]
|
||||
#define ARM_r9 uregs[9]
|
||||
#define ARM_r8 uregs[8]
|
||||
#define ARM_r7 uregs[7]
|
||||
#define ARM_r6 uregs[6]
|
||||
#define ARM_r5 uregs[5]
|
||||
#define ARM_r4 uregs[4]
|
||||
#define ARM_r3 uregs[3]
|
||||
#define ARM_r2 uregs[2]
|
||||
#define ARM_r1 uregs[1]
|
||||
#define ARM_r0 uregs[0]
|
||||
#define ARM_ORIG_r0 uregs[17]
|
||||
|
||||
-914
@@ -1,491 +1,3 @@
|
||||
/* from linux/unistd.h */
|
||||
|
||||
#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
|
||||
#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)
|
||||
|
||||
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
|
||||
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
|
||||
#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */
|
||||
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
unsigned short __pad1;
|
||||
target_ulong st_ino;
|
||||
unsigned short st_mode;
|
||||
unsigned short st_nlink;
|
||||
unsigned short st_uid;
|
||||
unsigned short st_gid;
|
||||
unsigned short st_rdev;
|
||||
unsigned short __pad2;
|
||||
target_ulong st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong st_blocks;
|
||||
target_ulong target_st_atime;
|
||||
target_ulong __unused1;
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
/* This matches struct stat64 in glibc2.1, hence the absolutely
|
||||
* insane amounts of padding around dev_t's.
|
||||
*/
|
||||
struct target_stat64 {
|
||||
unsigned short st_dev;
|
||||
unsigned char __pad0[10];
|
||||
|
||||
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
|
||||
target_ulong __st_ino;
|
||||
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
|
||||
target_ulong st_uid;
|
||||
target_ulong st_gid;
|
||||
|
||||
unsigned short st_rdev;
|
||||
unsigned char __pad3[10];
|
||||
|
||||
long long st_size;
|
||||
target_ulong st_blksize;
|
||||
|
||||
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
|
||||
target_ulong __pad4; /* future possible st_blocks high bits */
|
||||
|
||||
target_ulong target_st_atime;
|
||||
target_ulong __pad5;
|
||||
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong __pad6;
|
||||
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong __pad7; /* will be high 32 bits of ctime someday */
|
||||
|
||||
unsigned long long st_ino;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
#define TARGET_SA_SIGINFO 0x00000004
|
||||
#define TARGET_SA_ONSTACK 0x08000000
|
||||
#define TARGET_SA_RESTART 0x10000000
|
||||
#define TARGET_SA_NODEFER 0x40000000
|
||||
#define TARGET_SA_RESETHAND 0x80000000
|
||||
#define TARGET_SA_RESTORER 0x04000000
|
||||
|
||||
#define TARGET_SIGHUP 1
|
||||
#define TARGET_SIGINT 2
|
||||
#define TARGET_SIGQUIT 3
|
||||
#define TARGET_SIGILL 4
|
||||
#define TARGET_SIGTRAP 5
|
||||
#define TARGET_SIGABRT 6
|
||||
#define TARGET_SIGIOT 6
|
||||
#define TARGET_SIGBUS 7
|
||||
#define TARGET_SIGFPE 8
|
||||
#define TARGET_SIGKILL 9
|
||||
#define TARGET_SIGUSR1 10
|
||||
#define TARGET_SIGSEGV 11
|
||||
#define TARGET_SIGUSR2 12
|
||||
#define TARGET_SIGPIPE 13
|
||||
#define TARGET_SIGALRM 14
|
||||
#define TARGET_SIGTERM 15
|
||||
#define TARGET_SIGSTKFLT 16
|
||||
#define TARGET_SIGCHLD 17
|
||||
#define TARGET_SIGCONT 18
|
||||
#define TARGET_SIGSTOP 19
|
||||
#define TARGET_SIGTSTP 20
|
||||
#define TARGET_SIGTTIN 21
|
||||
#define TARGET_SIGTTOU 22
|
||||
#define TARGET_SIGURG 23
|
||||
#define TARGET_SIGXCPU 24
|
||||
#define TARGET_SIGXFSZ 25
|
||||
#define TARGET_SIGVTALRM 26
|
||||
#define TARGET_SIGPROF 27
|
||||
#define TARGET_SIGWINCH 28
|
||||
#define TARGET_SIGIO 29
|
||||
#define TARGET_SIGRTMIN 32
|
||||
|
||||
struct target_old_sigaction {
|
||||
target_ulong _sa_handler;
|
||||
target_ulong sa_mask;
|
||||
target_ulong sa_flags;
|
||||
target_ulong sa_restorer;
|
||||
};
|
||||
|
||||
struct target_sigaction {
|
||||
target_ulong _sa_handler;
|
||||
target_ulong sa_flags;
|
||||
target_ulong sa_restorer;
|
||||
target_sigset_t sa_mask;
|
||||
};
|
||||
|
||||
typedef union target_sigval {
|
||||
int sival_int;
|
||||
target_ulong sival_ptr;
|
||||
} target_sigval_t;
|
||||
|
||||
#define TARGET_SI_MAX_SIZE 128
|
||||
#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
|
||||
|
||||
typedef struct target_siginfo {
|
||||
int si_signo;
|
||||
int si_errno;
|
||||
int si_code;
|
||||
|
||||
union {
|
||||
int _pad[TARGET_SI_PAD_SIZE];
|
||||
|
||||
/* kill() */
|
||||
struct {
|
||||
pid_t _pid; /* sender's pid */
|
||||
uid_t _uid; /* sender's uid */
|
||||
} _kill;
|
||||
|
||||
/* POSIX.1b timers */
|
||||
struct {
|
||||
unsigned int _timer1;
|
||||
unsigned int _timer2;
|
||||
} _timer;
|
||||
|
||||
/* POSIX.1b signals */
|
||||
struct {
|
||||
pid_t _pid; /* sender's pid */
|
||||
uid_t _uid; /* sender's uid */
|
||||
target_sigval_t _sigval;
|
||||
} _rt;
|
||||
|
||||
/* SIGCHLD */
|
||||
struct {
|
||||
pid_t _pid; /* which child */
|
||||
uid_t _uid; /* sender's uid */
|
||||
int _status; /* exit code */
|
||||
target_clock_t _utime;
|
||||
target_clock_t _stime;
|
||||
} _sigchld;
|
||||
|
||||
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
|
||||
struct {
|
||||
target_ulong _addr; /* faulting insn/memory ref. */
|
||||
} _sigfault;
|
||||
|
||||
/* SIGPOLL */
|
||||
struct {
|
||||
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
|
||||
int _fd;
|
||||
} _sigpoll;
|
||||
} _sifields;
|
||||
} target_siginfo_t;
|
||||
|
||||
/*
|
||||
* si_code values
|
||||
* Digital reserves positive values for kernel-generated signals.
|
||||
*/
|
||||
#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */
|
||||
#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */
|
||||
#define TARGET_SI_QUEUE -1 /* sent by sigqueue */
|
||||
#define TARGET_SI_TIMER -2 /* sent by timer expiration */
|
||||
#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */
|
||||
#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */
|
||||
#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */
|
||||
|
||||
/*
|
||||
* SIGILL si_codes
|
||||
*/
|
||||
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
|
||||
|
||||
/*
|
||||
* SIGFPE si_codes
|
||||
*/
|
||||
#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
|
||||
#define TARGET_FPE_INTOVF (2) /* integer overflow */
|
||||
#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
|
||||
#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
|
||||
#define TARGET_FPE_FLTUND (5) /* floating point underflow */
|
||||
#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
|
||||
#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
|
||||
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
|
||||
#define TARGET_NSIGFPE 8
|
||||
|
||||
/*
|
||||
* SIGSEGV si_codes
|
||||
*/
|
||||
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
|
||||
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
|
||||
|
||||
/*
|
||||
* SIGTRAP si_codes
|
||||
*/
|
||||
#define TARGET_TRAP_BRKPT (1) /* process breakpoint */
|
||||
#define TARGET_TRAP_TRACE (2) /* process trace trap */
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_CS (0x23)
|
||||
#define __USER_DS (0x2B)
|
||||
@@ -510,261 +22,6 @@ struct target_pt_regs {
|
||||
|
||||
/* ioctls */
|
||||
|
||||
/*
|
||||
* The following is for compatibility across the various Linux
|
||||
* platforms. The i386 ioctl numbering scheme doesn't really enforce
|
||||
* a type field. De facto, however, the top 8 bits of the lower 16
|
||||
* bits are indeed used as a type field, so we might just as well make
|
||||
* this explicit here. Please be sure to use the decoding macros
|
||||
* below from now on.
|
||||
*/
|
||||
#define TARGET_IOC_NRBITS 8
|
||||
#define TARGET_IOC_TYPEBITS 8
|
||||
#define TARGET_IOC_SIZEBITS 14
|
||||
#define TARGET_IOC_DIRBITS 2
|
||||
|
||||
#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1)
|
||||
#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1)
|
||||
#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1)
|
||||
#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1)
|
||||
|
||||
#define TARGET_IOC_NRSHIFT 0
|
||||
#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS)
|
||||
#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS)
|
||||
#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS)
|
||||
|
||||
/*
|
||||
* Direction bits.
|
||||
*/
|
||||
#define TARGET_IOC_NONE 0U
|
||||
#define TARGET_IOC_WRITE 1U
|
||||
#define TARGET_IOC_READ 2U
|
||||
|
||||
#define TARGET_IOC(dir,type,nr,size) \
|
||||
(((dir) << TARGET_IOC_DIRSHIFT) | \
|
||||
((type) << TARGET_IOC_TYPESHIFT) | \
|
||||
((nr) << TARGET_IOC_NRSHIFT) | \
|
||||
((size) << TARGET_IOC_SIZESHIFT))
|
||||
|
||||
/* used to create numbers */
|
||||
#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0)
|
||||
#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size))
|
||||
#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size))
|
||||
#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size))
|
||||
|
||||
/* 0x54 is just a magic number to make these relatively unique ('T') */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
|
||||
#define TARGET_LDT_ENTRIES 8192
|
||||
#define TARGET_LDT_ENTRY_SIZE 8
|
||||
|
||||
@@ -779,7 +36,6 @@ struct target_modify_ldt_ldt_s {
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
|
||||
/* vm86 defines */
|
||||
|
||||
#define TARGET_BIOSSEG 0x0f000
|
||||
@@ -910,11 +166,6 @@ struct target_ipc_kludge {
|
||||
int msgtyp;
|
||||
};
|
||||
|
||||
struct alpha_msgbuf {
|
||||
long mtype;
|
||||
char mtext[4096];
|
||||
};
|
||||
|
||||
struct target_ipc_perm {
|
||||
int key;
|
||||
unsigned short uid;
|
||||
@@ -967,168 +218,3 @@ union target_semun {
|
||||
unsigned int __pad; /* really void* */
|
||||
};
|
||||
|
||||
#define TARGET_F_DUPFD 0 /* dup */
|
||||
#define TARGET_F_GETFD 1 /* get close_on_exec */
|
||||
#define TARGET_F_SETFD 2 /* set/clear close_on_exec */
|
||||
#define TARGET_F_GETFL 3 /* get file->f_flags */
|
||||
#define TARGET_F_SETFL 4 /* set file->f_flags */
|
||||
#define TARGET_F_GETLK 5
|
||||
#define TARGET_F_SETLK 6
|
||||
#define TARGET_F_SETLKW 7
|
||||
|
||||
#define TARGET_F_SETOWN 8 /* for sockets. */
|
||||
#define TARGET_F_GETOWN 9 /* for sockets. */
|
||||
#define TARGET_F_SETSIG 10 /* for sockets. */
|
||||
#define TARGET_F_GETSIG 11 /* for sockets. */
|
||||
|
||||
#define TARGET_F_GETLK64 12 /* using 'struct flock64' */
|
||||
#define TARGET_F_SETLK64 13
|
||||
#define TARGET_F_SETLKW64 14
|
||||
|
||||
struct target_flock {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
target_ulong l_start;
|
||||
target_ulong l_len;
|
||||
int l_pid;
|
||||
};
|
||||
|
||||
struct target_flock64 {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
unsigned long long l_start;
|
||||
unsigned long long l_len;
|
||||
int l_pid;
|
||||
};
|
||||
|
||||
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
|
||||
|
||||
#define TARGET_SNDCTL_COPR_HALT 0xc0144307
|
||||
#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301
|
||||
#define TARGET_SNDCTL_COPR_RCODE 0xc0144303
|
||||
#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309
|
||||
#define TARGET_SNDCTL_COPR_RDATA 0xc0144302
|
||||
#define TARGET_SNDCTL_COPR_RESET 0x00004300
|
||||
#define TARGET_SNDCTL_COPR_RUN 0xc0144306
|
||||
#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308
|
||||
#define TARGET_SNDCTL_COPR_WCODE 0x40144305
|
||||
#define TARGET_SNDCTL_COPR_WDATA 0x40144304
|
||||
#define TARGET_SNDCTL_DSP_CHANNELS 0xc0045006
|
||||
#define TARGET_SNDCTL_DSP_GETBLKSIZE 0xc0045004
|
||||
#define TARGET_SNDCTL_DSP_GETCAPS 0x8004500f
|
||||
#define TARGET_SNDCTL_DSP_GETFMTS 0x8004500b
|
||||
#define TARGET_SNDCTL_DSP_GETIPTR 0x800c5011
|
||||
#define TARGET_SNDCTL_DSP_GETISPACE 0x8010500d
|
||||
#define TARGET_SNDCTL_DSP_GETOPTR 0x800c5012
|
||||
#define TARGET_SNDCTL_DSP_GETOSPACE 0x8010500c
|
||||
#define TARGET_SNDCTL_DSP_GETTRIGGER 0x80045010
|
||||
#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013
|
||||
#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014
|
||||
#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e
|
||||
#define TARGET_SNDCTL_DSP_POST 0x00005008
|
||||
#define TARGET_SNDCTL_DSP_RESET 0x00005000
|
||||
#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005
|
||||
#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016
|
||||
#define TARGET_SNDCTL_DSP_SETFMT 0xc0045005
|
||||
#define TARGET_SNDCTL_DSP_SETFRAGMENT 0xc004500a
|
||||
#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015
|
||||
#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010
|
||||
#define TARGET_SNDCTL_DSP_SPEED 0xc0045002
|
||||
#define TARGET_SNDCTL_DSP_STEREO 0xc0045003
|
||||
#define TARGET_SNDCTL_DSP_SUBDIVIDE 0xc0045009
|
||||
#define TARGET_SNDCTL_DSP_SYNC 0x00005001
|
||||
#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f
|
||||
#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107
|
||||
#define TARGET_SNDCTL_MIDI_INFO 0xc074510c
|
||||
#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02
|
||||
#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01
|
||||
#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00
|
||||
#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110
|
||||
#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001
|
||||
#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103
|
||||
#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105
|
||||
#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104
|
||||
#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b
|
||||
#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a
|
||||
#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112
|
||||
#define TARGET_SNDCTL_SEQ_PANIC 0x00005111
|
||||
#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106
|
||||
#define TARGET_SNDCTL_SEQ_RESET 0x00005100
|
||||
#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109
|
||||
#define TARGET_SNDCTL_SEQ_SYNC 0x00005101
|
||||
#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108
|
||||
#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d
|
||||
#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d
|
||||
#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102
|
||||
#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e
|
||||
#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404
|
||||
#define TARGET_SNDCTL_TMR_METRONOME 0x40045407
|
||||
#define TARGET_SNDCTL_TMR_SELECT 0x40045408
|
||||
#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406
|
||||
#define TARGET_SNDCTL_TMR_START 0x00005402
|
||||
#define TARGET_SNDCTL_TMR_STOP 0x00005403
|
||||
#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405
|
||||
#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401
|
||||
#define TARGET_SOUND_PCM_WRITE_FILTER 0xc0045007
|
||||
#define TARGET_SOUND_PCM_READ_RATE 0x80045002
|
||||
#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006
|
||||
#define TARGET_SOUND_PCM_READ_BITS 0x80045005
|
||||
#define TARGET_SOUND_PCM_READ_FILTER 0x80045007
|
||||
#define TARGET_SOUND_MIXER_INFO 0x80304d65
|
||||
#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66
|
||||
#define TARGET_SOUND_MIXER_PRIVATE1 0xc0044d6f
|
||||
#define TARGET_SOUND_MIXER_PRIVATE2 0xc0044d70
|
||||
#define TARGET_SOUND_MIXER_PRIVATE3 0xc0044d71
|
||||
#define TARGET_SOUND_MIXER_PRIVATE4 0xc0044d72
|
||||
#define TARGET_SOUND_MIXER_PRIVATE5 0xc0044d73
|
||||
#define TARGET_SOUND_MIXER_READ_VOLUME 0x80044d00
|
||||
#define TARGET_SOUND_MIXER_READ_BASS 0x80044d01
|
||||
#define TARGET_SOUND_MIXER_READ_TREBLE 0x80044d02
|
||||
#define TARGET_SOUND_MIXER_READ_SYNTH 0x80044d03
|
||||
#define TARGET_SOUND_MIXER_READ_PCM 0x80044d04
|
||||
#define TARGET_SOUND_MIXER_READ_SPEAKER 0x80044d05
|
||||
#define TARGET_SOUND_MIXER_READ_LINE 0x80044d06
|
||||
#define TARGET_SOUND_MIXER_READ_MIC 0x80044d07
|
||||
#define TARGET_SOUND_MIXER_READ_CD 0x80044d08
|
||||
#define TARGET_SOUND_MIXER_READ_IMIX 0x80044d09
|
||||
#define TARGET_SOUND_MIXER_READ_ALTPCM 0x80044d0a
|
||||
#define TARGET_SOUND_MIXER_READ_RECLEV 0x80044d0b
|
||||
#define TARGET_SOUND_MIXER_READ_IGAIN 0x80044d0c
|
||||
#define TARGET_SOUND_MIXER_READ_OGAIN 0x80044d0d
|
||||
#define TARGET_SOUND_MIXER_READ_LINE1 0x80044d0e
|
||||
#define TARGET_SOUND_MIXER_READ_LINE2 0x80044d0f
|
||||
#define TARGET_SOUND_MIXER_READ_LINE3 0x80044d10
|
||||
#define TARGET_SOUND_MIXER_READ_MUTE 0x80044d1f
|
||||
#define TARGET_SOUND_MIXER_READ_ENHANCE 0x80044d1f
|
||||
#define TARGET_SOUND_MIXER_READ_LOUD 0x80044d1f
|
||||
#define TARGET_SOUND_MIXER_READ_RECSRC 0x80044dff
|
||||
#define TARGET_SOUND_MIXER_READ_DEVMASK 0x80044dfe
|
||||
#define TARGET_SOUND_MIXER_READ_RECMASK 0x80044dfd
|
||||
#define TARGET_SOUND_MIXER_READ_STEREODEVS 0x80044dfb
|
||||
#define TARGET_SOUND_MIXER_READ_CAPS 0x80044dfc
|
||||
#define TARGET_SOUND_MIXER_WRITE_VOLUME 0xc0044d00
|
||||
#define TARGET_SOUND_MIXER_WRITE_BASS 0xc0044d01
|
||||
#define TARGET_SOUND_MIXER_WRITE_TREBLE 0xc0044d02
|
||||
#define TARGET_SOUND_MIXER_WRITE_SYNTH 0xc0044d03
|
||||
#define TARGET_SOUND_MIXER_WRITE_PCM 0xc0044d04
|
||||
#define TARGET_SOUND_MIXER_WRITE_SPEAKER 0xc0044d05
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE 0xc0044d06
|
||||
#define TARGET_SOUND_MIXER_WRITE_MIC 0xc0044d07
|
||||
#define TARGET_SOUND_MIXER_WRITE_CD 0xc0044d08
|
||||
#define TARGET_SOUND_MIXER_WRITE_IMIX 0xc0044d09
|
||||
#define TARGET_SOUND_MIXER_WRITE_ALTPCM 0xc0044d0a
|
||||
#define TARGET_SOUND_MIXER_WRITE_RECLEV 0xc0044d0b
|
||||
#define TARGET_SOUND_MIXER_WRITE_IGAIN 0xc0044d0c
|
||||
#define TARGET_SOUND_MIXER_WRITE_OGAIN 0xc0044d0d
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE1 0xc0044d0e
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE2 0xc0044d0f
|
||||
#define TARGET_SOUND_MIXER_WRITE_LINE3 0xc0044d10
|
||||
#define TARGET_SOUND_MIXER_WRITE_MUTE 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f
|
||||
#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff
|
||||
|
||||
#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201
|
||||
#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202
|
||||
|
||||
#define TARGET_SIOCATMARK 0x8905
|
||||
@@ -1,6 +1,7 @@
|
||||
gmon.out
|
||||
testsig
|
||||
hello
|
||||
hello-arm
|
||||
sha1.test.c
|
||||
sha1.c
|
||||
test-i386
|
||||
|
||||
+10
-1
@@ -35,9 +35,11 @@ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
|
||||
test-i386-code16.S test-i386-vm86.S -lm
|
||||
|
||||
test: test-i386
|
||||
ifeq ($(ARCH),i386)
|
||||
test: test-i386
|
||||
./test-i386 > test-i386.ref
|
||||
else
|
||||
test:
|
||||
endif
|
||||
$(QEMU) test-i386 > test-i386.out
|
||||
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
|
||||
@@ -57,5 +59,12 @@ speed: sha1 sha1-i386
|
||||
runcom: runcom.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
# arm test
|
||||
hello-arm: hello-arm.o
|
||||
arm-linux-ld -o $@ $<
|
||||
|
||||
hello-arm.o: hello-arm.c
|
||||
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o $(TESTS)
|
||||
@@ -0,0 +1,113 @@
|
||||
#define __NR_SYSCALL_BASE 0x900000
|
||||
#define __NR_exit1 (__NR_SYSCALL_BASE+ 1)
|
||||
#define __NR_write (__NR_SYSCALL_BASE+ 4)
|
||||
|
||||
#define __sys2(x) #x
|
||||
#define __sys1(x) __sys2(x)
|
||||
|
||||
#ifndef __syscall
|
||||
#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
|
||||
#endif
|
||||
|
||||
#define __syscall_return(type, res) \
|
||||
do { \
|
||||
return (type) (res); \
|
||||
} while (0)
|
||||
|
||||
#define _syscall0(type,name) \
|
||||
type name(void) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
__syscall(name) \
|
||||
"mov %0,r0" \
|
||||
:"=r" (__res) : : "r0","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
#define _syscall1(type,name,type1,arg1) \
|
||||
type name(type1 arg1) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
__syscall(name) \
|
||||
"mov %0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)) \
|
||||
: "r0","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
#define _syscall2(type,name,type1,arg1,type2,arg2) \
|
||||
type name(type1 arg1,type2 arg2) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)) \
|
||||
: "r0","r1","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
|
||||
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
|
||||
type name(type1 arg1,type2 arg2,type3 arg3) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
"mov\tr2,%3\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \
|
||||
: "r0","r1","r2","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
|
||||
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
|
||||
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
"mov\tr2,%3\n\t" \
|
||||
"mov\tr3,%4\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \
|
||||
: "r0","r1","r2","r3","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
|
||||
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
|
||||
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
|
||||
long __res; \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov\tr0,%1\n\t" \
|
||||
"mov\tr1,%2\n\t" \
|
||||
"mov\tr2,%3\n\t" \
|
||||
"mov\tr3,%4\n\t" \
|
||||
"mov\tr4,%5\n\t" \
|
||||
__syscall(name) \
|
||||
"mov\t%0,r0" \
|
||||
: "=r" (__res) \
|
||||
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \
|
||||
"r" ((long)(arg5)) \
|
||||
: "r0","r1","r2","r3","r4","lr"); \
|
||||
__syscall_return(type,__res); \
|
||||
}
|
||||
|
||||
_syscall1(int,exit1,int,status);
|
||||
_syscall3(int,write,int,fd,const char *,buf, int, len);
|
||||
|
||||
void _start(void)
|
||||
{
|
||||
write(1, "Hello World\n", 12);
|
||||
exit1(0);
|
||||
}
|
||||
+89
-5
@@ -9,7 +9,8 @@
|
||||
#include <sys/mman.h>
|
||||
#include <asm/vm86.h>
|
||||
|
||||
#define TEST_CMOV 0
|
||||
#define TEST_CMOV 0
|
||||
#define TEST_FCOMI 0
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
@@ -510,12 +511,28 @@ void test_fcmp(double a, double b)
|
||||
a, b, a > b);
|
||||
printf("(%f<=%f)=%d\n",
|
||||
a, b, a >= b);
|
||||
if (TEST_FCOMI) {
|
||||
unsigned int eflags;
|
||||
/* test f(u)comi instruction */
|
||||
asm("fcomi %2, %1\n"
|
||||
"pushf\n"
|
||||
"pop %0\n"
|
||||
: "=r" (eflags)
|
||||
: "t" (a), "u" (b));
|
||||
printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C));
|
||||
}
|
||||
}
|
||||
|
||||
void test_fcvt(double a)
|
||||
{
|
||||
float fa;
|
||||
long double la;
|
||||
int16_t fpuc;
|
||||
int i;
|
||||
int64_t lla;
|
||||
int ia;
|
||||
int16_t wa;
|
||||
double ra;
|
||||
|
||||
fa = a;
|
||||
la = a;
|
||||
@@ -524,9 +541,21 @@ void test_fcvt(double a)
|
||||
printf("a=%016Lx\n", *(long long *)&a);
|
||||
printf("la=%016Lx %04x\n", *(long long *)&la,
|
||||
*(unsigned short *)((char *)(&la) + 8));
|
||||
printf("a=%f floor(a)=%f\n", a, floor(a));
|
||||
printf("a=%f ceil(a)=%f\n", a, ceil(a));
|
||||
printf("a=%f rint(a)=%f\n", a, rint(a));
|
||||
|
||||
/* test all roundings */
|
||||
asm volatile ("fstcw %0" : "=m" (fpuc));
|
||||
for(i=0;i<4;i++) {
|
||||
asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10)));
|
||||
asm volatile ("fist %0" : "=m" (wa) : "t" (a));
|
||||
asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
|
||||
asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
|
||||
asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
|
||||
asm volatile ("fldcw %0" : : "m" (fpuc));
|
||||
printf("(short)a = %d\n", wa);
|
||||
printf("(int)a = %d\n", ia);
|
||||
printf("(int64_t)a = %Ld\n", lla);
|
||||
printf("rint(a) = %f\n", ra);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST(N) \
|
||||
@@ -556,6 +585,57 @@ void test_fbcd(double a)
|
||||
a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
|
||||
}
|
||||
|
||||
#define TEST_ENV(env, prefix)\
|
||||
{\
|
||||
memset((env), 0xaa, sizeof(*(env)));\
|
||||
asm("fld1\n"\
|
||||
prefix "fnstenv %1\n"\
|
||||
prefix "fldenv %1\n"\
|
||||
: "=t" (res) : "m" (*(env)) : "st");\
|
||||
printf("res=%f\n", res);\
|
||||
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
|
||||
(env)->fpuc,\
|
||||
(env)->fpus & 0xff00,\
|
||||
(env)->fptag);\
|
||||
memset((env), 0xaa, sizeof(*(env)));\
|
||||
asm("fld1\n"\
|
||||
prefix "fnsave %1\n"\
|
||||
prefix "frstor %1\n"\
|
||||
: "=t" (res) : "m" (*(env)) : "st");\
|
||||
printf("res=%f\n", res);\
|
||||
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
|
||||
(env)->fpuc,\
|
||||
(env)->fpus & 0xff00,\
|
||||
(env)->fptag);\
|
||||
printf("ST(0) = %Lf\n",\
|
||||
(env)->fpregs[0]);\
|
||||
}
|
||||
|
||||
void test_fenv(void)
|
||||
{
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t fpuc;
|
||||
uint16_t dummy1;
|
||||
uint16_t fpus;
|
||||
uint16_t dummy2;
|
||||
uint16_t fptag;
|
||||
uint16_t dummy3;
|
||||
uint32_t ignored[4];
|
||||
long double fpregs[8];
|
||||
} float_env32;
|
||||
struct __attribute__((packed)) {
|
||||
uint16_t fpuc;
|
||||
uint16_t fpus;
|
||||
uint16_t fptag;
|
||||
uint16_t ignored[4];
|
||||
long double fpregs[8];
|
||||
} float_env16;
|
||||
double res;
|
||||
|
||||
TEST_ENV(&float_env16, "data16 ");
|
||||
TEST_ENV(&float_env32, "");
|
||||
}
|
||||
|
||||
void test_floats(void)
|
||||
{
|
||||
test_fops(2, 3);
|
||||
@@ -563,12 +643,16 @@ void test_floats(void)
|
||||
test_fcmp(2, -1);
|
||||
test_fcmp(2, 2);
|
||||
test_fcmp(2, 3);
|
||||
test_fcvt(0.5);
|
||||
test_fcvt(-0.5);
|
||||
test_fcvt(1.0/7.0);
|
||||
test_fcvt(-1.0/9.0);
|
||||
test_fcvt(1e30);
|
||||
test_fcvt(32768);
|
||||
test_fcvt(-1e20);
|
||||
test_fconst();
|
||||
test_fbcd(1234567890123456);
|
||||
test_fbcd(-123451234567890);
|
||||
test_fenv();
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
|
||||
@@ -29,80 +29,7 @@
|
||||
#define MAX_STRUCTS 128
|
||||
|
||||
/* XXX: make it dynamic */
|
||||
static StructEntry struct_entries[MAX_STRUCTS];
|
||||
|
||||
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type, size;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
size = type_ptr[1];
|
||||
return size * thunk_type_size(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->size[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
return thunk_type_align(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->align[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
StructEntry struct_entries[MAX_STRUCTS];
|
||||
|
||||
static inline const argtype *thunk_type_next(const argtype *type_ptr)
|
||||
{
|
||||
@@ -167,6 +94,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types)
|
||||
offset += size;
|
||||
if (align > max_align)
|
||||
max_align = align;
|
||||
type_ptr = thunk_type_next(type_ptr);
|
||||
}
|
||||
offset = (offset + max_align - 1) & ~(max_align - 1);
|
||||
se->size[i] = offset;
|
||||
|
||||
@@ -61,15 +61,13 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define BSWAP_NEEDED
|
||||
#endif
|
||||
|
||||
/* XXX: autoconf */
|
||||
#define TARGET_I386
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
|
||||
#if defined(__alpha__) || defined (__ia64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
@@ -77,7 +75,7 @@
|
||||
#endif
|
||||
|
||||
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
|
||||
#define HOST_LONG_SIZE (TARGET_LONG_BITS / 8)
|
||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
@@ -239,6 +237,81 @@ void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
|
||||
const argtype *thunk_convert(void *dst, const void *src,
|
||||
const argtype *type_ptr, int to_host);
|
||||
|
||||
extern StructEntry struct_entries[];
|
||||
|
||||
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type, size;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
size = type_ptr[1];
|
||||
return size * thunk_type_size(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->size[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
|
||||
{
|
||||
int type;
|
||||
const StructEntry *se;
|
||||
|
||||
type = *type_ptr;
|
||||
switch(type) {
|
||||
case TYPE_CHAR:
|
||||
return 1;
|
||||
case TYPE_SHORT:
|
||||
return 2;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_LONGLONG:
|
||||
case TYPE_ULONGLONG:
|
||||
return 8;
|
||||
case TYPE_LONG:
|
||||
case TYPE_ULONG:
|
||||
case TYPE_PTRVOID:
|
||||
case TYPE_PTR:
|
||||
if (is_host) {
|
||||
return HOST_LONG_SIZE;
|
||||
} else {
|
||||
return TARGET_LONG_SIZE;
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
return thunk_type_align(type_ptr + 2, is_host);
|
||||
case TYPE_STRUCT:
|
||||
se = struct_entries + type_ptr[1];
|
||||
return se->align[is_host];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int target_to_host_bitmask(unsigned int x86_mask,
|
||||
bitmask_transtbl * trans_tbl);
|
||||
unsigned int host_to_target_bitmask(unsigned int alpha_mask,
|
||||
|
||||
+750
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* ARM translation
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* internal defines */
|
||||
typedef struct DisasContext {
|
||||
uint8_t *pc;
|
||||
int is_jmp;
|
||||
struct TranslationBlock *tb;
|
||||
} DisasContext;
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
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-arm.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op-arm.h"
|
||||
|
||||
typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
||||
typedef void (GenOpFunc2)(long, long);
|
||||
typedef void (GenOpFunc3)(long, long, long);
|
||||
|
||||
static GenOpFunc2 *gen_test_cc[14] = {
|
||||
gen_op_test_eq,
|
||||
gen_op_test_ne,
|
||||
gen_op_test_cs,
|
||||
gen_op_test_cc,
|
||||
gen_op_test_mi,
|
||||
gen_op_test_pl,
|
||||
gen_op_test_vs,
|
||||
gen_op_test_vc,
|
||||
gen_op_test_hi,
|
||||
gen_op_test_ls,
|
||||
gen_op_test_ge,
|
||||
gen_op_test_lt,
|
||||
gen_op_test_gt,
|
||||
gen_op_test_le,
|
||||
};
|
||||
|
||||
const uint8_t table_logic_cc[16] = {
|
||||
1, /* and */
|
||||
1, /* xor */
|
||||
0, /* sub */
|
||||
0, /* rsb */
|
||||
0, /* add */
|
||||
0, /* adc */
|
||||
0, /* sbc */
|
||||
0, /* rsc */
|
||||
1, /* andl */
|
||||
1, /* xorl */
|
||||
0, /* cmp */
|
||||
0, /* cmn */
|
||||
1, /* orr */
|
||||
1, /* mov */
|
||||
1, /* bic */
|
||||
1, /* mvn */
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_shift_T1_im[4] = {
|
||||
gen_op_shll_T1_im,
|
||||
gen_op_shrl_T1_im,
|
||||
gen_op_sarl_T1_im,
|
||||
gen_op_rorl_T1_im,
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_shift_T2_im[4] = {
|
||||
gen_op_shll_T2_im,
|
||||
gen_op_shrl_T2_im,
|
||||
gen_op_sarl_T2_im,
|
||||
gen_op_rorl_T2_im,
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
|
||||
gen_op_shll_T1_im_cc,
|
||||
gen_op_shrl_T1_im_cc,
|
||||
gen_op_sarl_T1_im_cc,
|
||||
gen_op_rorl_T1_im_cc,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_shift_T1_T0[4] = {
|
||||
gen_op_shll_T1_T0,
|
||||
gen_op_shrl_T1_T0,
|
||||
gen_op_sarl_T1_T0,
|
||||
gen_op_rorl_T1_T0,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_shift_T1_T0_cc[4] = {
|
||||
gen_op_shll_T1_T0_cc,
|
||||
gen_op_shrl_T1_T0_cc,
|
||||
gen_op_sarl_T1_T0_cc,
|
||||
gen_op_rorl_T1_T0_cc,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
|
||||
{
|
||||
gen_op_movl_T0_r0,
|
||||
gen_op_movl_T0_r1,
|
||||
gen_op_movl_T0_r2,
|
||||
gen_op_movl_T0_r3,
|
||||
gen_op_movl_T0_r4,
|
||||
gen_op_movl_T0_r5,
|
||||
gen_op_movl_T0_r6,
|
||||
gen_op_movl_T0_r7,
|
||||
gen_op_movl_T0_r8,
|
||||
gen_op_movl_T0_r9,
|
||||
gen_op_movl_T0_r10,
|
||||
gen_op_movl_T0_r11,
|
||||
gen_op_movl_T0_r12,
|
||||
gen_op_movl_T0_r13,
|
||||
gen_op_movl_T0_r14,
|
||||
gen_op_movl_T0_r15,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T1_r0,
|
||||
gen_op_movl_T1_r1,
|
||||
gen_op_movl_T1_r2,
|
||||
gen_op_movl_T1_r3,
|
||||
gen_op_movl_T1_r4,
|
||||
gen_op_movl_T1_r5,
|
||||
gen_op_movl_T1_r6,
|
||||
gen_op_movl_T1_r7,
|
||||
gen_op_movl_T1_r8,
|
||||
gen_op_movl_T1_r9,
|
||||
gen_op_movl_T1_r10,
|
||||
gen_op_movl_T1_r11,
|
||||
gen_op_movl_T1_r12,
|
||||
gen_op_movl_T1_r13,
|
||||
gen_op_movl_T1_r14,
|
||||
gen_op_movl_T1_r15,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T2_r0,
|
||||
gen_op_movl_T2_r1,
|
||||
gen_op_movl_T2_r2,
|
||||
gen_op_movl_T2_r3,
|
||||
gen_op_movl_T2_r4,
|
||||
gen_op_movl_T2_r5,
|
||||
gen_op_movl_T2_r6,
|
||||
gen_op_movl_T2_r7,
|
||||
gen_op_movl_T2_r8,
|
||||
gen_op_movl_T2_r9,
|
||||
gen_op_movl_T2_r10,
|
||||
gen_op_movl_T2_r11,
|
||||
gen_op_movl_T2_r12,
|
||||
gen_op_movl_T2_r13,
|
||||
gen_op_movl_T2_r14,
|
||||
gen_op_movl_T2_r15,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
|
||||
{
|
||||
gen_op_movl_r0_T0,
|
||||
gen_op_movl_r1_T0,
|
||||
gen_op_movl_r2_T0,
|
||||
gen_op_movl_r3_T0,
|
||||
gen_op_movl_r4_T0,
|
||||
gen_op_movl_r5_T0,
|
||||
gen_op_movl_r6_T0,
|
||||
gen_op_movl_r7_T0,
|
||||
gen_op_movl_r8_T0,
|
||||
gen_op_movl_r9_T0,
|
||||
gen_op_movl_r10_T0,
|
||||
gen_op_movl_r11_T0,
|
||||
gen_op_movl_r12_T0,
|
||||
gen_op_movl_r13_T0,
|
||||
gen_op_movl_r14_T0,
|
||||
gen_op_movl_r15_T0,
|
||||
},
|
||||
{
|
||||
gen_op_movl_r0_T1,
|
||||
gen_op_movl_r1_T1,
|
||||
gen_op_movl_r2_T1,
|
||||
gen_op_movl_r3_T1,
|
||||
gen_op_movl_r4_T1,
|
||||
gen_op_movl_r5_T1,
|
||||
gen_op_movl_r6_T1,
|
||||
gen_op_movl_r7_T1,
|
||||
gen_op_movl_r8_T1,
|
||||
gen_op_movl_r9_T1,
|
||||
gen_op_movl_r10_T1,
|
||||
gen_op_movl_r11_T1,
|
||||
gen_op_movl_r12_T1,
|
||||
gen_op_movl_r13_T1,
|
||||
gen_op_movl_r14_T1,
|
||||
gen_op_movl_r15_T1,
|
||||
},
|
||||
};
|
||||
|
||||
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_TN_reg(DisasContext *s, int reg, int t)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (reg == 15) {
|
||||
/* normaly, since we updated PC, we need only to add 4 */
|
||||
val = (long)s->pc + 4;
|
||||
gen_op_movl_TN_im[t](val);
|
||||
} else {
|
||||
gen_op_movl_TN_reg[t][reg]();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_TN_reg(s, reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_T1_reg(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_TN_reg(s, reg, 1);
|
||||
}
|
||||
|
||||
static inline void gen_movl_T2_reg(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_TN_reg(s, reg, 2);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
|
||||
{
|
||||
gen_op_movl_reg_TN[t][reg]();
|
||||
if (reg == 15) {
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T0(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_reg_TN(s, reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T1(DisasContext *s, int reg)
|
||||
{
|
||||
gen_movl_reg_TN(s, reg, 1);
|
||||
}
|
||||
|
||||
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
|
||||
{
|
||||
int val, rm, shift;
|
||||
|
||||
if (!(insn & (1 << 25))) {
|
||||
/* immediate */
|
||||
val = insn & 0xfff;
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
gen_op_addl_T1_im(val);
|
||||
} else {
|
||||
/* shift/register */
|
||||
rm = (insn) & 0xf;
|
||||
shift = (insn >> 7) & 0x1f;
|
||||
gen_movl_T2_reg(s, rm);
|
||||
if (shift != 0) {
|
||||
gen_shift_T2_im[(insn >> 5) & 3](shift);
|
||||
}
|
||||
if (!(insn & (1 << 23)))
|
||||
gen_op_subl_T1_T2();
|
||||
else
|
||||
gen_op_addl_T1_T2();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
|
||||
{
|
||||
int val, rm;
|
||||
|
||||
if (insn & (1 << 22)) {
|
||||
/* immediate */
|
||||
val = (insn & 0xf) | ((insn >> 4) & 0xf0);
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
gen_op_addl_T1_im(val);
|
||||
} else {
|
||||
/* register */
|
||||
rm = (insn) & 0xf;
|
||||
gen_movl_T2_reg(s, rm);
|
||||
if (!(insn & (1 << 23)))
|
||||
gen_op_subl_T1_T2();
|
||||
else
|
||||
gen_op_addl_T1_T2();
|
||||
}
|
||||
}
|
||||
|
||||
static void disas_arm_insn(DisasContext *s)
|
||||
{
|
||||
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
|
||||
|
||||
insn = ldl(s->pc);
|
||||
s->pc += 4;
|
||||
|
||||
cond = insn >> 28;
|
||||
if (cond == 0xf)
|
||||
goto illegal_op;
|
||||
if (cond != 0xe) {
|
||||
/* if not always execute, we generate a conditional jump to
|
||||
next instruction */
|
||||
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
|
||||
s->is_jmp = 1;
|
||||
}
|
||||
if ((insn & 0x0c000000) == 0 &&
|
||||
(insn & 0x00000090) != 0x90) {
|
||||
int set_cc, logic_cc, shiftop;
|
||||
|
||||
op1 = (insn >> 21) & 0xf;
|
||||
set_cc = (insn >> 20) & 1;
|
||||
logic_cc = table_logic_cc[op1] & set_cc;
|
||||
|
||||
/* data processing instruction */
|
||||
if (insn & (1 << 25)) {
|
||||
/* immediate operand */
|
||||
val = insn & 0xff;
|
||||
shift = ((insn >> 8) & 0xf) * 2;
|
||||
if (shift)
|
||||
val = (val >> shift) | (val << (32 - shift));
|
||||
gen_op_movl_T1_im(val);
|
||||
/* XXX: is CF modified ? */
|
||||
} else {
|
||||
/* register */
|
||||
rm = (insn) & 0xf;
|
||||
gen_movl_T1_reg(s, rm);
|
||||
shiftop = (insn >> 5) & 3;
|
||||
if (!(insn & (1 << 4))) {
|
||||
shift = (insn >> 7) & 0x1f;
|
||||
if (shift != 0) {
|
||||
if (logic_cc) {
|
||||
gen_shift_T1_im_cc[shiftop](shift);
|
||||
} else {
|
||||
gen_shift_T1_im[shiftop](shift);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rs = (insn >> 16) & 0xf;
|
||||
gen_movl_T0_reg(s, rs);
|
||||
if (logic_cc) {
|
||||
gen_shift_T1_T0_cc[shiftop]();
|
||||
} else {
|
||||
gen_shift_T1_T0[shiftop]();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op1 != 0x0f && op1 != 0x0d) {
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T0_reg(s, rn);
|
||||
}
|
||||
rd = (insn >> 12) & 0xf;
|
||||
switch(op1) {
|
||||
case 0x00:
|
||||
gen_op_andl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x01:
|
||||
gen_op_xorl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x02:
|
||||
if (set_cc)
|
||||
gen_op_subl_T0_T1_cc();
|
||||
else
|
||||
gen_op_subl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x03:
|
||||
if (set_cc)
|
||||
gen_op_rsbl_T0_T1_cc();
|
||||
else
|
||||
gen_op_rsbl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x04:
|
||||
if (set_cc)
|
||||
gen_op_addl_T0_T1_cc();
|
||||
else
|
||||
gen_op_addl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x05:
|
||||
if (set_cc)
|
||||
gen_op_adcl_T0_T1_cc();
|
||||
else
|
||||
gen_op_adcl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x06:
|
||||
if (set_cc)
|
||||
gen_op_sbcl_T0_T1_cc();
|
||||
else
|
||||
gen_op_sbcl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x07:
|
||||
if (set_cc)
|
||||
gen_op_rscl_T0_T1_cc();
|
||||
else
|
||||
gen_op_rscl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x08:
|
||||
if (set_cc) {
|
||||
gen_op_andl_T0_T1();
|
||||
}
|
||||
break;
|
||||
case 0x09:
|
||||
if (set_cc) {
|
||||
gen_op_xorl_T0_T1();
|
||||
}
|
||||
break;
|
||||
case 0x0a:
|
||||
if (set_cc) {
|
||||
gen_op_subl_T0_T1_cc();
|
||||
}
|
||||
break;
|
||||
case 0x0b:
|
||||
if (set_cc) {
|
||||
gen_op_addl_T0_T1_cc();
|
||||
}
|
||||
break;
|
||||
case 0x0c:
|
||||
gen_op_orl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x0d:
|
||||
gen_movl_reg_T1(s, rd);
|
||||
break;
|
||||
case 0x0e:
|
||||
gen_op_bicl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
default:
|
||||
case 0x0f:
|
||||
gen_op_notl_T1();
|
||||
gen_movl_reg_T1(s, rd);
|
||||
break;
|
||||
}
|
||||
if (logic_cc)
|
||||
gen_op_logic_cc();
|
||||
} else {
|
||||
/* other instructions */
|
||||
op1 = (insn >> 24) & 0xf;
|
||||
switch(op1) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
sh = (insn >> 5) & 3;
|
||||
if (sh == 0) {
|
||||
if (op1 == 0x0) {
|
||||
rd = (insn >> 16) & 0xf;
|
||||
rn = (insn >> 12) & 0xf;
|
||||
rs = (insn >> 8) & 0xf;
|
||||
rm = (insn) & 0xf;
|
||||
if (!(insn & (1 << 23))) {
|
||||
/* 32 bit mul */
|
||||
gen_movl_T0_reg(s, rs);
|
||||
gen_movl_T1_reg(s, rm);
|
||||
gen_op_mul_T0_T1();
|
||||
if (insn & (1 << 21)) {
|
||||
gen_movl_T1_reg(s, rn);
|
||||
gen_op_addl_T0_T1();
|
||||
}
|
||||
if (insn & (1 << 20))
|
||||
gen_op_logic_cc();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
} else {
|
||||
/* 64 bit mul */
|
||||
gen_movl_T0_reg(s, rs);
|
||||
gen_movl_T1_reg(s, rm);
|
||||
if (insn & (1 << 22))
|
||||
gen_op_mull_T0_T1();
|
||||
else
|
||||
gen_op_imull_T0_T1();
|
||||
if (insn & (1 << 21))
|
||||
gen_op_addq_T0_T1(rn, rd);
|
||||
if (insn & (1 << 20))
|
||||
gen_op_logicq_cc();
|
||||
gen_movl_reg_T0(s, rn);
|
||||
gen_movl_reg_T1(s, rd);
|
||||
}
|
||||
} else {
|
||||
/* SWP instruction */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
rm = (insn) & 0xf;
|
||||
|
||||
gen_movl_T0_reg(s, rm);
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 22)) {
|
||||
gen_op_swpb_T0_T1();
|
||||
} else {
|
||||
gen_op_swpl_T0_T1();
|
||||
}
|
||||
gen_movl_reg_T0(s, rd);
|
||||
}
|
||||
} else {
|
||||
/* load/store half word */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 25))
|
||||
gen_add_datah_offset(s, insn);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
switch(sh) {
|
||||
case 1:
|
||||
gen_op_lduw_T0_T1();
|
||||
break;
|
||||
case 2:
|
||||
gen_op_ldsb_T0_T1();
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
gen_op_ldsw_T0_T1();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* store */
|
||||
gen_op_stw_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_add_datah_offset(s, insn);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
}
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
/* load/store byte/word */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 24))
|
||||
gen_add_data_offset(s, insn);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
if (insn & (1 << 22))
|
||||
gen_op_ldub_T0_T1();
|
||||
else
|
||||
gen_op_ldl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
} else {
|
||||
/* store */
|
||||
gen_movl_T0_reg(s, rd);
|
||||
if (insn & (1 << 22))
|
||||
gen_op_stb_T0_T1();
|
||||
else
|
||||
gen_op_stl_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_add_data_offset(s, insn);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
/* load/store multiple words */
|
||||
if (insn & (1 << 22))
|
||||
goto illegal_op; /* only usable in supervisor mode */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
val = 4;
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
for(i=0;i<16;i++) {
|
||||
if (insn & (1 << i)) {
|
||||
if (insn & (1 << 24))
|
||||
gen_op_addl_T1_im(val);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
gen_op_ldl_T0_T1();
|
||||
gen_movl_reg_T0(s, i);
|
||||
} else {
|
||||
/* store */
|
||||
gen_movl_T0_reg(s, i);
|
||||
gen_op_stl_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
}
|
||||
}
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
break;
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
{
|
||||
int offset;
|
||||
|
||||
/* branch (and link) */
|
||||
val = (int)s->pc;
|
||||
if (insn & (1 << 24)) {
|
||||
gen_op_movl_T0_im(val);
|
||||
gen_op_movl_reg_TN[0][14]();
|
||||
}
|
||||
offset = (((int)insn << 8) >> 8);
|
||||
val += (offset << 2) + 4;
|
||||
gen_op_jmp((long)s->tb, val);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
}
|
||||
break;
|
||||
case 0xf:
|
||||
/* swi */
|
||||
gen_op_movl_T0_im((long)s->pc);
|
||||
gen_op_movl_reg_TN[0][15]();
|
||||
gen_op_swi();
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
break;
|
||||
default:
|
||||
illegal_op:
|
||||
gen_op_movl_T0_im((long)s->pc - 4);
|
||||
gen_op_movl_reg_TN[0][15]();
|
||||
gen_op_undef_insn();
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
|
||||
basic block 'tb'. If search_pc is TRUE, also generate PC
|
||||
information for each intermediate instruction. */
|
||||
int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
{
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
uint16_t *gen_opc_end;
|
||||
int j, lj;
|
||||
uint8_t *pc_start;
|
||||
|
||||
/* generate intermediate code */
|
||||
pc_start = (uint8_t *)tb->pc;
|
||||
|
||||
dc->tb = tb;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->pc = pc_start;
|
||||
lj = -1;
|
||||
do {
|
||||
if (search_pc) {
|
||||
j = gen_opc_ptr - gen_opc_buf;
|
||||
if (lj < j) {
|
||||
lj++;
|
||||
while (lj < j)
|
||||
gen_opc_instr_start[lj++] = 0;
|
||||
gen_opc_pc[lj] = (uint32_t)dc->pc;
|
||||
gen_opc_instr_start[lj] = 1;
|
||||
}
|
||||
}
|
||||
disas_arm_insn(dc);
|
||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
/* we must store the eflags state if it is not already done */
|
||||
if (dc->is_jmp != DISAS_TB_JUMP &&
|
||||
dc->is_jmp != DISAS_JUMP) {
|
||||
gen_op_movl_T0_im((long)dc->pc - 4);
|
||||
gen_op_movl_reg_TN[0][15]();
|
||||
}
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
}
|
||||
*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
|
||||
if (!search_pc)
|
||||
tb->size = dc->pc - pc_start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CPUARMState *cpu_arm_init(void)
|
||||
{
|
||||
CPUARMState *env;
|
||||
|
||||
cpu_exec_init();
|
||||
|
||||
env = malloc(sizeof(CPUARMState));
|
||||
if (!env)
|
||||
return NULL;
|
||||
memset(env, 0, sizeof(CPUARMState));
|
||||
return env;
|
||||
}
|
||||
|
||||
void cpu_arm_close(CPUARMState *env)
|
||||
{
|
||||
free(env);
|
||||
}
|
||||
|
||||
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<16;i++) {
|
||||
fprintf(f, "R%02d=%08x", i, env->regs[i]);
|
||||
if ((i % 4) == 3)
|
||||
fprintf(f, "\n");
|
||||
else
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, "CPSR=%08x", env->cpsr);
|
||||
}
|
||||
+103
-263
@@ -25,87 +25,13 @@
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "disas.h"
|
||||
|
||||
#define DEBUG_DISAS
|
||||
|
||||
#define IN_OP_I386
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
int __op_jmp0, __op_jmp1;
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(8UL - 1UL);
|
||||
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
|
||||
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
#define PREFIX_REPZ 0x01
|
||||
#define PREFIX_REPNZ 0x02
|
||||
@@ -132,7 +58,7 @@ typedef struct DisasContext {
|
||||
int cpl;
|
||||
int iopl;
|
||||
int tf; /* TF cpu flag */
|
||||
TranslationBlock *tb;
|
||||
struct TranslationBlock *tb;
|
||||
} DisasContext;
|
||||
|
||||
/* i386 arith/logic operations */
|
||||
@@ -166,7 +92,7 @@ enum {
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "op-i386.h"
|
||||
#include "gen-op-i386.h"
|
||||
|
||||
/* operand size */
|
||||
enum {
|
||||
@@ -1273,21 +1199,40 @@ static void gen_pop_T0(DisasContext *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_pop_update(DisasContext *s)
|
||||
static inline void gen_stack_update(DisasContext *s, int addend)
|
||||
{
|
||||
if (s->ss32) {
|
||||
if (s->dflag)
|
||||
gen_op_addl_ESP_4();
|
||||
else
|
||||
if (addend == 2)
|
||||
gen_op_addl_ESP_2();
|
||||
else if (addend == 4)
|
||||
gen_op_addl_ESP_4();
|
||||
else
|
||||
gen_op_addl_ESP_im(addend);
|
||||
} else {
|
||||
if (s->dflag)
|
||||
if (addend == 2)
|
||||
gen_op_addw_ESP_2();
|
||||
else if (addend == 4)
|
||||
gen_op_addw_ESP_4();
|
||||
else
|
||||
gen_op_addw_ESP_2();
|
||||
gen_op_addw_ESP_im(addend);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_pop_update(DisasContext *s)
|
||||
{
|
||||
gen_stack_update(s, 2 << s->dflag);
|
||||
}
|
||||
|
||||
static void gen_stack_A0(DisasContext *s)
|
||||
{
|
||||
gen_op_movl_A0_ESP();
|
||||
if (!s->ss32)
|
||||
gen_op_andl_A0_ffff();
|
||||
gen_op_movl_T1_A0();
|
||||
if (s->addseg)
|
||||
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
|
||||
}
|
||||
|
||||
/* NOTE: wrap around in 16 bit not fully handled */
|
||||
static void gen_pusha(DisasContext *s)
|
||||
{
|
||||
@@ -1957,7 +1902,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
break;
|
||||
case 0xc9: /* leave */
|
||||
/* XXX: exception not precise (ESP is update before potential exception) */
|
||||
/* XXX: exception not precise (ESP is updated before potential exception) */
|
||||
if (s->ss32) {
|
||||
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
|
||||
gen_op_mov_reg_T0[OT_LONG][R_ESP]();
|
||||
@@ -2453,9 +2398,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0c: /* fldenv mem */
|
||||
gen_op_fldenv_A0(s->dflag);
|
||||
break;
|
||||
case 0x0d: /* fldcw mem */
|
||||
gen_op_fldcw_A0();
|
||||
break;
|
||||
case 0x0e: /* fnstenv mem */
|
||||
gen_op_fnstenv_A0(s->dflag);
|
||||
break;
|
||||
case 0x0f: /* fnstcw mem */
|
||||
gen_op_fnstcw_A0();
|
||||
break;
|
||||
@@ -2467,6 +2418,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_fstt_ST0_A0();
|
||||
gen_op_fpop();
|
||||
break;
|
||||
case 0x2c: /* frstor mem */
|
||||
gen_op_frstor_A0(s->dflag);
|
||||
break;
|
||||
case 0x2e: /* fnsave mem */
|
||||
gen_op_fnsave_A0(s->dflag);
|
||||
break;
|
||||
case 0x2f: /* fnstsw mem */
|
||||
gen_op_fnstsw_A0();
|
||||
break;
|
||||
@@ -2672,6 +2629,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
case 0x1d: /* fucomi */
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_fmov_FT0_STN(opreg);
|
||||
gen_op_fucomi_ST0_FT0();
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
break;
|
||||
case 0x1e: /* fcomi */
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_fmov_FT0_STN(opreg);
|
||||
gen_op_fcomi_ST0_FT0();
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
break;
|
||||
case 0x2a: /* fst sti */
|
||||
gen_op_fmov_STN_ST0(opreg);
|
||||
break;
|
||||
@@ -2709,6 +2680,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
case 0x3d: /* fucomip */
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_fmov_FT0_STN(opreg);
|
||||
gen_op_fucomi_ST0_FT0();
|
||||
gen_op_fpop();
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
break;
|
||||
case 0x3e: /* fcomip */
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_fmov_FT0_STN(opreg);
|
||||
gen_op_fcomi_ST0_FT0();
|
||||
gen_op_fpop();
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
@@ -2901,10 +2888,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
val = ldsw(s->pc);
|
||||
s->pc += 2;
|
||||
gen_pop_T0(s);
|
||||
if (s->ss32)
|
||||
gen_op_addl_ESP_im(val + (2 << s->dflag));
|
||||
else
|
||||
gen_op_addw_ESP_im(val + (2 << s->dflag));
|
||||
gen_stack_update(s, val + (2 << s->dflag));
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
gen_op_jmp_T0();
|
||||
@@ -2919,63 +2903,55 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
s->is_jmp = 1;
|
||||
break;
|
||||
case 0xca: /* lret im */
|
||||
/* XXX: not restartable */
|
||||
val = ldsw(s->pc);
|
||||
s->pc += 2;
|
||||
do_lret:
|
||||
gen_stack_A0(s);
|
||||
/* pop offset */
|
||||
gen_pop_T0(s);
|
||||
gen_op_ld_T0_A0[1 + s->dflag]();
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
/* NOTE: keeping EIP updated is not a problem in case of
|
||||
exception */
|
||||
gen_op_jmp_T0();
|
||||
gen_pop_update(s);
|
||||
/* pop selector */
|
||||
gen_pop_T0(s);
|
||||
gen_op_addl_A0_im(2 << s->dflag);
|
||||
gen_op_ld_T0_A0[1 + s->dflag]();
|
||||
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
|
||||
gen_pop_update(s);
|
||||
/* add stack offset */
|
||||
if (s->ss32)
|
||||
gen_op_addl_ESP_im(val);
|
||||
else
|
||||
gen_op_addw_ESP_im(val);
|
||||
gen_stack_update(s, val + (4 << s->dflag));
|
||||
s->is_jmp = 1;
|
||||
break;
|
||||
case 0xcb: /* lret */
|
||||
/* XXX: not restartable */
|
||||
/* pop offset */
|
||||
gen_pop_T0(s);
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
gen_op_jmp_T0();
|
||||
gen_pop_update(s);
|
||||
/* pop selector */
|
||||
gen_pop_T0(s);
|
||||
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
|
||||
gen_pop_update(s);
|
||||
s->is_jmp = 1;
|
||||
break;
|
||||
val = 0;
|
||||
goto do_lret;
|
||||
case 0xcf: /* iret */
|
||||
if (s->vm86 && s->iopl != 3) {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
} else {
|
||||
/* XXX: not restartable */
|
||||
gen_stack_A0(s);
|
||||
/* pop offset */
|
||||
gen_pop_T0(s);
|
||||
gen_op_ld_T0_A0[1 + s->dflag]();
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
gen_op_jmp_T0();
|
||||
gen_pop_update(s);
|
||||
/* NOTE: keeping EIP updated is not a problem in case of
|
||||
exception */
|
||||
gen_op_jmp_T0();
|
||||
/* pop selector */
|
||||
gen_pop_T0(s);
|
||||
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
|
||||
gen_pop_update(s);
|
||||
gen_op_addl_A0_im(2 << s->dflag);
|
||||
gen_op_ld_T0_A0[1 + s->dflag]();
|
||||
/* pop eflags */
|
||||
gen_pop_T0(s);
|
||||
gen_op_addl_A0_im(2 << s->dflag);
|
||||
gen_op_ld_T1_A0[1 + s->dflag]();
|
||||
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
|
||||
gen_op_movl_T0_T1();
|
||||
if (s->dflag) {
|
||||
gen_op_movl_eflags_T0();
|
||||
} else {
|
||||
gen_op_movw_eflags_T0();
|
||||
}
|
||||
gen_pop_update(s);
|
||||
gen_stack_update(s, (6 << s->dflag));
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
}
|
||||
s->is_jmp = 1;
|
||||
@@ -2997,6 +2973,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0x9a: /* lcall im */
|
||||
{
|
||||
unsigned int selector, offset;
|
||||
/* XXX: not restartable */
|
||||
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
offset = insn_get(s, ot);
|
||||
@@ -3613,6 +3590,8 @@ static uint16_t opc_write_flags[NB_OPS] = {
|
||||
[INDEX_op_cmpxchg8b] = CC_Z,
|
||||
[INDEX_op_lar] = CC_Z,
|
||||
[INDEX_op_lsl] = CC_Z,
|
||||
[INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C,
|
||||
[INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C,
|
||||
};
|
||||
|
||||
/* simpler form of an operation if no flags need to be generated */
|
||||
@@ -3684,61 +3663,10 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include "opc-i386.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include "opc-i386.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
|
||||
{
|
||||
const uint16_t *opc_ptr;
|
||||
const uint32_t *opparam_ptr;
|
||||
int c, n, i;
|
||||
|
||||
opc_ptr = opc_buf;
|
||||
opparam_ptr = opparam_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr++;
|
||||
n = op_nb_args[c];
|
||||
fprintf(logfile, "0x%04x: %s",
|
||||
(int)(opc_ptr - opc_buf - 1), op_str[c]);
|
||||
for(i = 0; i < n; i++) {
|
||||
fprintf(logfile, " 0x%x", opparam_ptr[i]);
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
if (c == INDEX_op_end)
|
||||
break;
|
||||
opparam_ptr += n;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 32
|
||||
#define OPC_BUF_SIZE 512
|
||||
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
static uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
static uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
static uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
|
||||
basic block 'tb'. If search_pc is TRUE, also generate PC
|
||||
information for each intermediate instruction. */
|
||||
static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
{
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
uint8_t *pc_ptr;
|
||||
@@ -3769,7 +3697,7 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
dc->is_jmp = 0;
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
pc_ptr = pc_start;
|
||||
lj = -1;
|
||||
do {
|
||||
@@ -3801,10 +3729,10 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
/* we must store the eflags state if it is not already done */
|
||||
if (dc->is_jmp != 3) {
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
if (dc->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(dc->cc_op);
|
||||
if (dc->is_jmp != 1) {
|
||||
if (dc->is_jmp != DISAS_JUMP) {
|
||||
/* we add an additionnal jmp to update the simulated PC */
|
||||
gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
|
||||
}
|
||||
@@ -3816,15 +3744,13 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
}
|
||||
|
||||
*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, pc_ptr - pc_start,
|
||||
dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086);
|
||||
disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32);
|
||||
fprintf(logfile, "\n");
|
||||
|
||||
fprintf(logfile, "OP:\n");
|
||||
@@ -3848,98 +3774,13 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* return non zero if the very first instruction is invalid so that
|
||||
the virtual CPU can trigger an exception.
|
||||
|
||||
'*gen_code_size_ptr' contains the size of the generated code (host
|
||||
code).
|
||||
*/
|
||||
int cpu_x86_gen_code(TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr)
|
||||
{
|
||||
uint8_t *gen_code_buf;
|
||||
int gen_code_size;
|
||||
|
||||
if (gen_intermediate_code(tb, 0) < 0)
|
||||
return -1;
|
||||
|
||||
/* generate machine code */
|
||||
tb->tb_next_offset[0] = 0xffff;
|
||||
tb->tb_next_offset[1] = 0xffff;
|
||||
gen_code_buf = tb->tc_ptr;
|
||||
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
tb->tb_jmp_offset,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
gen_opc_buf, gen_opparam_buf);
|
||||
flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
|
||||
|
||||
*gen_code_size_ptr = gen_code_size;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
|
||||
disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include "opc-i386.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
/* The simulated PC corresponding to
|
||||
'searched_pc' in the generated code is searched. 0 is returned if
|
||||
found. *found_pc contains the found PC.
|
||||
*/
|
||||
int cpu_x86_search_pc(TranslationBlock *tb,
|
||||
uint32_t *found_pc, unsigned long searched_pc)
|
||||
{
|
||||
int j, c;
|
||||
unsigned long tc_ptr;
|
||||
uint16_t *opc_ptr;
|
||||
|
||||
if (gen_intermediate_code(tb, 1) < 0)
|
||||
return -1;
|
||||
|
||||
/* find opc index corresponding to search_pc */
|
||||
tc_ptr = (unsigned long)tb->tc_ptr;
|
||||
if (searched_pc < tc_ptr)
|
||||
return -1;
|
||||
j = 0;
|
||||
opc_ptr = gen_opc_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr;
|
||||
if (c == INDEX_op_end)
|
||||
return -1;
|
||||
tc_ptr += opc_copy_size[c];
|
||||
if (searched_pc < tc_ptr)
|
||||
break;
|
||||
opc_ptr++;
|
||||
}
|
||||
j = opc_ptr - gen_opc_buf;
|
||||
/* now find start of instruction before */
|
||||
while (gen_opc_instr_start[j] == 0)
|
||||
j--;
|
||||
*found_pc = gen_opc_pc[j];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
CPUX86State *cpu_x86_init(void)
|
||||
{
|
||||
CPUX86State *env;
|
||||
int i;
|
||||
static int inited;
|
||||
|
||||
cpu_x86_tblocks_init();
|
||||
cpu_exec_init();
|
||||
|
||||
env = malloc(sizeof(CPUX86State));
|
||||
if (!env)
|
||||
@@ -3956,7 +3797,6 @@ CPUX86State *cpu_x86_init(void)
|
||||
if (!inited) {
|
||||
inited = 1;
|
||||
optimize_flags_init();
|
||||
page_init();
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Host code generation
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#define IN_OP_I386
|
||||
#include "cpu-" TARGET_ARCH ".h"
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "dyngen.h"
|
||||
#include "op-" TARGET_ARCH ".h"
|
||||
|
||||
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
uint32_t gen_opc_pc[OPC_BUF_SIZE];
|
||||
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
|
||||
{
|
||||
const uint16_t *opc_ptr;
|
||||
const uint32_t *opparam_ptr;
|
||||
int c, n, i;
|
||||
|
||||
opc_ptr = opc_buf;
|
||||
opparam_ptr = opparam_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr++;
|
||||
n = op_nb_args[c];
|
||||
fprintf(logfile, "0x%04x: %s",
|
||||
(int)(opc_ptr - opc_buf - 1), op_str[c]);
|
||||
for(i = 0; i < n; i++) {
|
||||
fprintf(logfile, " 0x%x", opparam_ptr[i]);
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
if (c == INDEX_op_end)
|
||||
break;
|
||||
opparam_ptr += n;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* return non zero if the very first instruction is invalid so that
|
||||
the virtual CPU can trigger an exception.
|
||||
|
||||
'*gen_code_size_ptr' contains the size of the generated code (host
|
||||
code).
|
||||
*/
|
||||
int cpu_gen_code(TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr)
|
||||
{
|
||||
uint8_t *gen_code_buf;
|
||||
int gen_code_size;
|
||||
|
||||
if (gen_intermediate_code(tb, 0) < 0)
|
||||
return -1;
|
||||
|
||||
/* generate machine code */
|
||||
tb->tb_next_offset[0] = 0xffff;
|
||||
tb->tb_next_offset[1] = 0xffff;
|
||||
gen_code_buf = tb->tc_ptr;
|
||||
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
tb->tb_jmp_offset,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
gen_opc_buf, gen_opparam_buf);
|
||||
*gen_code_size_ptr = gen_code_size;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
|
||||
disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
/* The simulated PC corresponding to
|
||||
'searched_pc' in the generated code is searched. 0 is returned if
|
||||
found. *found_pc contains the found PC.
|
||||
*/
|
||||
int cpu_search_pc(TranslationBlock *tb,
|
||||
uint32_t *found_pc, unsigned long searched_pc)
|
||||
{
|
||||
int j, c;
|
||||
unsigned long tc_ptr;
|
||||
uint16_t *opc_ptr;
|
||||
|
||||
if (gen_intermediate_code(tb, 1) < 0)
|
||||
return -1;
|
||||
|
||||
/* find opc index corresponding to search_pc */
|
||||
tc_ptr = (unsigned long)tb->tc_ptr;
|
||||
if (searched_pc < tc_ptr)
|
||||
return -1;
|
||||
j = 0;
|
||||
opc_ptr = gen_opc_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr;
|
||||
if (c == INDEX_op_end)
|
||||
return -1;
|
||||
tc_ptr += opc_copy_size[c];
|
||||
if (searched_pc < tc_ptr)
|
||||
break;
|
||||
opc_ptr++;
|
||||
}
|
||||
j = opc_ptr - gen_opc_buf;
|
||||
/* now find start of instruction before */
|
||||
while (gen_opc_instr_start[j] == 0)
|
||||
j--;
|
||||
*found_pc = gen_opc_pc[j];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user