Compare commits
136 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fcf8fcc8e5 | ||
|
dbc5594cb6 | ||
|
4cbb86e1c4 | ||
|
f513a41a3d | ||
|
c106152d26 | ||
|
facc68be25 | ||
|
3ff0631ed9 | ||
|
b1ba65744e | ||
|
b67d59594e | ||
|
2e255c6b9f | ||
|
3f33731662 | ||
|
d05e66d217 | ||
|
2d80ae8987 | ||
|
17383a2a2a | ||
|
9257a9e49c | ||
|
70a194b930 | ||
|
2573109866 | ||
|
9dfa5b421d | ||
|
9da8ba18e6 | ||
|
76bc683820 | ||
|
3b22c4707d | ||
|
96e6e05372 | ||
|
e2222c3924 | ||
|
31e8f3c894 | ||
|
9368caf64d | ||
|
38e584a072 | ||
|
313aa56710 | ||
|
4cbf74b6b8 | ||
|
33417e7025 | ||
|
4021dab059 | ||
|
626df76abb | ||
|
abcd5da72e | ||
|
97a847bc03 | ||
|
ab93bbe2ae | ||
|
0f0b726444 | ||
|
b92e5a22ec | ||
|
17b0018b42 | ||
|
39cf780327 | ||
|
e89f66eca9 | ||
|
b6d78bfa0d | ||
|
c33a346edf | ||
|
61a2ad53cb | ||
|
2c1794c42e | ||
|
8a4c1cc411 | ||
|
330d0414a5 | ||
|
3802ce26a1 | ||
|
4abe615b84 | ||
|
a412ac572f | ||
|
b2b5fb228f | ||
|
8f186479e2 | ||
|
4c3a88a284 | ||
|
d6b4936796 | ||
|
9d0fe224f4 | ||
|
6e0374f6b5 | ||
|
9e5f5284b3 | ||
|
c596ed1713 | ||
|
91cf4d88fb | ||
|
a96fc003bd | ||
|
d44b29c21e | ||
|
070893f425 | ||
|
9621339dca | ||
|
ede28208d8 | ||
|
7739f36e38 | ||
|
f8c8799840 | ||
|
43fff2384e | ||
|
1b21b62ab4 | ||
|
a1516e92b6 | ||
|
6fb883e8e3 | ||
|
6e295807ac | ||
|
f2674e31e0 | ||
|
4690764bba | ||
|
3c1cf9fa86 | ||
|
1f47a9223e | ||
|
33e3963e1b | ||
|
cd4c3e888a | ||
|
7916e2245d | ||
|
abd0aaff03 | ||
|
c39d5b78f6 | ||
|
4d40895f2c | ||
|
e477b8b81b | ||
|
b118d61e55 | ||
|
2f62b397b5 | ||
|
907a5b2690 | ||
|
0849bf0821 | ||
|
305034817d | ||
|
ec410fc9ce | ||
|
68a7931591 | ||
|
c9159e5321 | ||
|
8c9b861e74 | ||
|
5797fa5d7e | ||
|
8ef9a8ece3 | ||
|
fc01f7e7f9 | ||
|
3b0dca51b0 | ||
|
da415d54bf | ||
|
b4608c0455 | ||
|
d5a0b50c6f | ||
|
87858c89ca | ||
|
a6f816d697 | ||
|
0ad041d476 | ||
|
1eb20527c8 | ||
|
e3e86d56c4 | ||
|
1df912cf9e | ||
|
4351832355 | ||
|
59faf6d6a6 | ||
|
725af7d460 | ||
|
a363e34cc5 | ||
|
ea041c0e33 | ||
|
83479e770d | ||
|
e2f2289897 | ||
|
844c72eccc | ||
|
6b1534cc67 | ||
|
e8cd23de30 | ||
|
7c2d6a781c | ||
|
f1510b2cc3 | ||
|
357a94326c | ||
|
0824d6fc67 | ||
|
6c0372d30b | ||
|
92ccca6aa8 | ||
|
dd3587f38e | ||
|
7d83131cc5 | ||
|
66e85a21c7 | ||
|
90a9fdae1f | ||
|
3fb2ded1d5 | ||
|
f76af4b3f3 | ||
|
717fc2ad8d | ||
|
c05bab779e | ||
|
a52c757c9f | ||
|
970a87a6bb | ||
|
d8bc1fd0ae | ||
|
7501267e22 | ||
|
13b55754af | ||
|
972ddf7840 | ||
|
322d0c6657 | ||
|
2054396a04 | ||
|
039de852ec | ||
|
144c345daf |
57
Changelog
57
Changelog
@@ -1,19 +1,66 @@
|
||||
version 0.4.4:
|
||||
|
||||
- full hardware level VGA emulation
|
||||
- graphical display with SDL
|
||||
- added PS/2 mouse and keyboard emulation
|
||||
- popw (%esp) fix
|
||||
- mov to/from segment data width fix
|
||||
- added real mode support
|
||||
- added Bochs BIOS and LGPL'ed VGA BIOS loader in vl
|
||||
- m68k host port (Richard Zidlicky)
|
||||
- partial soft MMU support for memory mapped I/Os
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping thru string operations
|
||||
|
||||
version 0.4.3:
|
||||
|
||||
- x86 exception fix in case of nop instruction.
|
||||
- gcc 3.2.2 bug workaround (RedHat 9 fix)
|
||||
- sparc and Alpha host fixes
|
||||
- many ARM target fixes: 'ls' and 'bash' can be launched.
|
||||
|
||||
version 0.4.2:
|
||||
|
||||
- many exception handling fixes (can compile a Linux kernel inside vl)
|
||||
- IDE emulation support
|
||||
- initial GDB stub support
|
||||
- deferred update support for disk images (Rusty Russell)
|
||||
- accept User Mode Linux Copy On Write disk images
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
- more accurate timer support in vl.
|
||||
- more reliable NE2000 probe in vl.
|
||||
- added 2.5.66 kernel in vl-test.
|
||||
- added VLTMPDIR environment variable in vl.
|
||||
|
||||
version 0.4:
|
||||
|
||||
- initial support for ring 0 x86 processor emulation
|
||||
- fixed signal handling for correct dosemu DPMI emulation
|
||||
- fast x86 MMU emulation with mmap()
|
||||
- fixed popl (%esp) case
|
||||
- Linux kernel can be executed by QEMU with the 'vl' command.
|
||||
|
||||
version 0.3:
|
||||
|
||||
- initial support for ARM emulation
|
||||
- added fnsave, frstor, fnstenv, fldenv FPU instructions
|
||||
- added FPU register save in signal emulation
|
||||
- ARM port
|
||||
- initial 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)
|
||||
- flock support (Rusty Russel)
|
||||
- ugetrlimit support (Rusty Russel)
|
||||
- fstat64 fix (Rusty Russel)
|
||||
- PowerPC disassembly and ELF symbols output (Rusty Russell)
|
||||
- flock support (Rusty Russell)
|
||||
- ugetrlimit support (Rusty Russell)
|
||||
- fstat64 fix (Rusty Russell)
|
||||
- initial Alpha port (Falk Hueffner)
|
||||
- initial IA64 port (Matt Wilson)
|
||||
- initial Sparc and Sparc64 port (David S. Miller)
|
||||
|
216
Makefile
216
Makefile
@@ -1,190 +1,48 @@
|
||||
include config.mak
|
||||
include config-host.mak
|
||||
|
||||
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
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(GCC_MAJOR),3)
|
||||
OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-Wl,-T,i386.ld
|
||||
else
|
||||
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
||||
# that the kernel ELF loader considers as an executable. I think this
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,ppc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,s390.ld
|
||||
endif
|
||||
|
||||
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)
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,alpha.ld
|
||||
endif
|
||||
|
||||
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
|
||||
endif
|
||||
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
LIBS+=-lm
|
||||
TOOLS=vlmkcow
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
all: dyngen $(TOOLS) qemu-doc.html
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
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
|
||||
vlmkcow: vlmkcow.o
|
||||
$(HOST_CC) -o $@ $^ $(LIBS)
|
||||
|
||||
# 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
|
||||
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 ($(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
|
||||
endif
|
||||
|
||||
all: qemu qemu-doc.html
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
|
||||
endif
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
dyngen: dyngen.c
|
||||
$(HOST_CC) -O2 -Wall -g $< -o $@
|
||||
|
||||
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -o $@ $<
|
||||
|
||||
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
|
||||
./dyngen -c -o $@ $<
|
||||
|
||||
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
|
||||
dyngen: dyngen.o
|
||||
$(HOST_CC) -o $@ $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
$(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(MAKE) -C tests clean
|
||||
rm -f *.o *.a *~ qemu dyngen TAGS
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.a $(TOOLS) dyngen TAGS
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
rm -f config.mak config.h
|
||||
rm -f config-host.mak config-host.h
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -f $$d/config.h $$d/config.mak || exit 1 ; \
|
||||
done
|
||||
|
||||
install: qemu
|
||||
install -m 755 -s qemu $(prefix)/bin
|
||||
install: all
|
||||
mkdir -p $(prefix)/bin
|
||||
install -m 755 -s $(TOOLS) $(prefix)/bin
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
# various test targets
|
||||
test speed: qemu
|
||||
test speed: all
|
||||
make -C tests $@
|
||||
|
||||
TAGS:
|
||||
@@ -196,22 +54,24 @@ qemu-doc.html: qemu-doc.texi
|
||||
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
configure \
|
||||
configure Makefile Makefile.target \
|
||||
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
Makefile elf.h elfload.c main.c signal.c qemu.h \
|
||||
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 \
|
||||
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld m68k.ld \
|
||||
vl.c i386-vl.ld vl.h block.c vlmkcow.c vga.c vga_template.h sdl.c \
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h cpu-defs.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c gdbstub.c bswap.h \
|
||||
cpu-i386.h op-i386.c helper-i386.c helper2-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
|
||||
ops_mem.h softmmu_template.h softmmu_header.h \
|
||||
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
|
||||
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
|
||||
arm-dis.c \
|
||||
tests/Makefile \
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
|
||||
tests/hello.c tests/hello \
|
||||
tests/hello-i386.c tests/hello-i386 \
|
||||
tests/hello-arm.c tests/hello-arm \
|
||||
tests/sha1.c \
|
||||
tests/testsig.c tests/testclone.c tests/testthread.c \
|
||||
|
206
Makefile.target
Normal file
206
Makefile.target
Normal file
@@ -0,0 +1,206 @@
|
||||
include config.mak
|
||||
|
||||
VPATH=$(SRC_PATH)
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-I.
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen
|
||||
ifndef CONFIG_SOFTMMU
|
||||
PROGS=qemu
|
||||
endif
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
OP_CFLAGS+= -falign-functions=0
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
|
||||
else
|
||||
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
|
||||
# that the kernel ELF loader considers as an executable. I think this
|
||||
# is the simplest way to make it self virtualizable!
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
PROGS+=vl
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
|
||||
endif
|
||||
|
||||
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
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),m68k)
|
||||
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,m68k.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE
|
||||
LIBS+=-lm
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
# cpu emulator library
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o helper2-i386.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
LIBOBJS+=translate-arm.o op-arm.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
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 ($(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
|
||||
endif
|
||||
|
||||
all: $(PROGS) qemu-doc.html
|
||||
|
||||
qemu: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
VL_OBJS=vl.o block.o vga.o
|
||||
ifdef CONFIG_SDL
|
||||
VL_OBJS+=sdl.o
|
||||
SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl
|
||||
endif
|
||||
|
||||
vl: $(VL_OBJS) libqemu.a
|
||||
$(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS)
|
||||
|
||||
sdl.o: sdl.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
|
||||
|
||||
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN)
|
||||
$(DYNGEN) -o $@ $<
|
||||
|
||||
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN)
|
||||
$(DYNGEN) -c -o $@ $<
|
||||
|
||||
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 ops_template_mem.h ops_mem.h
|
||||
|
||||
op-arm.o: op-arm.c op-arm-template.h
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) \
|
||||
gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h op-$(TARGET_ARCH).h
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
22
README
22
README
@@ -45,22 +45,30 @@ 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
|
||||
host gcc binutils glibc linux distribution
|
||||
----------------------------------------------------------------------
|
||||
x86 2.95.2 2.13.2 2.1.3 2.4.18
|
||||
3.2 2.13.2 2.1.3 2.4.18
|
||||
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
|
||||
3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
|
||||
|
||||
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2
|
||||
PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
|
||||
3.2
|
||||
|
||||
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2]
|
||||
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
|
||||
|
||||
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18
|
||||
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
|
||||
|
||||
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9-ac10-rmk2-np1-cerf2
|
||||
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
|
||||
|
||||
[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).
|
||||
[3] 2.4.9-ac10-rmk2-np1-cerf2
|
||||
|
||||
[4] gcc 2.95.x generates invalid code when using too many register
|
||||
variables. You must use gcc 3.x on PowerPC.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
13
TODO
13
TODO
@@ -1,16 +1,17 @@
|
||||
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
||||
fix cr0.TS emulation
|
||||
- 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()).
|
||||
- add gcc 2.96 test configure (some gcc3 flags are needed)
|
||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- add IPC syscalls
|
||||
- submit a patch to fix DOSEMU coopthreads
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- sysenter/sysexit emulation
|
||||
- SMP support
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- handle rare page fault cases (in particular if page fault in heplers or
|
||||
|
@@ -560,8 +560,8 @@ static arm_regname regnames[] =
|
||||
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
|
||||
};
|
||||
|
||||
/* Default to GCC register name set. */
|
||||
static unsigned int regname_selected = 1;
|
||||
/* Default to STD register name set. */
|
||||
static unsigned int regname_selected = 2;
|
||||
|
||||
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
|
||||
#define arm_regnames regnames[regname_selected].reg_names
|
||||
|
326
block.c
Normal file
326
block.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* QEMU System Emulator block driver
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
|
||||
struct BlockDriverState {
|
||||
int fd; /* if -1, only COW mappings */
|
||||
int64_t total_sectors;
|
||||
int read_only;
|
||||
|
||||
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
||||
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
||||
int cow_bitmap_size;
|
||||
int cow_fd;
|
||||
int64_t cow_sectors_offset;
|
||||
char filename[1024];
|
||||
};
|
||||
|
||||
BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int fd, cow_fd;
|
||||
int64_t size;
|
||||
char template[] = "/tmp/vl.XXXXXX";
|
||||
struct cow_header_v2 cow_header;
|
||||
struct stat st;
|
||||
|
||||
bs = malloc(sizeof(BlockDriverState));
|
||||
if(!bs)
|
||||
return NULL;
|
||||
bs->read_only = 0;
|
||||
bs->fd = -1;
|
||||
bs->cow_fd = -1;
|
||||
bs->cow_bitmap = NULL;
|
||||
strcpy(bs->filename, filename);
|
||||
|
||||
/* open standard HD image */
|
||||
fd = open(filename, O_RDWR | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
/* read only image on disk */
|
||||
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
perror(filename);
|
||||
goto fail;
|
||||
}
|
||||
if (!snapshot)
|
||||
bs->read_only = 1;
|
||||
}
|
||||
bs->fd = fd;
|
||||
|
||||
/* see if it is a cow image */
|
||||
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
|
||||
fprintf(stderr, "%s: could not read header\n", filename);
|
||||
goto fail;
|
||||
}
|
||||
if (cow_header.magic == htonl(COW_MAGIC) &&
|
||||
cow_header.version == htonl(COW_VERSION)) {
|
||||
/* cow image found */
|
||||
size = cow_header.size;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
size = bswap64(size);
|
||||
#endif
|
||||
bs->total_sectors = size / 512;
|
||||
|
||||
bs->cow_fd = fd;
|
||||
bs->fd = -1;
|
||||
if (cow_header.backing_file[0] != '\0') {
|
||||
if (stat(cow_header.backing_file, &st) != 0) {
|
||||
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
if (st.st_mtime != htonl(cow_header.mtime)) {
|
||||
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
bs->fd = fd;
|
||||
}
|
||||
/* mmap the bitmap */
|
||||
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
|
||||
bs->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, bs->cow_fd, 0);
|
||||
if (bs->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
||||
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
|
||||
snapshot = 0;
|
||||
} else {
|
||||
/* standard raw image */
|
||||
size = lseek64(fd, 0, SEEK_END);
|
||||
bs->total_sectors = size / 512;
|
||||
bs->fd = fd;
|
||||
}
|
||||
|
||||
if (snapshot) {
|
||||
/* create a temporary COW file */
|
||||
cow_fd = mkstemp(template);
|
||||
if (cow_fd < 0)
|
||||
goto fail;
|
||||
bs->cow_fd = cow_fd;
|
||||
unlink(template);
|
||||
|
||||
/* just need to allocate bitmap */
|
||||
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
|
||||
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
|
||||
bs->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (bs->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
bs->cow_bitmap = bs->cow_bitmap_addr;
|
||||
bs->cow_sectors_offset = 0;
|
||||
}
|
||||
|
||||
return bs;
|
||||
fail:
|
||||
bdrv_close(bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
/* we unmap the mapping so that it is written to the COW file */
|
||||
if (bs->cow_bitmap_addr)
|
||||
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
||||
if (bs->cow_fd >= 0)
|
||||
close(bs->cow_fd);
|
||||
if (bs->fd >= 0)
|
||||
close(bs->fd);
|
||||
free(bs);
|
||||
}
|
||||
|
||||
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
bitmap[bitnum / 8] |= (1 << (bitnum%8));
|
||||
}
|
||||
|
||||
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if first block has been changed (ie. current version is
|
||||
* in COW file). Set the number of continuous blocks for which that
|
||||
* is true. */
|
||||
static int is_changed(uint8_t *bitmap,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
int *num_same)
|
||||
{
|
||||
int changed;
|
||||
|
||||
if (!bitmap || nb_sectors == 0) {
|
||||
*num_same = nb_sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
changed = is_bit_set(bitmap, sector_num);
|
||||
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
|
||||
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
|
||||
break;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* commit COW file into the raw image */
|
||||
int bdrv_commit(BlockDriverState *bs)
|
||||
{
|
||||
int64_t i;
|
||||
uint8_t *cow_bitmap;
|
||||
|
||||
if (!bs->cow_bitmap) {
|
||||
fprintf(stderr, "Already committed to %s\n", bs->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bs->read_only) {
|
||||
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cow_bitmap = bs->cow_bitmap;
|
||||
for (i = 0; i < bs->total_sectors; i++) {
|
||||
if (is_bit_set(cow_bitmap, i)) {
|
||||
unsigned char sector[512];
|
||||
if (bdrv_read(bs, i, sector, 1) != 0) {
|
||||
fprintf(stderr, "Error reading sector %lli: aborting commit\n",
|
||||
(long long)i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make bdrv_write write to real file for a moment. */
|
||||
bs->cow_bitmap = NULL;
|
||||
if (bdrv_write(bs, i, sector, 1) != 0) {
|
||||
fprintf(stderr, "Error writing sector %lli: aborting commit\n",
|
||||
(long long)i);
|
||||
bs->cow_bitmap = cow_bitmap;
|
||||
return -1;
|
||||
}
|
||||
bs->cow_bitmap = cow_bitmap;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, n, fd;
|
||||
int64_t offset;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
/* no file, just return empty sectors */
|
||||
memset(buf, 0, n * 512);
|
||||
} else {
|
||||
offset += sector_num * 512;
|
||||
lseek64(fd, offset, SEEK_SET);
|
||||
ret = read(fd, buf, n * 512);
|
||||
if (ret != n * 512) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, fd, i;
|
||||
int64_t offset, retl;
|
||||
|
||||
if (bs->read_only)
|
||||
return -1;
|
||||
|
||||
if (bs->cow_bitmap) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
offset += sector_num * 512;
|
||||
retl = lseek64(fd, offset, SEEK_SET);
|
||||
if (retl == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret = write(fd, buf, nb_sectors * 512);
|
||||
if (ret != nb_sectors * 512) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bs->cow_bitmap) {
|
||||
for (i = 0; i < nb_sectors; i++)
|
||||
set_bit(bs->cow_bitmap, sector_num + i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
||||
{
|
||||
*nb_sectors_ptr = bs->total_sectors;
|
||||
}
|
84
bswap.h
Normal file
84
bswap.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef BSWAP_H
|
||||
#define BSWAP_H
|
||||
|
||||
#include "config-host.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
||||
#define bswap_16(x) \
|
||||
({ \
|
||||
uint16_t __x = (x); \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
|
||||
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
|
||||
})
|
||||
|
||||
#define bswap_32(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 bswap_64(x) \
|
||||
({ \
|
||||
uint64_t __x = (x); \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
|
||||
})
|
||||
|
||||
#endif /* !HAVE_BYTESWAP_H */
|
||||
|
||||
#if defined(__alpha__) || defined (__ia64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
#define HOST_LONG_BITS 32
|
||||
#endif
|
||||
|
||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return bswap_16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
{
|
||||
return bswap_32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
{
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
static inline void bswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static inline void bswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static inline void bswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
|
||||
#endif /* BSWAP_H */
|
240
configure
vendored
240
configure
vendored
@@ -15,7 +15,6 @@ TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
|
||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
|
||||
TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
prefix="/usr/local"
|
||||
@@ -27,12 +26,11 @@ host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
target_cpu="x86"
|
||||
target_bigendian="default"
|
||||
cpu=`uname -m`
|
||||
target_list="i386 i386-softmmu arm"
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="x86"
|
||||
cpu="i386"
|
||||
;;
|
||||
armv4l)
|
||||
cpu="armv4l"
|
||||
@@ -58,6 +56,9 @@ case "$cpu" in
|
||||
ia64)
|
||||
cpu="ia64"
|
||||
;;
|
||||
m68k)
|
||||
cpu="m68k"
|
||||
;;
|
||||
*)
|
||||
cpu="unknown"
|
||||
;;
|
||||
@@ -71,6 +72,26 @@ case $targetos in
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
##########################################
|
||||
# SDL probe
|
||||
|
||||
cat > $TMPC << EOF
|
||||
#include <SDL.h>
|
||||
#undef main /* We don't want SDL to override our main() */
|
||||
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
|
||||
EOF
|
||||
|
||||
sdl_too_old=no
|
||||
sdl=no
|
||||
if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 2> /dev/null ; then
|
||||
_sdlversion=`sdl-config --version | sed 's/[^0-9]//g'`
|
||||
if test "$_sdlversion" -lt 121 ; then
|
||||
sdl_too_old=yes
|
||||
else
|
||||
sdl=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
# find source path
|
||||
# XXX: we assume an absolute path is given when launching configure,
|
||||
# except in './configure' case.
|
||||
@@ -104,16 +125,14 @@ 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"
|
||||
--target-list=*) target_list=${opt#--target-list=}
|
||||
;;
|
||||
--enable-gprof) gprof="yes"
|
||||
;;
|
||||
--static) static="yes"
|
||||
;;
|
||||
--disable-sdl) sdl="no"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -147,36 +166,21 @@ fi
|
||||
else
|
||||
|
||||
# if cross compiling, cannot launch a program, so make a static guess
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then
|
||||
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then
|
||||
bigendian="yes"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# check gcc version
|
||||
# check gcc options support
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
|
||||
return 0;
|
||||
#else
|
||||
#error gcc < 3.2
|
||||
#endif
|
||||
}
|
||||
EOF
|
||||
|
||||
gcc_major="2"
|
||||
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
|
||||
have_gcc3_options="no"
|
||||
if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
|
||||
have_gcc3_options="yes"
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
@@ -190,7 +194,7 @@ 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 " --target-list=LIST set target list [$target_list]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
@@ -210,92 +214,142 @@ 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 "target list $target_list"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "static build $static"
|
||||
echo "SDL support $sdl"
|
||||
if test $sdl_too_old = "yes"; then
|
||||
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
|
||||
fi
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
config_mak="config-host.mak"
|
||||
config_h="config-host.h"
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > config.mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
||||
echo "Creating $config_mak and $config_h"
|
||||
|
||||
echo "prefix=$prefix" >> config.mak
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
|
||||
echo "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
||||
echo "HOST_CC=$host_cc" >> config.mak
|
||||
echo "AR=$ar" >> config.mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
|
||||
echo "CFLAGS=$CFLAGS" >> config.mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> config.mak
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
echo "#define HOST_I386 1" >> $TMPH
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
echo "prefix=$prefix" >> $config_mak
|
||||
echo "MAKE=$make" >> $config_mak
|
||||
echo "CC=$cc" >> $config_mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
|
||||
fi
|
||||
echo "HOST_CC=$host_cc" >> $config_mak
|
||||
echo "AR=$ar" >> $config_mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
|
||||
echo "CFLAGS=$CFLAGS" >> $config_mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> $config_mak
|
||||
if test "$cpu" = "i386" ; then
|
||||
echo "ARCH=i386" >> $config_mak
|
||||
echo "#define HOST_I386 1" >> $config_h
|
||||
elif test "$cpu" = "armv4l" ; then
|
||||
echo "ARCH=arm" >> config.mak
|
||||
echo "#define HOST_ARM 1" >> $TMPH
|
||||
echo "ARCH=arm" >> $config_mak
|
||||
echo "#define HOST_ARM 1" >> $config_h
|
||||
elif test "$cpu" = "powerpc" ; then
|
||||
echo "ARCH=ppc" >> config.mak
|
||||
echo "#define HOST_PPC 1" >> $TMPH
|
||||
echo "ARCH=ppc" >> $config_mak
|
||||
echo "#define HOST_PPC 1" >> $config_h
|
||||
elif test "$cpu" = "mips" ; then
|
||||
echo "ARCH=mips" >> config.mak
|
||||
echo "#define HOST_MIPS 1" >> $TMPH
|
||||
echo "ARCH=mips" >> $config_mak
|
||||
echo "#define HOST_MIPS 1" >> $config_h
|
||||
elif test "$cpu" = "s390" ; then
|
||||
echo "ARCH=s390" >> config.mak
|
||||
echo "#define HOST_S390 1" >> $TMPH
|
||||
echo "ARCH=s390" >> $config_mak
|
||||
echo "#define HOST_S390 1" >> $config_h
|
||||
elif test "$cpu" = "alpha" ; then
|
||||
echo "ARCH=alpha" >> config.mak
|
||||
echo "#define HOST_ALPHA 1" >> $TMPH
|
||||
echo "ARCH=alpha" >> $config_mak
|
||||
echo "#define HOST_ALPHA 1" >> $config_h
|
||||
elif test "$cpu" = "sparc" ; then
|
||||
echo "ARCH=sparc" >> config.mak
|
||||
echo "#define HOST_SPARC 1" >> $TMPH
|
||||
echo "ARCH=sparc" >> $config_mak
|
||||
echo "#define HOST_SPARC 1" >> $config_h
|
||||
elif test "$cpu" = "sparc64" ; then
|
||||
echo "ARCH=sparc64" >> config.mak
|
||||
echo "#define HOST_SPARC64 1" >> $TMPH
|
||||
echo "ARCH=sparc64" >> $config_mak
|
||||
echo "#define HOST_SPARC64 1" >> $config_h
|
||||
elif test "$cpu" = "ia64" ; then
|
||||
echo "ARCH=ia64" >> config.mak
|
||||
echo "#define HOST_IA64 1" >> $TMPH
|
||||
echo "ARCH=ia64" >> $config_mak
|
||||
echo "#define HOST_IA64 1" >> $config_h
|
||||
elif test "$cpu" = "m68k" ; then
|
||||
echo "ARCH=m68k" >> config.mak
|
||||
echo "#define HOST_M68K 1" >> $TMPH
|
||||
else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> config.mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
|
||||
echo "WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
echo "#define HAVE_BYTESWAP_H 1" >> $config_h
|
||||
if test "$gprof" = "yes" ; then
|
||||
echo "TARGET_GPROF=yes" >> $config_mak
|
||||
echo "#define HAVE_GPROF 1" >> $config_h
|
||||
fi
|
||||
if test "$static" = "yes" ; then
|
||||
echo "CONFIG_STATIC=yes" >> $config_mak
|
||||
fi
|
||||
if test "$sdl" = "yes" ; then
|
||||
echo "CONFIG_SDL=yes" >> $config_mak
|
||||
echo "#define CONFIG_SDL 1" >> $config_h
|
||||
echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak
|
||||
echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak
|
||||
fi
|
||||
echo -n "VERSION=" >>$config_mak
|
||||
head $source_path/VERSION >>$config_mak
|
||||
echo "" >>$config_mak
|
||||
echo -n "#define QEMU_VERSION \"" >> $config_h
|
||||
head $source_path/VERSION >> $config_h
|
||||
echo "\"" >> $config_h
|
||||
|
||||
echo "SRC_PATH=$source_path" >> $config_mak
|
||||
echo "TARGET_DIRS=$target_list" >> $config_mak
|
||||
|
||||
for target in $target_list; do
|
||||
|
||||
target_dir="$target"
|
||||
config_mak=$target_dir/config.mak
|
||||
config_h=$target_dir/config.h
|
||||
target_cpu=`echo $target | cut -d '-' -f 1`
|
||||
target_bigendian="no"
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
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
|
||||
echo "Creating $config_mak, $config_h and $target_dir/Makefile"
|
||||
|
||||
mkdir -p $target_dir
|
||||
ln -sf $source_path/Makefile.target $target_dir/Makefile
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
|
||||
echo "include ../config-host.mak" >> $config_mak
|
||||
echo "#include \"../config-host.h\"" >> $config_h
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $config_h
|
||||
|
||||
if test "$target_cpu" = "i386" ; then
|
||||
echo "TARGET_ARCH=i386" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"i386\"" >> $config_h
|
||||
echo "#define TARGET_I386 1" >> $config_h
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
echo "TARGET_ARCH=arm" >> config.mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $TMPH
|
||||
echo "#define TARGET_ARM 1" >> $TMPH
|
||||
echo "TARGET_ARCH=arm" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $config_h
|
||||
echo "#define TARGET_ARM 1" >> $config_h
|
||||
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
|
||||
echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
if test "$target_softmmu" = "yes" ; then
|
||||
echo "CONFIG_SOFTMMU=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTMMU 1" >> $config_h
|
||||
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
|
||||
echo -n "#define QEMU_VERSION \"" >> $TMPH
|
||||
head $source_path/VERSION >> $TMPH
|
||||
echo "\"" >> $TMPH
|
||||
done # for target in $targets
|
||||
|
||||
# build tree in object directory if source path is different from current one
|
||||
if test "$source_path_used" = "yes" ; then
|
||||
@@ -308,13 +362,5 @@ if test "$source_path_used" = "yes" ; then
|
||||
ln -sf $source_path/$f $f
|
||||
done
|
||||
fi
|
||||
echo "SRC_PATH=$source_path" >> config.mak
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
mv -f $TMPH config.h
|
||||
else
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS
|
||||
|
32
cpu-all.h
32
cpu-all.h
@@ -140,6 +140,7 @@ static inline void stfl(void *ptr, float 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 ! */
|
||||
@@ -302,6 +303,35 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* SINGLE_CPU_DEFINES */
|
||||
|
||||
#define DEFAULT_GDBSTUB_PORT 1234
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||
extern CPUState *cpu_single_env;
|
||||
|
||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||
void cpu_interrupt(CPUState *s, int mask);
|
||||
|
||||
int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
|
||||
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
|
||||
void cpu_single_step(CPUState *env, int enabled);
|
||||
|
||||
/* memory API */
|
||||
|
||||
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
||||
typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
|
||||
|
||||
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
|
||||
long phys_offset);
|
||||
int cpu_register_io_memory(int io_index,
|
||||
CPUReadMemoryFunc **mem_read,
|
||||
CPUWriteMemoryFunc **mem_write);
|
||||
|
||||
/* gdb stub API */
|
||||
extern int gdbstub_fd;
|
||||
CPUState *cpu_gdbstub_get_env(void *opaque);
|
||||
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port);
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
|
@@ -20,12 +20,10 @@
|
||||
#ifndef CPU_ARM_H
|
||||
#define CPU_ARM_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
#include "cpu-defs.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];
|
||||
@@ -40,6 +38,8 @@ typedef struct CPUARMState {
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
struct TranslationBlock *current_tb;
|
||||
int user_mode_only;
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
@@ -47,7 +47,6 @@ typedef struct 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
|
||||
|
39
cpu-defs.h
Normal file
39
cpu-defs.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* common defines for all 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_DEFS_H
|
||||
#define CPU_DEFS_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
||||
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
|
||||
|
||||
#define MAX_BREAKPOINTS 32
|
||||
|
||||
#define CPU_TLB_SIZE 256
|
||||
|
||||
typedef struct CPUTLBEntry {
|
||||
uint32_t address;
|
||||
uint32_t addend;
|
||||
} CPUTLBEntry;
|
||||
|
||||
#endif
|
377
cpu-exec.c
377
cpu-exec.c
@@ -71,7 +71,7 @@ int cpu_exec(CPUState *env1)
|
||||
#ifdef __sparc__
|
||||
int saved_i7, tmp_T0;
|
||||
#endif
|
||||
int code_gen_size, ret;
|
||||
int code_gen_size, ret, interrupt_request;
|
||||
void (*gen_func)(void);
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
@@ -139,147 +139,193 @@ int cpu_exec(CPUState *env1)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
env->interrupt_request = 0;
|
||||
env->exception_index = -1;
|
||||
|
||||
/* 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) {
|
||||
for(;;) {
|
||||
if (setjmp(env->jmp_env) == 0) {
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (env->exception_index >= 0) {
|
||||
if (env->exception_index >= EXCP_INTERRUPT) {
|
||||
/* exit request from the cpu execution loop */
|
||||
ret = env->exception_index;
|
||||
break;
|
||||
} else if (env->user_mode_only) {
|
||||
/* if user mode only, we simulate a fake exception
|
||||
which will be hanlded outside the cpu execution
|
||||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->regs[R_EAX] = EAX;
|
||||
env->regs[R_EBX] = EBX;
|
||||
env->regs[R_ECX] = ECX;
|
||||
env->regs[R_EDX] = EDX;
|
||||
env->regs[R_ESI] = ESI;
|
||||
env->regs[R_EDI] = EDI;
|
||||
env->regs[R_EBP] = EBP;
|
||||
env->regs[R_ESP] = ESP;
|
||||
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);
|
||||
do_interrupt_user(env->exception_index,
|
||||
env->exception_is_int,
|
||||
env->error_code,
|
||||
env->exception_next_eip);
|
||||
#endif
|
||||
ret = env->exception_index;
|
||||
break;
|
||||
} else {
|
||||
#if defined(TARGET_I386)
|
||||
/* simulate a real cpu exception. On i386, it can
|
||||
trigger new exceptions, but we do not handle
|
||||
double or triple faults yet. */
|
||||
do_interrupt(env->exception_index,
|
||||
env->exception_is_int,
|
||||
env->error_code,
|
||||
env->exception_next_eip, 0);
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
}
|
||||
T0 = 0; /* force lookup of first TB */
|
||||
for(;;) {
|
||||
#ifdef __sparc__
|
||||
/* g1 can be modified by some libc? functions */
|
||||
tmp_T0 = T0;
|
||||
#endif
|
||||
interrupt_request = env->interrupt_request;
|
||||
if (__builtin_expect(interrupt_request, 0)) {
|
||||
#if defined(TARGET_I386)
|
||||
/* if hardware interrupt pending, we execute it */
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->eflags & IF_MASK) &&
|
||||
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
||||
int intno;
|
||||
intno = cpu_x86_get_pic_interrupt(env);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
||||
}
|
||||
do_interrupt(intno, 0, 0, 0, 1);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
#ifdef __sparc__
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
T0 = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_EXIT) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
env->regs[R_EAX] = EAX;
|
||||
env->regs[R_EBX] = EBX;
|
||||
env->regs[R_ECX] = ECX;
|
||||
env->regs[R_EDX] = EDX;
|
||||
env->regs[R_ESI] = ESI;
|
||||
env->regs[R_EDI] = EDI;
|
||||
env->regs[R_EBP] = EBP;
|
||||
env->regs[R_ESP] = ESP;
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
|
||||
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);
|
||||
env->cpsr = compute_cpsr();
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
env->cpsr &= ~0xf0000000;
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
/* we record a subset of the CPU state. It will
|
||||
always be the same before a given translated block
|
||||
is executed. */
|
||||
#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 |
|
||||
(unsigned long)env->seg_cache[R_ES].base |
|
||||
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
|
||||
GEN_FLAG_ADDSEG_SHIFT;
|
||||
if (!(env->eflags & VM_MASK)) {
|
||||
flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
|
||||
} else {
|
||||
/* NOTE: a dummy CPL is kept */
|
||||
flags |= (1 << GEN_FLAG_VM_SHIFT);
|
||||
flags |= (3 << GEN_FLAG_CPL_SHIFT);
|
||||
}
|
||||
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
|
||||
cs_base = env->seg_cache[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
flags = env->hflags;
|
||||
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
|
||||
cs_base = env->segs[R_CS].base;
|
||||
pc = cs_base + env->eip;
|
||||
#elif defined(TARGET_ARM)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->regs[15];
|
||||
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) {
|
||||
spin_lock(&tb_lock);
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
|
||||
flags);
|
||||
if (!tb) {
|
||||
/* flush must be done */
|
||||
tb_flush();
|
||||
/* cannot fail at this point */
|
||||
spin_lock(&tb_lock);
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
/* don't forget to invalidate previous TB info */
|
||||
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
|
||||
T0 = 0;
|
||||
}
|
||||
tc_ptr = code_gen_ptr;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
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
|
||||
can leave it */
|
||||
if (!tb) {
|
||||
/* flush must be done */
|
||||
tb_flush();
|
||||
/* cannot fail at this point */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
/* don't forget to invalidate previous TB info */
|
||||
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
|
||||
T0 = 0;
|
||||
}
|
||||
tc_ptr = code_gen_ptr;
|
||||
tb->tc_ptr = tc_ptr;
|
||||
tb->cs_base = (unsigned long)cs_base;
|
||||
tb->flags = flags;
|
||||
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
tb_link(tb);
|
||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||
spin_unlock(&tb_lock);
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
}
|
||||
#endif
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
tb_link(tb);
|
||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
|
||||
(long)tb->tc_ptr, (long)tb->pc,
|
||||
lookup_symbol((void *)tb->pc));
|
||||
}
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
|
||||
(long)tb->tc_ptr, (long)tb->pc,
|
||||
lookup_symbol((void *)tb->pc));
|
||||
}
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
T0 = tmp_T0;
|
||||
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;
|
||||
/* see if we can patch the calling TB. */
|
||||
if (T0 != 0) {
|
||||
spin_lock(&tb_lock);
|
||||
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
|
||||
spin_unlock(&tb_lock);
|
||||
}
|
||||
tc_ptr = tb->tc_ptr;
|
||||
env->current_tb = tb;
|
||||
/* execute the generated code */
|
||||
gen_func = (void *)tc_ptr;
|
||||
#if defined(__sparc__)
|
||||
__asm__ __volatile__("call %0\n\t"
|
||||
"mov %%o7,%%i0"
|
||||
: /* no outputs */
|
||||
: "r" (gen_func)
|
||||
: "i0", "i1", "i2", "i3", "i4", "i5");
|
||||
__asm__ __volatile__("call %0\n\t"
|
||||
"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");
|
||||
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();
|
||||
gen_func();
|
||||
#endif
|
||||
env->current_tb = NULL;
|
||||
/* reset soft MMU for next block (it can currently
|
||||
only be set by a memory fault) */
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
|
||||
if (env->hflags & HF_SOFTMMU_MASK) {
|
||||
env->hflags &= ~HF_SOFTMMU_MASK;
|
||||
/* do not allow linking to another block */
|
||||
T0 = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
ret = env->exception_index;
|
||||
} /* for(;;) */
|
||||
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
@@ -311,12 +357,7 @@ int cpu_exec(CPUState *env1)
|
||||
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);
|
||||
}
|
||||
env->cpsr = compute_cpsr();
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -330,12 +371,6 @@ int cpu_exec(CPUState *env1)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -344,16 +379,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
|
||||
saved_env = env;
|
||||
env = s;
|
||||
if (env->eflags & VM_MASK) {
|
||||
SegmentCache *sc;
|
||||
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
|
||||
selector &= 0xffff;
|
||||
sc = &env->seg_cache[seg_reg];
|
||||
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
|
||||
so we must load them here */
|
||||
sc->base = (void *)(selector << 4);
|
||||
sc->limit = 0xffff;
|
||||
sc->seg_32bit = 0;
|
||||
env->segs[seg_reg] = selector;
|
||||
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
||||
(uint8_t *)(selector << 4), 0xffff, 0);
|
||||
} else {
|
||||
load_seg(seg_reg, selector, 0);
|
||||
}
|
||||
@@ -398,6 +427,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
|
||||
#include <signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
/* 'pc' is the host PC at which the exception was raised. 'address' is
|
||||
the effective address of the memory exception. 'is_write' is 1 if a
|
||||
write caused the exception and otherwise 0'. 'old_set' is the
|
||||
@@ -407,42 +438,59 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
uint32_t found_pc;
|
||||
|
||||
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address)) {
|
||||
return 1;
|
||||
}
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
return 1; /* the MMU fault was handled without causing real CPU fault */
|
||||
/* now we have a real cpu fault */
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
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;
|
||||
cpu_restore_state(tb, env, pc);
|
||||
}
|
||||
if (ret == 1) {
|
||||
#if 0
|
||||
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
|
||||
env->eip, env->cr[2], env->error_code);
|
||||
#endif
|
||||
/* 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));
|
||||
raise_exception_err(EXCP0E_PAGE, env->error_code);
|
||||
} else {
|
||||
/* activate soft MMU for this block */
|
||||
env->hflags |= HF_SOFTMMU_MASK;
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
cpu_loop_exit();
|
||||
}
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
env->regs[15] = found_pc;
|
||||
/* XXX: do more */
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
/* XXX: do more */
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
/* never comes here */
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
@@ -568,8 +616,25 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
&uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__mc68000)
|
||||
|
||||
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[16];
|
||||
/* 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
|
||||
#error host CPU specific signal handler needed
|
||||
|
||||
#endif
|
||||
|
192
cpu-i386.h
192
cpu-i386.h
@@ -20,8 +20,7 @@
|
||||
#ifndef CPU_I386_H
|
||||
#define CPU_I386_H
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
#include "cpu-defs.h"
|
||||
|
||||
#define R_EAX 0
|
||||
#define R_ECX 1
|
||||
@@ -50,7 +49,8 @@
|
||||
|
||||
/* segment descriptor fields */
|
||||
#define DESC_G_MASK (1 << 23)
|
||||
#define DESC_B_MASK (1 << 22)
|
||||
#define DESC_B_SHIFT 22
|
||||
#define DESC_B_MASK (1 << DESC_B_SHIFT)
|
||||
#define DESC_AVL_MASK (1 << 20)
|
||||
#define DESC_P_MASK (1 << 15)
|
||||
#define DESC_DPL_SHIFT 13
|
||||
@@ -73,6 +73,10 @@
|
||||
#define CC_S 0x0080
|
||||
#define CC_O 0x0800
|
||||
|
||||
#define TF_SHIFT 8
|
||||
#define IOPL_SHIFT 12
|
||||
#define VM_SHIFT 17
|
||||
|
||||
#define TF_MASK 0x00000100
|
||||
#define IF_MASK 0x00000200
|
||||
#define DF_MASK 0x00000400
|
||||
@@ -85,6 +89,77 @@
|
||||
#define VIP_MASK 0x00100000
|
||||
#define ID_MASK 0x00200000
|
||||
|
||||
/* hidden flags - used internally by qemu to represent additionnal cpu
|
||||
states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid
|
||||
using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
|
||||
with eflags. */
|
||||
/* current cpl */
|
||||
#define HF_CPL_SHIFT 0
|
||||
/* true if soft mmu is being used */
|
||||
#define HF_SOFTMMU_SHIFT 2
|
||||
/* true if hardware interrupts must be disabled for next instruction */
|
||||
#define HF_INHIBIT_IRQ_SHIFT 3
|
||||
/* 16 or 32 segments */
|
||||
#define HF_CS32_SHIFT 4
|
||||
#define HF_SS32_SHIFT 5
|
||||
/* zero base for DS, ES and SS */
|
||||
#define HF_ADDSEG_SHIFT 6
|
||||
|
||||
#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
|
||||
#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
|
||||
#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
|
||||
#define HF_CS32_MASK (1 << HF_CS32_SHIFT)
|
||||
#define HF_SS32_MASK (1 << HF_SS32_SHIFT)
|
||||
#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
|
||||
|
||||
#define CR0_PE_MASK (1 << 0)
|
||||
#define CR0_TS_MASK (1 << 3)
|
||||
#define CR0_WP_MASK (1 << 16)
|
||||
#define CR0_AM_MASK (1 << 18)
|
||||
#define CR0_PG_MASK (1 << 31)
|
||||
|
||||
#define CR4_VME_MASK (1 << 0)
|
||||
#define CR4_PVI_MASK (1 << 1)
|
||||
#define CR4_TSD_MASK (1 << 2)
|
||||
#define CR4_DE_MASK (1 << 3)
|
||||
#define CR4_PSE_MASK (1 << 4)
|
||||
|
||||
#define PG_PRESENT_BIT 0
|
||||
#define PG_RW_BIT 1
|
||||
#define PG_USER_BIT 2
|
||||
#define PG_PWT_BIT 3
|
||||
#define PG_PCD_BIT 4
|
||||
#define PG_ACCESSED_BIT 5
|
||||
#define PG_DIRTY_BIT 6
|
||||
#define PG_PSE_BIT 7
|
||||
#define PG_GLOBAL_BIT 8
|
||||
|
||||
#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT)
|
||||
#define PG_RW_MASK (1 << PG_RW_BIT)
|
||||
#define PG_USER_MASK (1 << PG_USER_BIT)
|
||||
#define PG_PWT_MASK (1 << PG_PWT_BIT)
|
||||
#define PG_PCD_MASK (1 << PG_PCD_BIT)
|
||||
#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
|
||||
#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT)
|
||||
#define PG_PSE_MASK (1 << PG_PSE_BIT)
|
||||
#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT)
|
||||
|
||||
#define PG_ERROR_W_BIT 1
|
||||
|
||||
#define PG_ERROR_P_MASK 0x01
|
||||
#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT)
|
||||
#define PG_ERROR_U_MASK 0x04
|
||||
#define PG_ERROR_RSVD_MASK 0x08
|
||||
|
||||
#define MSR_IA32_APICBASE 0x1b
|
||||
#define MSR_IA32_APICBASE_BSP (1<<8)
|
||||
#define MSR_IA32_APICBASE_ENABLE (1<<11)
|
||||
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
|
||||
|
||||
#define MSR_IA32_SYSENTER_CS 0x174
|
||||
#define MSR_IA32_SYSENTER_ESP 0x175
|
||||
#define MSR_IA32_SYSENTER_EIP 0x176
|
||||
|
||||
#define EXCP00_DIVZ 0
|
||||
#define EXCP01_SSTP 1
|
||||
#define EXCP02_NMI 2
|
||||
@@ -104,8 +179,6 @@
|
||||
#define EXCP11_ALGN 17
|
||||
#define EXCP12_MCHK 18
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
|
||||
@@ -161,19 +234,12 @@ typedef double CPU86_LDouble;
|
||||
#endif
|
||||
|
||||
typedef struct SegmentCache {
|
||||
uint32_t selector;
|
||||
uint8_t *base;
|
||||
unsigned long limit;
|
||||
uint8_t seg_32bit;
|
||||
uint32_t limit;
|
||||
uint32_t flags;
|
||||
} SegmentCache;
|
||||
|
||||
typedef struct SegmentDescriptorTable {
|
||||
uint8_t *base;
|
||||
unsigned long limit;
|
||||
/* this is the returned base when reading the register, just to
|
||||
avoid that the emulated program modifies it */
|
||||
unsigned long emu_base;
|
||||
} SegmentDescriptorTable;
|
||||
|
||||
typedef struct CPUX86State {
|
||||
/* standard registers */
|
||||
uint32_t regs[8];
|
||||
@@ -187,6 +253,7 @@ typedef struct CPUX86State {
|
||||
uint32_t cc_dst;
|
||||
uint32_t cc_op;
|
||||
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
|
||||
uint32_t hflags; /* hidden flags, see HF_xxx constants */
|
||||
|
||||
/* FPU state */
|
||||
unsigned int fpstt; /* top of stack index */
|
||||
@@ -205,18 +272,38 @@ typedef struct CPUX86State {
|
||||
} fp_convert;
|
||||
|
||||
/* segments */
|
||||
uint32_t segs[6]; /* selector values */
|
||||
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
|
||||
SegmentDescriptorTable gdt;
|
||||
SegmentDescriptorTable ldt;
|
||||
SegmentDescriptorTable idt;
|
||||
SegmentCache segs[6]; /* selector values */
|
||||
SegmentCache ldt;
|
||||
SegmentCache tr;
|
||||
SegmentCache gdt; /* only base and limit are used */
|
||||
SegmentCache idt; /* only base and limit are used */
|
||||
|
||||
/* sysenter registers */
|
||||
uint32_t sysenter_cs;
|
||||
uint32_t sysenter_esp;
|
||||
uint32_t sysenter_eip;
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int error_code;
|
||||
uint32_t cr2;
|
||||
int interrupt_request;
|
||||
int exception_is_int;
|
||||
int exception_next_eip;
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */
|
||||
uint32_t cr[5]; /* NOTE: cr1 is unused */
|
||||
uint32_t dr[8]; /* debug registers */
|
||||
int interrupt_request;
|
||||
int user_mode_only; /* user mode only simulation */
|
||||
|
||||
/* soft mmu support */
|
||||
/* 0 = kernel, 1 = user */
|
||||
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
|
||||
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
|
||||
|
||||
/* ice debug support */
|
||||
uint32_t breakpoints[MAX_BREAKPOINTS];
|
||||
int nb_breakpoints;
|
||||
int singlestep_enabled;
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
@@ -233,13 +320,60 @@ int cpu_x86_inl(CPUX86State *env, int addr);
|
||||
|
||||
CPUX86State *cpu_x86_init(void);
|
||||
int cpu_x86_exec(CPUX86State *s);
|
||||
void cpu_x86_interrupt(CPUX86State *s);
|
||||
void cpu_x86_close(CPUX86State *s);
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *s);
|
||||
|
||||
/* needed to load some predefinied segment registers */
|
||||
/* this function must always be used to load data in the segment
|
||||
cache: it synchronizes the hflags with the segment cache values */
|
||||
static inline void cpu_x86_load_seg_cache(CPUX86State *env,
|
||||
int seg_reg, unsigned int selector,
|
||||
uint8_t *base, unsigned int limit,
|
||||
unsigned int flags)
|
||||
{
|
||||
SegmentCache *sc;
|
||||
unsigned int new_hflags;
|
||||
|
||||
sc = &env->segs[seg_reg];
|
||||
sc->selector = selector;
|
||||
sc->base = base;
|
||||
sc->limit = limit;
|
||||
sc->flags = flags;
|
||||
|
||||
/* update the hidden flags */
|
||||
new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - HF_CS32_SHIFT);
|
||||
new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - HF_SS32_SHIFT);
|
||||
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
|
||||
/* XXX: try to avoid this test. The problem comes from the
|
||||
fact that is real mode or vm86 mode we only modify the
|
||||
'base' and 'selector' fields of the segment cache to go
|
||||
faster. A solution may be to force addseg to one in
|
||||
translate-i386.c. */
|
||||
new_hflags |= HF_ADDSEG_MASK;
|
||||
} else {
|
||||
new_hflags |= (((unsigned long)env->segs[R_DS].base |
|
||||
(unsigned long)env->segs[R_ES].base |
|
||||
(unsigned long)env->segs[R_SS].base) != 0) <<
|
||||
HF_ADDSEG_SHIFT;
|
||||
}
|
||||
env->hflags = (env->hflags &
|
||||
~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
|
||||
}
|
||||
|
||||
/* wrapper, just in case memory mappings must be changed */
|
||||
static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
|
||||
{
|
||||
#if HF_CPL_MASK == 3
|
||||
s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
|
||||
#else
|
||||
#error HF_CPL_MASK is hardcoded
|
||||
#endif
|
||||
}
|
||||
|
||||
/* the following helpers are only usable in user mode simulation as
|
||||
they can trigger unexpected exceptions */
|
||||
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);
|
||||
|
||||
@@ -250,6 +384,12 @@ struct siginfo;
|
||||
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
/* MMU defines */
|
||||
void cpu_x86_init_mmu(CPUX86State *env);
|
||||
extern int phys_ram_size;
|
||||
extern int phys_ram_fd;
|
||||
extern uint8_t *phys_ram_base;
|
||||
|
||||
/* used to debug */
|
||||
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
|
||||
#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
|
||||
|
4
disas.c
4
disas.c
@@ -42,7 +42,7 @@ perror_memory (status, memaddr, info)
|
||||
/* 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);
|
||||
"Address 0x%llx is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
@@ -57,7 +57,7 @@ generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%x", addr);
|
||||
(*info->fprintf_func) (info->stream, "0x%llx", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
|
@@ -109,6 +109,13 @@ extern int printf(const char *, ...);
|
||||
#define AREG5 "$13"
|
||||
#define AREG6 "$14"
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define AREG0 "%a5"
|
||||
#define AREG1 "%a4"
|
||||
#define AREG2 "%d7"
|
||||
#define AREG3 "%d6"
|
||||
#define AREG4 "%d5"
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
@@ -125,6 +132,8 @@ extern int printf(const char *, ...);
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#ifdef __alpha__
|
||||
/* the symbols are considered non exported so a br immediate is generated */
|
||||
@@ -152,4 +161,30 @@ extern int __op_param1, __op_param2, __op_param3;
|
||||
#define PARAM3 ((long)(&__op_param3))
|
||||
#endif
|
||||
|
||||
extern int __op_jmp0, __op_jmp1;
|
||||
extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#ifdef __i386__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define EXIT_TB() asm volatile ("blr")
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define EXIT_TB() asm volatile ("br %r14")
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
|
||||
"nop")
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define EXIT_TB() asm volatile ("b exec_loop")
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define EXIT_TB() asm volatile ("rts")
|
||||
#endif
|
||||
|
123
dyngen.c
123
dyngen.c
@@ -25,7 +25,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "config-host.h"
|
||||
|
||||
/* elf format definitions. We use these macros to test the CPU to
|
||||
allow cross compilation (this tool must be ran on the build
|
||||
@@ -86,6 +86,13 @@
|
||||
#define elf_check_arch(x) ((x) == EM_ARM)
|
||||
#define ELF_USES_RELOC
|
||||
|
||||
#elif defined(HOST_M68K)
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_ARCH EM_68K
|
||||
#define elf_check_arch(x) ((x) == EM_68K)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#else
|
||||
#error unsupported CPU - please update the code
|
||||
#endif
|
||||
@@ -108,7 +115,7 @@ typedef uint64_t host_ulong;
|
||||
#define SHT_RELOC SHT_REL
|
||||
#endif
|
||||
|
||||
#include "thunk.h"
|
||||
#include "bswap.h"
|
||||
|
||||
enum {
|
||||
OUT_GEN_OP,
|
||||
@@ -575,6 +582,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
relocs, nb_relocs);
|
||||
break;
|
||||
#endif
|
||||
case EM_68K:
|
||||
{
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 2);
|
||||
if (p == p_start)
|
||||
error("empty code for %s", name);
|
||||
// remove NOP's, probably added for alignment
|
||||
while ((get16((uint16_t *)p) == 0x4e71) &&
|
||||
(p>p_start))
|
||||
p -= 2;
|
||||
if (get16((uint16_t *)p) != 0x4e75)
|
||||
error("rts expected at the end of %s", name);
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
@@ -647,14 +669,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
const char *sym_name, *p;
|
||||
target_ulong val;
|
||||
unsigned long val;
|
||||
int n;
|
||||
|
||||
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
|
||||
@@ -663,7 +684,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
if (!ptr)
|
||||
error("__op_labelN in invalid section");
|
||||
offset = sym->st_value;
|
||||
addend = 0;
|
||||
val = *(unsigned long *)(ptr + offset);
|
||||
#ifdef ELF_USES_RELOCA
|
||||
{
|
||||
int reloc_shndx, nb_relocs1, j;
|
||||
@@ -676,7 +697,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
rel = (ELF_RELOC *)sdata[reloc_shndx];
|
||||
for(j = 0; j < nb_relocs1; j++) {
|
||||
if (rel->r_offset == offset) {
|
||||
addend = rel->r_addend;
|
||||
val = rel->r_addend;
|
||||
break;
|
||||
}
|
||||
rel++;
|
||||
@@ -684,12 +705,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
}
|
||||
#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);
|
||||
fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1065,6 +1084,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_M68K)
|
||||
{
|
||||
char name[256];
|
||||
int type;
|
||||
int addend;
|
||||
Elf32_Sym *sym;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
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)) + rel->r_addend;
|
||||
switch(type) {
|
||||
case R_68K_32:
|
||||
fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
|
||||
rel->r_offset - start_offset, name, addend );
|
||||
break;
|
||||
case R_68K_PC32:
|
||||
fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
|
||||
rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported m68k relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@@ -1203,6 +1257,10 @@ int load_elf(const char *filename, FILE *outfile, int out_type)
|
||||
|
||||
if (out_type == OUT_INDEX_OP) {
|
||||
fprintf(outfile, "DEF(end, 0, 0)\n");
|
||||
fprintf(outfile, "DEF(nop, 0, 0)\n");
|
||||
fprintf(outfile, "DEF(nop1, 1, 0)\n");
|
||||
fprintf(outfile, "DEF(nop2, 2, 0)\n");
|
||||
fprintf(outfile, "DEF(nop3, 3, 0)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name, *p;
|
||||
name = strtab + sym->st_name;
|
||||
@@ -1272,6 +1330,17 @@ fprintf(outfile,
|
||||
}
|
||||
|
||||
fprintf(outfile,
|
||||
" case INDEX_op_nop:\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop1:\n"
|
||||
" opparam_ptr++;\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop2:\n"
|
||||
" opparam_ptr += 2;\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop3:\n"
|
||||
" opparam_ptr += 3;\n"
|
||||
" break;\n"
|
||||
" default:\n"
|
||||
" goto the_end;\n"
|
||||
" }\n");
|
||||
@@ -1293,38 +1362,10 @@ fprintf(outfile,
|
||||
" the_end:\n"
|
||||
);
|
||||
|
||||
/* generate epilogue */
|
||||
switch(ELF_ARCH) {
|
||||
case EM_386:
|
||||
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
|
||||
break;
|
||||
case EM_PPC:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
|
||||
break;
|
||||
case EM_S390:
|
||||
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
|
||||
break;
|
||||
case EM_ALPHA:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n");
|
||||
break;
|
||||
case EM_IA_64:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
|
||||
break;
|
||||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\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");
|
||||
}
|
||||
/* generate some code patching */
|
||||
#ifdef HOST_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");
|
||||
#endif
|
||||
/* flush instruction cache */
|
||||
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
|
||||
|
||||
|
16
dyngen.h
16
dyngen.h
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
int __op_jmp0, __op_jmp1;
|
||||
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
@@ -94,6 +94,14 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
#include <asm/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
@@ -152,11 +160,7 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
|
||||
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 {
|
||||
if (gen_jmp) {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
|
@@ -30,3 +30,11 @@ register uint32_t T2 asm(AREG3);
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void cpu_loop_exit(void);
|
||||
|
||||
static inline int compute_cpsr(void)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
|
||||
}
|
||||
|
90
exec-i386.h
90
exec-i386.h
@@ -123,8 +123,28 @@ typedef struct CCTable {
|
||||
extern CCTable cc_table[];
|
||||
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip);
|
||||
void helper_ljmp_protected_T0_T1(void);
|
||||
void helper_lcall_real_T0_T1(int shift, int next_eip);
|
||||
void helper_lcall_protected_T0_T1(int shift, int next_eip);
|
||||
void helper_iret_real(int shift);
|
||||
void helper_iret_protected(int shift);
|
||||
void helper_lret_protected(int shift, int addend);
|
||||
void helper_lldt_T0(void);
|
||||
void helper_ltr_T0(void);
|
||||
void helper_movl_crN_T0(int reg);
|
||||
void helper_movl_drN_T0(int reg);
|
||||
void helper_invlpg(unsigned int addr);
|
||||
void cpu_x86_update_cr0(CPUX86State *env);
|
||||
void cpu_x86_update_cr3(CPUX86State *env);
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write);
|
||||
void tlb_fill(unsigned long addr, int is_write, void *retaddr);
|
||||
void __hidden cpu_lock(void);
|
||||
void __hidden cpu_unlock(void);
|
||||
void do_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip, int is_hw);
|
||||
void do_interrupt_user(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
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);
|
||||
@@ -144,6 +164,8 @@ void helper_idivl_EAX_T0(uint32_t eip);
|
||||
void helper_cmpxchg8b(void);
|
||||
void helper_cpuid(void);
|
||||
void helper_rdtsc(void);
|
||||
void helper_rdmsr(void);
|
||||
void helper_wrmsr(void);
|
||||
void helper_lsl(void);
|
||||
void helper_lar(void);
|
||||
|
||||
@@ -324,3 +346,71 @@ 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];
|
||||
|
||||
static inline uint32_t compute_eflags(void)
|
||||
{
|
||||
return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
}
|
||||
|
||||
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
|
||||
|
||||
#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \
|
||||
RF_MASK | AC_MASK | ID_MASK)
|
||||
|
||||
/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
|
||||
static inline void load_eflags(int eflags, int update_mask)
|
||||
{
|
||||
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((eflags >> 10) & 1));
|
||||
env->eflags = (env->eflags & ~update_mask) |
|
||||
(eflags & update_mask);
|
||||
}
|
||||
|
||||
/* memory access macros */
|
||||
|
||||
#define ldul ldl
|
||||
#define lduq ldq
|
||||
#define ldul_user ldl_user
|
||||
#define ldul_kernel ldl_kernel
|
||||
|
||||
#define ldub_raw ldub
|
||||
#define ldsb_raw ldsb
|
||||
#define lduw_raw lduw
|
||||
#define ldsw_raw ldsw
|
||||
#define ldl_raw ldl
|
||||
#define ldq_raw ldq
|
||||
|
||||
#define stb_raw stb
|
||||
#define stw_raw stw
|
||||
#define stl_raw stl
|
||||
#define stq_raw stq
|
||||
|
||||
#define MEMUSER 0
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#undef MEMUSER
|
||||
#define MEMUSER 1
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#undef MEMUSER
|
||||
|
||||
|
321
exec.c
321
exec.c
@@ -26,11 +26,17 @@
|
||||
#include <inttypes.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_TB_INVALIDATE
|
||||
#define DEBUG_FLUSH
|
||||
//#define DEBUG_FLUSH
|
||||
|
||||
/* make various TB consistency checks */
|
||||
//#define DEBUG_TB_CHECK
|
||||
@@ -62,6 +68,7 @@ typedef struct PageDesc {
|
||||
#define L2_SIZE (1 << L2_BITS)
|
||||
|
||||
static void tb_invalidate_page(unsigned long address);
|
||||
static void io_mem_init(void);
|
||||
|
||||
unsigned long real_host_page_size;
|
||||
unsigned long host_page_bits;
|
||||
@@ -70,6 +77,12 @@ unsigned long host_page_mask;
|
||||
|
||||
static PageDesc *l1_map[L1_SIZE];
|
||||
|
||||
/* io memory support */
|
||||
static unsigned long *l1_physmap[L1_SIZE];
|
||||
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||
static int io_mem_nb;
|
||||
|
||||
static void page_init(void)
|
||||
{
|
||||
/* NOTE: we can always suppose that host_page_size >=
|
||||
@@ -195,6 +208,7 @@ void cpu_exec_init(void)
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
page_init();
|
||||
io_mem_init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,3 +577,308 @@ TranslationBlock *tb_find_pc(unsigned long tc_ptr)
|
||||
}
|
||||
return &tbs[m_max];
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb);
|
||||
|
||||
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
|
||||
{
|
||||
TranslationBlock *tb1, *tb_next, **ptb;
|
||||
unsigned int n1;
|
||||
|
||||
tb1 = tb->jmp_next[n];
|
||||
if (tb1 != NULL) {
|
||||
/* find head of list */
|
||||
for(;;) {
|
||||
n1 = (long)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
if (n1 == 2)
|
||||
break;
|
||||
tb1 = tb1->jmp_next[n1];
|
||||
}
|
||||
/* we are now sure now that tb jumps to tb1 */
|
||||
tb_next = tb1;
|
||||
|
||||
/* remove tb from the jmp_first list */
|
||||
ptb = &tb_next->jmp_first;
|
||||
for(;;) {
|
||||
tb1 = *ptb;
|
||||
n1 = (long)tb1 & 3;
|
||||
tb1 = (TranslationBlock *)((long)tb1 & ~3);
|
||||
if (n1 == n && tb1 == tb)
|
||||
break;
|
||||
ptb = &tb1->jmp_next[n1];
|
||||
}
|
||||
*ptb = tb->jmp_next[n];
|
||||
tb->jmp_next[n] = NULL;
|
||||
|
||||
/* suppress the jump to next tb in generated code */
|
||||
tb_reset_jump(tb, n);
|
||||
|
||||
/* suppress jumps in the tb on which we could have jump */
|
||||
tb_reset_jump_recursive(tb_next);
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_reset_jump_recursive(TranslationBlock *tb)
|
||||
{
|
||||
tb_reset_jump_recursive2(tb, 0);
|
||||
tb_reset_jump_recursive2(tb, 1);
|
||||
}
|
||||
|
||||
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
|
||||
breakpoint is reached */
|
||||
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
int i;
|
||||
|
||||
for(i = 0; i < env->nb_breakpoints; i++) {
|
||||
if (env->breakpoints[i] == pc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (env->nb_breakpoints >= MAX_BREAKPOINTS)
|
||||
return -1;
|
||||
env->breakpoints[env->nb_breakpoints++] = pc;
|
||||
tb_invalidate_page(pc);
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* remove a breakpoint */
|
||||
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
int i;
|
||||
for(i = 0; i < env->nb_breakpoints; i++) {
|
||||
if (env->breakpoints[i] == pc)
|
||||
goto found;
|
||||
}
|
||||
return -1;
|
||||
found:
|
||||
memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
|
||||
(env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
|
||||
env->nb_breakpoints--;
|
||||
tb_invalidate_page(pc);
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable or disable single step mode. EXCP_DEBUG is returned by the
|
||||
CPU loop after each instruction */
|
||||
void cpu_single_step(CPUState *env, int enabled)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
if (env->singlestep_enabled != enabled) {
|
||||
env->singlestep_enabled = enabled;
|
||||
/* must flush all the translated code to avoid inconsistancies */
|
||||
tb_flush();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* mask must never be zero */
|
||||
void cpu_interrupt(CPUState *env, int mask)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
env->interrupt_request |= mask;
|
||||
/* if the cpu is currently executing code, we must unlink it and
|
||||
all the potentially executing TB */
|
||||
tb = env->current_tb;
|
||||
if (tb) {
|
||||
tb_reset_jump_recursive(tb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "qemu: fatal: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
#ifdef TARGET_I386
|
||||
cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
|
||||
#endif
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* unmap all maped pages and flush all associated code */
|
||||
void page_unmap(void)
|
||||
{
|
||||
PageDesc *p, *pmap;
|
||||
unsigned long addr;
|
||||
int i, j, ret, j1;
|
||||
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
pmap = l1_map[i];
|
||||
if (pmap) {
|
||||
p = pmap;
|
||||
for(j = 0;j < L2_SIZE;) {
|
||||
if (p->flags & PAGE_VALID) {
|
||||
addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
|
||||
/* we try to find a range to make less syscalls */
|
||||
j1 = j;
|
||||
p++;
|
||||
j++;
|
||||
while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
|
||||
p++;
|
||||
j++;
|
||||
}
|
||||
ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
free(pmap);
|
||||
l1_map[i] = NULL;
|
||||
}
|
||||
}
|
||||
tb_flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
void tlb_flush(CPUState *env)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
int i;
|
||||
for(i = 0; i < CPU_TLB_SIZE; i++) {
|
||||
env->tlb_read[0][i].address = -1;
|
||||
env->tlb_write[0][i].address = -1;
|
||||
env->tlb_read[1][i].address = -1;
|
||||
env->tlb_write[1][i].address = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
int i;
|
||||
|
||||
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
env->tlb_read[0][i].address = -1;
|
||||
env->tlb_write[0][i].address = -1;
|
||||
env->tlb_read[1][i].address = -1;
|
||||
env->tlb_write[1][i].address = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long *physpage_find_alloc(unsigned int page)
|
||||
{
|
||||
unsigned long **lp, *p;
|
||||
unsigned int index, i;
|
||||
|
||||
index = page >> TARGET_PAGE_BITS;
|
||||
lp = &l1_physmap[index >> L2_BITS];
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
/* allocate if not found */
|
||||
p = malloc(sizeof(unsigned long) * L2_SIZE);
|
||||
for(i = 0; i < L2_SIZE; i++)
|
||||
p[i] = IO_MEM_UNASSIGNED;
|
||||
*lp = p;
|
||||
}
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
}
|
||||
|
||||
/* return NULL if no page defined (unused memory) */
|
||||
unsigned long physpage_find(unsigned long page)
|
||||
{
|
||||
unsigned long *p;
|
||||
unsigned int index;
|
||||
index = page >> TARGET_PAGE_BITS;
|
||||
p = l1_physmap[index >> L2_BITS];
|
||||
if (!p)
|
||||
return IO_MEM_UNASSIGNED;
|
||||
return p[index & (L2_SIZE - 1)];
|
||||
}
|
||||
|
||||
/* register physical memory. 'size' must be a multiple of the target
|
||||
page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
|
||||
io memory page */
|
||||
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
|
||||
long phys_offset)
|
||||
{
|
||||
unsigned long addr, end_addr;
|
||||
unsigned long *p;
|
||||
|
||||
end_addr = start_addr + size;
|
||||
for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
|
||||
p = physpage_find_alloc(addr);
|
||||
*p = phys_offset;
|
||||
if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
|
||||
phys_offset += TARGET_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t unassigned_mem_readb(uint32_t addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
|
||||
{
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
|
||||
unassigned_mem_readb,
|
||||
unassigned_mem_readb,
|
||||
unassigned_mem_readb,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
|
||||
unassigned_mem_writeb,
|
||||
unassigned_mem_writeb,
|
||||
unassigned_mem_writeb,
|
||||
};
|
||||
|
||||
|
||||
static void io_mem_init(void)
|
||||
{
|
||||
io_mem_nb = 1;
|
||||
cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
|
||||
}
|
||||
|
||||
/* mem_read and mem_write are arrays of functions containing the
|
||||
function to access byte (index 0), word (index 1) and dword (index
|
||||
2). All functions must be supplied. If io_index is non zero, the
|
||||
corresponding io zone is modified. If it is zero, a new io zone is
|
||||
allocated. The return value can be used with
|
||||
cpu_register_physical_memory(). (-1) is returned if error. */
|
||||
int cpu_register_io_memory(int io_index,
|
||||
CPUReadMemoryFunc **mem_read,
|
||||
CPUWriteMemoryFunc **mem_write)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (io_index <= 0) {
|
||||
if (io_index >= IO_MEM_NB_ENTRIES)
|
||||
return -1;
|
||||
io_index = io_mem_nb++;
|
||||
} else {
|
||||
if (io_index >= IO_MEM_NB_ENTRIES)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0;i < 3; i++) {
|
||||
io_mem_read[io_index][i] = mem_read[i];
|
||||
io_mem_write[io_index][i] = mem_write[i];
|
||||
}
|
||||
return io_index << IO_MEM_SHIFT;
|
||||
}
|
||||
|
129
exec.h
129
exec.h
@@ -21,6 +21,23 @@
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
#ifndef glue
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
#endif
|
||||
|
||||
#if GCC_MAJOR < 3
|
||||
#define __builtin_expect(x, n) (x)
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#define REGPARM(n) __attribute((regparm(n)))
|
||||
#else
|
||||
#define REGPARM(n)
|
||||
#endif
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
@@ -39,32 +56,30 @@ struct TranslationBlock;
|
||||
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_cc_op[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
|
||||
#define GEN_FLAG_VM_SHIFT 3
|
||||
#define GEN_FLAG_ST_SHIFT 4
|
||||
#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */
|
||||
#define GEN_FLAG_CPL_SHIFT 9
|
||||
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
|
||||
void optimize_flags_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(struct TranslationBlock *tb, int search_pc);
|
||||
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
int cpu_gen_code(struct TranslationBlock *tb,
|
||||
int cpu_gen_code(CPUState *env, 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);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc);
|
||||
void cpu_exec_init(void);
|
||||
int page_unprotect(unsigned long address);
|
||||
void page_unmap(void);
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr);
|
||||
void tlb_flush(CPUState *env);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
@@ -93,7 +108,7 @@ typedef struct TranslationBlock {
|
||||
the code of this one. */
|
||||
uint16_t tb_next_offset[2]; /* offset of original jump target */
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
|
||||
uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
|
||||
#else
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
@@ -145,18 +160,14 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||
{
|
||||
uint32_t val, *ptr;
|
||||
unsigned long offset;
|
||||
|
||||
offset = (unsigned long)(tb->tc_ptr + tb->tb_jmp_offset[n]);
|
||||
|
||||
/* patch the branch destination */
|
||||
ptr = (uint32_t *)offset;
|
||||
ptr = (uint32_t *)jmp_addr;
|
||||
val = *ptr;
|
||||
val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc);
|
||||
val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc);
|
||||
*ptr = val;
|
||||
/* flush icache */
|
||||
asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory");
|
||||
@@ -166,6 +177,18 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
offset = tb->tb_jmp_offset[n];
|
||||
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
|
||||
offset = tb->tb_jmp_offset[n + 2];
|
||||
if (offset != 0xffff)
|
||||
tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* set the jump target */
|
||||
@@ -200,30 +223,59 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
#if defined(__powerpc__)
|
||||
|
||||
/* on PowerPC we patch the jump instruction directly */
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
|
||||
label ## n:\
|
||||
asm volatile (".section \".data\"\n"\
|
||||
"__op_label" #n "." stringify(opname) ":\n"\
|
||||
".long 1f\n"\
|
||||
".previous\n"\
|
||||
"b __op_jmp" #n "\n"\
|
||||
"1:\n");\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
#define JUMP_TB2(opname, tbparam, n)\
|
||||
do {\
|
||||
asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\
|
||||
} 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)\
|
||||
#define JUMP_TB(opname, tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
dummy_label ## n:\
|
||||
EXIT_TB();\
|
||||
} while (0)
|
||||
|
||||
/* second jump to same destination 'n' */
|
||||
#define JUMP_TB2(opname, tbparam, n)\
|
||||
do {\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
/* physical memory access */
|
||||
#define IO_MEM_NB_ENTRIES 256
|
||||
#define TLB_INVALID_MASK (1 << 3)
|
||||
#define IO_MEM_SHIFT 4
|
||||
#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT)
|
||||
|
||||
unsigned long physpage_find(unsigned long page);
|
||||
|
||||
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
@@ -315,10 +367,23 @@ static inline int testandset (int *spinlock)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
__asm__ __volatile__("tas %1; sne %0"
|
||||
: "=r" (ret)
|
||||
: "m" (p)
|
||||
: "cc","memory");
|
||||
return ret == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
#if 1
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
@@ -333,6 +398,20 @@ static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return !testandset(lock);
|
||||
}
|
||||
#else
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
|
453
gdbstub.c
Normal file
453
gdbstub.c
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* gdb server stub
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "thunk.h"
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
int gdbstub_fd = -1;
|
||||
|
||||
/* return 0 if OK */
|
||||
static int gdbstub_open(int port)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
int fd, val, ret;
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(port);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
ret = listen(fd, 0);
|
||||
if (ret < 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now wait for one connection */
|
||||
for(;;) {
|
||||
len = sizeof(sockaddr);
|
||||
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
|
||||
if (gdbstub_fd < 0 && errno != EINTR) {
|
||||
perror("accept");
|
||||
return -1;
|
||||
} else if (gdbstub_fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set short latency */
|
||||
val = 1;
|
||||
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_char(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
int ret;
|
||||
|
||||
for(;;) {
|
||||
ret = read(gdbstub_fd, &ch, 1);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return -1;
|
||||
} else if (ret == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void put_buffer(const uint8_t *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = write(gdbstub_fd, buf, len);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return;
|
||||
} else {
|
||||
buf += ret;
|
||||
len -= ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int fromhex(int v)
|
||||
{
|
||||
if (v >= '0' && v <= '9')
|
||||
return v - '0';
|
||||
else if (v >= 'A' && v <= 'F')
|
||||
return v - 'A' + 10;
|
||||
else if (v >= 'a' && v <= 'f')
|
||||
return v - 'a' + 10;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tohex(int v)
|
||||
{
|
||||
if (v < 10)
|
||||
return v + '0';
|
||||
else
|
||||
return v - 10 + 'a';
|
||||
}
|
||||
|
||||
static void memtohex(char *buf, const uint8_t *mem, int len)
|
||||
{
|
||||
int i, c;
|
||||
char *q;
|
||||
q = buf;
|
||||
for(i = 0; i < len; i++) {
|
||||
c = mem[i];
|
||||
*q++ = tohex(c >> 4);
|
||||
*q++ = tohex(c & 0xf);
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
static void hextomem(uint8_t *mem, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if error or EOF */
|
||||
static int get_packet(char *buf, int buf_size)
|
||||
{
|
||||
int ch, len, csum, csum1;
|
||||
char reply[1];
|
||||
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '$')
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
csum = 0;
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '#')
|
||||
break;
|
||||
if (len > buf_size - 1)
|
||||
return -1;
|
||||
buf[len++] = ch;
|
||||
csum += ch;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 = fromhex(ch) << 4;
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 |= fromhex(ch);
|
||||
if ((csum & 0xff) != csum1) {
|
||||
reply[0] = '-';
|
||||
put_buffer(reply, 1);
|
||||
} else {
|
||||
reply[0] = '+';
|
||||
put_buffer(reply, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_GDB
|
||||
printf("command='%s'\n", buf);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/* return -1 if error, 0 if OK */
|
||||
static int put_packet(char *buf)
|
||||
{
|
||||
char buf1[3];
|
||||
int len, csum, ch, i;
|
||||
|
||||
#ifdef DEBUG_GDB
|
||||
printf("reply='%s'\n", buf);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
buf1[0] = '$';
|
||||
put_buffer(buf1, 1);
|
||||
len = strlen(buf);
|
||||
put_buffer(buf, len);
|
||||
csum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
csum += buf[i];
|
||||
}
|
||||
buf1[0] = '#';
|
||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||
buf1[2] = tohex((csum) & 0xf);
|
||||
|
||||
put_buffer(buf1, 3);
|
||||
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '+')
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
{
|
||||
int l, flags;
|
||||
uint32_t page;
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
l = (page + TARGET_PAGE_SIZE) - addr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
flags = page_get_flags(page);
|
||||
if (!(flags & PAGE_VALID))
|
||||
return -1;
|
||||
if (is_write) {
|
||||
if (!(flags & PAGE_WRITE))
|
||||
return -1;
|
||||
memcpy((uint8_t *)addr, buf, l);
|
||||
} else {
|
||||
if (!(flags & PAGE_READ))
|
||||
return -1;
|
||||
memcpy(buf, (uint8_t *)addr, l);
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* port = 0 means default port */
|
||||
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
|
||||
{
|
||||
CPUState *env;
|
||||
const char *p;
|
||||
int ret, ch, nb_regs, i, type;
|
||||
char buf[4096];
|
||||
uint8_t mem_buf[2000];
|
||||
uint32_t *registers;
|
||||
uint32_t addr, len;
|
||||
|
||||
printf("Waiting gdb connection on port %d\n", port);
|
||||
if (gdbstub_open(port) < 0)
|
||||
return -1;
|
||||
printf("Connected\n");
|
||||
for(;;) {
|
||||
ret = get_packet(buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
break;
|
||||
p = buf;
|
||||
ch = *p++;
|
||||
switch(ch) {
|
||||
case '?':
|
||||
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'c':
|
||||
if (*p != '\0') {
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
#if defined(TARGET_I386)
|
||||
env->eip = addr;
|
||||
#endif
|
||||
}
|
||||
ret = main_loop(opaque);
|
||||
if (ret == EXCP_DEBUG)
|
||||
ret = SIGTRAP;
|
||||
else
|
||||
ret = 0;
|
||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 's':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
if (*p != '\0') {
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
#if defined(TARGET_I386)
|
||||
env->eip = addr;
|
||||
#endif
|
||||
}
|
||||
cpu_single_step(env, 1);
|
||||
ret = main_loop(opaque);
|
||||
cpu_single_step(env, 0);
|
||||
if (ret == EXCP_DEBUG)
|
||||
ret = SIGTRAP;
|
||||
else
|
||||
ret = 0;
|
||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'g':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
registers = (void *)mem_buf;
|
||||
#if defined(TARGET_I386)
|
||||
for(i = 0; i < 8; i++) {
|
||||
registers[i] = tswapl(env->regs[i]);
|
||||
}
|
||||
registers[8] = env->eip;
|
||||
registers[9] = env->eflags;
|
||||
registers[10] = env->segs[R_CS].selector;
|
||||
registers[11] = env->segs[R_SS].selector;
|
||||
registers[12] = env->segs[R_DS].selector;
|
||||
registers[13] = env->segs[R_ES].selector;
|
||||
registers[14] = env->segs[R_FS].selector;
|
||||
registers[15] = env->segs[R_GS].selector;
|
||||
nb_regs = 16;
|
||||
#endif
|
||||
memtohex(buf, (const uint8_t *)registers,
|
||||
sizeof(registers[0]) * nb_regs);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'G':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
registers = (void *)mem_buf;
|
||||
#if defined(TARGET_I386)
|
||||
hextomem((uint8_t *)registers, p, 16 * 4);
|
||||
for(i = 0; i < 8; i++) {
|
||||
env->regs[i] = tswapl(registers[i]);
|
||||
}
|
||||
env->eip = registers[8];
|
||||
env->eflags = registers[9];
|
||||
#define LOAD_SEG(index, sreg)\
|
||||
if (tswapl(registers[index]) != env->segs[sreg].selector)\
|
||||
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
|
||||
LOAD_SEG(10, R_CS);
|
||||
LOAD_SEG(11, R_SS);
|
||||
LOAD_SEG(12, R_DS);
|
||||
LOAD_SEG(13, R_ES);
|
||||
LOAD_SEG(14, R_FS);
|
||||
LOAD_SEG(15, R_GS);
|
||||
#endif
|
||||
put_packet("OK");
|
||||
break;
|
||||
case 'm':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, NULL, 16);
|
||||
if (memory_rw(mem_buf, addr, len, 0) != 0)
|
||||
memset(mem_buf, 0, len);
|
||||
memtohex(buf, mem_buf, len);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'M':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
hextomem(mem_buf, p, len);
|
||||
if (memory_rw(mem_buf, addr, len, 1) != 0)
|
||||
put_packet("ENN");
|
||||
else
|
||||
put_packet("OK");
|
||||
break;
|
||||
case 'Z':
|
||||
type = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (type == 0 || type == 1) {
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
if (cpu_breakpoint_insert(env, addr) < 0)
|
||||
goto breakpoint_error;
|
||||
put_packet("OK");
|
||||
} else {
|
||||
breakpoint_error:
|
||||
put_packet("ENN");
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
type = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (type == 0 || type == 1) {
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
cpu_breakpoint_remove(env, addr);
|
||||
put_packet("OK");
|
||||
} else {
|
||||
goto breakpoint_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
1129
helper-i386.c
1129
helper-i386.c
File diff suppressed because it is too large
Load Diff
390
helper2-i386.c
Normal file
390
helper2-i386.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* i386 helpers (without register variable usage)
|
||||
*
|
||||
* 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 <signal.h>
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_MMU
|
||||
|
||||
CPUX86State *cpu_x86_init(void)
|
||||
{
|
||||
CPUX86State *env;
|
||||
int i;
|
||||
static int inited;
|
||||
|
||||
cpu_exec_init();
|
||||
|
||||
env = malloc(sizeof(CPUX86State));
|
||||
if (!env)
|
||||
return NULL;
|
||||
memset(env, 0, sizeof(CPUX86State));
|
||||
/* basic FPU init */
|
||||
for(i = 0;i < 8; i++)
|
||||
env->fptags[i] = 1;
|
||||
env->fpuc = 0x37f;
|
||||
/* flags setup : we activate the IRQs by default as in user mode */
|
||||
env->eflags = 0x2 | IF_MASK;
|
||||
|
||||
tlb_flush(env);
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
env->hflags |= HF_SOFTMMU_MASK;
|
||||
#endif
|
||||
/* init various static tables */
|
||||
if (!inited) {
|
||||
inited = 1;
|
||||
optimize_flags_init();
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
void cpu_x86_close(CPUX86State *env)
|
||||
{
|
||||
free(env);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* x86 debug */
|
||||
|
||||
static const char *cc_op_str[] = {
|
||||
"DYNAMIC",
|
||||
"EFLAGS",
|
||||
"MUL",
|
||||
"ADDB",
|
||||
"ADDW",
|
||||
"ADDL",
|
||||
"ADCB",
|
||||
"ADCW",
|
||||
"ADCL",
|
||||
"SUBB",
|
||||
"SUBW",
|
||||
"SUBL",
|
||||
"SBBB",
|
||||
"SBBW",
|
||||
"SBBL",
|
||||
"LOGICB",
|
||||
"LOGICW",
|
||||
"LOGICL",
|
||||
"INCB",
|
||||
"INCW",
|
||||
"INCL",
|
||||
"DECB",
|
||||
"DECW",
|
||||
"DECL",
|
||||
"SHLB",
|
||||
"SHLW",
|
||||
"SHLL",
|
||||
"SARB",
|
||||
"SARW",
|
||||
"SARL",
|
||||
};
|
||||
|
||||
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
|
||||
{
|
||||
int eflags;
|
||||
char cc_op_name[32];
|
||||
|
||||
eflags = env->eflags;
|
||||
fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n",
|
||||
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
|
||||
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
|
||||
env->eip, eflags,
|
||||
eflags & DF_MASK ? 'D' : '-',
|
||||
eflags & CC_O ? 'O' : '-',
|
||||
eflags & CC_S ? 'S' : '-',
|
||||
eflags & CC_Z ? 'Z' : '-',
|
||||
eflags & CC_A ? 'A' : '-',
|
||||
eflags & CC_P ? 'P' : '-',
|
||||
eflags & CC_C ? 'C' : '-');
|
||||
fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
|
||||
env->segs[R_CS].selector,
|
||||
env->segs[R_SS].selector,
|
||||
env->segs[R_DS].selector,
|
||||
env->segs[R_ES].selector,
|
||||
env->segs[R_FS].selector,
|
||||
env->segs[R_GS].selector);
|
||||
if (flags & X86_DUMP_CCOP) {
|
||||
if ((unsigned)env->cc_op < CC_OP_NB)
|
||||
strcpy(cc_op_name, cc_op_str[env->cc_op]);
|
||||
else
|
||||
snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
|
||||
fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
|
||||
env->cc_src, env->cc_dst, cc_op_name);
|
||||
}
|
||||
if (flags & X86_DUMP_FPU) {
|
||||
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
|
||||
(double)env->fpregs[0],
|
||||
(double)env->fpregs[1],
|
||||
(double)env->fpregs[2],
|
||||
(double)env->fpregs[3]);
|
||||
fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
|
||||
(double)env->fpregs[4],
|
||||
(double)env->fpregs[5],
|
||||
(double)env->fpregs[7],
|
||||
(double)env->fpregs[8]);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* x86 mmu */
|
||||
/* XXX: add PGE support */
|
||||
|
||||
/* called when cr3 or PG bit are modified */
|
||||
static int last_pg_state = -1;
|
||||
static int last_pe_state = 0;
|
||||
int phys_ram_size;
|
||||
int phys_ram_fd;
|
||||
uint8_t *phys_ram_base;
|
||||
|
||||
void cpu_x86_update_cr0(CPUX86State *env)
|
||||
{
|
||||
int pg_state, pe_state;
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
printf("CR0 update: CR0=0x%08x\n", env->cr[0]);
|
||||
#endif
|
||||
pg_state = env->cr[0] & CR0_PG_MASK;
|
||||
if (pg_state != last_pg_state) {
|
||||
page_unmap();
|
||||
tlb_flush(env);
|
||||
last_pg_state = pg_state;
|
||||
}
|
||||
pe_state = env->cr[0] & CR0_PE_MASK;
|
||||
if (last_pe_state != pe_state) {
|
||||
tb_flush();
|
||||
last_pe_state = pe_state;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_x86_update_cr3(CPUX86State *env)
|
||||
{
|
||||
if (env->cr[0] & CR0_PG_MASK) {
|
||||
#if defined(DEBUG_MMU)
|
||||
printf("CR3 update: CR3=%08x\n", env->cr[3]);
|
||||
#endif
|
||||
page_unmap();
|
||||
tlb_flush(env);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_x86_init_mmu(CPUX86State *env)
|
||||
{
|
||||
last_pg_state = -1;
|
||||
cpu_x86_update_cr0(env);
|
||||
}
|
||||
|
||||
/* XXX: also flush 4MB pages */
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
|
||||
{
|
||||
int flags;
|
||||
unsigned long virt_addr;
|
||||
|
||||
tlb_flush_page(env, addr);
|
||||
|
||||
flags = page_get_flags(addr);
|
||||
if (flags & PAGE_VALID) {
|
||||
virt_addr = addr & ~0xfff;
|
||||
munmap((void *)virt_addr, 4096);
|
||||
page_set_flags(virt_addr, virt_addr + 4096, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* return value:
|
||||
-1 = cannot handle fault
|
||||
0 = nothing more to do
|
||||
1 = generate PF fault
|
||||
2 = soft MMU activation required for this block
|
||||
*/
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
|
||||
{
|
||||
uint8_t *pde_ptr, *pte_ptr;
|
||||
uint32_t pde, pte, virt_addr;
|
||||
int cpl, error_code, is_dirty, is_user, prot, page_size, ret;
|
||||
unsigned long pd;
|
||||
|
||||
cpl = env->hflags & HF_CPL_MASK;
|
||||
is_user = (cpl == 3);
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
|
||||
addr, is_write, is_user, env->eip);
|
||||
#endif
|
||||
|
||||
if (env->user_mode_only) {
|
||||
/* user mode only emulation */
|
||||
error_code = 0;
|
||||
goto do_fault;
|
||||
}
|
||||
|
||||
if (!(env->cr[0] & CR0_PG_MASK)) {
|
||||
pte = addr;
|
||||
virt_addr = addr & ~0xfff;
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
page_size = 4096;
|
||||
goto do_mapping;
|
||||
}
|
||||
|
||||
/* page directory entry */
|
||||
pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3));
|
||||
pde = ldl(pde_ptr);
|
||||
if (!(pde & PG_PRESENT_MASK)) {
|
||||
error_code = 0;
|
||||
goto do_fault;
|
||||
}
|
||||
if (is_user) {
|
||||
if (!(pde & PG_USER_MASK))
|
||||
goto do_fault_protect;
|
||||
if (is_write && !(pde & PG_RW_MASK))
|
||||
goto do_fault_protect;
|
||||
} else {
|
||||
if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) &&
|
||||
is_write && !(pde & PG_RW_MASK))
|
||||
goto do_fault_protect;
|
||||
}
|
||||
/* if PSE bit is set, then we use a 4MB page */
|
||||
if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
|
||||
is_dirty = is_write && !(pde & PG_DIRTY_MASK);
|
||||
if (!(pde & PG_ACCESSED_MASK)) {
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
if (is_dirty)
|
||||
pde |= PG_DIRTY_MASK;
|
||||
stl(pde_ptr, pde);
|
||||
}
|
||||
|
||||
pte = pde & ~0x003ff000; /* align to 4MB */
|
||||
page_size = 4096 * 1024;
|
||||
virt_addr = addr & ~0x003fffff;
|
||||
} else {
|
||||
if (!(pde & PG_ACCESSED_MASK)) {
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
stl(pde_ptr, pde);
|
||||
}
|
||||
|
||||
/* page directory entry */
|
||||
pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc));
|
||||
pte = ldl(pte_ptr);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
error_code = 0;
|
||||
goto do_fault;
|
||||
}
|
||||
if (is_user) {
|
||||
if (!(pte & PG_USER_MASK))
|
||||
goto do_fault_protect;
|
||||
if (is_write && !(pte & PG_RW_MASK))
|
||||
goto do_fault_protect;
|
||||
} else {
|
||||
if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) &&
|
||||
is_write && !(pte & PG_RW_MASK))
|
||||
goto do_fault_protect;
|
||||
}
|
||||
is_dirty = is_write && !(pte & PG_DIRTY_MASK);
|
||||
if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
|
||||
pte |= PG_ACCESSED_MASK;
|
||||
if (is_dirty)
|
||||
pte |= PG_DIRTY_MASK;
|
||||
stl(pte_ptr, pte);
|
||||
}
|
||||
page_size = 4096;
|
||||
virt_addr = addr & ~0xfff;
|
||||
}
|
||||
/* the page can be put in the TLB */
|
||||
prot = PROT_READ;
|
||||
if (is_user) {
|
||||
if (pte & PG_RW_MASK)
|
||||
prot |= PROT_WRITE;
|
||||
} else {
|
||||
if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) ||
|
||||
(pte & PG_RW_MASK))
|
||||
prot |= PROT_WRITE;
|
||||
}
|
||||
|
||||
do_mapping:
|
||||
if (env->hflags & HF_SOFTMMU_MASK) {
|
||||
unsigned long paddr, vaddr, address, addend, page_offset;
|
||||
int index;
|
||||
|
||||
/* software MMU case. Even if 4MB pages, we map only one 4KB
|
||||
page in the cache to avoid filling it too fast */
|
||||
page_offset = (addr & ~0xfff) & (page_size - 1);
|
||||
paddr = (pte & ~0xfff) + page_offset;
|
||||
vaddr = virt_addr + page_offset;
|
||||
index = (addr >> 12) & (CPU_TLB_SIZE - 1);
|
||||
pd = physpage_find(paddr);
|
||||
if (pd & 0xfff) {
|
||||
/* IO memory case */
|
||||
address = vaddr | pd;
|
||||
addend = paddr;
|
||||
} else {
|
||||
/* standard memory */
|
||||
address = vaddr;
|
||||
addend = (unsigned long)phys_ram_base + pd;
|
||||
}
|
||||
addend -= vaddr;
|
||||
env->tlb_read[is_user][index].address = address;
|
||||
env->tlb_read[is_user][index].addend = addend;
|
||||
if (prot & PROT_WRITE) {
|
||||
env->tlb_write[is_user][index].address = address;
|
||||
env->tlb_write[is_user][index].addend = addend;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
/* XXX: incorrect for 4MB pages */
|
||||
pd = physpage_find(pte & ~0xfff);
|
||||
if ((pd & 0xfff) != 0) {
|
||||
/* IO access: no mapping is done as it will be handled by the
|
||||
soft MMU */
|
||||
if (!(env->hflags & HF_SOFTMMU_MASK))
|
||||
ret = 2;
|
||||
} else {
|
||||
void *map_addr;
|
||||
map_addr = mmap((void *)virt_addr, page_size, prot,
|
||||
MAP_SHARED | MAP_FIXED, phys_ram_fd, pd);
|
||||
if (map_addr == MAP_FAILED) {
|
||||
fprintf(stderr,
|
||||
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
|
||||
pte & ~0xfff, virt_addr);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
|
||||
pte & ~0xfff, virt_addr, (page_size != 4096));
|
||||
#endif
|
||||
page_set_flags(virt_addr, virt_addr + page_size,
|
||||
PAGE_VALID | PAGE_EXEC | prot);
|
||||
}
|
||||
return ret;
|
||||
do_fault_protect:
|
||||
error_code = PG_ERROR_P_MASK;
|
||||
do_fault:
|
||||
env->cr[2] = addr;
|
||||
env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
|
||||
if (is_user)
|
||||
env->error_code |= PG_ERROR_U_MASK;
|
||||
return 1;
|
||||
}
|
420
hw/vga_template.h
Normal file
420
hw/vga_template.h
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* QEMU VGA Emulator templates
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
#define BPP 1
|
||||
#define PIXEL_TYPE uint8_t
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
#define BPP 2
|
||||
#define PIXEL_TYPE uint16_t
|
||||
#elif DEPTH == 32
|
||||
#define BPP 4
|
||||
#define PIXEL_TYPE uint32_t
|
||||
#else
|
||||
#error unsupport depth
|
||||
#endif
|
||||
|
||||
#if DEPTH != 15
|
||||
|
||||
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
|
||||
uint32_t font_data,
|
||||
uint32_t xorcol,
|
||||
uint32_t bgcol)
|
||||
{
|
||||
#if BPP == 1
|
||||
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
#elif BPP == 2
|
||||
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol)
|
||||
{
|
||||
uint32_t font_data, xorcol;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d,
|
||||
expand4to8[font_data >> 4],
|
||||
xorcol, bgcol);
|
||||
glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
|
||||
expand4to8[font_data & 0x0f],
|
||||
xorcol, bgcol);
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
|
||||
const uint8_t *font_ptr, int h,
|
||||
uint32_t fgcol, uint32_t bgcol, int dup9)
|
||||
{
|
||||
uint32_t font_data, xorcol, v;
|
||||
|
||||
xorcol = bgcol ^ fgcol;
|
||||
do {
|
||||
font_data = font_ptr[0];
|
||||
/* XXX: unaligned accesses are done */
|
||||
#if BPP == 1
|
||||
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
||||
v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = v;
|
||||
if (dup9)
|
||||
((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
|
||||
else
|
||||
((uint8_t *)d)[8] = bgcol;
|
||||
|
||||
#elif BPP == 2
|
||||
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
||||
v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = v;
|
||||
if (dup9)
|
||||
((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
|
||||
else
|
||||
((uint16_t *)d)[8] = bgcol;
|
||||
#else
|
||||
((uint32_t *)d)[0] = ((-(font_data >> 7)) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[1] = ((-(font_data >> 6) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[2] = ((-(font_data >> 5) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[3] = ((-(font_data >> 4) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[4] = ((-(font_data >> 3) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[5] = ((-(font_data >> 2) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[6] = ((-(font_data >> 1) & 1) & xorcol) ^ bgcol;
|
||||
v = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol;
|
||||
((uint32_t *)d)[7] = v;
|
||||
if (dup9)
|
||||
((uint32_t *)d)[8] = v;
|
||||
else
|
||||
((uint32_t *)d)[8] = bgcol;
|
||||
#endif
|
||||
font_ptr += 4;
|
||||
d += linesize;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
/*
|
||||
* 4 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
((PIXEL_TYPE *)d)[4] = palette[v >> 12];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP == 1
|
||||
#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
|
||||
#elif BPP == 2
|
||||
#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
|
||||
#else
|
||||
#define PUT_PIXEL2(d, n, v) \
|
||||
((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
|
||||
|
||||
v = expand2[GET_PLANE(data, 1)];
|
||||
v |= expand2[GET_PLANE(data, 3)] << 2;
|
||||
PUT_PIXEL2(d, 4, palette[v >> 12]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode
|
||||
*/
|
||||
static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
((PIXEL_TYPE *)d)[0] = palette[v >> 28];
|
||||
((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
|
||||
((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
|
||||
((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
|
||||
((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
|
||||
((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
|
||||
((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode, dup2 horizontal
|
||||
*/
|
||||
static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
plane_mask = mask16[s1->ar[0x12] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
data = ((uint32_t *)s)[0];
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
v |= expand4[GET_PLANE(data, 2)] << 2;
|
||||
v |= expand4[GET_PLANE(data, 3)] << 3;
|
||||
PUT_PIXEL2(d, 0, palette[v >> 28]);
|
||||
PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
|
||||
PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
|
||||
PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
|
||||
PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
|
||||
PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += BPP * 16;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 256 color mode, double pixels
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
PUT_PIXEL2(d, 0, palette[s[0]]);
|
||||
PUT_PIXEL2(d, 1, palette[s[1]]);
|
||||
PUT_PIXEL2(d, 2, palette[s[2]]);
|
||||
PUT_PIXEL2(d, 3, palette[s[3]]);
|
||||
d += BPP * 8;
|
||||
s += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* standard 256 color mode
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
palette = s1->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
((PIXEL_TYPE *)d)[0] = palette[s[0]];
|
||||
((PIXEL_TYPE *)d)[1] = palette[s[1]];
|
||||
((PIXEL_TYPE *)d)[2] = palette[s[2]];
|
||||
((PIXEL_TYPE *)d)[3] = palette[s[3]];
|
||||
((PIXEL_TYPE *)d)[4] = palette[s[4]];
|
||||
((PIXEL_TYPE *)d)[5] = palette[s[5]];
|
||||
((PIXEL_TYPE *)d)[6] = palette[s[6]];
|
||||
((PIXEL_TYPE *)d)[7] = palette[s[7]];
|
||||
d += BPP * 8;
|
||||
s += 8;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEPTH != 15 */
|
||||
|
||||
|
||||
/* XXX: optimize */
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 15 && !defined(WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 16 && !defined(WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 32 && !defined(WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 4);
|
||||
#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 4;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef PUT_PIXEL2
|
||||
#undef DEPTH
|
||||
#undef BPP
|
||||
#undef PIXEL_TYPE
|
140
i386-vl.ld
Normal file
140
i386-vl.ld
Normal file
@@ -0,0 +1,140 @@
|
||||
/* ld script to make i386 Linux kernel
|
||||
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
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: */
|
||||
. = 0xa8000000 + 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) }
|
||||
__preinit_array_start = .;
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
__preinit_array_end = .;
|
||||
__init_array_start = .;
|
||||
.init_array : { *(.init_array) }
|
||||
__init_array_end = .;
|
||||
__fini_array_start = .;
|
||||
.fini_array : { *(.fini_array) }
|
||||
__fini_array_end = .;
|
||||
|
||||
/* 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 . */
|
||||
}
|
@@ -74,7 +74,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
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 */
|
||||
/* XXX: it seems that r0 is zeroed after ! */
|
||||
// regs->ARM_r0 = tswapl(stack[0]); /* argc */
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -490,7 +491,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
* Force 16 byte alignment here for generality.
|
||||
*/
|
||||
sp = (unsigned int *) (~15UL & (unsigned long) p);
|
||||
sp -= exec ? DLINFO_ITEMS*2 : 2;
|
||||
sp -= DLINFO_ITEMS*2;
|
||||
dlinfo = sp;
|
||||
sp -= envc+1;
|
||||
envp = sp;
|
||||
@@ -505,21 +506,20 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
put_user (tswapl(id), dlinfo++); \
|
||||
put_user (tswapl(val), dlinfo++)
|
||||
|
||||
if (exec) { /* Put this here for an ELF program interpreter */
|
||||
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
||||
}
|
||||
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
||||
NEW_AUX_ENT (AT_NULL, 0);
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
put_user(tswapl(argc),--sp);
|
||||
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
||||
while (argc-->0) {
|
||||
@@ -1087,7 +1087,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
create_elf_tables((char *)bprm->p,
|
||||
bprm->argc,
|
||||
bprm->envc,
|
||||
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
|
||||
&elf_ex,
|
||||
load_addr, load_bias,
|
||||
interp_load_addr,
|
||||
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
||||
|
@@ -26,8 +26,6 @@
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
#include "cpu-i386.h"
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
FILE *logfile = NULL;
|
||||
@@ -100,6 +98,11 @@ int cpu_x86_inl(CPUX86State *env, int addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *env)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int flags)
|
||||
{
|
||||
@@ -176,7 +179,7 @@ void cpu_loop(CPUX86State *env)
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
else
|
||||
info.si_code = TARGET_SEGV_ACCERR;
|
||||
info._sifields._sigfault._addr = env->cr2;
|
||||
info._sifields._sigfault._addr = env->cr[2];
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP00_DIVZ:
|
||||
@@ -231,7 +234,7 @@ void cpu_loop(CPUX86State *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
pc = env->seg_cache[R_CS].base + env->eip;
|
||||
pc = env->segs[R_CS].base + env->eip;
|
||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||
(long)pc, trapnr);
|
||||
abort();
|
||||
@@ -243,8 +246,6 @@ void cpu_loop(CPUX86State *env)
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
@@ -282,6 +283,9 @@ void cpu_loop(CPUARMState *env)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
@@ -317,6 +321,9 @@ void usage(void)
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
CPUState *global_env;
|
||||
/* used only if single thread */
|
||||
CPUState *cpu_single_env = NULL;
|
||||
|
||||
/* used to free thread contexts */
|
||||
TaskState *first_task_state;
|
||||
|
||||
@@ -395,7 +402,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_init();
|
||||
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
_exit(1);
|
||||
@@ -423,8 +430,13 @@ int main(int argc, char **argv)
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
env->opaque = ts;
|
||||
ts->used = 1;
|
||||
env->user_mode_only = 1;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
cpu_x86_set_cpl(env, 3);
|
||||
|
||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||
|
||||
/* linux register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
env->regs[R_EBX] = regs->ebx;
|
||||
@@ -476,6 +488,7 @@ 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;
|
||||
|
@@ -6,8 +6,15 @@
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#include "cpu-" TARGET_ARCH ".h"
|
||||
#include "syscall-" TARGET_ARCH ".h"
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#include "syscall-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
* Basically, it replicates in user space what would be certain
|
||||
|
@@ -60,44 +60,122 @@ static int signal_pending; /* non zero if a signal may be pending */
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc);
|
||||
|
||||
/* XXX: do it properly */
|
||||
static uint8_t host_to_target_signal_table[65] = {
|
||||
[SIGHUP] = TARGET_SIGHUP,
|
||||
[SIGINT] = TARGET_SIGINT,
|
||||
[SIGQUIT] = TARGET_SIGQUIT,
|
||||
[SIGILL] = TARGET_SIGILL,
|
||||
[SIGTRAP] = TARGET_SIGTRAP,
|
||||
[SIGABRT] = TARGET_SIGABRT,
|
||||
[SIGIOT] = TARGET_SIGIOT,
|
||||
[SIGBUS] = TARGET_SIGBUS,
|
||||
[SIGFPE] = TARGET_SIGFPE,
|
||||
[SIGKILL] = TARGET_SIGKILL,
|
||||
[SIGUSR1] = TARGET_SIGUSR1,
|
||||
[SIGSEGV] = TARGET_SIGSEGV,
|
||||
[SIGUSR2] = TARGET_SIGUSR2,
|
||||
[SIGPIPE] = TARGET_SIGPIPE,
|
||||
[SIGALRM] = TARGET_SIGALRM,
|
||||
[SIGTERM] = TARGET_SIGTERM,
|
||||
#ifdef SIGSTKFLT
|
||||
[SIGSTKFLT] = TARGET_SIGSTKFLT,
|
||||
#endif
|
||||
[SIGCHLD] = TARGET_SIGCHLD,
|
||||
[SIGCONT] = TARGET_SIGCONT,
|
||||
[SIGSTOP] = TARGET_SIGSTOP,
|
||||
[SIGTSTP] = TARGET_SIGTSTP,
|
||||
[SIGTTIN] = TARGET_SIGTTIN,
|
||||
[SIGTTOU] = TARGET_SIGTTOU,
|
||||
[SIGURG] = TARGET_SIGURG,
|
||||
[SIGXCPU] = TARGET_SIGXCPU,
|
||||
[SIGXFSZ] = TARGET_SIGXFSZ,
|
||||
[SIGVTALRM] = TARGET_SIGVTALRM,
|
||||
[SIGPROF] = TARGET_SIGPROF,
|
||||
[SIGWINCH] = TARGET_SIGWINCH,
|
||||
[SIGIO] = TARGET_SIGIO,
|
||||
[SIGPWR] = TARGET_SIGPWR,
|
||||
[SIGSYS] = TARGET_SIGSYS,
|
||||
/* next signals stay the same */
|
||||
};
|
||||
static uint8_t target_to_host_signal_table[65];
|
||||
|
||||
static inline int host_to_target_signal(int sig)
|
||||
{
|
||||
return sig;
|
||||
return host_to_target_signal_table[sig];
|
||||
}
|
||||
|
||||
static inline int target_to_host_signal(int sig)
|
||||
{
|
||||
return sig;
|
||||
return target_to_host_signal_table[sig];
|
||||
}
|
||||
|
||||
void host_to_target_sigset(target_sigset_t *d, sigset_t *s)
|
||||
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
|
||||
unsigned long sigmask;
|
||||
uint32_t target_sigmask;
|
||||
|
||||
sigmask = ((unsigned long *)s)[0];
|
||||
target_sigmask = 0;
|
||||
for(i = 0; i < 32; i++) {
|
||||
if (sigmask & (1 << i))
|
||||
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
|
||||
}
|
||||
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
||||
d->sig[0] = tswapl(target_sigmask);
|
||||
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
||||
d->sig[i] = tswapl(((unsigned long *)s)[i]);
|
||||
}
|
||||
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
||||
d->sig[0] = tswapl(target_sigmask);
|
||||
d->sig[1] = tswapl(sigmask >> 32);
|
||||
#else
|
||||
#error host_to_target_sigset
|
||||
#endif
|
||||
}
|
||||
|
||||
void target_to_host_sigset(sigset_t *d, target_sigset_t *s)
|
||||
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
|
||||
unsigned long sigmask;
|
||||
target_ulong target_sigmask;
|
||||
|
||||
target_sigmask = tswapl(s->sig[0]);
|
||||
sigmask = 0;
|
||||
for(i = 0; i < 32; i++) {
|
||||
if (target_sigmask & (1 << i))
|
||||
sigmask |= 1 << (target_to_host_signal(i + 1) - 1);
|
||||
}
|
||||
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
|
||||
((unsigned long *)d)[0] = sigmask;
|
||||
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
|
||||
((unsigned long *)d)[i] = tswapl(s->sig[i]);
|
||||
}
|
||||
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
|
||||
((unsigned long *)d)[0] = sigmask | ((unsigned long)tswapl(s->sig[1]) << 32);
|
||||
#else
|
||||
#error target_to_host_sigset
|
||||
#endif /* TARGET_LONG_BITS */
|
||||
}
|
||||
|
||||
void host_to_target_old_sigset(target_ulong *old_sigset,
|
||||
const sigset_t *sigset)
|
||||
{
|
||||
*old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff);
|
||||
target_sigset_t d;
|
||||
host_to_target_sigset(&d, sigset);
|
||||
*old_sigset = d.sig[0];
|
||||
}
|
||||
|
||||
void target_to_host_old_sigset(sigset_t *sigset,
|
||||
const target_ulong *old_sigset)
|
||||
{
|
||||
sigemptyset(sigset);
|
||||
*(unsigned long *)sigset = tswapl(*old_sigset);
|
||||
target_sigset_t d;
|
||||
int i;
|
||||
|
||||
d.sig[0] = *old_sigset;
|
||||
for(i = 1;i < TARGET_NSIG_WORDS; i++)
|
||||
d.sig[i] = 0;
|
||||
target_to_host_sigset(sigset, &d);
|
||||
}
|
||||
|
||||
/* siginfo conversion */
|
||||
@@ -167,8 +245,18 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
|
||||
void signal_init(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
/* generate signal conversion tables */
|
||||
for(i = 1; i <= 64; i++) {
|
||||
if (host_to_target_signal_table[i] == 0)
|
||||
host_to_target_signal_table[i] = i;
|
||||
}
|
||||
for(i = 1; i <= 64; i++) {
|
||||
j = host_to_target_signal_table[i];
|
||||
target_to_host_signal_table[j] = i;
|
||||
}
|
||||
|
||||
/* set all host signal handlers. ALL signals are blocked during
|
||||
the handlers to serialize them. */
|
||||
sigfillset(&act.sa_mask);
|
||||
@@ -333,7 +421,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_interrupt(global_env);
|
||||
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,6 +452,80 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define __put_user(x,ptr)\
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
stb(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 2:\
|
||||
stw(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 4:\
|
||||
stl(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 8:\
|
||||
stq(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __get_user(x, ptr) \
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
x = (typeof(*ptr))ldub(ptr);\
|
||||
break;\
|
||||
case 2:\
|
||||
x = (typeof(*ptr))lduw(ptr);\
|
||||
break;\
|
||||
case 4:\
|
||||
x = (typeof(*ptr))ldl(ptr);\
|
||||
break;\
|
||||
case 8:\
|
||||
x = (typeof(*ptr))ldq(ptr);\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
|
||||
#define __copy_to_user(dst, src, size)\
|
||||
({\
|
||||
memcpy(dst, src, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __copy_from_user(dst, src, size)\
|
||||
({\
|
||||
memcpy(dst, src, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define __clear_user(dst, size)\
|
||||
({\
|
||||
memset(dst, 0, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
|
||||
const target_siginfo_t *info)
|
||||
{
|
||||
tswap_siginfo(tinfo, info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
/* from the Linux kernel */
|
||||
@@ -472,44 +634,6 @@ struct rt_sigframe
|
||||
* Set up a signal frame.
|
||||
*/
|
||||
|
||||
#define __put_user(x,ptr)\
|
||||
({\
|
||||
int size = sizeof(*ptr);\
|
||||
switch(size) {\
|
||||
case 1:\
|
||||
stb(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 2:\
|
||||
stw(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 4:\
|
||||
stl(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
case 8:\
|
||||
stq(ptr, (typeof(*ptr))(x));\
|
||||
break;\
|
||||
default:\
|
||||
abort();\
|
||||
}\
|
||||
0;\
|
||||
})
|
||||
|
||||
#define get_user(val, ptr) (typeof(*ptr))(*(ptr))
|
||||
|
||||
|
||||
#define __copy_to_user(dst, src, size)\
|
||||
({\
|
||||
memcpy(dst, src, size);\
|
||||
0;\
|
||||
})
|
||||
|
||||
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
|
||||
const target_siginfo_t *info)
|
||||
{
|
||||
tswap_siginfo(tinfo, info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: save x87 state */
|
||||
static int
|
||||
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
@@ -517,10 +641,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs);
|
||||
err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs);
|
||||
err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es);
|
||||
err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds);
|
||||
err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
|
||||
err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
|
||||
err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
|
||||
err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
|
||||
err |= __put_user(env->regs[R_EDI], &sc->edi);
|
||||
err |= __put_user(env->regs[R_ESI], &sc->esi);
|
||||
err |= __put_user(env->regs[R_EBP], &sc->ebp);
|
||||
@@ -532,10 +656,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
err |= __put_user(env->exception_index, &sc->trapno);
|
||||
err |= __put_user(env->error_code, &sc->err);
|
||||
err |= __put_user(env->eip, &sc->eip);
|
||||
err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs);
|
||||
err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
|
||||
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);
|
||||
err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
|
||||
|
||||
cpu_x86_fsave(env, (void *)fpstate, 1);
|
||||
fpstate->status = fpstate->sw;
|
||||
@@ -544,7 +668,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
|
||||
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __put_user(env->cr2, &sc->cr2);
|
||||
err |= __put_user(env->cr[2], &sc->cr2);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -567,13 +691,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
|
||||
}
|
||||
|
||||
/* This is the legacy signal stack switching. */
|
||||
else if ((regs->xss & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & SA_RESTORER) &&
|
||||
ka->sa.sa_restorer) {
|
||||
esp = (unsigned long) ka->sa.sa_restorer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return (void *)((esp - frame_size) & -8ul);
|
||||
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
|
||||
ka->sa.sa_restorer) {
|
||||
esp = (unsigned long) ka->sa.sa_restorer;
|
||||
}
|
||||
return (void *)((esp - frame_size) & -8ul);
|
||||
}
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
@@ -824,6 +949,377 @@ badframe:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
struct target_sigcontext {
|
||||
target_ulong trap_no;
|
||||
target_ulong error_code;
|
||||
target_ulong oldmask;
|
||||
target_ulong arm_r0;
|
||||
target_ulong arm_r1;
|
||||
target_ulong arm_r2;
|
||||
target_ulong arm_r3;
|
||||
target_ulong arm_r4;
|
||||
target_ulong arm_r5;
|
||||
target_ulong arm_r6;
|
||||
target_ulong arm_r7;
|
||||
target_ulong arm_r8;
|
||||
target_ulong arm_r9;
|
||||
target_ulong arm_r10;
|
||||
target_ulong arm_fp;
|
||||
target_ulong arm_ip;
|
||||
target_ulong arm_sp;
|
||||
target_ulong arm_lr;
|
||||
target_ulong arm_pc;
|
||||
target_ulong arm_cpsr;
|
||||
target_ulong fault_address;
|
||||
};
|
||||
|
||||
typedef struct target_sigaltstack {
|
||||
target_ulong ss_sp;
|
||||
int ss_flags;
|
||||
target_ulong ss_size;
|
||||
} target_stack_t;
|
||||
|
||||
struct target_ucontext {
|
||||
target_ulong uc_flags;
|
||||
target_ulong uc_link;
|
||||
target_stack_t uc_stack;
|
||||
struct target_sigcontext uc_mcontext;
|
||||
target_sigset_t uc_sigmask; /* mask last for extensibility */
|
||||
};
|
||||
|
||||
struct sigframe
|
||||
{
|
||||
struct target_sigcontext sc;
|
||||
target_ulong extramask[TARGET_NSIG_WORDS-1];
|
||||
target_ulong retcode;
|
||||
};
|
||||
|
||||
struct rt_sigframe
|
||||
{
|
||||
struct target_siginfo *pinfo;
|
||||
void *puc;
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
target_ulong retcode;
|
||||
};
|
||||
|
||||
#define TARGET_CONFIG_CPU_32 1
|
||||
|
||||
/*
|
||||
* For ARM syscalls, we encode the syscall number into the instruction.
|
||||
*/
|
||||
#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
|
||||
#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
|
||||
|
||||
/*
|
||||
* For Thumb syscalls, we pass the syscall number via r7. We therefore
|
||||
* need two 16-bit instructions.
|
||||
*/
|
||||
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
|
||||
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
|
||||
|
||||
static const target_ulong retcodes[4] = {
|
||||
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
|
||||
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
|
||||
};
|
||||
|
||||
|
||||
#define __put_user_error(x,p,e) __put_user(x, p)
|
||||
#define __get_user_error(x,p,e) __get_user(x, p)
|
||||
|
||||
static inline int valid_user_regs(CPUState *regs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
|
||||
CPUState *env, unsigned long mask)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
__put_user_error(env->regs[0], &sc->arm_r0, err);
|
||||
__put_user_error(env->regs[1], &sc->arm_r1, err);
|
||||
__put_user_error(env->regs[2], &sc->arm_r2, err);
|
||||
__put_user_error(env->regs[3], &sc->arm_r3, err);
|
||||
__put_user_error(env->regs[4], &sc->arm_r4, err);
|
||||
__put_user_error(env->regs[5], &sc->arm_r5, err);
|
||||
__put_user_error(env->regs[6], &sc->arm_r6, err);
|
||||
__put_user_error(env->regs[7], &sc->arm_r7, err);
|
||||
__put_user_error(env->regs[8], &sc->arm_r8, err);
|
||||
__put_user_error(env->regs[9], &sc->arm_r9, err);
|
||||
__put_user_error(env->regs[10], &sc->arm_r10, err);
|
||||
__put_user_error(env->regs[11], &sc->arm_fp, err);
|
||||
__put_user_error(env->regs[12], &sc->arm_ip, err);
|
||||
__put_user_error(env->regs[13], &sc->arm_sp, err);
|
||||
__put_user_error(env->regs[14], &sc->arm_lr, err);
|
||||
__put_user_error(env->regs[15], &sc->arm_pc, err);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__put_user_error(env->cpsr, &sc->arm_cpsr, err);
|
||||
#endif
|
||||
|
||||
__put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
|
||||
__put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err);
|
||||
__put_user_error(/* current->thread.address */ 0, &sc->fault_address, err);
|
||||
__put_user_error(mask, &sc->oldmask, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize)
|
||||
{
|
||||
unsigned long sp = regs->regs[13];
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is the X/Open sanctioned signal stack switching.
|
||||
*/
|
||||
if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
|
||||
sp = current->sas_ss_sp + current->sas_ss_size;
|
||||
#endif
|
||||
/*
|
||||
* ATPCS B01 mandates 8-byte alignment
|
||||
*/
|
||||
return (void *)((sp - framesize) & ~7);
|
||||
}
|
||||
|
||||
static int
|
||||
setup_return(CPUState *env, struct emulated_sigaction *ka,
|
||||
target_ulong *rc, void *frame, int usig)
|
||||
{
|
||||
target_ulong handler = (target_ulong)ka->sa._sa_handler;
|
||||
target_ulong retcode;
|
||||
int thumb = 0;
|
||||
#if defined(TARGET_CONFIG_CPU_32)
|
||||
target_ulong cpsr = env->cpsr;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
|
||||
*/
|
||||
if (ka->sa.sa_flags & SA_THIRTYTWO)
|
||||
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
|
||||
|
||||
#ifdef CONFIG_ARM_THUMB
|
||||
if (elf_hwcap & HWCAP_THUMB) {
|
||||
/*
|
||||
* The LSB of the handler determines if we're going to
|
||||
* be using THUMB or ARM mode for this signal handler.
|
||||
*/
|
||||
thumb = handler & 1;
|
||||
|
||||
if (thumb)
|
||||
cpsr |= T_BIT;
|
||||
else
|
||||
cpsr &= ~T_BIT;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif /* TARGET_CONFIG_CPU_32 */
|
||||
|
||||
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
|
||||
retcode = (target_ulong)ka->sa.sa_restorer;
|
||||
} else {
|
||||
unsigned int idx = thumb;
|
||||
|
||||
if (ka->sa.sa_flags & TARGET_SA_SIGINFO)
|
||||
idx += 2;
|
||||
|
||||
if (__put_user(retcodes[idx], rc))
|
||||
return 1;
|
||||
#if 0
|
||||
flush_icache_range((target_ulong)rc,
|
||||
(target_ulong)(rc + 1));
|
||||
#endif
|
||||
retcode = ((target_ulong)rc) + thumb;
|
||||
}
|
||||
|
||||
env->regs[0] = usig;
|
||||
env->regs[13] = (target_ulong)frame;
|
||||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
env->cpsr = cpsr;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_frame(int usig, struct emulated_sigaction *ka,
|
||||
target_sigset_t *set, CPUState *regs)
|
||||
{
|
||||
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
int err = 0;
|
||||
|
||||
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
|
||||
|
||||
if (TARGET_NSIG_WORDS > 1) {
|
||||
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask));
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
err = setup_return(regs, ka, &frame->retcode, frame, usig);
|
||||
// return err;
|
||||
}
|
||||
|
||||
static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
int err = 0;
|
||||
|
||||
#if 0
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
|
||||
return 1;
|
||||
#endif
|
||||
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
|
||||
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
|
||||
err |= copy_siginfo_to_user(&frame->info, info);
|
||||
|
||||
/* Clear all the bits of the ucontext we don't use. */
|
||||
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
|
||||
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
|
||||
env, set->sig[0]);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
if (err == 0)
|
||||
err = setup_return(env, ka, &frame->retcode, frame, usig);
|
||||
|
||||
if (err == 0) {
|
||||
/*
|
||||
* For realtime signals we must also set the second and third
|
||||
* arguments for the signal handler.
|
||||
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
|
||||
*/
|
||||
env->regs[1] = (target_ulong)frame->pinfo;
|
||||
env->regs[2] = (target_ulong)frame->puc;
|
||||
}
|
||||
|
||||
// return err;
|
||||
}
|
||||
|
||||
static int
|
||||
restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
__get_user_error(env->regs[0], &sc->arm_r0, err);
|
||||
__get_user_error(env->regs[1], &sc->arm_r1, err);
|
||||
__get_user_error(env->regs[2], &sc->arm_r2, err);
|
||||
__get_user_error(env->regs[3], &sc->arm_r3, err);
|
||||
__get_user_error(env->regs[4], &sc->arm_r4, err);
|
||||
__get_user_error(env->regs[5], &sc->arm_r5, err);
|
||||
__get_user_error(env->regs[6], &sc->arm_r6, err);
|
||||
__get_user_error(env->regs[7], &sc->arm_r7, err);
|
||||
__get_user_error(env->regs[8], &sc->arm_r8, err);
|
||||
__get_user_error(env->regs[9], &sc->arm_r9, err);
|
||||
__get_user_error(env->regs[10], &sc->arm_r10, err);
|
||||
__get_user_error(env->regs[11], &sc->arm_fp, err);
|
||||
__get_user_error(env->regs[12], &sc->arm_ip, err);
|
||||
__get_user_error(env->regs[13], &sc->arm_sp, err);
|
||||
__get_user_error(env->regs[14], &sc->arm_lr, err);
|
||||
__get_user_error(env->regs[15], &sc->arm_pc, err);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__get_user_error(env->cpsr, &sc->arm_cpsr, err);
|
||||
#endif
|
||||
|
||||
err |= !valid_user_regs(env);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUState *env)
|
||||
{
|
||||
struct sigframe *frame;
|
||||
target_sigset_t set;
|
||||
sigset_t host_set;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
* then 'sp' should be word aligned here. If it's
|
||||
* not, then the user is trying to mess with us.
|
||||
*/
|
||||
if (env->regs[13] & 7)
|
||||
goto badframe;
|
||||
|
||||
frame = (struct sigframe *)env->regs[13];
|
||||
|
||||
#if 0
|
||||
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
||||
goto badframe;
|
||||
#endif
|
||||
if (__get_user(set.sig[0], &frame->sc.oldmask)
|
||||
|| (TARGET_NSIG_WORDS > 1
|
||||
&& __copy_from_user(&set.sig[1], &frame->extramask,
|
||||
sizeof(frame->extramask))))
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset(&host_set, &set);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->sc))
|
||||
goto badframe;
|
||||
|
||||
#if 0
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
if (ptrace_cancel_bpt(current))
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
#endif
|
||||
return env->regs[0];
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV /* , current */);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUState *env)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
target_sigset_t set;
|
||||
sigset_t host_set;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
* then 'sp' should be word aligned here. If it's
|
||||
* not, then the user is trying to mess with us.
|
||||
*/
|
||||
if (env->regs[13] & 7)
|
||||
goto badframe;
|
||||
|
||||
frame = (struct rt_sigframe *)env->regs[13];
|
||||
|
||||
#if 0
|
||||
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
|
||||
goto badframe;
|
||||
#endif
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset(&host_set, &set);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
|
||||
goto badframe;
|
||||
|
||||
#if 0
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
if (ptrace_cancel_bpt(current))
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
#endif
|
||||
return env->regs[0];
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV /* , current */);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
|
@@ -68,6 +68,129 @@
|
||||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
|
||||
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
|
||||
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#undef __syscall_nr
|
||||
#undef __sc_loadargs_0
|
||||
#undef __sc_loadargs_1
|
||||
#undef __sc_loadargs_2
|
||||
#undef __sc_loadargs_3
|
||||
#undef __sc_loadargs_4
|
||||
#undef __sc_loadargs_5
|
||||
#undef __sc_asm_input_0
|
||||
#undef __sc_asm_input_1
|
||||
#undef __sc_asm_input_2
|
||||
#undef __sc_asm_input_3
|
||||
#undef __sc_asm_input_4
|
||||
#undef __sc_asm_input_5
|
||||
#undef _syscall0
|
||||
#undef _syscall1
|
||||
#undef _syscall2
|
||||
#undef _syscall3
|
||||
#undef _syscall4
|
||||
#undef _syscall5
|
||||
|
||||
/* need to redefine syscalls as Linux kernel defines are incorrect for
|
||||
the clobber list */
|
||||
/* On powerpc a system call basically clobbers the same registers like a
|
||||
* function call, with the exception of LR (which is needed for the
|
||||
* "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal
|
||||
* an error return status).
|
||||
*/
|
||||
|
||||
#define __syscall_nr(nr, type, name, args...) \
|
||||
unsigned long __sc_ret, __sc_err; \
|
||||
{ \
|
||||
register unsigned long __sc_0 __asm__ ("r0"); \
|
||||
register unsigned long __sc_3 __asm__ ("r3"); \
|
||||
register unsigned long __sc_4 __asm__ ("r4"); \
|
||||
register unsigned long __sc_5 __asm__ ("r5"); \
|
||||
register unsigned long __sc_6 __asm__ ("r6"); \
|
||||
register unsigned long __sc_7 __asm__ ("r7"); \
|
||||
\
|
||||
__sc_loadargs_##nr(name, args); \
|
||||
__asm__ __volatile__ \
|
||||
("sc \n\t" \
|
||||
"mfcr %0 " \
|
||||
: "=&r" (__sc_0), \
|
||||
"=&r" (__sc_3), "=&r" (__sc_4), \
|
||||
"=&r" (__sc_5), "=&r" (__sc_6), \
|
||||
"=&r" (__sc_7) \
|
||||
: __sc_asm_input_##nr \
|
||||
: "cr0", "ctr", "memory", \
|
||||
"r8", "r9", "r10","r11", "r12"); \
|
||||
__sc_ret = __sc_3; \
|
||||
__sc_err = __sc_0; \
|
||||
} \
|
||||
if (__sc_err & 0x10000000) \
|
||||
{ \
|
||||
errno = __sc_ret; \
|
||||
__sc_ret = -1; \
|
||||
} \
|
||||
return (type) __sc_ret
|
||||
|
||||
#define __sc_loadargs_0(name, dummy...) \
|
||||
__sc_0 = __NR_##name
|
||||
#define __sc_loadargs_1(name, arg1) \
|
||||
__sc_loadargs_0(name); \
|
||||
__sc_3 = (unsigned long) (arg1)
|
||||
#define __sc_loadargs_2(name, arg1, arg2) \
|
||||
__sc_loadargs_1(name, arg1); \
|
||||
__sc_4 = (unsigned long) (arg2)
|
||||
#define __sc_loadargs_3(name, arg1, arg2, arg3) \
|
||||
__sc_loadargs_2(name, arg1, arg2); \
|
||||
__sc_5 = (unsigned long) (arg3)
|
||||
#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4) \
|
||||
__sc_loadargs_3(name, arg1, arg2, arg3); \
|
||||
__sc_6 = (unsigned long) (arg4)
|
||||
#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5) \
|
||||
__sc_loadargs_4(name, arg1, arg2, arg3, arg4); \
|
||||
__sc_7 = (unsigned long) (arg5)
|
||||
|
||||
#define __sc_asm_input_0 "0" (__sc_0)
|
||||
#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
|
||||
#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4)
|
||||
#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
|
||||
#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
|
||||
#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
|
||||
|
||||
#define _syscall0(type,name) \
|
||||
type name(void) \
|
||||
{ \
|
||||
__syscall_nr(0, type, name); \
|
||||
}
|
||||
|
||||
#define _syscall1(type,name,type1,arg1) \
|
||||
type name(type1 arg1) \
|
||||
{ \
|
||||
__syscall_nr(1, type, name, arg1); \
|
||||
}
|
||||
|
||||
#define _syscall2(type,name,type1,arg1,type2,arg2) \
|
||||
type name(type1 arg1, type2 arg2) \
|
||||
{ \
|
||||
__syscall_nr(2, type, name, arg1, arg2); \
|
||||
}
|
||||
|
||||
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
|
||||
type name(type1 arg1, type2 arg2, type3 arg3) \
|
||||
{ \
|
||||
__syscall_nr(3, type, name, arg1, arg2, arg3); \
|
||||
}
|
||||
|
||||
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
|
||||
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
|
||||
{ \
|
||||
__syscall_nr(4, type, name, arg1, arg2, arg3, arg4); \
|
||||
}
|
||||
|
||||
#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) \
|
||||
{ \
|
||||
__syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define __NR_sys_uname __NR_uname
|
||||
#define __NR_sys_getcwd1 __NR_getcwd
|
||||
#define __NR_sys_statfs __NR_statfs
|
||||
@@ -210,6 +333,21 @@ static inline void host_to_target_fds(target_long *target_fds,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__alpha__)
|
||||
#define HOST_HZ 1024
|
||||
#else
|
||||
#define HOST_HZ 100
|
||||
#endif
|
||||
|
||||
static inline long host_to_target_clock_t(long ticks)
|
||||
{
|
||||
#if HOST_HZ == TARGET_HZ
|
||||
return ticks;
|
||||
#else
|
||||
return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void host_to_target_rusage(struct target_rusage *target_rusage,
|
||||
const struct rusage *rusage)
|
||||
{
|
||||
@@ -1423,11 +1561,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
struct tms tms;
|
||||
ret = get_errno(times(&tms));
|
||||
if (tmsp) {
|
||||
tmsp->tms_utime = tswapl(tms.tms_utime);
|
||||
tmsp->tms_stime = tswapl(tms.tms_stime);
|
||||
tmsp->tms_cutime = tswapl(tms.tms_cutime);
|
||||
tmsp->tms_cstime = tswapl(tms.tms_cstime);
|
||||
tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
|
||||
tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
|
||||
tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
|
||||
tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
|
||||
}
|
||||
if (!is_error(ret))
|
||||
ret = host_to_target_clock_t(ret);
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_prof:
|
||||
@@ -1763,7 +1903,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_select:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct target_sel_arg_struct *sel = (void *)arg1;
|
||||
sel->n = tswapl(sel->n);
|
||||
sel->inp = tswapl(sel->inp);
|
||||
sel->outp = tswapl(sel->outp);
|
||||
sel->exp = tswapl(sel->exp);
|
||||
sel->tvp = tswapl(sel->tvp);
|
||||
ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp,
|
||||
(void *)sel->exp, (void *)sel->tvp);
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_symlink:
|
||||
ret = get_errno(symlink((const char *)arg1, (const char *)arg2));
|
||||
break;
|
||||
@@ -1781,8 +1931,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
goto unimplemented;
|
||||
case TARGET_NR_readdir:
|
||||
goto unimplemented;
|
||||
#ifdef TARGET_I386
|
||||
case TARGET_NR_mmap:
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
{
|
||||
uint32_t v1, v2, v3, v4, v5, v6, *vptr;
|
||||
vptr = (uint32_t *)arg1;
|
||||
@@ -1796,13 +1946,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
target_to_host_bitmask(v4, mmap_flags_tbl),
|
||||
v5, v6));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_I386
|
||||
case TARGET_NR_mmap2:
|
||||
#else
|
||||
case TARGET_NR_mmap:
|
||||
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
||||
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
||||
arg5,
|
||||
arg6));
|
||||
#endif
|
||||
break;
|
||||
case TARGET_NR_mmap2:
|
||||
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
||||
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
||||
arg5,
|
||||
|
@@ -383,6 +383,8 @@ struct target_itimerval {
|
||||
|
||||
typedef target_long target_clock_t;
|
||||
|
||||
#define TARGET_HZ 100
|
||||
|
||||
struct target_tms {
|
||||
target_clock_t tms_utime;
|
||||
target_clock_t tms_stime;
|
||||
@@ -390,6 +392,12 @@ struct target_tms {
|
||||
target_clock_t tms_cstime;
|
||||
};
|
||||
|
||||
struct target_sel_arg_struct {
|
||||
target_long n;
|
||||
target_long inp, outp, exp;
|
||||
target_long tvp;
|
||||
};
|
||||
|
||||
struct target_iovec {
|
||||
target_long iov_base; /* Starting address */
|
||||
target_long iov_len; /* Number of bytes */
|
||||
@@ -533,8 +541,8 @@ static inline void target_siginitset(target_sigset_t *d, target_ulong set)
|
||||
d->sig[i] = 0;
|
||||
}
|
||||
|
||||
void host_to_target_sigset(target_sigset_t *d, sigset_t *s);
|
||||
void target_to_host_sigset(sigset_t *d, target_sigset_t *s);
|
||||
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
|
||||
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
|
||||
void host_to_target_old_sigset(target_ulong *old_sigset,
|
||||
const sigset_t *sigset);
|
||||
void target_to_host_old_sigset(sigset_t *sigset,
|
||||
@@ -584,6 +592,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
#define TARGET_SIGPROF 27
|
||||
#define TARGET_SIGWINCH 28
|
||||
#define TARGET_SIGIO 29
|
||||
#define TARGET_SIGPWR 30
|
||||
#define TARGET_SIGSYS 31
|
||||
#define TARGET_SIGRTMIN 32
|
||||
|
||||
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
|
||||
|
@@ -73,17 +73,17 @@ void save_v86_state(CPUX86State *env)
|
||||
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
|
||||
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
|
||||
ts->target_v86->regs.eip = tswap32(env->eip);
|
||||
ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
|
||||
ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
|
||||
ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
|
||||
ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
|
||||
ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
|
||||
ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
|
||||
ts->target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
|
||||
ts->target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
|
||||
ts->target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
|
||||
ts->target_v86->regs.es = tswap16(env->segs[R_ES].selector);
|
||||
ts->target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
|
||||
ts->target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
|
||||
set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
|
||||
ts->target_v86->regs.eflags = tswap32(env->eflags);
|
||||
#ifdef DEBUG_VM86
|
||||
fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
|
||||
env->eflags, env->segs[R_CS], env->eip);
|
||||
env->eflags, env->segs[R_CS].selector, env->eip);
|
||||
#endif
|
||||
|
||||
/* restore 32 bit registers */
|
||||
@@ -180,6 +180,7 @@ static inline unsigned int get_vflags(CPUX86State *env)
|
||||
flags = env->eflags & RETURN_MASK;
|
||||
if (ts->v86flags & VIF_MASK)
|
||||
flags |= IF_MASK;
|
||||
flags |= IOPL_MASK;
|
||||
return flags | (ts->v86flags & ts->v86mask);
|
||||
}
|
||||
|
||||
@@ -194,7 +195,7 @@ static void do_int(CPUX86State *env, int intno)
|
||||
uint8_t *ssp;
|
||||
unsigned int sp;
|
||||
|
||||
if (env->segs[R_CS] == TARGET_BIOSSEG)
|
||||
if (env->segs[R_CS].selector == TARGET_BIOSSEG)
|
||||
goto cannot_handle;
|
||||
if (is_revectored(intno, &ts->vm86plus.int_revectored))
|
||||
goto cannot_handle;
|
||||
@@ -210,10 +211,10 @@ static void do_int(CPUX86State *env, int intno)
|
||||
intno, segoffs >> 16, segoffs & 0xffff);
|
||||
#endif
|
||||
/* save old state */
|
||||
ssp = (uint8_t *)(env->segs[R_SS] << 4);
|
||||
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
|
||||
sp = env->regs[R_ESP] & 0xffff;
|
||||
vm_putw(ssp, sp - 2, get_vflags(env));
|
||||
vm_putw(ssp, sp - 4, env->segs[R_CS]);
|
||||
vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
|
||||
vm_putw(ssp, sp - 6, env->eip);
|
||||
ADD16(env->regs[R_ESP], -6);
|
||||
/* goto interrupt handler */
|
||||
@@ -257,16 +258,16 @@ void handle_vm86_fault(CPUX86State *env)
|
||||
unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
|
||||
int data32, pref_done;
|
||||
|
||||
csp = (uint8_t *)(env->segs[R_CS] << 4);
|
||||
csp = (uint8_t *)(env->segs[R_CS].selector << 4);
|
||||
ip = env->eip & 0xffff;
|
||||
pc = csp + ip;
|
||||
|
||||
ssp = (uint8_t *)(env->segs[R_SS] << 4);
|
||||
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
|
||||
sp = env->regs[R_ESP] & 0xffff;
|
||||
|
||||
#if defined(DEBUG_VM86)
|
||||
fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n",
|
||||
env->segs[R_CS], env->eip, pc[0], pc[1]);
|
||||
env->segs[R_CS].selector, env->eip, pc[0], pc[1]);
|
||||
#endif
|
||||
|
||||
data32 = 0;
|
||||
@@ -413,12 +414,12 @@ int do_vm86(CPUX86State *env, long subfunction,
|
||||
ts->vm86_saved_regs.esp = env->regs[R_ESP];
|
||||
ts->vm86_saved_regs.eflags = env->eflags;
|
||||
ts->vm86_saved_regs.eip = env->eip;
|
||||
ts->vm86_saved_regs.cs = env->segs[R_CS];
|
||||
ts->vm86_saved_regs.ss = env->segs[R_SS];
|
||||
ts->vm86_saved_regs.ds = env->segs[R_DS];
|
||||
ts->vm86_saved_regs.es = env->segs[R_ES];
|
||||
ts->vm86_saved_regs.fs = env->segs[R_FS];
|
||||
ts->vm86_saved_regs.gs = env->segs[R_GS];
|
||||
ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
|
||||
ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
|
||||
ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
|
||||
ts->vm86_saved_regs.es = env->segs[R_ES].selector;
|
||||
ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
|
||||
ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
|
||||
|
||||
/* build vm86 CPU state */
|
||||
ts->v86flags = tswap32(target_v86->regs.eflags);
|
||||
@@ -466,7 +467,8 @@ int do_vm86(CPUX86State *env, long subfunction,
|
||||
target_v86->vm86plus.vm86dbg_intxxtab, 32);
|
||||
|
||||
#ifdef DEBUG_VM86
|
||||
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip);
|
||||
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
|
||||
env->segs[R_CS].selector, env->eip);
|
||||
#endif
|
||||
/* now the virtual CPU is ready for vm86 execution ! */
|
||||
out:
|
||||
|
177
m68k.ld
Normal file
177
m68k.ld
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Script for -z combreloc: combine and sort reloc sections */
|
||||
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k",
|
||||
"elf32-m68k")
|
||||
OUTPUT_ARCH(m68k)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR("/usr/local/m68k-linux/lib");
|
||||
/* Do we need any of these for elf?
|
||||
__DYNAMIC = 0; */
|
||||
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.dyn :
|
||||
{
|
||||
*(.rel.init)
|
||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
||||
*(.rel.fini)
|
||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
||||
*(.rel.ctors)
|
||||
*(.rel.dtors)
|
||||
*(.rel.got)
|
||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
||||
}
|
||||
.rela.dyn :
|
||||
{
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
} =0x4e754e75
|
||||
.plt : { *(.plt) }
|
||||
.text :
|
||||
{
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
} =0x4e754e75
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(.fini))
|
||||
} =0x4e754e75
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||
/* 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(0x2000) + (. & (0x2000 - 1));
|
||||
/* Ensure the __preinit_array_start label is properly aligned. We
|
||||
could instead move the label definition inside the section, but
|
||||
the linker would then create the section even if it turns out to
|
||||
be empty, which isn't pretty. */
|
||||
. = ALIGN(32 / 8);
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
PROVIDE (__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE (__init_array_end = .);
|
||||
PROVIDE (__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE (__fini_array_end = .);
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.eh_frame : { KEEP (*(.eh_frame)) }
|
||||
.gcc_except_table : { *(.gcc_except_table) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
from the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP (*(.jcr)) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections. */
|
||||
. = ALIGN(32 / 8);
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
_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 .gnu.linkonce.wi.*) }
|
||||
.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) }
|
||||
}
|
66
op-arm.c
66
op-arm.c
@@ -154,11 +154,11 @@ void OPPROTO op_adcl_T0_T1_cc(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#define OPSUB(sub, sbc, T0, T1) \
|
||||
#define OPSUB(sub, sbc, res, T0, T1) \
|
||||
\
|
||||
void OPPROTO op_ ## sub ## l_T0_T1(void) \
|
||||
{ \
|
||||
T0 -= T1; \
|
||||
res = T0 - T1; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
|
||||
@@ -167,13 +167,14 @@ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
|
||||
src1 = T0; \
|
||||
T0 -= T1; \
|
||||
env->NZF = T0; \
|
||||
env->CF = src1 < T1; \
|
||||
env->CF = src1 >= T1; \
|
||||
env->VF = (src1 ^ T1) & (src1 ^ T0); \
|
||||
res = T0; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
|
||||
{ \
|
||||
T0 = T0 - T1 + env->CF - 1; \
|
||||
res = T0 - T1 + env->CF - 1; \
|
||||
} \
|
||||
\
|
||||
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
|
||||
@@ -182,20 +183,20 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
|
||||
src1 = T0; \
|
||||
if (!env->CF) { \
|
||||
T0 = T0 - T1 - 1; \
|
||||
T0 += T1; \
|
||||
env->CF = src1 < T1; \
|
||||
env->CF = src1 >= T1; \
|
||||
} else { \
|
||||
T0 = T0 - T1; \
|
||||
env->CF = src1 <= T1; \
|
||||
env->CF = src1 > T1; \
|
||||
} \
|
||||
env->VF = (src1 ^ T1) & (src1 ^ T0); \
|
||||
env->NZF = T0; \
|
||||
res = T0; \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
OPSUB(sub, sbc, T0, T1)
|
||||
OPSUB(sub, sbc, T0, T0, T1)
|
||||
|
||||
OPSUB(rsb, rsc, T1, T0)
|
||||
OPSUB(rsb, rsc, T0, T1, T0)
|
||||
|
||||
void OPPROTO op_andl_T0_T1(void)
|
||||
{
|
||||
@@ -222,122 +223,129 @@ void OPPROTO op_notl_T1(void)
|
||||
T1 = ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_logic_cc(void)
|
||||
void OPPROTO op_logic_T0_cc(void)
|
||||
{
|
||||
env->NZF = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_logic_T1_cc(void)
|
||||
{
|
||||
env->NZF = T1;
|
||||
}
|
||||
|
||||
#define EIP (env->regs[15])
|
||||
|
||||
void OPPROTO op_test_eq(void)
|
||||
{
|
||||
if (env->NZF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_eq, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ne(void)
|
||||
{
|
||||
if (env->NZF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_ne, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_cs(void)
|
||||
{
|
||||
if (env->CF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_cs, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_cc(void)
|
||||
{
|
||||
if (env->CF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_cc, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_mi(void)
|
||||
{
|
||||
if ((env->NZF & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_mi, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_pl(void)
|
||||
{
|
||||
if ((env->NZF & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_pl, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_vs(void)
|
||||
{
|
||||
if ((env->VF & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_vs, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_vc(void)
|
||||
{
|
||||
if ((env->VF & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_vc, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_hi(void)
|
||||
{
|
||||
if (env->CF != 0 && env->NZF != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_hi, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ls(void)
|
||||
{
|
||||
if (env->CF == 0 || env->NZF == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_ls, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_ge(void)
|
||||
{
|
||||
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_ge, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_test_lt(void)
|
||||
{
|
||||
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_test_lt, 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);
|
||||
JUMP_TB(op_test_gt, 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);
|
||||
JUMP_TB(op_test_le, PARAM1, 0, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp(void)
|
||||
{
|
||||
JUMP_TB(PARAM1, 1, PARAM2);
|
||||
JUMP_TB(op_jmp, PARAM1, 1, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
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);
|
||||
T0 = compute_cpsr();
|
||||
}
|
||||
|
||||
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
|
||||
|
399
op-i386.c
399
op-i386.c
@@ -80,62 +80,34 @@ static inline int lshift(int x, int n)
|
||||
|
||||
/* operations with flags */
|
||||
|
||||
void OPPROTO op_addl_T0_T1_cc(void)
|
||||
/* update flags with T0 and T1 (add/sub case) */
|
||||
void OPPROTO op_update2_cc(void)
|
||||
{
|
||||
CC_SRC = T0;
|
||||
T0 += T1;
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_orl_T0_T1_cc(void)
|
||||
/* update flags with T0 (logic operation case) */
|
||||
void OPPROTO op_update1_cc(void)
|
||||
{
|
||||
T0 |= T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_andl_T0_T1_cc(void)
|
||||
void OPPROTO op_update_neg_cc(void)
|
||||
{
|
||||
T0 &= T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_subl_T0_T1_cc(void)
|
||||
{
|
||||
CC_SRC = T0;
|
||||
T0 -= T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_xorl_T0_T1_cc(void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
CC_SRC = -T0;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_cmpl_T0_T1_cc(void)
|
||||
{
|
||||
CC_SRC = T0;
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0 - T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_negl_T0_cc(void)
|
||||
{
|
||||
CC_SRC = 0;
|
||||
T0 = -T0;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_incl_T0_cc(void)
|
||||
void OPPROTO op_update_inc_cc(void)
|
||||
{
|
||||
CC_SRC = cc_table[CC_OP].compute_c();
|
||||
T0++;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_decl_T0_cc(void)
|
||||
{
|
||||
CC_SRC = cc_table[CC_OP].compute_c();
|
||||
T0--;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
@@ -357,6 +329,11 @@ void OPPROTO op_andl_T0_ffff(void)
|
||||
T0 = T0 & 0xffff;
|
||||
}
|
||||
|
||||
void OPPROTO op_andl_T0_im(void)
|
||||
{
|
||||
T0 = T0 & PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_T1(void)
|
||||
{
|
||||
T0 = T1;
|
||||
@@ -399,70 +376,14 @@ void OPPROTO op_andl_A0_ffff(void)
|
||||
|
||||
/* memory access */
|
||||
|
||||
void OPPROTO op_ldub_T0_A0(void)
|
||||
{
|
||||
T0 = ldub((uint8_t *)A0);
|
||||
}
|
||||
#define MEMSUFFIX
|
||||
#include "ops_mem.h"
|
||||
|
||||
void OPPROTO op_ldsb_T0_A0(void)
|
||||
{
|
||||
T0 = ldsb((int8_t *)A0);
|
||||
}
|
||||
#define MEMSUFFIX _user
|
||||
#include "ops_mem.h"
|
||||
|
||||
void OPPROTO op_lduw_T0_A0(void)
|
||||
{
|
||||
T0 = lduw((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsw_T0_A0(void)
|
||||
{
|
||||
T0 = ldsw((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldl_T0_A0(void)
|
||||
{
|
||||
T0 = ldl((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldub_T1_A0(void)
|
||||
{
|
||||
T1 = ldub((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsb_T1_A0(void)
|
||||
{
|
||||
T1 = ldsb((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_lduw_T1_A0(void)
|
||||
{
|
||||
T1 = lduw((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsw_T1_A0(void)
|
||||
{
|
||||
T1 = ldsw((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldl_T1_A0(void)
|
||||
{
|
||||
T1 = ldl((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stb_T0_A0(void)
|
||||
{
|
||||
stb((uint8_t *)A0, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stw_T0_A0(void)
|
||||
{
|
||||
stw((uint8_t *)A0, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stl_T0_A0(void)
|
||||
{
|
||||
stl((uint8_t *)A0, T0);
|
||||
}
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "ops_mem.h"
|
||||
|
||||
/* used for bit operations */
|
||||
|
||||
@@ -488,6 +409,18 @@ void OPPROTO op_jmp_im(void)
|
||||
EIP = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_hlt(void)
|
||||
{
|
||||
env->exception_index = EXCP_HLT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_debug(void)
|
||||
{
|
||||
env->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_raise_interrupt(void)
|
||||
{
|
||||
int intno;
|
||||
@@ -524,6 +457,16 @@ void OPPROTO op_sti(void)
|
||||
env->eflags |= IF_MASK;
|
||||
}
|
||||
|
||||
void OPPROTO op_set_inhibit_irq(void)
|
||||
{
|
||||
env->hflags |= HF_INHIBIT_IRQ_MASK;
|
||||
}
|
||||
|
||||
void OPPROTO op_reset_inhibit_irq(void)
|
||||
{
|
||||
env->hflags &= ~HF_INHIBIT_IRQ_MASK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* vm86plus instructions */
|
||||
void OPPROTO op_cli_vm(void)
|
||||
@@ -573,9 +516,9 @@ void OPPROTO op_cmpxchg8b(void)
|
||||
helper_cmpxchg8b();
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp_tb_next(void)
|
||||
void OPPROTO op_jmp(void)
|
||||
{
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_jmp, PARAM1, 0, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
@@ -583,6 +526,11 @@ void OPPROTO op_movl_T0_0(void)
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
/* multiple size ops */
|
||||
|
||||
#define ldul ldl
|
||||
@@ -641,6 +589,38 @@ void OPPROTO op_movswl_DX_AX(void)
|
||||
EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff);
|
||||
}
|
||||
|
||||
/* string ops helpers */
|
||||
|
||||
void OPPROTO op_addl_ESI_T0(void)
|
||||
{
|
||||
ESI += T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_addw_ESI_T0(void)
|
||||
{
|
||||
ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_EDI_T0(void)
|
||||
{
|
||||
EDI += T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_addw_EDI_T0(void)
|
||||
{
|
||||
EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO op_decl_ECX(void)
|
||||
{
|
||||
ECX--;
|
||||
}
|
||||
|
||||
void OPPROTO op_decw_ECX(void)
|
||||
{
|
||||
ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff);
|
||||
}
|
||||
|
||||
/* push/pop */
|
||||
|
||||
void op_pushl_T0(void)
|
||||
@@ -665,7 +645,7 @@ void op_pushl_ss32_T0(void)
|
||||
{
|
||||
uint32_t offset;
|
||||
offset = ESP - 4;
|
||||
stl(env->seg_cache[R_SS].base + offset, T0);
|
||||
stl(env->segs[R_SS].base + offset, T0);
|
||||
/* modify ESP after to handle exceptions correctly */
|
||||
ESP = offset;
|
||||
}
|
||||
@@ -674,7 +654,7 @@ void op_pushw_ss32_T0(void)
|
||||
{
|
||||
uint32_t offset;
|
||||
offset = ESP - 2;
|
||||
stw(env->seg_cache[R_SS].base + offset, T0);
|
||||
stw(env->segs[R_SS].base + offset, T0);
|
||||
/* modify ESP after to handle exceptions correctly */
|
||||
ESP = offset;
|
||||
}
|
||||
@@ -683,7 +663,7 @@ void op_pushl_ss16_T0(void)
|
||||
{
|
||||
uint32_t offset;
|
||||
offset = (ESP - 4) & 0xffff;
|
||||
stl(env->seg_cache[R_SS].base + offset, T0);
|
||||
stl(env->segs[R_SS].base + offset, T0);
|
||||
/* modify ESP after to handle exceptions correctly */
|
||||
ESP = (ESP & ~0xffff) | offset;
|
||||
}
|
||||
@@ -692,7 +672,7 @@ void op_pushw_ss16_T0(void)
|
||||
{
|
||||
uint32_t offset;
|
||||
offset = (ESP - 2) & 0xffff;
|
||||
stw(env->seg_cache[R_SS].base + offset, T0);
|
||||
stw(env->segs[R_SS].base + offset, T0);
|
||||
/* modify ESP after to handle exceptions correctly */
|
||||
ESP = (ESP & ~0xffff) | offset;
|
||||
}
|
||||
@@ -710,22 +690,22 @@ void op_popw_T0(void)
|
||||
|
||||
void op_popl_ss32_T0(void)
|
||||
{
|
||||
T0 = ldl(env->seg_cache[R_SS].base + ESP);
|
||||
T0 = ldl(env->segs[R_SS].base + ESP);
|
||||
}
|
||||
|
||||
void op_popw_ss32_T0(void)
|
||||
{
|
||||
T0 = lduw(env->seg_cache[R_SS].base + ESP);
|
||||
T0 = lduw(env->segs[R_SS].base + ESP);
|
||||
}
|
||||
|
||||
void op_popl_ss16_T0(void)
|
||||
{
|
||||
T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff));
|
||||
T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff));
|
||||
}
|
||||
|
||||
void op_popw_ss16_T0(void)
|
||||
{
|
||||
T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff));
|
||||
T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff));
|
||||
}
|
||||
|
||||
void op_addl_ESP_4(void)
|
||||
@@ -768,6 +748,16 @@ void OPPROTO op_cpuid(void)
|
||||
helper_cpuid();
|
||||
}
|
||||
|
||||
void OPPROTO op_rdmsr(void)
|
||||
{
|
||||
helper_rdmsr();
|
||||
}
|
||||
|
||||
void OPPROTO op_wrmsr(void)
|
||||
{
|
||||
helper_wrmsr();
|
||||
}
|
||||
|
||||
/* bcd */
|
||||
|
||||
/* XXX: exception */
|
||||
@@ -900,6 +890,7 @@ void OPPROTO op_das(void)
|
||||
|
||||
/* segment handling */
|
||||
|
||||
/* never use it with R_CS */
|
||||
void OPPROTO op_movl_seg_T0(void)
|
||||
{
|
||||
load_seg(PARAM1, T0 & 0xffff, PARAM2);
|
||||
@@ -909,17 +900,18 @@ void OPPROTO op_movl_seg_T0(void)
|
||||
void OPPROTO op_movl_seg_T0_vm(void)
|
||||
{
|
||||
int selector;
|
||||
SegmentCache *sc;
|
||||
|
||||
selector = T0 & 0xffff;
|
||||
/* env->segs[] access */
|
||||
*(uint32_t *)((char *)env + PARAM1) = selector;
|
||||
/* env->seg_cache[] access */
|
||||
((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
|
||||
sc = (SegmentCache *)((char *)env + PARAM1);
|
||||
sc->selector = selector;
|
||||
sc->base = (void *)(selector << 4);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_seg(void)
|
||||
{
|
||||
T0 = env->segs[PARAM1];
|
||||
T0 = env->segs[PARAM1].selector;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_A0_seg(void)
|
||||
@@ -942,6 +934,91 @@ void OPPROTO op_lar(void)
|
||||
helper_lar();
|
||||
}
|
||||
|
||||
/* T0: segment, T1:eip */
|
||||
void OPPROTO op_ljmp_protected_T0_T1(void)
|
||||
{
|
||||
helper_ljmp_protected_T0_T1();
|
||||
}
|
||||
|
||||
void OPPROTO op_lcall_real_T0_T1(void)
|
||||
{
|
||||
helper_lcall_real_T0_T1(PARAM1, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_lcall_protected_T0_T1(void)
|
||||
{
|
||||
helper_lcall_protected_T0_T1(PARAM1, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_iret_real(void)
|
||||
{
|
||||
helper_iret_real(PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_iret_protected(void)
|
||||
{
|
||||
helper_iret_protected(PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_lret_protected(void)
|
||||
{
|
||||
helper_lret_protected(PARAM1, PARAM2);
|
||||
}
|
||||
|
||||
void OPPROTO op_lldt_T0(void)
|
||||
{
|
||||
helper_lldt_T0();
|
||||
}
|
||||
|
||||
void OPPROTO op_ltr_T0(void)
|
||||
{
|
||||
helper_ltr_T0();
|
||||
}
|
||||
|
||||
/* CR registers access */
|
||||
void OPPROTO op_movl_crN_T0(void)
|
||||
{
|
||||
helper_movl_crN_T0(PARAM1);
|
||||
}
|
||||
|
||||
/* DR registers access */
|
||||
void OPPROTO op_movl_drN_T0(void)
|
||||
{
|
||||
helper_movl_drN_T0(PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_lmsw_T0(void)
|
||||
{
|
||||
/* only 4 lower bits of CR0 are modified */
|
||||
T0 = (env->cr[0] & ~0xf) | (T0 & 0xf);
|
||||
helper_movl_crN_T0(0);
|
||||
}
|
||||
|
||||
void OPPROTO op_invlpg_A0(void)
|
||||
{
|
||||
helper_invlpg(A0);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_env(void)
|
||||
{
|
||||
T0 = *(uint32_t *)((char *)env + PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_env_T0(void)
|
||||
{
|
||||
*(uint32_t *)((char *)env + PARAM1) = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_env_T1(void)
|
||||
{
|
||||
*(uint32_t *)((char *)env + PARAM1) = T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_clts(void)
|
||||
{
|
||||
env->cr[0] &= ~CR0_TS_MASK;
|
||||
}
|
||||
|
||||
/* flags handling */
|
||||
|
||||
/* slow jumps cases : in order to avoid calling a function with a
|
||||
@@ -950,9 +1027,18 @@ void OPPROTO op_lar(void)
|
||||
void OPPROTO op_jcc(void)
|
||||
{
|
||||
if (T0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(op_jcc, PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(op_jcc, PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_jcc_im(void)
|
||||
{
|
||||
if (T0)
|
||||
EIP = PARAM1;
|
||||
else
|
||||
EIP = PARAM2;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -1021,8 +1107,7 @@ void OPPROTO op_set_cc_op(void)
|
||||
CC_OP = PARAM1;
|
||||
}
|
||||
|
||||
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
|
||||
#define FL_UPDATE_MASK16 (TF_MASK)
|
||||
#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff)
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void)
|
||||
{
|
||||
@@ -1031,7 +1116,8 @@ void OPPROTO op_movl_eflags_T0(void)
|
||||
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((eflags >> 10) & 1));
|
||||
/* we also update some system flags as in user mode */
|
||||
env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32);
|
||||
env->eflags = (env->eflags & ~FL_UPDATE_MASK32) |
|
||||
(eflags & FL_UPDATE_MASK32);
|
||||
}
|
||||
|
||||
void OPPROTO op_movw_eflags_T0(void)
|
||||
@@ -1041,7 +1127,18 @@ void OPPROTO op_movw_eflags_T0(void)
|
||||
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((eflags >> 10) & 1));
|
||||
/* we also update some system flags as in user mode */
|
||||
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16);
|
||||
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) |
|
||||
(eflags & FL_UPDATE_MASK16);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_eflags_T0_cpl0(void)
|
||||
{
|
||||
load_eflags(T0, FL_UPDATE_CPL0_MASK);
|
||||
}
|
||||
|
||||
void OPPROTO op_movw_eflags_T0_cpl0(void)
|
||||
{
|
||||
load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -1346,28 +1443,40 @@ void OPPROTO op_fildll_FT0_A0(void)
|
||||
|
||||
void OPPROTO op_flds_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldl((void *)A0);
|
||||
ST0 = FP_CONVERT.f;
|
||||
env->fpregs[new_fpstt] = FP_CONVERT.f;
|
||||
#else
|
||||
ST0 = ldfl((void *)A0);
|
||||
env->fpregs[new_fpstt] = ldfl((void *)A0);
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fldl_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = ldq((void *)A0);
|
||||
ST0 = FP_CONVERT.d;
|
||||
env->fpregs[new_fpstt] = FP_CONVERT.d;
|
||||
#else
|
||||
ST0 = ldfq((void *)A0);
|
||||
env->fpregs[new_fpstt] = ldfq((void *)A0);
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
void OPPROTO op_fldt_ST0_A0(void)
|
||||
{
|
||||
ST0 = *(long double *)A0;
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = *(long double *)A0;
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
#else
|
||||
void OPPROTO op_fldt_ST0_A0(void)
|
||||
@@ -1381,17 +1490,29 @@ void OPPROTO op_fldt_ST0_A0(void)
|
||||
|
||||
void helper_fild_ST0_A0(void)
|
||||
{
|
||||
ST0 = (CPU86_LDouble)ldsw((void *)A0);
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void helper_fildl_ST0_A0(void)
|
||||
{
|
||||
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void helper_fildll_ST0_A0(void)
|
||||
{
|
||||
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fild_ST0_A0(void)
|
||||
@@ -1413,32 +1534,44 @@ void OPPROTO op_fildll_ST0_A0(void)
|
||||
|
||||
void OPPROTO op_fild_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldsw((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)ldsw((void *)A0);
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fildl_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fildll_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i64;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
245
op_string.h
245
op_string.h
@@ -1,245 +0,0 @@
|
||||
|
||||
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int inc;
|
||||
glue(st, SUFFIX)(DI_ADDR, EAX);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int inc;
|
||||
inc = (DF << SHIFT);
|
||||
while (CX != 0) {
|
||||
glue(st, SUFFIX)(DI_ADDR, EAX);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
#if SHIFT == 0
|
||||
EAX = (EAX & ~0xff) | v;
|
||||
#elif SHIFT == 1
|
||||
EAX = (EAX & ~0xffff) | v;
|
||||
#else
|
||||
EAX = v;
|
||||
#endif
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
}
|
||||
|
||||
/* don't know if it is used */
|
||||
void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
#if SHIFT == 0
|
||||
EAX = (EAX & ~0xff) | v;
|
||||
#elif SHIFT == 1
|
||||
EAX = (EAX & ~0xffff) | v;
|
||||
#else
|
||||
EAX = v;
|
||||
#endif
|
||||
INC_SI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
|
||||
v = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
CC_SRC = EAX;
|
||||
CC_DST = EAX - v;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
|
||||
if (CX != 0) {
|
||||
/* NOTE: the flags are not modified if CX == 0 */
|
||||
v1 = EAX & DATA_MASK;
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
|
||||
if (CX != 0) {
|
||||
/* NOTE: the flags are not modified if CX == 0 */
|
||||
v1 = EAX & DATA_MASK;
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
v1 = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
CC_SRC = v1;
|
||||
CC_DST = v1 - v2;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
if (CX != 0) {
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v1 = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v1, v2, inc;
|
||||
if (CX != 0) {
|
||||
inc = (DF << SHIFT);
|
||||
do {
|
||||
v1 = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
v2 = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
dx = EDX & 0xffff;
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(cpu_x86_out, SUFFIX)(env, dx, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
inc = (DF << SHIFT);
|
||||
dx = EDX & 0xffff;
|
||||
while (CX != 0) {
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(cpu_x86_out, SUFFIX)(env, dx, v);
|
||||
INC_SI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
dx = EDX & 0xffff;
|
||||
v = glue(cpu_x86_in, SUFFIX)(env, dx);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, dx, inc;
|
||||
inc = (DF << SHIFT);
|
||||
dx = EDX & 0xffff;
|
||||
while (CX != 0) {
|
||||
v = glue(cpu_x86_in, SUFFIX)(env, dx);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
INC_DI();
|
||||
DEC_CX();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#undef STRING_SUFFIX
|
||||
#undef SI_ADDR
|
||||
#undef DI_ADDR
|
||||
#undef INC_SI
|
||||
#undef INC_DI
|
||||
#undef CX
|
||||
#undef DEC_CX
|
66
ops_mem.h
Normal file
66
ops_mem.h
Normal file
@@ -0,0 +1,66 @@
|
||||
void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
|
||||
{
|
||||
T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
|
||||
{
|
||||
T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
|
||||
{
|
||||
T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
|
||||
{
|
||||
T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void)
|
||||
{
|
||||
T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
glue(stb, MEMSUFFIX)((uint8_t *)A0, T0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
glue(stw, MEMSUFFIX)((uint8_t *)A0, T0);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void)
|
||||
{
|
||||
glue(stl, MEMSUFFIX)((uint8_t *)A0, T0);
|
||||
}
|
||||
|
||||
#undef MEMSUFFIX
|
496
ops_template.h
496
ops_template.h
@@ -93,8 +93,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = (CC_DST ^ src1 ^ src2) & 0x10;
|
||||
@@ -107,8 +107,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
|
||||
static int glue(compute_c_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2, cf;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
|
||||
return cf;
|
||||
}
|
||||
@@ -117,8 +117,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST - 1;
|
||||
src1 = CC_DST + CC_SRC + 1;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = (CC_DST ^ src1 ^ src2) & 0x10;
|
||||
@@ -131,8 +131,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
|
||||
static int glue(compute_c_sbb, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2, cf;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST - 1;
|
||||
src1 = CC_DST + CC_SRC + 1;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
|
||||
return cf;
|
||||
}
|
||||
@@ -234,70 +234,70 @@ static int glue(compute_all_sar, SUFFIX)(void)
|
||||
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jz_sub, SUFFIX)(void)
|
||||
{
|
||||
if ((DATA_TYPE)CC_DST == 0)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_js_sub, SUFFIX)(void)
|
||||
{
|
||||
if (CC_DST & SIGN_MASK)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2);
|
||||
else
|
||||
JUMP_TB(PARAM1, 1, PARAM3);
|
||||
JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -361,8 +361,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
|
||||
}
|
||||
@@ -375,8 +375,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
|
||||
}
|
||||
@@ -389,8 +389,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
|
||||
}
|
||||
@@ -398,135 +398,14 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
|
||||
}
|
||||
|
||||
/* shifts */
|
||||
|
||||
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
(T0 & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((T0 >> (DATA_BITS - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
|
||||
if (count > 1)
|
||||
res |= T0 >> (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (DATA_BITS - count)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
|
||||
if (count > 1)
|
||||
res |= T0 << (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (count - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
CC_SRC = (DATA_TYPE)T0 << (count - 1);
|
||||
T0 = T0 << count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
@@ -535,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = T0 >> count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
@@ -558,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_STYPE)T0;
|
||||
CC_SRC = src >> (count - 1);
|
||||
T0 = src >> count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count, src;
|
||||
@@ -581,166 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS == 16
|
||||
/* XXX: overflow flag might be incorrect in some cases in shldw */
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
count = PARAM1;
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
CC_SRC = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
CC_DST = T0;
|
||||
}
|
||||
#undef MEM_WRITE
|
||||
#include "ops_template_mem.h"
|
||||
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
CC_SRC = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
|
||||
count = PARAM1;
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
CC_SRC = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
CC_SRC = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* carry add/sub (we only need to set CC_OP differently) */
|
||||
|
||||
void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
CC_SRC = T0;
|
||||
T0 = T0 + T1 + cf;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
CC_SRC = T0;
|
||||
T0 = T0 - T1 - cf;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void)
|
||||
{
|
||||
CC_SRC = EAX;
|
||||
CC_DST = EAX - T0;
|
||||
if ((DATA_TYPE)CC_DST == 0) {
|
||||
T0 = T1;
|
||||
} else {
|
||||
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#define MEM_WRITE
|
||||
#include "ops_template_mem.h"
|
||||
|
||||
/* bit operations */
|
||||
#if DATA_BITS >= 16
|
||||
@@ -756,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 |= (1 << count);
|
||||
}
|
||||
|
||||
@@ -764,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 &= ~(1 << count);
|
||||
}
|
||||
|
||||
@@ -772,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 ^= (1 << count);
|
||||
}
|
||||
|
||||
@@ -814,35 +510,81 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
|
||||
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO op_update_bt_cc(void)
|
||||
{
|
||||
CC_SRC = T1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* string operations */
|
||||
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
|
||||
|
||||
#define STRING_SUFFIX _fast
|
||||
#define SI_ADDR (void *)ESI
|
||||
#define DI_ADDR (void *)EDI
|
||||
#define INC_SI() ESI += inc
|
||||
#define INC_DI() EDI += inc
|
||||
#define CX ECX
|
||||
#define DEC_CX() ECX--
|
||||
#include "op_string.h"
|
||||
void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void)
|
||||
{
|
||||
T0 = DF << SHIFT;
|
||||
}
|
||||
|
||||
#define STRING_SUFFIX _a32
|
||||
#define SI_ADDR (uint8_t *)A0 + ESI
|
||||
#define DI_ADDR env->seg_cache[R_ES].base + EDI
|
||||
#define INC_SI() ESI += inc
|
||||
#define INC_DI() EDI += inc
|
||||
#define CX ECX
|
||||
#define DEC_CX() ECX--
|
||||
#include "op_string.h"
|
||||
void OPPROTO glue(op_string_jz_sub, SUFFIX)(void)
|
||||
{
|
||||
if ((DATA_TYPE)CC_DST == 0)
|
||||
JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#define STRING_SUFFIX _a16
|
||||
#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
|
||||
#define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff)
|
||||
#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
|
||||
#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
|
||||
#define CX (ECX & 0xffff)
|
||||
#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
|
||||
#include "op_string.h"
|
||||
void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void)
|
||||
{
|
||||
if ((DATA_TYPE)CC_DST != 0)
|
||||
JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void)
|
||||
{
|
||||
if ((DATA_TYPE)CC_DST == 0) {
|
||||
EIP = PARAM1;
|
||||
if (env->eflags & TF_MASK) {
|
||||
raise_exception(EXCP01_SSTP);
|
||||
}
|
||||
T0 = 0;
|
||||
EXIT_TB();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void)
|
||||
{
|
||||
if ((DATA_TYPE)CC_DST != 0) {
|
||||
EIP = PARAM1;
|
||||
if (env->eflags & TF_MASK) {
|
||||
raise_exception(EXCP01_SSTP);
|
||||
}
|
||||
T0 = 0;
|
||||
EXIT_TB();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS >= 16
|
||||
void OPPROTO glue(op_jz_ecx, SUFFIX)(void)
|
||||
{
|
||||
if ((DATA_TYPE)ECX == 0)
|
||||
JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void)
|
||||
{
|
||||
if ((DATA_TYPE)ECX == 0) {
|
||||
EIP = PARAM1;
|
||||
if (env->eflags & TF_MASK) {
|
||||
raise_exception(EXCP01_SSTP);
|
||||
}
|
||||
T0 = 0;
|
||||
EXIT_TB();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* port I/O */
|
||||
|
||||
@@ -856,6 +598,16 @@ void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
|
||||
T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void)
|
||||
{
|
||||
T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void)
|
||||
{
|
||||
glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0);
|
||||
}
|
||||
|
||||
#undef DATA_BITS
|
||||
#undef SHIFT_MASK
|
||||
#undef SIGN_MASK
|
||||
|
429
ops_template_mem.h
Normal file
429
ops_template_mem.h
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* i386 micro operations (included several times to generate
|
||||
* different operand sizes)
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifdef MEM_WRITE
|
||||
|
||||
#if DATA_BITS == 8
|
||||
#define MEM_SUFFIX b_mem
|
||||
#elif DATA_BITS == 16
|
||||
#define MEM_SUFFIX w_mem
|
||||
#elif DATA_BITS == 32
|
||||
#define MEM_SUFFIX l_mem
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define MEM_SUFFIX SUFFIX
|
||||
|
||||
#endif
|
||||
|
||||
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#else
|
||||
/* gcc 3.2 workaround. This is really a bug in gcc. */
|
||||
asm volatile("" : : "r" (T0));
|
||||
#endif
|
||||
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
(T0 & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#else
|
||||
/* gcc 3.2 workaround. This is really a bug in gcc. */
|
||||
asm volatile("" : : "r" (T0));
|
||||
#endif
|
||||
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((T0 >> (DATA_BITS - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
|
||||
if (count > 1)
|
||||
res |= T0 >> (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (DATA_BITS - count)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
|
||||
if (count > 1)
|
||||
res |= T0 << (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (count - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_TYPE)T0 << (count - 1);
|
||||
T0 = T0 << count;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
src = T0 >> (count - 1);
|
||||
T0 = T0 >> count;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_STYPE)T0;
|
||||
T0 = src >> count;
|
||||
src = src >> (count - 1);
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS == 16
|
||||
/* XXX: overflow flag might be incorrect in some cases in shldw */
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
count = PARAM1;
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
tmp = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
tmp = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
|
||||
count = PARAM1;
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
tmp = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
tmp = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* carry add/sub (we only need to set CC_OP differently) */
|
||||
|
||||
void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
T0 = T0 + T1 + cf;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
T0 = T0 - T1 - cf;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
|
||||
{
|
||||
unsigned int src, dst;
|
||||
|
||||
src = T0;
|
||||
dst = EAX - T0;
|
||||
if ((DATA_TYPE)dst == 0) {
|
||||
T0 = T1;
|
||||
} else {
|
||||
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
|
||||
}
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = dst;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#undef MEM_SUFFIX
|
||||
#undef MEM_WRITE
|
@@ -3074,7 +3074,8 @@ static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int
|
||||
|
||||
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
return print_insn_powerpc (info->stream, *(unsigned *)(long)pc, pc,
|
||||
return print_insn_powerpc (info->stream,
|
||||
(unsigned int)bfd_getb32((bfd_byte *)pc), pc,
|
||||
PPC_OPCODE_PPC | PPC_OPCODE_601);
|
||||
}
|
||||
|
||||
|
574
qemu-doc.texi
574
qemu-doc.texi
@@ -1,51 +1,87 @@
|
||||
\input texinfo @c -*- texinfo -*-
|
||||
|
||||
@settitle QEMU x86 Emulator Reference Documentation
|
||||
@settitle QEMU CPU Emulator Reference Documentation
|
||||
@titlepage
|
||||
@sp 7
|
||||
@center @titlefont{QEMU x86 Emulator Reference Documentation}
|
||||
@center @titlefont{QEMU CPU Emulator Reference Documentation}
|
||||
@sp 3
|
||||
@end titlepage
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
|
||||
processes on non-x86 Linux architectures such as PowerPC. By using
|
||||
dynamic translation it achieves a reasonnable speed while being easy to
|
||||
port on new host CPUs. Its main goal is to be able to launch the
|
||||
@code{Wine} Windows API emulator (@url{http://www.winehq.org}) or
|
||||
@code{DOSEMU} (@url{http://www.dosemu.org}) on non-x86 CPUs.
|
||||
@section Features
|
||||
|
||||
QEMU features:
|
||||
QEMU is a FAST! processor emulator. By using dynamic translation it
|
||||
achieves a reasonnable speed while being easy to port on new host
|
||||
CPUs.
|
||||
|
||||
QEMU has two operating modes:
|
||||
@itemize
|
||||
@item User mode emulation. In this mode, QEMU can launch Linux processes
|
||||
compiled for one CPU on another CPU. Linux system calls are converted
|
||||
because of endianness and 32/64 bit mismatches. The Wine Windows API
|
||||
emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator
|
||||
(@url{www.dosemu.org}) are the main targets for QEMU.
|
||||
|
||||
@item Full system emulation. In this mode, QEMU emulates a full
|
||||
system, including a processor and various peripherials. Currently, it
|
||||
is only used to launch an x86 Linux kernel on an x86 Linux system. It
|
||||
enables easier testing and debugging of system code. It can also be
|
||||
used to provide virtual hosting of several virtual PCs on a single
|
||||
server.
|
||||
|
||||
@end itemize
|
||||
|
||||
As QEMU requires no host kernel patches to run, it is very safe and
|
||||
easy to use.
|
||||
|
||||
QEMU generic features:
|
||||
|
||||
@itemize
|
||||
|
||||
@item User space only x86 emulator.
|
||||
|
||||
@item Currently ported on i386, PowerPC. Work in progress for S390, Alpha and Sparc.
|
||||
@item User space only or full system emulation.
|
||||
|
||||
@item Using dynamic translation to native code for reasonnable speed.
|
||||
|
||||
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
|
||||
User space LDT and GDT are emulated. VM86 mode is also supported.
|
||||
@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390.
|
||||
|
||||
@item Self-modifying code support.
|
||||
|
||||
@item Precise exceptions support.
|
||||
|
||||
@item The virtual CPU is a library (@code{libqemu}) which can be used
|
||||
in other projects.
|
||||
|
||||
@end itemize
|
||||
|
||||
QEMU user mode emulation features:
|
||||
@itemize
|
||||
@item Generic Linux system call converter, including most ioctls.
|
||||
|
||||
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
|
||||
|
||||
@item Accurate signal handling by remapping host signals to virtual x86 signals.
|
||||
@item Accurate signal handling by remapping host signals to target signals.
|
||||
@end itemize
|
||||
@end itemize
|
||||
|
||||
@item Precise user space x86 exceptions.
|
||||
QEMU full system emulation features:
|
||||
@itemize
|
||||
@item Using mmap() system calls to simulate the MMU
|
||||
@end itemize
|
||||
|
||||
@item Self-modifying code support.
|
||||
@section x86 emulation
|
||||
|
||||
@item Support of host page sizes bigger than 4KB.
|
||||
QEMU x86 target features:
|
||||
|
||||
@itemize
|
||||
|
||||
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
|
||||
LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU.
|
||||
|
||||
@item Support of host page sizes bigger than 4KB in user mode emulation.
|
||||
|
||||
@item QEMU can emulate itself on x86.
|
||||
|
||||
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
|
||||
in other projects.
|
||||
|
||||
@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
|
||||
It can be used to test other x86 virtual CPUs.
|
||||
|
||||
@@ -62,18 +98,43 @@ Current QEMU limitations:
|
||||
@item IPC syscalls are missing.
|
||||
|
||||
@item The x86 segment limits and access rights are not tested at every
|
||||
memory access (and will never be to have good performances).
|
||||
memory access.
|
||||
|
||||
@item On non x86 host CPUs, @code{double}s are used instead of the non standard
|
||||
10 byte @code{long double}s of x86 for floating point emulation to get
|
||||
maximum performances.
|
||||
|
||||
@item Full system emulation only works if no data are mapped above the virtual address
|
||||
0xc0000000 (yet).
|
||||
|
||||
@item Some priviledged instructions or behaviors are missing. Only the ones
|
||||
needed for proper Linux kernel operation are emulated.
|
||||
|
||||
@item No memory separation between the kernel and the user processes is done.
|
||||
It will be implemented very soon.
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter Invocation
|
||||
@section ARM emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@item ARM emulation can currently launch small programs while using the
|
||||
generic dynamic code generation architecture of QEMU.
|
||||
|
||||
@item No FPU support (yet).
|
||||
|
||||
@item No automatic regression testing (yet).
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter QEMU User space emulator invocation
|
||||
|
||||
@section Quick Start
|
||||
|
||||
If you need to compile QEMU, please read the @file{README} which gives
|
||||
the related information.
|
||||
|
||||
In order to launch a Linux process, QEMU needs the process executable
|
||||
itself and all the target (x86) dynamic libraries used by it.
|
||||
|
||||
@@ -171,27 +232,421 @@ Activate log (logfile=/tmp/qemu.log)
|
||||
Act as if the host page size was 'pagesize' bytes
|
||||
@end table
|
||||
|
||||
@chapter QEMU System emulator invocation
|
||||
|
||||
@section Quick Start
|
||||
|
||||
This section explains how to launch a Linux kernel inside QEMU.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image. The archive also contains a precompiled
|
||||
version of @file{vl}, the QEMU System emulator.
|
||||
|
||||
@item Optional: If you want network support (for example to launch X11 examples), you
|
||||
must copy the script @file{vl-ifup} in @file{/etc} and configure
|
||||
properly @code{sudo} so that the command @code{ifconfig} contained in
|
||||
@file{vl-ifup} can be executed as root. You must verify that your host
|
||||
kernel supports the TUN/TAP network interfaces: the device
|
||||
@file{/dev/net/tun} must be present.
|
||||
|
||||
When network is enabled, there is a virtual network connection between
|
||||
the host kernel and the emulated kernel. The emulated kernel is seen
|
||||
from the host kernel at IP address 172.20.0.2 and the host kernel is
|
||||
seen from the emulated kernel at IP address 172.20.0.1.
|
||||
|
||||
@item Launch @code{vl.sh}. You should have the following output:
|
||||
|
||||
@example
|
||||
> ./vl.sh
|
||||
connected to host network interface: tun0
|
||||
Uncompressing Linux... Ok, booting the kernel.
|
||||
Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003
|
||||
BIOS-provided physical RAM map:
|
||||
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
|
||||
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
|
||||
32MB LOWMEM available.
|
||||
On node 0 totalpages: 8192
|
||||
zone(0): 4096 pages.
|
||||
zone(1): 4096 pages.
|
||||
zone(2): 0 pages.
|
||||
Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
|
||||
ide_setup: ide1=noprobe
|
||||
ide_setup: ide2=noprobe
|
||||
ide_setup: ide3=noprobe
|
||||
ide_setup: ide4=noprobe
|
||||
ide_setup: ide5=noprobe
|
||||
Initializing CPU#0
|
||||
Detected 501.285 MHz processor.
|
||||
Calibrating delay loop... 989.59 BogoMIPS
|
||||
Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem)
|
||||
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
|
||||
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
|
||||
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
|
||||
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
|
||||
Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
|
||||
CPU: Intel Pentium Pro stepping 03
|
||||
Checking 'hlt' instruction... OK.
|
||||
POSIX conformance testing by UNIFIX
|
||||
Linux NET4.0 for Linux 2.4
|
||||
Based upon Swansea University Computer Society NET3.039
|
||||
Initializing RT netlink socket
|
||||
apm: BIOS not found.
|
||||
Starting kswapd
|
||||
Journalled Block Device driver loaded
|
||||
pty: 256 Unix98 ptys configured
|
||||
Serial driver version 5.05c (2001-07-08) with no serial options enabled
|
||||
ttyS00 at 0x03f8 (irq = 4) is a 16450
|
||||
Uniform Multi-Platform E-IDE driver Revision: 6.31
|
||||
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
|
||||
hda: QEMU HARDDISK, ATA DISK drive
|
||||
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
|
||||
hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63
|
||||
Partition check:
|
||||
hda: unknown partition table
|
||||
ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
|
||||
Last modified Nov 1, 2000 by Paul Gortmaker
|
||||
NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
|
||||
eth0: NE2000 found at 0x300, using IRQ 9.
|
||||
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
|
||||
NET4: Linux TCP/IP 1.0 for NET4.0
|
||||
IP Protocols: ICMP, UDP, TCP, IGMP
|
||||
IP: routing cache hash table of 512 buckets, 4Kbytes
|
||||
TCP: Hash tables configured (established 2048 bind 4096)
|
||||
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
|
||||
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
|
||||
VFS: Mounted root (ext2 filesystem).
|
||||
Freeing unused kernel memory: 52k freed
|
||||
sh: can't access tty; job control turned off
|
||||
#
|
||||
@end example
|
||||
|
||||
@item
|
||||
Then you can play with the kernel inside the virtual serial console. You
|
||||
can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
|
||||
about the keys you can type inside the virtual serial console. In
|
||||
particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
|
||||
the Magic SysRq key.
|
||||
|
||||
@item
|
||||
If the network is enabled, launch the script @file{/etc/linuxrc} in the
|
||||
emulator (don't forget the leading dot):
|
||||
@example
|
||||
. /etc/linuxrc
|
||||
@end example
|
||||
|
||||
Then enable X11 connections on your PC from the emulated Linux:
|
||||
@example
|
||||
xhost +172.20.0.2
|
||||
@end example
|
||||
|
||||
You can now launch @file{xterm} or @file{xlogo} and verify that you have
|
||||
a real Virtual Linux system !
|
||||
|
||||
@end enumerate
|
||||
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
A 2.5.74 kernel is also included in the vl-test archive. Just
|
||||
replace the bzImage in vl.sh to try it.
|
||||
|
||||
@item
|
||||
vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the
|
||||
default) containing all the simulated PC memory. If possible, try to use
|
||||
a temporary directory using the tmpfs filesystem to avoid too many
|
||||
unnecessary disk accesses.
|
||||
|
||||
@item
|
||||
In order to exit cleanly for vl, you can do a @emph{shutdown} inside
|
||||
vl. vl will automatically exit when the Linux shutdown is done.
|
||||
|
||||
@item
|
||||
You can boot slightly faster by disabling the probe of non present IDE
|
||||
interfaces. To do so, add the following options on the kernel command
|
||||
line:
|
||||
@example
|
||||
ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
|
||||
@end example
|
||||
|
||||
@item
|
||||
The example disk image is a modified version of the one made by Kevin
|
||||
Lawton for the plex86 Project (@url{www.plex86.org}).
|
||||
|
||||
@end enumerate
|
||||
|
||||
@section Invocation
|
||||
|
||||
@example
|
||||
usage: vl [options] bzImage [kernel parameters...]
|
||||
@end example
|
||||
|
||||
@file{bzImage} is a Linux kernel image.
|
||||
|
||||
General options:
|
||||
@table @option
|
||||
@item -hda file
|
||||
@item -hdb file
|
||||
Use 'file' as hard disk 0 or 1 image (@xref{disk_images}).
|
||||
|
||||
@item -snapshot
|
||||
|
||||
Write to temporary files instead of disk image files. In this case,
|
||||
the raw disk image you use is not written back. You can however force
|
||||
the write back by pressing @key{C-a s} (@xref{disk_images}).
|
||||
|
||||
@item -m megs
|
||||
Set virtual RAM size to @var{megs} megabytes.
|
||||
|
||||
@item -n script
|
||||
Set network init script [default=/etc/vl-ifup]. This script is
|
||||
launched to configure the host network interface (usually tun0)
|
||||
corresponding to the virtual NE2000 card.
|
||||
|
||||
@item -initrd file
|
||||
Use 'file' as initial ram disk.
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
@table @option
|
||||
@item -s
|
||||
Wait gdb connection to port 1234.
|
||||
@item -p port
|
||||
Change gdb connection port.
|
||||
@item -d
|
||||
Output log in /tmp/vl.log
|
||||
@end table
|
||||
|
||||
During emulation, use @key{C-a h} to get terminal commands:
|
||||
|
||||
@table @key
|
||||
@item C-a h
|
||||
Print this help
|
||||
@item C-a x
|
||||
Exit emulatior
|
||||
@item C-a s
|
||||
Save disk data back to file (if -snapshot)
|
||||
@item C-a b
|
||||
Send break (magic sysrq)
|
||||
@item C-a C-a
|
||||
Send C-a
|
||||
@end table
|
||||
|
||||
@node disk_images
|
||||
@section Disk Images
|
||||
|
||||
@subsection Raw disk images
|
||||
|
||||
The disk images can simply be raw images of the hard disk. You can
|
||||
create them with the command:
|
||||
@example
|
||||
dd if=/dev/zero of=myimage bs=1024 count=mysize
|
||||
@end example
|
||||
where @var{myimage} is the image filename and @var{mysize} is its size
|
||||
in kilobytes.
|
||||
|
||||
@subsection Snapshot mode
|
||||
|
||||
If you use the option @option{-snapshot}, all disk images are
|
||||
considered as read only. When sectors in written, they are written in
|
||||
a temporary file created in @file{/tmp}. You can however force the
|
||||
write back to the raw disk images by pressing @key{C-a s}.
|
||||
|
||||
NOTE: The snapshot mode only works with raw disk images.
|
||||
|
||||
@subsection Copy On Write disk images
|
||||
|
||||
QEMU also supports user mode Linux
|
||||
(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW)
|
||||
disk images. The COW disk images are much smaller than normal images
|
||||
as they store only modified sectors. They also permit the use of the
|
||||
same disk image template for many users.
|
||||
|
||||
To create a COW disk images, use the command:
|
||||
|
||||
@example
|
||||
vlmkcow -f myrawimage.bin mycowimage.cow
|
||||
@end example
|
||||
|
||||
@file{myrawimage.bin} is a raw image you want to use as original disk
|
||||
image. It will never be written to.
|
||||
|
||||
@file{mycowimage.cow} is the COW disk image which is created by
|
||||
@code{vlmkcow}. You can use it directly with the @option{-hdx}
|
||||
options. You must not modify the original raw disk image if you use
|
||||
COW images, as COW images only store the modified sectors from the raw
|
||||
disk image. QEMU stores the original raw disk image name and its
|
||||
modified time in the COW disk image so that chances of mistakes are
|
||||
reduced.
|
||||
|
||||
If the raw disk image is not read-only, by pressing @key{C-a s} you
|
||||
can flush the COW disk image back into the raw disk image, as in
|
||||
snapshot mode.
|
||||
|
||||
COW disk images can also be created without a corresponding raw disk
|
||||
image. It is useful to have a big initial virtual disk image without
|
||||
using much disk space. Use:
|
||||
|
||||
@example
|
||||
vlmkcow mycowimage.cow 1024
|
||||
@end example
|
||||
|
||||
to create a 1 gigabyte empty COW disk image.
|
||||
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
COW disk images must be created on file systems supporting
|
||||
@emph{holes} such as ext2 or ext3.
|
||||
@item
|
||||
Since holes are used, the displayed size of the COW disk image is not
|
||||
the real one. To know it, use the @code{ls -ls} command.
|
||||
@end enumerate
|
||||
|
||||
@section Linux Kernel Compilation
|
||||
|
||||
You should be able to use any kernel with QEMU provided you make the
|
||||
following changes (only 2.4.x and 2.5.x were tested):
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
The kernel must be mapped at 0x90000000 (the default is
|
||||
0xc0000000). You must modify only two lines in the kernel source:
|
||||
|
||||
In @file{include/asm/page.h}, replace
|
||||
@example
|
||||
#define __PAGE_OFFSET (0xc0000000)
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
#define __PAGE_OFFSET (0x90000000)
|
||||
@end example
|
||||
|
||||
And in @file{arch/i386/vmlinux.lds}, replace
|
||||
@example
|
||||
. = 0xc0000000 + 0x100000;
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
. = 0x90000000 + 0x100000;
|
||||
@end example
|
||||
|
||||
@item
|
||||
If you want to enable SMP (Symmetric Multi-Processing) support, you
|
||||
must make the following change in @file{include/asm/fixmap.h}. Replace
|
||||
@example
|
||||
#define FIXADDR_TOP (0xffffX000UL)
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
#define FIXADDR_TOP (0xa7ffX000UL)
|
||||
@end example
|
||||
(X is 'e' or 'f' depending on the kernel version). Although you can
|
||||
use an SMP kernel with QEMU, it only supports one CPU.
|
||||
|
||||
@item
|
||||
If you are not using a 2.5 kernel as host kernel but if you use a target
|
||||
2.5 kernel, you must also ensure that the 'HZ' define is set to 100
|
||||
(1000 is the default) as QEMU cannot currently emulate timers at
|
||||
frequencies greater than 100 Hz on host Linux systems < 2.5. In
|
||||
@file{include/asm/param.h}, replace:
|
||||
|
||||
@example
|
||||
# define HZ 1000 /* Internal kernel timer frequency */
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
# define HZ 100 /* Internal kernel timer frequency */
|
||||
@end example
|
||||
|
||||
@end enumerate
|
||||
|
||||
The file config-2.x.x gives the configuration of the example kernels.
|
||||
|
||||
Just type
|
||||
@example
|
||||
make bzImage
|
||||
@end example
|
||||
|
||||
As you would do to make a real kernel. Then you can use with QEMU
|
||||
exactly the same kernel as you would boot on your PC (in
|
||||
@file{arch/i386/boot/bzImage}).
|
||||
|
||||
@section PC Emulation
|
||||
|
||||
QEMU emulates the following PC peripherials:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
PIC (interrupt controler)
|
||||
@item
|
||||
PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@item
|
||||
Dumb VGA (to print the @code{Uncompressing Linux} message)
|
||||
@item
|
||||
Serial port (port=0x3f8, irq=4)
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
IDE disk interface (port=0x1f0, irq=14)
|
||||
@end itemize
|
||||
|
||||
@section GDB usage
|
||||
|
||||
QEMU has a primitive support to work with gdb, so that you can do
|
||||
'Ctrl-C' while the kernel is running and inspect its state.
|
||||
|
||||
In order to use gdb, launch vl with the '-s' option. It will wait for a
|
||||
gdb connection:
|
||||
@example
|
||||
> vl -s arch/i386/boot/bzImage -hda root-2.4.20.img root=/dev/hda
|
||||
Connected to host network interface: tun0
|
||||
Waiting gdb connection on port 1234
|
||||
@end example
|
||||
|
||||
Then launch gdb on the 'vmlinux' executable:
|
||||
@example
|
||||
> gdb vmlinux
|
||||
@end example
|
||||
|
||||
In gdb, connect to QEMU:
|
||||
@example
|
||||
(gdb) target remote locahost:1234
|
||||
@end example
|
||||
|
||||
Then you can use gdb normally. For example, type 'c' to launch the kernel:
|
||||
@example
|
||||
(gdb) c
|
||||
@end example
|
||||
|
||||
WARNING: breakpoints and single stepping are not yet supported.
|
||||
|
||||
@chapter QEMU Internals
|
||||
|
||||
@section QEMU compared to other emulators
|
||||
|
||||
Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that
|
||||
you cannot launch an operating system with it. The benefit is that it is
|
||||
simpler and faster due to the fact that some of the low level CPU state
|
||||
can be ignored (in particular, no virtual memory needs to be emulated).
|
||||
Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
|
||||
bochs as it uses dynamic compilation and because it uses the host MMU to
|
||||
simulate the x86 MMU. The downside is that currently the emulation is
|
||||
not as accurate as bochs (for example, you cannot currently run Windows
|
||||
inside QEMU).
|
||||
|
||||
Like Valgrind [2], QEMU does user space emulation and dynamic
|
||||
translation. Valgrind is mainly a memory debugger while QEMU has no
|
||||
support for it (QEMU could be used to detect out of bound memory accesses
|
||||
as Valgrind, but it has no support to track uninitialised data as
|
||||
Valgrind does). Valgrind dynamic translator generates better code than
|
||||
QEMU (in particular it does register allocation) but it is closely tied
|
||||
to an x86 host.
|
||||
support for it (QEMU could be used to detect out of bound memory
|
||||
accesses as Valgrind, but it has no support to track uninitialised data
|
||||
as Valgrind does). The Valgrind dynamic translator generates better code
|
||||
than QEMU (in particular it does register allocation) but it is closely
|
||||
tied to an x86 host and target and has no support for precise exceptions
|
||||
and system emulation.
|
||||
|
||||
EM86 [4] is the closest project to QEMU (and QEMU still uses some of its
|
||||
code, in particular the ELF file loader). EM86 was limited to an alpha
|
||||
host and used a proprietary and slow interpreter (the interpreter part
|
||||
of the FX!32 Digital Win32 code translator [5]).
|
||||
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
|
||||
some of its code, in particular the ELF file loader). EM86 was limited
|
||||
to an alpha host and used a proprietary and slow interpreter (the
|
||||
interpreter part of the FX!32 Digital Win32 code translator [5]).
|
||||
|
||||
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
|
||||
Wine but includes a protected mode x86 interpreter to launch x86 Windows
|
||||
@@ -200,11 +655,25 @@ Windows API is executed natively but it is far more difficult to develop
|
||||
because all the data structures and function parameters exchanged
|
||||
between the API and the x86 code must be converted.
|
||||
|
||||
User mode Linux [7] was the only solution before QEMU to launch a Linux
|
||||
kernel as a process while not needing any host kernel patches. However,
|
||||
user mode Linux requires heavy kernel patches while QEMU accepts
|
||||
unpatched Linux kernels. It would be interesting to compare the
|
||||
performance of the two approaches.
|
||||
|
||||
The new Plex86 [8] PC virtualizer is done in the same spirit as the QEMU
|
||||
system emulator. It requires a patched Linux kernel to work (you cannot
|
||||
launch the same kernel on your PC), but the patches are really small. As
|
||||
it is a PC virtualizer (no emulation is done except for some priveledged
|
||||
instructions), it has the potential of being faster than QEMU. The
|
||||
downside is that a complicated (and potentially unsafe) host kernel
|
||||
patch is needed.
|
||||
|
||||
@section Portable dynamic translation
|
||||
|
||||
QEMU is a dynamic translator. When it first encounters a piece of code,
|
||||
it converts it to the host instruction set. Usually dynamic translators
|
||||
are very complicated and highly CPU dependant. QEMU uses some tricks
|
||||
are very complicated and highly CPU dependent. QEMU uses some tricks
|
||||
which make it relatively easily portable and simple while achieving good
|
||||
performances.
|
||||
|
||||
@@ -304,7 +773,7 @@ Correct translated code invalidation is done efficiently by maintaining
|
||||
a linked list of every translated block contained in a given page. Other
|
||||
linked lists are also maintained to undo direct block chaining.
|
||||
|
||||
Althought the overhead of doing @code{mprotect()} calls is important,
|
||||
Although the overhead of doing @code{mprotect()} calls is important,
|
||||
most MSDOS programs can be emulated at reasonnable speed with QEMU and
|
||||
DOSEMU.
|
||||
|
||||
@@ -373,7 +842,7 @@ reentrancy.
|
||||
|
||||
@section Self-virtualization
|
||||
|
||||
QEMU was conceived so that ultimately it can emulate itself. Althought
|
||||
QEMU was conceived so that ultimately it can emulate itself. Although
|
||||
it is not very useful, it is an important test to show the power of the
|
||||
emulator.
|
||||
|
||||
@@ -382,6 +851,16 @@ space conflicts. QEMU solves this problem by being an executable ELF
|
||||
shared object as the ld-linux.so ELF interpreter. That way, it can be
|
||||
relocated at load time.
|
||||
|
||||
@section MMU emulation
|
||||
|
||||
For system emulation, QEMU uses the mmap() system call to emulate the
|
||||
target CPU MMU. It works as long the emulated OS does not use an area
|
||||
reserved by the host OS (such as the area above 0xc0000000 on x86
|
||||
Linux).
|
||||
|
||||
It is planned to add a slower but more precise MMU emulation
|
||||
with a software MMU.
|
||||
|
||||
@section Bibliography
|
||||
|
||||
@table @asis
|
||||
@@ -412,18 +891,31 @@ Chernoff and Ray Hookway.
|
||||
@url{http://www.willows.com/}, Windows API library emulation from
|
||||
Willows Software.
|
||||
|
||||
@item [7]
|
||||
@url{http://user-mode-linux.sourceforge.net/},
|
||||
The User-mode Linux Kernel.
|
||||
|
||||
@item [8]
|
||||
@url{http://www.plex86.org/},
|
||||
The new Plex86 project.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Regression Tests
|
||||
|
||||
In the directory @file{tests/}, various interesting x86 testing programs
|
||||
In the directory @file{tests/}, various interesting testing programs
|
||||
are available. There are used for regression testing.
|
||||
|
||||
@section @file{hello}
|
||||
@section @file{hello-i386}
|
||||
|
||||
Very simple statically linked x86 program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{hello-arm}
|
||||
|
||||
Very simple statically linked ARM program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{test-i386}
|
||||
|
||||
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||
|
275
sdl.c
Normal file
275
sdl.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* QEMU SDL display driver
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
static SDL_Surface *screen;
|
||||
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
|
||||
|
||||
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
|
||||
{
|
||||
SDL_UpdateRect(screen, x, y, w, h);
|
||||
}
|
||||
|
||||
static void sdl_resize(DisplayState *ds, int w, int h)
|
||||
{
|
||||
int flags;
|
||||
|
||||
// printf("resizing to %d %d\n", w, h);
|
||||
|
||||
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
|
||||
flags |= SDL_RESIZABLE;
|
||||
screen = SDL_SetVideoMode(w, h, 0, flags);
|
||||
if (!screen) {
|
||||
fprintf(stderr, "Could not open SDL display\n");
|
||||
exit(1);
|
||||
}
|
||||
ds->data = screen->pixels;
|
||||
ds->linesize = screen->pitch;
|
||||
ds->depth = screen->format->BitsPerPixel;
|
||||
}
|
||||
|
||||
static const uint32_t x_keycode_to_pc_keycode[61] = {
|
||||
0x47e0, /* 97 Home */
|
||||
0x48e0, /* 98 Up */
|
||||
0x49e0, /* 99 PgUp */
|
||||
0x4be0, /* 100 Left */
|
||||
0x4c, /* 101 KP-5 */
|
||||
0x4de0, /* 102 Right */
|
||||
0x4fe0, /* 103 End */
|
||||
0x50e0, /* 104 Down */
|
||||
0x51e0, /* 105 PgDn */
|
||||
0x52e0, /* 106 Ins */
|
||||
0x53e0, /* 107 Del */
|
||||
0x1ce0, /* 108 Enter */
|
||||
0x1de0, /* 109 Ctrl-R */
|
||||
0x451de1, /* 110 Pause */
|
||||
0x37e0, /* 111 Print */
|
||||
0x35e0, /* 112 Divide */
|
||||
0x38e0, /* 113 Alt-R */
|
||||
0x46e0, /* 114 Break */
|
||||
0x0, /* 115 */
|
||||
0x0, /* 116 */
|
||||
0x0, /* 117 */
|
||||
0x0, /* 118 */
|
||||
0x0, /* 119 */
|
||||
0x0, /* 120 */
|
||||
0x0, /* 121 */
|
||||
0x0, /* 122 */
|
||||
0x0, /* 123 */
|
||||
0x0, /* 124 */
|
||||
0x0, /* 125 */
|
||||
0x0, /* 126 */
|
||||
0x0, /* 127 */
|
||||
0x0, /* 128 */
|
||||
0x0, /* 129 */
|
||||
0x0, /* 130 */
|
||||
0x0, /* 131 */
|
||||
0x0, /* 132 */
|
||||
0x0, /* 133 */
|
||||
0x0, /* 134 */
|
||||
0x0, /* 135 */
|
||||
0x47, /* 136 KP_7 */
|
||||
0x48, /* 137 KP_8 */
|
||||
0x49, /* 138 KP_9 */
|
||||
0x4b, /* 139 KP_4 */
|
||||
0x4c, /* 140 KP_5 */
|
||||
0x4d, /* 141 KP_6 */
|
||||
0x4f, /* 142 KP_1 */
|
||||
0x50, /* 143 KP_2 */
|
||||
0x51, /* 144 KP_3 */
|
||||
0x52, /* 145 KP_0 */
|
||||
0x53, /* 146 KP_. */
|
||||
0x47, /* 147 KP_HOME */
|
||||
0x48, /* 148 KP_UP */
|
||||
0x49, /* 149 KP_PgUp */
|
||||
0x4b, /* 150 KP_Left */
|
||||
0x4c, /* 151 KP_ */
|
||||
0x4d, /* 152 KP_Right */
|
||||
0x4f, /* 153 KP_End */
|
||||
0x50, /* 154 KP_Down */
|
||||
0x51, /* 155 KP_PgDn */
|
||||
0x52, /* 156 KP_Ins */
|
||||
0x53, /* 157 KP_Del */
|
||||
};
|
||||
|
||||
static void sdl_process_key(SDL_KeyboardEvent *ev)
|
||||
{
|
||||
int keycode, v;
|
||||
|
||||
/* XXX: not portable, but avoids complicated mappings */
|
||||
keycode = ev->keysym.scancode;
|
||||
if (keycode < 9) {
|
||||
keycode = 0;
|
||||
} else if (keycode < 97) {
|
||||
keycode -= 8; /* just an offset */
|
||||
} else if (keycode < 158) {
|
||||
/* use conversion table */
|
||||
keycode = x_keycode_to_pc_keycode[keycode - 97];
|
||||
} else {
|
||||
keycode = 0;
|
||||
}
|
||||
|
||||
/* now send the key code */
|
||||
while (keycode != 0) {
|
||||
v = keycode & 0xff;
|
||||
if (ev->type == SDL_KEYUP)
|
||||
v |= 0x80;
|
||||
kbd_put_keycode(v);
|
||||
keycode >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_grab_start(void)
|
||||
{
|
||||
SDL_WM_SetCaption("QEMU - Press Ctrl-Shift to exit grab", "QEMU");
|
||||
SDL_ShowCursor(0);
|
||||
SDL_WM_GrabInput(SDL_GRAB_ON);
|
||||
/* dummy read to avoid moving the mouse */
|
||||
SDL_GetRelativeMouseState(NULL, NULL);
|
||||
gui_grab = 1;
|
||||
}
|
||||
|
||||
static void sdl_grab_end(void)
|
||||
{
|
||||
SDL_WM_SetCaption("QEMU", "QEMU");
|
||||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||
SDL_ShowCursor(1);
|
||||
gui_grab = 0;
|
||||
}
|
||||
|
||||
static void sdl_send_mouse_event(void)
|
||||
{
|
||||
int dx, dy, dz, state, buttons;
|
||||
state = SDL_GetRelativeMouseState(&dx, &dy);
|
||||
buttons = 0;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
|
||||
buttons |= MOUSE_EVENT_LBUTTON;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
|
||||
buttons |= MOUSE_EVENT_RBUTTON;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
|
||||
buttons |= MOUSE_EVENT_MBUTTON;
|
||||
/* XXX: test wheel */
|
||||
dz = 0;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP))
|
||||
dz--;
|
||||
if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
|
||||
dz++;
|
||||
kbd_mouse_event(dx, dy, dz, buttons);
|
||||
}
|
||||
|
||||
static void sdl_refresh(DisplayState *ds)
|
||||
{
|
||||
SDL_Event ev1, *ev = &ev1;
|
||||
|
||||
vga_update_display();
|
||||
while (SDL_PollEvent(ev)) {
|
||||
switch (ev->type) {
|
||||
case SDL_VIDEOEXPOSE:
|
||||
sdl_update(ds, 0, 0, screen->w, screen->h);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (ev->type == SDL_KEYDOWN) {
|
||||
if ((SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) ==
|
||||
(KMOD_LSHIFT | KMOD_LCTRL)) {
|
||||
/* exit/enter grab if pressing Ctrl-Shift */
|
||||
if (!gui_grab)
|
||||
sdl_grab_start();
|
||||
else
|
||||
sdl_grab_end();
|
||||
}
|
||||
}
|
||||
sdl_process_key(&ev->key);
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
reset_requested = 1;
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (gui_grab) {
|
||||
sdl_send_mouse_event();
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
{
|
||||
SDL_MouseButtonEvent *bev = &ev->button;
|
||||
if (!gui_grab) {
|
||||
if (ev->type == SDL_MOUSEBUTTONDOWN &&
|
||||
(bev->state & SDL_BUTTON_LMASK)) {
|
||||
/* start grabbing all events */
|
||||
sdl_grab_start();
|
||||
}
|
||||
} else {
|
||||
sdl_send_mouse_event();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sdl_display_init(DisplayState *ds)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
|
||||
if (SDL_Init (flags)) {
|
||||
fprintf(stderr, "Could not initialize SDL - exiting\n");
|
||||
exit(1);
|
||||
}
|
||||
ds->dpy_update = sdl_update;
|
||||
ds->dpy_resize = sdl_resize;
|
||||
ds->dpy_refresh = sdl_refresh;
|
||||
|
||||
sdl_resize(ds, 640, 400);
|
||||
SDL_WM_SetCaption("QEMU", "QEMU");
|
||||
SDL_EnableKeyRepeat(250, 50);
|
||||
gui_grab = 0;
|
||||
}
|
111
softmmu_header.h
Normal file
111
softmmu_header.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Software MMU support
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#if DATA_SIZE == 8
|
||||
#define SUFFIX q
|
||||
#define DATA_TYPE uint64_t
|
||||
#elif DATA_SIZE == 4
|
||||
#define SUFFIX l
|
||||
#define DATA_TYPE uint32_t
|
||||
#elif DATA_SIZE == 2
|
||||
#define SUFFIX w
|
||||
#define DATA_TYPE uint16_t
|
||||
#define DATA_STYPE int16_t
|
||||
#elif DATA_SIZE == 1
|
||||
#define SUFFIX b
|
||||
#define DATA_TYPE uint8_t
|
||||
#define DATA_STYPE int8_t
|
||||
#else
|
||||
#error unsupported data size
|
||||
#endif
|
||||
|
||||
#if MEMUSER == 0
|
||||
#define MEMSUFFIX _kernel
|
||||
#else
|
||||
#define MEMSUFFIX _user
|
||||
#endif
|
||||
|
||||
#if DATA_SIZE == 8
|
||||
#define RES_TYPE uint64_t
|
||||
#else
|
||||
#define RES_TYPE int
|
||||
#endif
|
||||
|
||||
|
||||
#if MEMUSER == 0
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr);
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE v);
|
||||
#endif
|
||||
|
||||
static inline int glue(glue(ldu, SUFFIX), MEMSUFFIX)(void *ptr)
|
||||
{
|
||||
int index;
|
||||
RES_TYPE res;
|
||||
unsigned long addr, physaddr;
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
if (__builtin_expect(env->tlb_read[MEMUSER][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
res = glue(glue(__ld, SUFFIX), _mmu)(addr);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_read[MEMUSER][index].addend;
|
||||
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#if DATA_SIZE <= 2
|
||||
static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr)
|
||||
{
|
||||
int res, index;
|
||||
unsigned long addr, physaddr;
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
if (__builtin_expect(env->tlb_read[MEMUSER][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
res = (DATA_STYPE)glue(glue(__ld, SUFFIX), _mmu)(addr);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_read[MEMUSER][index].addend;
|
||||
res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v)
|
||||
{
|
||||
int index;
|
||||
unsigned long addr, physaddr;
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
if (__builtin_expect(env->tlb_write[MEMUSER][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
glue(glue(__st, SUFFIX), _mmu)(addr, v);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_write[MEMUSER][index].addend;
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
|
||||
}
|
||||
}
|
||||
|
||||
#undef RES_TYPE
|
||||
#undef DATA_TYPE
|
||||
#undef DATA_STYPE
|
||||
#undef SUFFIX
|
||||
#undef DATA_SIZE
|
||||
#undef MEMSUFFIX
|
241
softmmu_template.h
Normal file
241
softmmu_template.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Software MMU support
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#define DATA_SIZE (1 << SHIFT)
|
||||
|
||||
#if DATA_SIZE == 8
|
||||
#define SUFFIX q
|
||||
#define DATA_TYPE uint64_t
|
||||
#elif DATA_SIZE == 4
|
||||
#define SUFFIX l
|
||||
#define DATA_TYPE uint32_t
|
||||
#elif DATA_SIZE == 2
|
||||
#define SUFFIX w
|
||||
#define DATA_TYPE uint16_t
|
||||
#elif DATA_SIZE == 1
|
||||
#define SUFFIX b
|
||||
#define DATA_TYPE uint8_t
|
||||
#else
|
||||
#error unsupported data size
|
||||
#endif
|
||||
|
||||
static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr);
|
||||
static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
void *retaddr);
|
||||
|
||||
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
|
||||
unsigned long tlb_addr)
|
||||
{
|
||||
DATA_TYPE res;
|
||||
int index;
|
||||
|
||||
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
#if SHIFT <= 2
|
||||
res = io_mem_read[index][SHIFT](physaddr);
|
||||
#else
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
res = (uint64_t)io_mem_read[index][2](physaddr) << 32;
|
||||
res |= io_mem_read[index][2](physaddr + 4);
|
||||
#else
|
||||
res = io_mem_read[index][2](physaddr);
|
||||
res |= (uint64_t)io_mem_read[index][2](physaddr + 4) << 32;
|
||||
#endif
|
||||
#endif /* SHIFT > 2 */
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
|
||||
DATA_TYPE val,
|
||||
unsigned long tlb_addr)
|
||||
{
|
||||
int index;
|
||||
|
||||
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
#if SHIFT <= 2
|
||||
io_mem_write[index][SHIFT](physaddr, val);
|
||||
#else
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
io_mem_write[index][2](physaddr, val >> 32);
|
||||
io_mem_write[index][2](physaddr + 4, val);
|
||||
#else
|
||||
io_mem_write[index][2](physaddr, val);
|
||||
io_mem_write[index][2](physaddr + 4, val >> 32);
|
||||
#endif
|
||||
#endif /* SHIFT > 2 */
|
||||
}
|
||||
|
||||
/* handle all cases except unaligned access which span two pages */
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr)
|
||||
{
|
||||
DATA_TYPE res;
|
||||
int is_user, index;
|
||||
unsigned long physaddr, tlb_addr;
|
||||
void *retaddr;
|
||||
|
||||
/* test if there is match for unaligned or IO access */
|
||||
/* XXX: could done more in memory macro in a non portable way */
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_read[is_user][index].address;
|
||||
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
if ((addr & (DATA_SIZE - 1)) != 0)
|
||||
goto do_unaligned_access;
|
||||
res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
|
||||
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
|
||||
/* slow unaligned access (it spans two pages or IO) */
|
||||
do_unaligned_access:
|
||||
retaddr = __builtin_return_address(0);
|
||||
res = glue(slow_ld, SUFFIX)(addr, retaddr);
|
||||
} else {
|
||||
/* unaligned access in the same page */
|
||||
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = __builtin_return_address(0);
|
||||
tlb_fill(addr, 0, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* handle all unaligned cases */
|
||||
static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr)
|
||||
{
|
||||
DATA_TYPE res, res1, res2;
|
||||
int is_user, index, shift;
|
||||
unsigned long physaddr, tlb_addr, addr1, addr2;
|
||||
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_read[is_user][index].address;
|
||||
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
if ((addr & (DATA_SIZE - 1)) != 0)
|
||||
goto do_unaligned_access;
|
||||
res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
|
||||
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
|
||||
do_unaligned_access:
|
||||
/* slow unaligned access (it spans two pages) */
|
||||
addr1 = addr & ~(DATA_SIZE - 1);
|
||||
addr2 = addr1 + DATA_SIZE;
|
||||
res1 = glue(slow_ld, SUFFIX)(addr1, retaddr);
|
||||
res2 = glue(slow_ld, SUFFIX)(addr2, retaddr);
|
||||
shift = (addr & (DATA_SIZE - 1)) * 8;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
|
||||
#else
|
||||
res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
|
||||
#endif
|
||||
} else {
|
||||
/* unaligned/aligned access in the same page */
|
||||
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
tlb_fill(addr, 0, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val)
|
||||
{
|
||||
unsigned long physaddr, tlb_addr;
|
||||
void *retaddr;
|
||||
int is_user, index;
|
||||
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_write[is_user][index].address;
|
||||
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
if ((addr & (DATA_SIZE - 1)) != 0)
|
||||
goto do_unaligned_access;
|
||||
glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
|
||||
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
|
||||
do_unaligned_access:
|
||||
retaddr = __builtin_return_address(0);
|
||||
glue(slow_st, SUFFIX)(addr, val, retaddr);
|
||||
} else {
|
||||
/* aligned/unaligned access in the same page */
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = __builtin_return_address(0);
|
||||
tlb_fill(addr, 1, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
||||
/* handles all unaligned cases */
|
||||
static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val,
|
||||
void *retaddr)
|
||||
{
|
||||
unsigned long physaddr, tlb_addr;
|
||||
int is_user, index, i;
|
||||
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_write[is_user][index].address;
|
||||
if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
if ((addr & (DATA_SIZE - 1)) != 0)
|
||||
goto do_unaligned_access;
|
||||
glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
|
||||
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
|
||||
do_unaligned_access:
|
||||
/* XXX: not efficient, but simple */
|
||||
for(i = 0;i < DATA_SIZE; i++) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
slow_stb(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), retaddr);
|
||||
#else
|
||||
slow_stb(addr + i, val >> (i * 8), retaddr);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* aligned/unaligned access in the same page */
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
tlb_fill(addr, 1, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SHIFT
|
||||
#undef DATA_TYPE
|
||||
#undef SUFFIX
|
||||
#undef DATA_SIZE
|
@@ -25,3 +25,4 @@ struct target_pt_regs {
|
||||
#define ARM_r0 uregs[0]
|
||||
#define ARM_ORIG_r0 uregs[17]
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
|
@@ -1,6 +1,6 @@
|
||||
gmon.out
|
||||
testsig
|
||||
hello
|
||||
hello-i386
|
||||
hello-arm
|
||||
sha1.test.c
|
||||
sha1.c
|
||||
|
@@ -1,4 +1,4 @@
|
||||
include ../config.mak
|
||||
include ../config-host.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=
|
||||
@@ -8,13 +8,13 @@ TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
||||
endif
|
||||
TESTS+=sha1 test_path
|
||||
|
||||
QEMU=../qemu
|
||||
QEMU=../i386/qemu
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
hello: hello.c
|
||||
hello-i386: hello-i386.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
strip hello
|
||||
strip $@
|
||||
|
||||
testclone: testclone.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
@@ -77,4 +77,21 @@ myfunc2:
|
||||
|
||||
|
||||
code16_end:
|
||||
|
||||
|
||||
/* other 32 bits tests */
|
||||
.code32
|
||||
|
||||
.globl func_lret32
|
||||
func_lret32:
|
||||
movl $0x87654321, %eax
|
||||
lret
|
||||
|
||||
.globl func_iret32
|
||||
func_iret32:
|
||||
movl $0xabcd4321, %eax
|
||||
iret
|
||||
|
||||
|
||||
|
||||
|
@@ -1,16 +1,19 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/mman.h>
|
||||
#include <asm/vm86.h>
|
||||
|
||||
#define TEST_CMOV 0
|
||||
#define TEST_FCOMI 0
|
||||
//#define LINUX_VM86_IOPL_FIX
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
@@ -591,7 +594,7 @@ void test_fbcd(double a)
|
||||
asm("fld1\n"\
|
||||
prefix "fnstenv %1\n"\
|
||||
prefix "fldenv %1\n"\
|
||||
: "=t" (res) : "m" (*(env)) : "st");\
|
||||
: "=t" (res) : "m" (*(env)));\
|
||||
printf("res=%f\n", res);\
|
||||
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
|
||||
(env)->fpuc,\
|
||||
@@ -601,7 +604,7 @@ void test_fbcd(double a)
|
||||
asm("fld1\n"\
|
||||
prefix "fnsave %1\n"\
|
||||
prefix "frstor %1\n"\
|
||||
: "=t" (res) : "m" (*(env)) : "st");\
|
||||
: "=t" (res) : "m" (*(env)));\
|
||||
printf("res=%f\n", res);\
|
||||
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
|
||||
(env)->fpuc,\
|
||||
@@ -854,7 +857,6 @@ void test_segs(void)
|
||||
#endif
|
||||
/* do some tests with fs or gs */
|
||||
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
|
||||
asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2)));
|
||||
|
||||
seg_data1[1] = 0xaa;
|
||||
seg_data2[1] = 0x55;
|
||||
@@ -862,7 +864,12 @@ void test_segs(void)
|
||||
asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
|
||||
printf("FS[1] = %02x\n", res);
|
||||
|
||||
asm volatile ("gs movzbl 0x1, %0" : "=r" (res));
|
||||
asm volatile ("pushl %%gs\n"
|
||||
"movl %1, %%gs\n"
|
||||
"gs movzbl 0x1, %0\n"
|
||||
"popl %%gs\n"
|
||||
: "=r" (res)
|
||||
: "r" (MK_SEL(2)));
|
||||
printf("GS[1] = %02x\n", res);
|
||||
|
||||
/* tests with ds/ss (implicit segment case) */
|
||||
@@ -937,6 +944,9 @@ void test_code16(void)
|
||||
printf("func3() = 0x%08x\n", res);
|
||||
}
|
||||
|
||||
extern char func_lret32;
|
||||
extern char func_iret32;
|
||||
|
||||
void test_misc(void)
|
||||
{
|
||||
char table[256];
|
||||
@@ -946,6 +956,26 @@ void test_misc(void)
|
||||
res = 0x12345678;
|
||||
asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
|
||||
printf("xlat: EAX=%08x\n", res);
|
||||
|
||||
asm volatile ("pushl %%cs ; call %1"
|
||||
: "=a" (res)
|
||||
: "m" (func_lret32): "memory", "cc");
|
||||
printf("func_lret32=%x\n", res);
|
||||
|
||||
asm volatile ("pushfl ; pushl %%cs ; call %1"
|
||||
: "=a" (res)
|
||||
: "m" (func_iret32): "memory", "cc");
|
||||
printf("func_iret32=%x\n", res);
|
||||
|
||||
/* specific popl test */
|
||||
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
|
||||
: "=g" (res));
|
||||
printf("popl esp=%x\n", res);
|
||||
|
||||
/* specific popw test */
|
||||
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0"
|
||||
: "=g" (res));
|
||||
printf("popw esp=%x\n", res);
|
||||
}
|
||||
|
||||
uint8_t str_buffer[4096];
|
||||
@@ -1077,7 +1107,7 @@ void test_vm86(void)
|
||||
switch(VM86_TYPE(ret)) {
|
||||
case VM86_INTx:
|
||||
{
|
||||
int int_num, ah;
|
||||
int int_num, ah, v;
|
||||
|
||||
int_num = VM86_ARG(ret);
|
||||
if (int_num != 0x21)
|
||||
@@ -1105,8 +1135,12 @@ void test_vm86(void)
|
||||
r->eax = (r->eax & ~0xff) | '$';
|
||||
}
|
||||
break;
|
||||
case 0xff: /* extension: write hex number in edx */
|
||||
printf("%08x\n", (int)r->edx);
|
||||
case 0xff: /* extension: write eflags number in edx */
|
||||
v = (int)r->edx;
|
||||
#ifndef LINUX_VM86_IOPL_FIX
|
||||
v &= ~0x3000;
|
||||
#endif
|
||||
printf("%08x\n", v);
|
||||
break;
|
||||
default:
|
||||
unknown_int:
|
||||
@@ -1231,6 +1265,8 @@ void test_exceptions(void)
|
||||
printf("PF exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
val = 1;
|
||||
/* we add a nop to test a weird PC retrieval case */
|
||||
asm volatile ("nop");
|
||||
/* now store in an invalid address */
|
||||
*(char *)0x1234 = 1;
|
||||
}
|
||||
@@ -1325,6 +1361,90 @@ void test_exceptions(void)
|
||||
printf("val=0x%x\n", val);
|
||||
}
|
||||
|
||||
/* specific precise single step test */
|
||||
void sig_trap_handler(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
printf("EIP=0x%08x\n", uc->uc_mcontext.gregs[REG_EIP]);
|
||||
}
|
||||
|
||||
const uint8_t sstep_buf1[4] = { 1, 2, 3, 4};
|
||||
uint8_t sstep_buf2[4];
|
||||
|
||||
void test_single_step(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
volatile int val;
|
||||
int i;
|
||||
|
||||
val = 0;
|
||||
act.sa_sigaction = sig_trap_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGTRAP, &act, NULL);
|
||||
asm volatile ("pushf\n"
|
||||
"orl $0x00100, (%%esp)\n"
|
||||
"popf\n"
|
||||
"movl $0xabcd, %0\n"
|
||||
|
||||
/* jmp test */
|
||||
"movl $3, %%ecx\n"
|
||||
"1:\n"
|
||||
"addl $1, %0\n"
|
||||
"decl %%ecx\n"
|
||||
"jnz 1b\n"
|
||||
|
||||
/* movsb: the single step should stop at each movsb iteration */
|
||||
"movl $sstep_buf1, %%esi\n"
|
||||
"movl $sstep_buf2, %%edi\n"
|
||||
"movl $0, %%ecx\n"
|
||||
"rep movsb\n"
|
||||
"movl $3, %%ecx\n"
|
||||
"rep movsb\n"
|
||||
"movl $1, %%ecx\n"
|
||||
"rep movsb\n"
|
||||
|
||||
/* cmpsb: the single step should stop at each cmpsb iteration */
|
||||
"movl $sstep_buf1, %%esi\n"
|
||||
"movl $sstep_buf2, %%edi\n"
|
||||
"movl $0, %%ecx\n"
|
||||
"rep cmpsb\n"
|
||||
"movl $4, %%ecx\n"
|
||||
"rep cmpsb\n"
|
||||
|
||||
/* getpid() syscall: single step should skip one
|
||||
instruction */
|
||||
"movl $20, %%eax\n"
|
||||
"int $0x80\n"
|
||||
"movl $0, %%eax\n"
|
||||
|
||||
/* when modifying SS, trace is not done on the next
|
||||
instruction */
|
||||
"movl %%ss, %%ecx\n"
|
||||
"movl %%ecx, %%ss\n"
|
||||
"addl $1, %0\n"
|
||||
"movl $1, %%eax\n"
|
||||
"movl %%ecx, %%ss\n"
|
||||
"jmp 1f\n"
|
||||
"addl $1, %0\n"
|
||||
"1:\n"
|
||||
"movl $1, %%eax\n"
|
||||
"pushl %%ecx\n"
|
||||
"popl %%ss\n"
|
||||
"addl $1, %0\n"
|
||||
"movl $1, %%eax\n"
|
||||
|
||||
"pushf\n"
|
||||
"andl $~0x00100, (%%esp)\n"
|
||||
"popf\n"
|
||||
: "=m" (val)
|
||||
:
|
||||
: "cc", "memory", "eax", "ecx", "esi", "edi");
|
||||
printf("val=%d\n", val);
|
||||
for(i = 0; i < 4; i++)
|
||||
printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]);
|
||||
}
|
||||
|
||||
/* self modifying code test */
|
||||
uint8_t code[] = {
|
||||
0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */
|
||||
@@ -1371,5 +1491,6 @@ int main(int argc, char **argv)
|
||||
test_vm86();
|
||||
test_exceptions();
|
||||
test_self_modifying_code();
|
||||
test_single_step();
|
||||
return 0;
|
||||
}
|
||||
|
78
thunk.h
78
thunk.h
@@ -23,43 +23,7 @@
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
||||
#define bswap_16(x) \
|
||||
({ \
|
||||
uint16_t __x = (x); \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
|
||||
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
|
||||
})
|
||||
|
||||
#define bswap_32(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 bswap_64(x) \
|
||||
({ \
|
||||
uint64_t __x = (x); \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
|
||||
})
|
||||
|
||||
#endif
|
||||
#include "bswap.h"
|
||||
|
||||
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define BSWAP_NEEDED
|
||||
@@ -68,44 +32,7 @@
|
||||
/* XXX: autoconf */
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
#if defined(__alpha__) || defined (__ia64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
#define HOST_LONG_BITS 32
|
||||
#endif
|
||||
|
||||
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
|
||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return bswap_16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
{
|
||||
return bswap_32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
{
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
static inline void bswap16s(uint16_t *s)
|
||||
{
|
||||
*s = bswap16(*s);
|
||||
}
|
||||
|
||||
static inline void bswap32s(uint32_t *s)
|
||||
{
|
||||
*s = bswap32(*s);
|
||||
}
|
||||
|
||||
static inline void bswap64s(uint64_t *s)
|
||||
{
|
||||
*s = bswap64(*s);
|
||||
}
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
|
||||
@@ -236,6 +163,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types);
|
||||
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);
|
||||
#ifndef NO_THUNK_TYPE_SIZE
|
||||
|
||||
extern StructEntry struct_entries[];
|
||||
|
||||
@@ -312,6 +240,8 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NO_THUNK_TYPE_SIZE */
|
||||
|
||||
unsigned int target_to_host_bitmask(unsigned int x86_mask,
|
||||
bitmask_transtbl * trans_tbl);
|
||||
unsigned int host_to_target_bitmask(unsigned int alpha_mask,
|
||||
|
243
translate-arm.c
243
translate-arm.c
@@ -34,6 +34,8 @@ typedef struct DisasContext {
|
||||
struct TranslationBlock *tb;
|
||||
} DisasContext;
|
||||
|
||||
#define DISAS_JUMP_NEXT 4
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
@@ -333,10 +335,11 @@ static void disas_arm_insn(DisasContext *s)
|
||||
/* 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;
|
||||
s->is_jmp = DISAS_JUMP_NEXT;
|
||||
}
|
||||
if ((insn & 0x0c000000) == 0 &&
|
||||
(insn & 0x00000090) != 0x90) {
|
||||
if (((insn & 0x0e000000) == 0 &&
|
||||
(insn & 0x00000090) != 0x90) ||
|
||||
((insn & 0x0e000000) == (1 << 25))) {
|
||||
int set_cc, logic_cc, shiftop;
|
||||
|
||||
op1 = (insn >> 21) & 0xf;
|
||||
@@ -367,7 +370,7 @@ static void disas_arm_insn(DisasContext *s)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rs = (insn >> 16) & 0xf;
|
||||
rs = (insn >> 8) & 0xf;
|
||||
gen_movl_T0_reg(s, rs);
|
||||
if (logic_cc) {
|
||||
gen_shift_T1_T0_cc[shiftop]();
|
||||
@@ -385,10 +388,14 @@ static void disas_arm_insn(DisasContext *s)
|
||||
case 0x00:
|
||||
gen_op_andl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
if (logic_cc)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x01:
|
||||
gen_op_xorl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
if (logic_cc)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x02:
|
||||
if (set_cc)
|
||||
@@ -435,11 +442,13 @@ static void disas_arm_insn(DisasContext *s)
|
||||
case 0x08:
|
||||
if (set_cc) {
|
||||
gen_op_andl_T0_T1();
|
||||
gen_op_logic_T0_cc();
|
||||
}
|
||||
break;
|
||||
case 0x09:
|
||||
if (set_cc) {
|
||||
gen_op_xorl_T0_T1();
|
||||
gen_op_logic_T0_cc();
|
||||
}
|
||||
break;
|
||||
case 0x0a:
|
||||
@@ -455,22 +464,28 @@ static void disas_arm_insn(DisasContext *s)
|
||||
case 0x0c:
|
||||
gen_op_orl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
if (logic_cc)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x0d:
|
||||
gen_movl_reg_T1(s, rd);
|
||||
if (logic_cc)
|
||||
gen_op_logic_T1_cc();
|
||||
break;
|
||||
case 0x0e:
|
||||
gen_op_bicl_T0_T1();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
if (logic_cc)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
default:
|
||||
case 0x0f:
|
||||
gen_op_notl_T1();
|
||||
gen_movl_reg_T1(s, rd);
|
||||
if (logic_cc)
|
||||
gen_op_logic_T1_cc();
|
||||
break;
|
||||
}
|
||||
if (logic_cc)
|
||||
gen_op_logic_cc();
|
||||
} else {
|
||||
/* other instructions */
|
||||
op1 = (insn >> 24) & 0xf;
|
||||
@@ -494,7 +509,7 @@ static void disas_arm_insn(DisasContext *s)
|
||||
gen_op_addl_T0_T1();
|
||||
}
|
||||
if (insn & (1 << 20))
|
||||
gen_op_logic_cc();
|
||||
gen_op_logic_T0_cc();
|
||||
gen_movl_reg_T0(s, rd);
|
||||
} else {
|
||||
/* 64 bit mul */
|
||||
@@ -551,10 +566,12 @@ static void disas_arm_insn(DisasContext *s)
|
||||
/* store */
|
||||
gen_op_stw_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
if (!(insn & (1 << 24))) {
|
||||
gen_add_datah_offset(s, insn);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
} else if (insn & (1 << 21)) {
|
||||
gen_movl_reg_T1(s, rn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x4:
|
||||
@@ -582,40 +599,94 @@ static void disas_arm_insn(DisasContext *s)
|
||||
else
|
||||
gen_op_stl_T0_T1();
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
if (!(insn & (1 << 24))) {
|
||||
gen_add_data_offset(s, insn);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
} else 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);
|
||||
{
|
||||
int j, n;
|
||||
/* load/store multiple words */
|
||||
/* XXX: store correct base if write back */
|
||||
if (insn & (1 << 22))
|
||||
goto illegal_op; /* only usable in supervisor mode */
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
|
||||
/* compute total size */
|
||||
n = 0;
|
||||
for(i=0;i<16;i++) {
|
||||
if (insn & (1 << i))
|
||||
n++;
|
||||
}
|
||||
/* XXX: test invalid n == 0 case ? */
|
||||
if (insn & (1 << 23)) {
|
||||
if (insn & (1 << 24)) {
|
||||
/* pre increment */
|
||||
gen_op_addl_T1_im(4);
|
||||
} else {
|
||||
/* store */
|
||||
gen_movl_T0_reg(s, i);
|
||||
gen_op_stl_T0_T1();
|
||||
/* post increment */
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
} else {
|
||||
if (insn & (1 << 24)) {
|
||||
/* pre decrement */
|
||||
gen_op_addl_T1_im(-(n * 4));
|
||||
} else {
|
||||
/* post decrement */
|
||||
if (n != 1)
|
||||
gen_op_addl_T1_im(-((n - 1) * 4));
|
||||
}
|
||||
}
|
||||
j = 0;
|
||||
for(i=0;i<16;i++) {
|
||||
if (insn & (1 << i)) {
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
gen_op_ldl_T0_T1();
|
||||
gen_movl_reg_T0(s, i);
|
||||
} else {
|
||||
/* store */
|
||||
if (i == 15) {
|
||||
/* special case: r15 = PC + 12 */
|
||||
val = (long)s->pc + 8;
|
||||
gen_op_movl_TN_im[0](val);
|
||||
} else {
|
||||
gen_movl_T0_reg(s, i);
|
||||
}
|
||||
gen_op_stl_T0_T1();
|
||||
}
|
||||
j++;
|
||||
/* no need to add after the last transfer */
|
||||
if (j != n)
|
||||
gen_op_addl_T1_im(4);
|
||||
}
|
||||
}
|
||||
if (insn & (1 << 21)) {
|
||||
/* write back */
|
||||
if (insn & (1 << 23)) {
|
||||
if (insn & (1 << 24)) {
|
||||
/* pre increment */
|
||||
} else {
|
||||
/* post increment */
|
||||
gen_op_addl_T1_im(4);
|
||||
}
|
||||
} else {
|
||||
if (insn & (1 << 24)) {
|
||||
/* pre decrement */
|
||||
if (n != 1)
|
||||
gen_op_addl_T1_im(-((n - 1) * 4));
|
||||
} else {
|
||||
/* post decrement */
|
||||
gen_op_addl_T1_im(-(n * 4));
|
||||
}
|
||||
}
|
||||
gen_movl_reg_T1(s, rn);
|
||||
}
|
||||
}
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
break;
|
||||
case 0xa:
|
||||
case 0xb:
|
||||
@@ -641,6 +712,66 @@ static void disas_arm_insn(DisasContext *s)
|
||||
gen_op_swi();
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
break;
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
rd = (insn >> 12) & 0x7;
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
val = (insn) & 0xff;
|
||||
if (!(insn & (1 << 23)))
|
||||
val = -val;
|
||||
switch((insn >> 8) & 0xf) {
|
||||
case 0x1:
|
||||
/* load/store */
|
||||
if ((insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
/* XXX: do it */
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
break;
|
||||
case 0x2:
|
||||
{
|
||||
int n, i;
|
||||
/* load store multiple */
|
||||
if ((insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
switch(insn & 0x00408000) {
|
||||
case 0x00008000: n = 1; break;
|
||||
case 0x00400000: n = 2; break;
|
||||
case 0x00408000: n = 3; break;
|
||||
default: n = 4; break;
|
||||
}
|
||||
for(i = 0;i < n; i++) {
|
||||
/* XXX: do it */
|
||||
}
|
||||
if (!(insn & (1 << 24)))
|
||||
gen_op_addl_T1_im(val);
|
||||
if (insn & (1 << 21))
|
||||
gen_movl_reg_T1(s, rn);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
case 0x0e:
|
||||
/* float ops */
|
||||
/* XXX: do it */
|
||||
switch((insn >> 20) & 0xf) {
|
||||
case 0x2: /* wfs */
|
||||
break;
|
||||
case 0x3: /* rfs */
|
||||
break;
|
||||
case 0x4: /* wfc */
|
||||
break;
|
||||
case 0x5: /* rfc */
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
illegal_op:
|
||||
gen_op_movl_T0_im((long)s->pc - 4);
|
||||
@@ -655,7 +786,9 @@ static void disas_arm_insn(DisasContext *s)
|
||||
/* 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)
|
||||
static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
TranslationBlock *tb,
|
||||
int search_pc)
|
||||
{
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
uint16_t *gen_opc_end;
|
||||
@@ -681,22 +814,27 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
lj++;
|
||||
while (lj < j)
|
||||
gen_opc_instr_start[lj++] = 0;
|
||||
gen_opc_pc[lj] = (uint32_t)dc->pc;
|
||||
gen_opc_instr_start[lj] = 1;
|
||||
}
|
||||
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) {
|
||||
switch(dc->is_jmp) {
|
||||
case DISAS_JUMP_NEXT:
|
||||
case DISAS_NEXT:
|
||||
gen_op_jmp((long)dc->tb, (long)dc->pc);
|
||||
break;
|
||||
default:
|
||||
case DISAS_JUMP:
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
break;
|
||||
case DISAS_TB_JUMP:
|
||||
/* nothing more to generate */
|
||||
break;
|
||||
}
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
|
||||
@@ -717,6 +855,16 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(env, tb, 0);
|
||||
}
|
||||
|
||||
int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(env, tb, 1);
|
||||
}
|
||||
|
||||
CPUARMState *cpu_arm_init(void)
|
||||
{
|
||||
CPUARMState *env;
|
||||
@@ -746,5 +894,10 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
|
||||
else
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, "CPSR=%08x", env->cpsr);
|
||||
fprintf(f, "PSR=%08x %c%c%c%c\n",
|
||||
env->cpsr,
|
||||
env->cpsr & (1 << 31) ? 'N' : '-',
|
||||
env->cpsr & (1 << 30) ? 'Z' : '-',
|
||||
env->cpsr & (1 << 29) ? 'C' : '-',
|
||||
env->cpsr & (1 << 28) ? 'V' : '-');
|
||||
}
|
||||
|
1759
translate-i386.c
1759
translate-i386.c
File diff suppressed because it is too large
Load Diff
76
translate.c
76
translate.c
@@ -24,37 +24,55 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define IN_OP_I386
|
||||
#include "cpu-" TARGET_ARCH ".h"
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#define OPC_CPU_H "opc-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#define OPC_CPU_H "opc-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "dyngen.h"
|
||||
#include "op-" TARGET_ARCH ".h"
|
||||
#if defined(TARGET_I386)
|
||||
#include "op-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "op-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
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];
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#include OPC_CPU_H
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
@@ -89,19 +107,24 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
|
||||
'*gen_code_size_ptr' contains the size of the generated code (host
|
||||
code).
|
||||
*/
|
||||
int cpu_gen_code(TranslationBlock *tb,
|
||||
int cpu_gen_code(CPUState *env, 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)
|
||||
if (gen_intermediate_code(env, tb) < 0)
|
||||
return -1;
|
||||
|
||||
/* generate machine code */
|
||||
tb->tb_next_offset[0] = 0xffff;
|
||||
tb->tb_next_offset[1] = 0xffff;
|
||||
gen_code_buf = tb->tc_ptr;
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
/* the following two entries are optional (only used for string ops) */
|
||||
tb->tb_jmp_offset[2] = 0xffff;
|
||||
tb->tb_jmp_offset[3] = 0xffff;
|
||||
#endif
|
||||
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
tb->tb_jmp_offset,
|
||||
@@ -123,22 +146,20 @@ int cpu_gen_code(TranslationBlock *tb,
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include "opc-" TARGET_ARCH ".h"
|
||||
#include OPC_CPU_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.
|
||||
/* The cpu state corresponding to 'searched_pc' is restored.
|
||||
*/
|
||||
int cpu_search_pc(TranslationBlock *tb,
|
||||
uint32_t *found_pc, unsigned long searched_pc)
|
||||
int cpu_restore_state(TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc)
|
||||
{
|
||||
int j, c;
|
||||
unsigned long tc_ptr;
|
||||
uint16_t *opc_ptr;
|
||||
|
||||
if (gen_intermediate_code(tb, 1) < 0)
|
||||
if (gen_intermediate_code_pc(env, tb) < 0)
|
||||
return -1;
|
||||
|
||||
/* find opc index corresponding to search_pc */
|
||||
@@ -160,7 +181,30 @@ int cpu_search_pc(TranslationBlock *tb,
|
||||
/* now find start of instruction before */
|
||||
while (gen_opc_instr_start[j] == 0)
|
||||
j--;
|
||||
*found_pc = gen_opc_pc[j];
|
||||
#if defined(TARGET_I386)
|
||||
{
|
||||
int cc_op;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
int i;
|
||||
fprintf(logfile, "RESTORE:\n");
|
||||
for(i=0;i<=j; i++) {
|
||||
if (gen_opc_instr_start[i]) {
|
||||
fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]);
|
||||
}
|
||||
}
|
||||
fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n",
|
||||
searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
|
||||
}
|
||||
#endif
|
||||
env->eip = gen_opc_pc[j] - tb->cs_base;
|
||||
cc_op = gen_opc_cc_op[j];
|
||||
if (cc_op != CC_OP_DYNAMIC)
|
||||
env->cc_op = cc_op;
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
env->regs[15] = gen_opc_pc[j];
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
100
vl.h
Normal file
100
vl.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* QEMU System Emulator header
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef VL_H
|
||||
#define VL_H
|
||||
|
||||
/* vl.c */
|
||||
struct CPUX86State;
|
||||
extern int reset_requested;
|
||||
|
||||
typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data);
|
||||
typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address);
|
||||
|
||||
void *get_mmap_addr(unsigned long size);
|
||||
int register_ioport_read(int start, int length, IOPortReadFunc *func, int size);
|
||||
int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size);
|
||||
|
||||
void kbd_put_keycode(int keycode);
|
||||
|
||||
#define MOUSE_EVENT_LBUTTON 0x01
|
||||
#define MOUSE_EVENT_RBUTTON 0x02
|
||||
#define MOUSE_EVENT_MBUTTON 0x04
|
||||
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
|
||||
|
||||
/* block.c */
|
||||
typedef struct BlockDriverState BlockDriverState;
|
||||
|
||||
BlockDriverState *bdrv_open(const char *filename, int snapshot);
|
||||
void bdrv_close(BlockDriverState *bs);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
|
||||
/* user mode linux compatible COW file */
|
||||
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
|
||||
#define COW_VERSION 2
|
||||
|
||||
struct cow_header_v2 {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
char backing_file[1024];
|
||||
int32_t mtime;
|
||||
uint64_t size;
|
||||
uint32_t sectorsize;
|
||||
};
|
||||
|
||||
/* vga.c */
|
||||
|
||||
#define VGA_RAM_SIZE (8192 * 1024)
|
||||
|
||||
typedef struct DisplayState {
|
||||
uint8_t *data;
|
||||
int linesize;
|
||||
int depth;
|
||||
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
|
||||
void (*dpy_resize)(struct DisplayState *s, int w, int h);
|
||||
void (*dpy_refresh)(struct DisplayState *s);
|
||||
} DisplayState;
|
||||
|
||||
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
|
||||
{
|
||||
s->dpy_update(s, x, y, w, h);
|
||||
}
|
||||
|
||||
static inline void dpy_resize(DisplayState *s, int w, int h)
|
||||
{
|
||||
s->dpy_resize(s, w, h);
|
||||
}
|
||||
|
||||
int vga_init(DisplayState *ds, uint8_t *vga_ram_base,
|
||||
unsigned long vga_ram_offset, int vga_ram_size);
|
||||
void vga_update_display(void);
|
||||
|
||||
/* sdl.c */
|
||||
void sdl_display_init(DisplayState *ds);
|
||||
|
||||
#endif /* VL_H */
|
143
vlmkcow.c
Normal file
143
vlmkcow.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* create a COW disk image
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#include "bswap.h"
|
||||
|
||||
int cow_create(int cow_fd, const char *image_filename,
|
||||
int64_t image_sectors)
|
||||
{
|
||||
struct cow_header_v2 cow_header;
|
||||
int fd;
|
||||
struct stat st;
|
||||
|
||||
memset(&cow_header, 0, sizeof(cow_header));
|
||||
cow_header.magic = htonl(COW_MAGIC);
|
||||
cow_header.version = htonl(COW_VERSION);
|
||||
if (image_filename) {
|
||||
fd = open(image_filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror(image_filename);
|
||||
exit(1);
|
||||
}
|
||||
image_sectors = lseek64(fd, 0, SEEK_END);
|
||||
if (fstat(fd, &st) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
image_sectors /= 512;
|
||||
cow_header.mtime = htonl(st.st_mtime);
|
||||
realpath(image_filename, cow_header.backing_file);
|
||||
}
|
||||
cow_header.sectorsize = htonl(512);
|
||||
cow_header.size = image_sectors * 512;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
cow_header.size = bswap64(cow_header.size);
|
||||
#endif
|
||||
write(cow_fd, &cow_header, sizeof(cow_header));
|
||||
/* resize to include at least all the bitmap */
|
||||
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
|
||||
lseek(cow_fd, 0, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
|
||||
"Create a Copy On Write disk image from an optional raw disk image\n"
|
||||
"\n"
|
||||
"-f disk_image set the raw disk image name\n"
|
||||
"cow_image the created cow_image\n"
|
||||
"cow_size the create cow_image size in MB if no raw disk image is used\n"
|
||||
"\n"
|
||||
"Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *image_filename, *cow_filename;
|
||||
int cow_fd, c, nb_args;
|
||||
int64_t image_size;
|
||||
|
||||
image_filename = NULL;
|
||||
image_size = 0;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hf:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
break;
|
||||
case 'f':
|
||||
image_filename = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!image_filename)
|
||||
nb_args = 2;
|
||||
else
|
||||
nb_args = 1;
|
||||
if (optind + nb_args != argc)
|
||||
help();
|
||||
|
||||
cow_filename = argv[optind];
|
||||
if (nb_args == 2) {
|
||||
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
|
||||
}
|
||||
|
||||
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
||||
if (!cow_fd < 0)
|
||||
return -1;
|
||||
if (cow_create(cow_fd, image_filename, image_size) < 0) {
|
||||
fprintf(stderr, "%s: error while formating\n", cow_filename);
|
||||
exit(1);
|
||||
}
|
||||
close(cow_fd);
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user