Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be26a5288e | ||
|
|
82c7e2a4c6 | ||
|
|
546cdbd77d | ||
|
|
c265508067 | ||
|
|
dd4e27d810 | ||
|
|
a41bc9af8f | ||
|
|
3bfd9da14f | ||
|
|
c573ff6752 | ||
|
|
060366c5ad | ||
|
|
6da41eafc4 | ||
|
|
0124311e00 | ||
|
|
f515528907 | ||
|
|
b453b70bd8 | ||
|
|
0ac4bd56a8 | ||
|
|
3811a291e2 | ||
|
|
3415a4ddb4 | ||
|
|
b7f0f463a5 | ||
|
|
8e682019e3 | ||
|
|
cf495bcf9f | ||
|
|
fb0eaffc6d | ||
|
|
07ad1b93a3 | ||
|
|
d36cd60e6c | ||
|
|
5e809a8095 | ||
|
|
791c2261d6 | ||
|
|
163a7cb620 | ||
|
|
6bb705711b | ||
|
|
4136f33c7e | ||
|
|
6dca2016fc | ||
|
|
678673089d | ||
|
|
28b6751f30 | ||
|
|
79aceca54a | ||
|
|
6a8c397deb | ||
|
|
9cdf757fd5 | ||
|
|
36bdbe5479 | ||
|
|
8004340674 | ||
|
|
a2cc3b2433 | ||
|
|
afa05eb15e | ||
|
|
de5eaa6452 | ||
|
|
7517502475 | ||
|
|
8f2b1fb008 | ||
|
|
891b38e446 | ||
|
|
7dea1da4ae | ||
|
|
4ce900b44c | ||
|
|
f3f2d9be03 | ||
|
|
77729c2445 | ||
|
|
d71b9a8b2f | ||
|
|
181f1558cd | ||
|
|
2750332396 | ||
|
|
f115e911d7 | ||
|
|
3ab493de4c | ||
|
|
3e25f9515a | ||
|
|
246d897f4c | ||
|
|
7e84c2498f | ||
|
|
e670b89e3b | ||
|
|
bd0d90b21d | ||
|
|
1a0636f8d7 | ||
|
|
2e134c9c55 | ||
|
|
5391d80669 | ||
|
|
36b486bb74 | ||
|
|
4ad06a29b2 | ||
|
|
e58143b355 | ||
|
|
1f5476fcce | ||
|
|
461c0471af | ||
|
|
9c3ad57432 | ||
|
|
e748ba4f53 | ||
|
|
b8ed223bfe | ||
|
|
c970a162e7 | ||
|
|
c321f67309 | ||
|
|
7f7f987341 | ||
|
|
aebcb60e55 | ||
|
|
1a18c71b50 | ||
|
|
03a6c5103d | ||
|
|
128b346e0a | ||
|
|
415fa2ea77 | ||
|
|
9951bf39f9 | ||
|
|
8948b5d613 | ||
|
|
5086347239 | ||
|
|
9d4520d0e0 | ||
|
|
5b9f457a89 | ||
|
|
3a4739d651 | ||
|
|
76b62fd001 | ||
|
|
b1f645758a | ||
|
|
bc1b050d85 | ||
|
|
03d5f74aee | ||
|
|
9f05cc34df | ||
|
|
285dc330bd | ||
|
|
baf8ebf01a | ||
|
|
9d16dd550e | ||
|
|
78d6da976c | ||
|
|
dd6ee15c37 | ||
|
|
0db634747e | ||
|
|
6e59c1db89 | ||
|
|
61382a500a | ||
|
|
3a51dee658 | ||
|
|
cc38b844d7 | ||
|
|
c6105c0a04 | ||
|
|
93a40ea926 | ||
|
|
db8d746688 | ||
|
|
997344f303 | ||
|
|
16e9b7de41 | ||
|
|
3486513433 | ||
|
|
0806e3f66f | ||
|
|
39b4da28b3 | ||
|
|
5a67135a0b | ||
|
|
42f1e0e49b | ||
|
|
27c3f2cb9b | ||
|
|
a07cf92aed | ||
|
|
01e3b763a6 | ||
|
|
0ae04d7367 | ||
|
|
ebc054881f | ||
|
|
a20dd508aa | ||
|
|
6180a1818a | ||
|
|
d3eead2eec | ||
|
|
853d6f7a83 | ||
|
|
93ac68bca5 | ||
|
|
1e43adfc89 | ||
|
|
7a3f194486 | ||
|
|
2c0262afa7 | ||
|
|
196ad10903 | ||
|
|
b7dda06abf | ||
|
|
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 |
No files matched your search
@@ -1,10 +1,54 @@
|
||||
version 0.5.1:
|
||||
|
||||
- float access fixes when using soft mmu
|
||||
- PC emulation support on PowerPC
|
||||
- A20 support
|
||||
- IDE CD-ROM emulation
|
||||
- ARM fixes (Ulrich Hecht)
|
||||
- SB16 emulation (malc)
|
||||
- IRET and INT fixes in VM86 mode with IOPL=3
|
||||
- Port I/Os use TSS io map
|
||||
- Full task switching/task gate support
|
||||
- added verr, verw, arpl, fcmovxx
|
||||
- PowerPC target support (Jocelyn Mayer)
|
||||
- Major SPARC target fixes (dynamically linked programs begin to work)
|
||||
|
||||
version 0.5.0:
|
||||
|
||||
- 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 qemu
|
||||
- m68k host port (Richard Zidlicky)
|
||||
- partial soft MMU support for memory mapped I/Os
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping thru string operations
|
||||
- preliminary SPARC target support (Thomas M. Ogrisegg)
|
||||
- tun-fd option (Rusty Russell)
|
||||
- automatic IDE geometry detection
|
||||
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
||||
- added man page
|
||||
- added full soft mmu mode to launch unpatched OSes.
|
||||
|
||||
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
|
||||
- accept User Mode Linux Copy On Write disk images
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
@@ -1,202 +1,52 @@
|
||||
include config.mak
|
||||
include config-host.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-DHAVE_BYTESWAP_H
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
PROGS=qemu
|
||||
|
||||
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,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 vlmkcow
|
||||
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 ($(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
|
||||
TOOLS=qemu-mkcow
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
all: dyngen $(TOOLS) qemu-doc.html qemu.1
|
||||
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
|
||||
qemu-mkcow: qemu-mkcow.o
|
||||
$(HOST_CC) -o $@ $^ $(LIBS)
|
||||
|
||||
# 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
|
||||
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: vl.o block.o libqemu.a
|
||||
$(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
|
||||
|
||||
vlmkcow: vlmkcow.o
|
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
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 ops_template_mem.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 qemu.pod
|
||||
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 -rf $$d || exit 1 ; \
|
||||
done
|
||||
|
||||
install: $(PROGS)
|
||||
install: all
|
||||
mkdir -p $(prefix)/bin
|
||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
||||
install -m 755 -s $(TOOLS) $(prefix)/bin
|
||||
mkdir -p $(sharedir)
|
||||
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin $(sharedir)
|
||||
mkdir -p $(mandir)/man1
|
||||
install qemu.1 $(mandir)/man1
|
||||
for d in $(TARGET_DIRS); do \
|
||||
make -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
# various test targets
|
||||
test speed: qemu
|
||||
test speed test2: all
|
||||
make -C tests $@
|
||||
|
||||
TAGS:
|
||||
@@ -206,49 +56,29 @@ TAGS:
|
||||
qemu-doc.html: qemu-doc.texi
|
||||
texi2html -monolithic -number $<
|
||||
|
||||
FILES= \
|
||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||
configure \
|
||||
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
Makefile elf.h elfload.c main.c signal.c qemu.h \
|
||||
syscall.c syscall_defs.h vm86.c path.c mmap.c \
|
||||
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
|
||||
vl.c i386-vl.ld vl.h block.c vlmkcow.c\
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c gdbstub.c\
|
||||
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
|
||||
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
|
||||
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
|
||||
arm-dis.c \
|
||||
tests/Makefile \
|
||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
|
||||
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
|
||||
tests/hello-i386.c tests/hello-i386 \
|
||||
tests/hello-arm.c tests/hello-arm \
|
||||
tests/sha1.c \
|
||||
tests/testsig.c tests/testclone.c tests/testthread.c \
|
||||
tests/runcom.c tests/pi_10.com \
|
||||
tests/test_path.c \
|
||||
qemu-doc.texi qemu-doc.html
|
||||
qemu.1: qemu-doc.texi
|
||||
./texi2pod.pl $< qemu.pod
|
||||
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
|
||||
|
||||
FILE=qemu-$(VERSION)
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
tar:
|
||||
rm -rf /tmp/$(FILE)
|
||||
mkdir -p /tmp/$(FILE)
|
||||
cp -P $(FILES) /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
||||
cp -r . /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
|
||||
rm -rf /tmp/$(FILE)
|
||||
|
||||
# generate a binary distribution including the test binary environnment
|
||||
BINPATH=/usr/local/qemu-i386
|
||||
|
||||
# generate a binary distribution
|
||||
tarbin:
|
||||
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
|
||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
|
||||
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
|
||||
$(BINPATH)/wine
|
||||
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
|
||||
$(prefix)/bin/qemu $(prefix)/bin/qemu-fast \
|
||||
$(prefix)/bin/qemu-i386 \
|
||||
$(prefix)/bin/qemu-arm \
|
||||
$(prefix)/bin/qemu-sparc \
|
||||
$(sharedir)/bios.bin \
|
||||
$(sharedir)/vgabios.bin \
|
||||
$(mandir)/man1/qemu.1 )
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
include config.mak
|
||||
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
|
||||
VPATH=$(SRC_PATH):$(TARGET_PATH)
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen
|
||||
# user emulator name
|
||||
QEMU_USER=qemu-$(TARGET_ARCH)
|
||||
# system emulator name
|
||||
ifdef CONFIG_SOFTMMU
|
||||
QEMU_SYSTEM=qemu
|
||||
else
|
||||
QEMU_SYSTEM=qemu-fast
|
||||
endif
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
PROGS=$(QEMU_USER)
|
||||
else
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
ifndef CONFIG_SOFTMMU
|
||||
CONFIG_STATIC=y
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH), ppc)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
||||
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
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
ifdef CONFIG_STATIC
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
ifdef USE_I386_LD
|
||||
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
|
||||
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-all.o cpu-exec.o gdbstub.o \
|
||||
translate.o op.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=helper.o helper2.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
LIBOBJS+=helper.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_USER): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# 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 ide.o vga.o sb16.o dma.o oss.o
|
||||
ifdef CONFIG_SDL
|
||||
VL_OBJS+=sdl.o
|
||||
ifdef CONFIG_STATIC
|
||||
SDL_LIBS:=$(SDL_STATIC_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
VL_LDFLAGS=
|
||||
# specific flags are needed for non soft mmu emulator
|
||||
ifdef CONFIG_STATIC
|
||||
VL_LDFLAGS+=-static
|
||||
endif
|
||||
ifndef CONFIG_SOFTMMU
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
|
||||
endif
|
||||
|
||||
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
|
||||
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS)
|
||||
|
||||
sdl.o: sdl.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
translate.o: translate.c gen-op.h opc.h cpu.h
|
||||
|
||||
translate-all.o: translate-all.c op.h opc.h cpu.h
|
||||
|
||||
op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -o $@ $<
|
||||
|
||||
opc.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -c -o $@ $<
|
||||
|
||||
gen-op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -g -o $@ $<
|
||||
|
||||
op.o: op.c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
helper.o: helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc)
|
||||
op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h
|
||||
|
||||
install: all
|
||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
@@ -6,35 +6,17 @@ INSTALLATION
|
||||
|
||||
Type
|
||||
|
||||
./configure --interp-prefix=/usr/local/qemu-i386
|
||||
./configure
|
||||
make
|
||||
|
||||
to build qemu and libqemu.a.
|
||||
to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various
|
||||
supported target CPUs).
|
||||
|
||||
Type
|
||||
|
||||
make install
|
||||
|
||||
to install QEMU in /usr/local/bin
|
||||
|
||||
* On x86 you should be able to launch any program by using the
|
||||
libraries installed on your PC. For example:
|
||||
|
||||
./qemu -L / /bin/ls
|
||||
|
||||
* On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||
LD_LIBRARY_PATH is not set:
|
||||
|
||||
unset LD_LIBRARY_PATH
|
||||
|
||||
Then you can launch the precompiled 'ls' x86 executable:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
|
||||
You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
|
||||
automatically launched by the Linux kernel when you try to launch x86
|
||||
executables.
|
||||
to install QEMU in /usr/local
|
||||
|
||||
Tested tool versions
|
||||
--------------------
|
||||
@@ -50,8 +32,10 @@ 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 Debian 3.0
|
||||
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] Debian 3.0
|
||||
|
||||
@@ -65,6 +49,9 @@ ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
|
||||
(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
|
||||
-------------
|
||||
|
||||
|
||||
+2
-2
@@ -6,11 +6,11 @@ x86 binary distribution:
|
||||
|
||||
* wine-20020411 tarball
|
||||
|
||||
./configure --prefix=/usr/local/qemu-i386/wine
|
||||
./configure --prefix=/usr/local/wine-i386
|
||||
|
||||
All exe and libs were stripped. Some compile time tools and the
|
||||
includes were deleted.
|
||||
|
||||
* ldconfig was launched to build the library links:
|
||||
|
||||
./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache
|
||||
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
|
||||
@@ -1,17 +1,23 @@
|
||||
- user/kernel PUSHL/POPL in helper.c
|
||||
- keyboard output buffer filling timing emulation
|
||||
- verify tb_flush() with a20 and TLBs
|
||||
|
||||
- cmos clock update and timers
|
||||
- test ldt limit < 7 ?
|
||||
- tests for each target CPU
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
||||
fix cr0.TS emulation
|
||||
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
|
||||
- sysenter/sysexit emulation
|
||||
- fix CCOP optimisation
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- add IPC syscalls
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- sysenter/sysexit emulation
|
||||
- add IPC syscalls
|
||||
- SMP support
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- handle rare page fault cases (in particular if page fault in heplers or
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -15,11 +15,10 @@ 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"
|
||||
interp_prefix="/usr/gnemul/qemu-i386"
|
||||
interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
@@ -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-user i386 i386-softmmu arm-user sparc-user ppc-user"
|
||||
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,7 +166,7 @@ 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
|
||||
|
||||
@@ -164,16 +183,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
|
||||
have_gcc3_options="yes"
|
||||
fi
|
||||
|
||||
if test "$target_bigendian" = "default" ; then
|
||||
if test "$target_cpu" = "x86" ; then
|
||||
target_bigendian="no"
|
||||
elif test "$target_cpu" = "arm" ; then
|
||||
target_bigendian="no"
|
||||
else
|
||||
target_bigendian="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
cat << EOF
|
||||
|
||||
@@ -184,8 +193,9 @@ EOF
|
||||
echo "Standard options:"
|
||||
echo " --help print this message"
|
||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
|
||||
echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]"
|
||||
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
|
||||
echo " use %M for cpu name [$interp_prefix]"
|
||||
echo " --target-list=LIST set target list [$target_list]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
@@ -198,101 +208,179 @@ echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mandir="$prefix/share/man"
|
||||
sharedir="$prefix/share/qemu"
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "Manual directory $mandir"
|
||||
echo "BIOS directory $sharedir"
|
||||
echo "ELF interp prefix $interp_prefix"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
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 "Creating config.mak and config.h"
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > config.mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
||||
|
||||
echo "prefix=$prefix" >> config.mak
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
|
||||
echo "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
echo "HAVE_GCC3_OPTIONS=yes" >> config.mak
|
||||
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 "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
|
||||
|
||||
config_mak="config-host.mak"
|
||||
config_h="config-host.h"
|
||||
|
||||
echo "Creating $config_mak and $config_h"
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
|
||||
echo "prefix=$prefix" >> $config_mak
|
||||
echo "mandir=$mandir" >> $config_mak
|
||||
echo "sharedir=$sharedir" >> $config_mak
|
||||
echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h
|
||||
echo "MAKE=$make" >> $config_mak
|
||||
echo "CC=$cc" >> $config_mak
|
||||
if test "$have_gcc3_options" = "yes" ; then
|
||||
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
|
||||
echo "#define CONFIG_STATIC 1" >> $config_h
|
||||
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_STATIC_LIBS=`sdl-config --static-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_cpu" = "sparc" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
fi
|
||||
target_user_only="no"
|
||||
if expr $target : '.*-user' > /dev/null ; then
|
||||
target_user_only="yes"
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
|
||||
|
||||
if test "$target_cpu" = "i386" ; then
|
||||
echo "TARGET_ARCH=i386" >> $config_mak
|
||||
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
|
||||
elif test "$target_cpu" = "sparc" ; then
|
||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||
echo "#define TARGET_SPARC 1" >> $config_h
|
||||
elif test "$target_cpu" = "ppc" ; then
|
||||
echo "TARGET_ARCH=ppc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
|
||||
echo "#define TARGET_PPC 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 "$target_user_only" = "yes" ; then
|
||||
echo "CONFIG_USER_ONLY=yes" >> $config_mak
|
||||
echo "#define CONFIG_USER_ONLY 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
|
||||
@@ -305,13 +393,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
|
||||
@@ -20,18 +20,53 @@
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
/* all CPU memory access use these macros */
|
||||
static inline int ldub(void *ptr)
|
||||
#if defined(__arm__) || defined(__sparc__)
|
||||
#define WORDS_ALIGNED
|
||||
#endif
|
||||
|
||||
/* some important defines:
|
||||
*
|
||||
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
|
||||
* memory accesses.
|
||||
*
|
||||
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
|
||||
* otherwise little endian.
|
||||
*
|
||||
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
|
||||
*
|
||||
* TARGET_WORDS_BIGENDIAN : same for target cpu
|
||||
*/
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
typedef union {
|
||||
double d;
|
||||
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
|
||||
struct {
|
||||
uint32_t lower;
|
||||
uint32_t upper;
|
||||
} l;
|
||||
#else
|
||||
struct {
|
||||
uint32_t upper;
|
||||
uint32_t lower;
|
||||
} l;
|
||||
#endif
|
||||
uint64_t ll;
|
||||
} CPU_DoubleU;
|
||||
|
||||
/* CPU memory access without any memory or io remapping */
|
||||
|
||||
static inline int ldub_raw(void *ptr)
|
||||
{
|
||||
return *(uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsb(void *ptr)
|
||||
static inline int ldsb_raw(void *ptr)
|
||||
{
|
||||
return *(int8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stb(void *ptr, int v)
|
||||
static inline void stb_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint8_t *)ptr = v;
|
||||
}
|
||||
@@ -39,10 +74,10 @@ static inline void stb(void *ptr, int v)
|
||||
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
|
||||
kernel handles unaligned load/stores may give better results, but
|
||||
it is a system wide setting : bad */
|
||||
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
|
||||
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||
|
||||
/* conservative code for little endian unaligned accesses */
|
||||
static inline int lduw(void *ptr)
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -54,7 +89,7 @@ static inline int lduw(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -66,7 +101,7 @@ static inline int ldsw(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
int val;
|
||||
@@ -78,16 +113,16 @@ static inline int ldl(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
uint32_t v1, v2;
|
||||
v1 = ldl(p);
|
||||
v2 = ldl(p + 4);
|
||||
v1 = ldl_raw(p);
|
||||
v2 = ldl_raw(p + 4);
|
||||
return v1 | ((uint64_t)v2 << 32);
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
|
||||
@@ -98,7 +133,7 @@ static inline void stw(void *ptr, int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
#ifdef __powerpc__
|
||||
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
|
||||
@@ -111,142 +146,241 @@ static inline void stl(void *ptr, int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
uint8_t *p = ptr;
|
||||
stl(p, (uint32_t)v);
|
||||
stl(p + 4, v >> 32);
|
||||
stl_raw(p, (uint32_t)v);
|
||||
stl_raw(p + 4, v >> 32);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
u.i = ldl_raw(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
stl_raw(ptr, u.i);
|
||||
}
|
||||
|
||||
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
|
||||
|
||||
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
u.tab[1] = ldl(ptr);
|
||||
u.tab[0] = ldl(ptr + 4);
|
||||
CPU_DoubleU u;
|
||||
u.l.lower = ldl_raw(ptr);
|
||||
u.l.upper = ldl_raw(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint32_t tab[2];
|
||||
} u;
|
||||
CPU_DoubleU u;
|
||||
u.d = v;
|
||||
stl(ptr, u.tab[1]);
|
||||
stl(ptr + 4, u.tab[0]);
|
||||
stl_raw(ptr, u.l.lower);
|
||||
stl_raw(ptr + 4, u.l.upper);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline double ldfq(void *ptr)
|
||||
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
|
||||
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return (b[0]<<8|b[1]);
|
||||
}
|
||||
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
int8_t *b = (int8_t *) ptr;
|
||||
return (b[0]<<8|b[1]);
|
||||
}
|
||||
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
uint8_t *b = (uint8_t *) ptr;
|
||||
return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]);
|
||||
}
|
||||
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
uint32_t a,b;
|
||||
a = ldl_raw(ptr);
|
||||
b = ldl_raw(ptr+4);
|
||||
return (((uint64_t)a<<32)|b);
|
||||
}
|
||||
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
uint8_t *d = (uint8_t *) ptr;
|
||||
d[0] = v >> 8;
|
||||
d[1] = v;
|
||||
}
|
||||
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
uint8_t *d = (uint8_t *) ptr;
|
||||
d[0] = v >> 24;
|
||||
d[1] = v >> 16;
|
||||
d[2] = v >> 8;
|
||||
d[3] = v;
|
||||
}
|
||||
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
stl_raw(ptr, v >> 32);
|
||||
stl_raw(ptr + 4, v);
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
u.i = ldl_raw(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl_raw(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
CPU_DoubleU u;
|
||||
u.l.upper = ldl_raw(ptr);
|
||||
u.l.lower = ldl_raw(ptr + 4);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
CPU_DoubleU u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
stl_raw(ptr, u.l.upper);
|
||||
stl_raw(ptr + 4, u.l.lower);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
static inline int lduw(void *ptr)
|
||||
static inline int lduw_raw(void *ptr)
|
||||
{
|
||||
return *(uint16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldsw(void *ptr)
|
||||
static inline int ldsw_raw(void *ptr)
|
||||
{
|
||||
return *(int16_t *)ptr;
|
||||
}
|
||||
|
||||
static inline int ldl(void *ptr)
|
||||
static inline int ldl_raw(void *ptr)
|
||||
{
|
||||
return *(uint32_t *)ptr;
|
||||
}
|
||||
|
||||
static inline uint64_t ldq(void *ptr)
|
||||
static inline uint64_t ldq_raw(void *ptr)
|
||||
{
|
||||
return *(uint64_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void stw(void *ptr, int v)
|
||||
static inline void stw_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint16_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stl(void *ptr, int v)
|
||||
static inline void stl_raw(void *ptr, int v)
|
||||
{
|
||||
*(uint32_t *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stq(void *ptr, uint64_t v)
|
||||
static inline void stq_raw(void *ptr, uint64_t v)
|
||||
{
|
||||
*(uint64_t *)ptr = v;
|
||||
}
|
||||
|
||||
/* float access */
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
static inline float ldfl_raw(void *ptr)
|
||||
{
|
||||
return *(float *)ptr;
|
||||
}
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
static inline double ldfq_raw(void *ptr)
|
||||
{
|
||||
return *(double *)ptr;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
static inline void stfl_raw(void *ptr, float v)
|
||||
{
|
||||
*(float *)ptr = v;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
static inline void stfq_raw(void *ptr, double v)
|
||||
{
|
||||
*(double *)ptr = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MMU memory access macros */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* if user mode, no other memory access functions */
|
||||
#define ldub(p) ldub_raw(p)
|
||||
#define ldsb(p) ldsb_raw(p)
|
||||
#define lduw(p) lduw_raw(p)
|
||||
#define ldsw(p) ldsw_raw(p)
|
||||
#define ldl(p) ldl_raw(p)
|
||||
#define ldq(p) ldq_raw(p)
|
||||
#define ldfl(p) ldfl_raw(p)
|
||||
#define ldfq(p) ldfq_raw(p)
|
||||
#define stb(p, v) stb_raw(p, v)
|
||||
#define stw(p, v) stw_raw(p, v)
|
||||
#define stl(p, v) stl_raw(p, v)
|
||||
#define stq(p, v) stq_raw(p, v)
|
||||
#define stfl(p, v) stfl_raw(p, v)
|
||||
#define stfq(p, v) stfq_raw(p, v)
|
||||
|
||||
#define ldub_code(p) ldub_raw(p)
|
||||
#define ldsb_code(p) ldsb_raw(p)
|
||||
#define lduw_code(p) lduw_raw(p)
|
||||
#define ldsw_code(p) ldsw_raw(p)
|
||||
#define ldl_code(p) ldl_raw(p)
|
||||
|
||||
#define ldub_kernel(p) ldub_raw(p)
|
||||
#define ldsb_kernel(p) ldsb_raw(p)
|
||||
#define lduw_kernel(p) lduw_raw(p)
|
||||
#define ldsw_kernel(p) ldsw_raw(p)
|
||||
#define ldl_kernel(p) ldl_raw(p)
|
||||
#define ldfl_kernel(p) ldfl_raw(p)
|
||||
#define ldfq_kernel(p) ldfq_raw(p)
|
||||
#define stb_kernel(p, v) stb_raw(p, v)
|
||||
#define stw_kernel(p, v) stw_raw(p, v)
|
||||
#define stl_kernel(p, v) stl_raw(p, v)
|
||||
#define stq_kernel(p, v) stq_raw(p, v)
|
||||
#define stfl_kernel(p, v) stfl_raw(p, v)
|
||||
#define stfq_kernel(p, vt) stfq_raw(p, v)
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
|
||||
@@ -296,6 +430,24 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
#define cpu_interrupt cpu_arm_interrupt
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
#define CPUState CPUSPARCState
|
||||
#define cpu_init cpu_sparc_init
|
||||
#define cpu_exec cpu_sparc_exec
|
||||
#define cpu_gen_code cpu_sparc_gen_code
|
||||
#define cpu_interrupt cpu_sparc_interrupt
|
||||
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
#define CPUState CPUPPCState
|
||||
#define cpu_init cpu_ppc_init
|
||||
#define cpu_exec cpu_ppc_exec
|
||||
#define cpu_gen_code cpu_ppc_gen_code
|
||||
#define cpu_interrupt cpu_ppc_interrupt
|
||||
#define cpu_signal_handler cpu_ppc_signal_handler
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported target CPU
|
||||
@@ -313,9 +465,28 @@ extern CPUState *cpu_single_env;
|
||||
#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);
|
||||
|
||||
#define CPU_LOG_ALL 1
|
||||
void cpu_set_log(int log_flags);
|
||||
void cpu_set_log_filename(const char *filename);
|
||||
|
||||
/* memory API */
|
||||
|
||||
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
|
||||
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, void (*main_loop)(void *opaque), int port);
|
||||
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port);
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 {
|
||||
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
|
||||
zone number
|
||||
bit 3 : indicates that the entry is invalid
|
||||
bit 2..0 : zero
|
||||
*/
|
||||
uint32_t address;
|
||||
/* addend to virtual address to get physical address */
|
||||
uint32_t addend;
|
||||
} CPUTLBEntry;
|
||||
|
||||
#endif
|
||||
+142
-74
@@ -18,19 +18,15 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "exec-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "exec-arm.h"
|
||||
#endif
|
||||
|
||||
#include "exec.h"
|
||||
#include "disas.h"
|
||||
|
||||
int tb_invalidated_flag;
|
||||
|
||||
//#define DEBUG_EXEC
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
/* XXX: unify with i386 target */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
@@ -136,6 +132,8 @@ int cpu_exec(CPUState *env1)
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
env->cpsr = psr & ~0xf0000000;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#elif defined(TARGET_PPC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -170,7 +168,7 @@ int cpu_exec(CPUState *env1)
|
||||
do_interrupt(env->exception_index,
|
||||
env->exception_is_int,
|
||||
env->error_code,
|
||||
env->exception_next_eip);
|
||||
env->exception_next_eip, 0);
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
@@ -182,17 +180,18 @@ int cpu_exec(CPUState *env1)
|
||||
tmp_T0 = T0;
|
||||
#endif
|
||||
interrupt_request = env->interrupt_request;
|
||||
if (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->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);
|
||||
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 */
|
||||
@@ -225,37 +224,38 @@ int cpu_exec(CPUState *env1)
|
||||
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)
|
||||
env->cpsr = compute_cpsr();
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
env->cpsr &= ~0xf0000000;
|
||||
#elif defined(TARGET_SPARC)
|
||||
cpu_sparc_dump_state (env, logfile, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
cpu_ppc_dump_state(env, logfile, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* we compute the CPU state. We assume it will not
|
||||
change during the whole generated block. */
|
||||
/* 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->segs[R_CS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
|
||||
flags |= (env->segs[R_SS].flags & DESC_B_MASK)
|
||||
>> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
|
||||
flags |= (((unsigned long)env->segs[R_DS].base |
|
||||
(unsigned long)env->segs[R_ES].base |
|
||||
(unsigned long)env->segs[R_SS].base) != 0) <<
|
||||
GEN_FLAG_ADDSEG_SHIFT;
|
||||
if (!(env->eflags & VM_MASK)) {
|
||||
flags |= (env->segs[R_CS].selector & 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));
|
||||
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];
|
||||
#elif defined(TARGET_SPARC)
|
||||
flags = 0;
|
||||
cs_base = env->npc;
|
||||
pc = (uint8_t *) env->pc;
|
||||
#elif defined(TARGET_PPC)
|
||||
flags = 0;
|
||||
cs_base = 0;
|
||||
pc = (uint8_t *)env->nip;
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@@ -267,7 +267,7 @@ int cpu_exec(CPUState *env1)
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
if (!tb) {
|
||||
/* flush must be done */
|
||||
tb_flush();
|
||||
tb_flush(env);
|
||||
/* cannot fail at this point */
|
||||
tb = tb_alloc((unsigned long)pc);
|
||||
/* don't forget to invalidate previous TB info */
|
||||
@@ -278,17 +278,17 @@ int cpu_exec(CPUState *env1)
|
||||
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 */
|
||||
spin_unlock(&tb_lock);
|
||||
raise_exception(EXCP06_ILLOP);
|
||||
tb_invalidated_flag = 0;
|
||||
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||
if (tb_invalidated_flag) {
|
||||
/* as some TB could have been invalidated because
|
||||
of memory exceptions while generating the code, we
|
||||
must recompute the hash index here */
|
||||
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
|
||||
while (*ptb != NULL)
|
||||
ptb = &(*ptb)->hash_next;
|
||||
T0 = 0;
|
||||
}
|
||||
#endif
|
||||
*ptb = tb;
|
||||
tb->hash_next = NULL;
|
||||
tb_link(tb);
|
||||
@@ -305,12 +305,8 @@ int cpu_exec(CPUState *env1)
|
||||
#ifdef __sparc__
|
||||
T0 = tmp_T0;
|
||||
#endif
|
||||
/* see if we can patch the calling TB. XXX: remove TF test */
|
||||
if (T0 != 0
|
||||
#if defined(TARGET_I386)
|
||||
&& !(env->eflags & TF_MASK)
|
||||
#endif
|
||||
) {
|
||||
/* 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);
|
||||
@@ -336,6 +332,15 @@ int cpu_exec(CPUState *env1)
|
||||
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 {
|
||||
}
|
||||
@@ -372,12 +377,9 @@ 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();
|
||||
#elif defined(TARGET_SPARC)
|
||||
#elif defined(TARGET_PPC)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -391,7 +393,7 @@ int cpu_exec(CPUState *env1)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
|
||||
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
||||
{
|
||||
@@ -399,18 +401,12 @@ 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->segs[seg_reg];
|
||||
/* NOTE: in VM86 mode, limit and flags are never reloaded,
|
||||
so we must load them here */
|
||||
sc->base = (void *)(selector << 4);
|
||||
sc->limit = 0xffff;
|
||||
sc->flags = 0;
|
||||
sc->selector = selector;
|
||||
cpu_x86_load_seg_cache(env, seg_reg, selector,
|
||||
(uint8_t *)(selector << 4), 0xffff, 0);
|
||||
} else {
|
||||
load_seg(seg_reg, selector, 0);
|
||||
load_seg(seg_reg, selector);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
@@ -476,7 +472,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
return 1;
|
||||
}
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
|
||||
ret = cpu_x86_handle_mmu_fault(env, address, is_write,
|
||||
((env->hflags & HF_CPL_MASK) == 3), 0);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
@@ -488,6 +485,68 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
a virtual CPU fault */
|
||||
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, 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)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
/* XXX: do more */
|
||||
return 0;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif defined (TARGET_PPC)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
#if 0
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#endif
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
cpu_restore_state(tb, env, pc);
|
||||
}
|
||||
#if 0
|
||||
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
|
||||
env->eip, env->cr[2], env->error_code);
|
||||
@@ -495,18 +554,10 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
raise_exception_err(EXCP0E_PAGE, env->error_code);
|
||||
raise_exception_err(EXCP_PROGRAM, env->error_code);
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
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
|
||||
@@ -635,6 +686,23 @@ 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 host CPU specific signal handler needed
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include "elf.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
unsigned int disas_num_syms;
|
||||
void *disas_symtab;
|
||||
@@ -19,14 +22,32 @@ buffer_read_memory (memaddr, myaddr, length, info)
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
if (memaddr < info->buffer_vma
|
||||
|| memaddr + length > info->buffer_vma + info->buffer_length)
|
||||
/* Out of bounds. Use EIO because GDB uses it. */
|
||||
return EIO;
|
||||
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
Transfer them to myaddr. */
|
||||
static int
|
||||
target_read_memory (memaddr, myaddr, length, info)
|
||||
bfd_vma memaddr;
|
||||
bfd_byte *myaddr;
|
||||
int length;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < length; i++) {
|
||||
myaddr[i] = ldub_code((void *)((long)memaddr + i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print an error message. We can assume that this is in response to
|
||||
an error return from buffer_read_memory. */
|
||||
void
|
||||
@@ -42,7 +63,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 +78,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. */
|
||||
@@ -103,6 +124,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!is_host) {
|
||||
disasm_info.read_memory_func = target_read_memory;
|
||||
}
|
||||
#endif
|
||||
|
||||
disasm_info.buffer = code;
|
||||
disasm_info.buffer_vma = (unsigned long)code;
|
||||
disasm_info.buffer_length = size;
|
||||
@@ -142,6 +169,10 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(TARGET_PPC)
|
||||
print_insn = print_insn_ppc;
|
||||
#else
|
||||
fprintf(out, "Asm output not supported on this arch\n");
|
||||
return;
|
||||
|
||||
+57
-1
@@ -17,6 +17,9 @@
|
||||
* 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 !defined(__DYNGEN_EXEC_H__)
|
||||
#define __DYNGEN_EXEC_H__
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
@@ -27,6 +30,19 @@ typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32767-1)
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
|
||||
#define INT8_MAX (127)
|
||||
#define INT16_MAX (32767)
|
||||
#define INT32_MAX (2147483647)
|
||||
#define INT64_MAX ((int64_t)(9223372036854775807))
|
||||
#define UINT8_MAX (255)
|
||||
#define UINT16_MAX (65535)
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#define UINT64_MAX ((uint64_t)(18446744073709551615))
|
||||
|
||||
#define bswap32(x) \
|
||||
({ \
|
||||
uint32_t __x = (x); \
|
||||
@@ -54,6 +70,8 @@ extern int printf(const char *, ...);
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
#define AREG3 "r26"
|
||||
/* XXX: suppress this hack */
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define AREG4 "r16"
|
||||
#define AREG5 "r17"
|
||||
#define AREG6 "r18"
|
||||
@@ -62,6 +80,7 @@ extern int printf(const char *, ...);
|
||||
#define AREG9 "r21"
|
||||
#define AREG10 "r22"
|
||||
#define AREG11 "r23"
|
||||
#endif
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#endif
|
||||
@@ -109,6 +128,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 +151,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 +180,32 @@ 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
|
||||
|
||||
#endif /* !defined(__DYNGEN_EXEC_H__) */
|
||||
@@ -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,8 +115,7 @@ typedef uint64_t host_ulong;
|
||||
#define SHT_RELOC SHT_REL
|
||||
#endif
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
#include "bswap.h"
|
||||
|
||||
enum {
|
||||
OUT_GEN_OP,
|
||||
@@ -576,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");
|
||||
}
|
||||
@@ -648,7 +669,7 @@ 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++) {
|
||||
@@ -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;
|
||||
val = *(target_ulong *)(ptr + offset);
|
||||
val = *(unsigned long *)(ptr + offset);
|
||||
#ifdef ELF_USES_RELOCA
|
||||
{
|
||||
int reloc_shndx, nb_relocs1, j;
|
||||
@@ -687,7 +708,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1063,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
|
||||
@@ -1306,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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+112
-27
@@ -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 */
|
||||
@@ -44,30 +61,26 @@ 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 gen_intermediate_code_pc(struct TranslationBlock *tb);
|
||||
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_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 tb_invalidate_page(unsigned long address);
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr);
|
||||
void tlb_flush_page_write(CPUState *env, uint32_t addr);
|
||||
void tlb_flush(CPUState *env);
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
@@ -96,7 +109,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
|
||||
@@ -114,7 +127,7 @@ static inline unsigned int tb_hash_func(unsigned long pc)
|
||||
}
|
||||
|
||||
TranslationBlock *tb_alloc(unsigned long pc);
|
||||
void tb_flush(void);
|
||||
void tb_flush(CPUState *env);
|
||||
void tb_link(TranslationBlock *tb);
|
||||
|
||||
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
@@ -148,18 +161,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");
|
||||
@@ -169,6 +178,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 */
|
||||
@@ -203,20 +224,29 @@ 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;\
|
||||
@@ -225,10 +255,28 @@ 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)
|
||||
{
|
||||
@@ -320,11 +368,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
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
@@ -356,3 +416,28 @@ static inline int spin_trylock(spinlock_t *lock)
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
extern int tb_invalidated_flag;
|
||||
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
|
||||
#define ACCESS_TYPE 3
|
||||
#define MEMSUFFIX _code
|
||||
#define env cpu_single_env
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
#undef env
|
||||
|
||||
#endif
|
||||
@@ -27,13 +27,8 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DEBUG_TB_INVALIDATE
|
||||
//#define DEBUG_FLUSH
|
||||
@@ -67,7 +62,7 @@ typedef struct PageDesc {
|
||||
#define L1_SIZE (1 << L1_BITS)
|
||||
#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;
|
||||
@@ -76,6 +71,17 @@ 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;
|
||||
|
||||
/* log support */
|
||||
char *logfilename = "/tmp/qemu.log";
|
||||
FILE *logfile;
|
||||
int loglevel;
|
||||
|
||||
static void page_init(void)
|
||||
{
|
||||
/* NOTE: we can always suppose that host_page_size >=
|
||||
@@ -201,6 +207,7 @@ void cpu_exec_init(void)
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
page_init();
|
||||
io_mem_init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,15 +228,19 @@ static void page_flush_tb(void)
|
||||
|
||||
/* flush all the translation blocks */
|
||||
/* XXX: tb_flush is currently not thread safe */
|
||||
void tb_flush(void)
|
||||
void tb_flush(CPUState *env)
|
||||
{
|
||||
int i;
|
||||
#ifdef DEBUG_FLUSH
|
||||
#if defined(DEBUG_FLUSH)
|
||||
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
|
||||
code_gen_ptr - code_gen_buffer,
|
||||
nb_tbs,
|
||||
(code_gen_ptr - code_gen_buffer) / nb_tbs);
|
||||
nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
|
||||
#endif
|
||||
/* must reset current TB so that interrupts cannot modify the
|
||||
links while we are modifying them */
|
||||
env->current_tb = NULL;
|
||||
|
||||
nb_tbs = 0;
|
||||
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
|
||||
tb_hash[i] = NULL;
|
||||
@@ -354,6 +365,8 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity)
|
||||
unsigned int h, n1;
|
||||
TranslationBlock *tb1, *tb2;
|
||||
|
||||
tb_invalidated_flag = 1;
|
||||
|
||||
/* remove the TB from the hash list */
|
||||
h = tb_hash_func(tb->pc);
|
||||
tb_remove(&tb_hash[h], tb,
|
||||
@@ -392,7 +405,7 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity)
|
||||
}
|
||||
|
||||
/* invalidate all TBs which intersect with the target page starting at addr */
|
||||
static void tb_invalidate_page(unsigned long address)
|
||||
void tb_invalidate_page(unsigned long address)
|
||||
{
|
||||
TranslationBlock *tb_next, *tb;
|
||||
unsigned int page_index;
|
||||
@@ -436,16 +449,20 @@ static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
|
||||
prot = 0;
|
||||
for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
|
||||
prot |= page_get_flags(addr);
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
#endif
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* suppress soft TLB */
|
||||
/* XXX: must flush on all processor with same address space */
|
||||
tlb_flush_page_write(cpu_single_env, host_start);
|
||||
#endif
|
||||
#ifdef DEBUG_TB_INVALIDATE
|
||||
printf("protecting code page: 0x%08lx\n",
|
||||
host_start);
|
||||
#endif
|
||||
p->flags &= ~PAGE_WRITE;
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_page_check();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,6 +492,9 @@ void tb_link(TranslationBlock *tb)
|
||||
if (page_index2 != page_index1) {
|
||||
tb_alloc_page(tb, page_index2);
|
||||
}
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_page_check();
|
||||
#endif
|
||||
tb->jmp_first = (TranslationBlock *)((long)tb | 2);
|
||||
tb->jmp_next[0] = NULL;
|
||||
tb->jmp_next[1] = NULL;
|
||||
@@ -509,20 +529,23 @@ int page_unprotect(unsigned long address)
|
||||
/* if the page was really writable, then we change its
|
||||
protection back to writable */
|
||||
if (prot & PAGE_WRITE_ORG) {
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) | PAGE_WRITE);
|
||||
pindex = (address - host_start) >> TARGET_PAGE_BITS;
|
||||
p1[pindex].flags |= PAGE_WRITE;
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
tb_invalidate_page(address);
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_invalidate_check(address);
|
||||
if (!(p1[pindex].flags & PAGE_WRITE)) {
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
mprotect((void *)host_start, host_page_size,
|
||||
(prot & PAGE_BITS) | PAGE_WRITE);
|
||||
#endif
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
p1[pindex].flags |= PAGE_WRITE;
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
tb_invalidate_page(address);
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_invalidate_check(address);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call this function when system calls directly modify a memory area */
|
||||
@@ -606,7 +629,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
|
||||
/* 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 */
|
||||
/* suppress jumps in the tb on which we could have jumped */
|
||||
tb_reset_jump_recursive(tb_next);
|
||||
}
|
||||
}
|
||||
@@ -617,7 +640,82 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
|
||||
tb_reset_jump_recursive2(tb, 1);
|
||||
}
|
||||
|
||||
/* mask must never be zero */
|
||||
/* 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(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable or disable low levels log */
|
||||
void cpu_set_log(int log_flags)
|
||||
{
|
||||
loglevel = log_flags;
|
||||
if (loglevel && !logfile) {
|
||||
logfile = fopen(logfilename, "w");
|
||||
if (!logfile) {
|
||||
perror(logfilename);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_set_log_filename(const char *filename)
|
||||
{
|
||||
logfilename = strdup(filename);
|
||||
}
|
||||
|
||||
/* mask must never be zero, except for A20 change call */
|
||||
void cpu_interrupt(CPUState *env, int mask)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
@@ -647,17 +745,22 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* unmap all maped pages and flush all associated code */
|
||||
void page_unmap(void)
|
||||
static void page_unmap(CPUState *env)
|
||||
{
|
||||
PageDesc *p, *pmap;
|
||||
unsigned long addr;
|
||||
int i, j, ret, j1;
|
||||
PageDesc *pmap;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
pmap = l1_map[i];
|
||||
if (pmap) {
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
PageDesc *p;
|
||||
unsigned long addr;
|
||||
int j, ret, j1;
|
||||
|
||||
p = pmap;
|
||||
for(j = 0;j < L2_SIZE;) {
|
||||
if (p->flags & PAGE_VALID) {
|
||||
@@ -680,10 +783,213 @@ void page_unmap(void)
|
||||
j++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(pmap);
|
||||
l1_map[i] = NULL;
|
||||
}
|
||||
}
|
||||
tb_flush();
|
||||
tb_flush(env);
|
||||
}
|
||||
|
||||
void tlb_flush(CPUState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* must reset current TB so that interrupts cannot modify the
|
||||
links while we are modifying them */
|
||||
env->current_tb = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
/* XXX: avoid flushing the TBs */
|
||||
page_unmap(env);
|
||||
}
|
||||
|
||||
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
|
||||
{
|
||||
if (addr == (tlb_entry->address &
|
||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)))
|
||||
tlb_entry->address = -1;
|
||||
}
|
||||
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr)
|
||||
{
|
||||
int i, flags;
|
||||
|
||||
/* must reset current TB so that interrupts cannot modify the
|
||||
links while we are modifying them */
|
||||
env->current_tb = NULL;
|
||||
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
tlb_flush_entry(&env->tlb_read[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_write[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_read[1][i], addr);
|
||||
tlb_flush_entry(&env->tlb_write[1][i], addr);
|
||||
|
||||
flags = page_get_flags(addr);
|
||||
if (flags & PAGE_VALID) {
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
munmap((void *)addr, TARGET_PAGE_SIZE);
|
||||
#endif
|
||||
page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* make all write to page 'addr' trigger a TLB exception to detect
|
||||
self modifying code */
|
||||
void tlb_flush_page_write(CPUState *env, uint32_t addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
tlb_flush_entry(&env->tlb_write[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_write[1][i], addr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void tlb_flush(CPUState *env)
|
||||
{
|
||||
}
|
||||
|
||||
void tlb_flush_page(CPUState *env, uint32_t addr)
|
||||
{
|
||||
}
|
||||
|
||||
void tlb_flush_page_write(CPUState *env, uint32_t addr)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _cmmu
|
||||
#define GETPC() NULL
|
||||
#define env cpu_single_env
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#undef env
|
||||
|
||||
#endif
|
||||
@@ -28,14 +28,9 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "cpu.h"
|
||||
#include "thunk.h"
|
||||
#include "exec.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
@@ -253,6 +248,23 @@ static int put_packet(char *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* better than nothing for SOFTMMU : we use physical addresses */
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
|
||||
if (addr >= phys_ram_size ||
|
||||
((int64_t)addr + len > phys_ram_size))
|
||||
return -1;
|
||||
ptr = phys_ram_base + addr;
|
||||
if (is_write)
|
||||
memcpy(ptr, buf, len);
|
||||
else
|
||||
memcpy(buf, ptr, len);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
{
|
||||
int l, flags;
|
||||
@@ -281,13 +293,91 @@ static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
static void to_le32(uint8_t *p, int v)
|
||||
{
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
p[2] = v >> 16;
|
||||
p[3] = v >> 24;
|
||||
}
|
||||
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
int i, fpus;
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
to_le32(mem_buf + i * 4, env->regs[i]);
|
||||
}
|
||||
to_le32(mem_buf + 8 * 4, env->eip);
|
||||
to_le32(mem_buf + 9 * 4, env->eflags);
|
||||
to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
|
||||
to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
|
||||
to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
|
||||
to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
|
||||
to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
|
||||
to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
|
||||
/* XXX: convert floats */
|
||||
for(i = 0; i < 8; i++) {
|
||||
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
|
||||
}
|
||||
to_le32(mem_buf + 36 * 4, env->fpuc);
|
||||
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
|
||||
to_le32(mem_buf + 37 * 4, fpus);
|
||||
to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
|
||||
to_le32(mem_buf + 39 * 4, 0); /* fiseg */
|
||||
to_le32(mem_buf + 40 * 4, 0); /* fioff */
|
||||
to_le32(mem_buf + 41 * 4, 0); /* foseg */
|
||||
to_le32(mem_buf + 42 * 4, 0); /* fooff */
|
||||
to_le32(mem_buf + 43 * 4, 0); /* fop */
|
||||
return 44 * 4;
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
env->regs[i] = tswapl(registers[i]);
|
||||
}
|
||||
env->eip = registers[8];
|
||||
env->eflags = registers[9];
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#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
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* port = 0 means default port */
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
|
||||
{
|
||||
CPUState *env;
|
||||
const char *p;
|
||||
int ret, ch, nb_regs, i;
|
||||
int ret, ch, reg_size, type;
|
||||
char buf[4096];
|
||||
uint8_t mem_buf[2000];
|
||||
uint32_t *registers;
|
||||
@@ -309,51 +399,51 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'c':
|
||||
main_loop(opaque);
|
||||
snprintf(buf, sizeof(buf), "S%02x", 0);
|
||||
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);
|
||||
reg_size = cpu_gdb_read_registers(env, mem_buf);
|
||||
memtohex(buf, mem_buf, reg_size);
|
||||
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
|
||||
len = strlen(p) / 2;
|
||||
hextomem((uint8_t *)registers, p, len);
|
||||
cpu_gdb_write_registers(env, mem_buf, len);
|
||||
put_packet("OK");
|
||||
break;
|
||||
case 'm':
|
||||
@@ -379,7 +469,60 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
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;
|
||||
case 'Q':
|
||||
if (!strncmp(p, "Tinit", 5)) {
|
||||
/* init traces */
|
||||
put_packet("OK");
|
||||
} else if (!strncmp(p, "TStart", 6)) {
|
||||
/* start log (gdb 'tstart' command) */
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
tb_flush(env);
|
||||
cpu_set_log(CPU_LOG_ALL);
|
||||
put_packet("OK");
|
||||
} else if (!strncmp(p, "TStop", 5)) {
|
||||
/* stop log (gdb 'tstop' command) */
|
||||
cpu_set_log(0);
|
||||
put_packet("OK");
|
||||
} else {
|
||||
goto unknown_command;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
unknown_command:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(buf);
|
||||
|
||||
-1471
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* QEMU DMA emulation
|
||||
*
|
||||
* Copyright (c) 2003 Vassili Karpov (malc)
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "vl.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||
#ifdef DEBUG_DMA
|
||||
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
|
||||
#else
|
||||
#define lwarn(...)
|
||||
#define linfo(...)
|
||||
#define ldebug(...)
|
||||
#endif
|
||||
|
||||
#define MEM_REAL(addr) ((addr)+(uint32_t)(phys_ram_base))
|
||||
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
|
||||
|
||||
struct dma_regs {
|
||||
int now[2];
|
||||
uint16_t base[2];
|
||||
uint8_t mode;
|
||||
uint8_t page;
|
||||
uint8_t dack;
|
||||
uint8_t eop;
|
||||
DMA_read_handler read_handler;
|
||||
DMA_misc_handler misc_handler;
|
||||
};
|
||||
|
||||
#define ADDR 0
|
||||
#define COUNT 1
|
||||
|
||||
static struct dma_cont {
|
||||
uint8_t status;
|
||||
uint8_t command;
|
||||
uint8_t mask;
|
||||
uint8_t flip_flop;
|
||||
struct dma_regs regs[4];
|
||||
} dma_controllers[2];
|
||||
|
||||
enum {
|
||||
CMD_MEMORY_TO_MEMORY = 0x01,
|
||||
CMD_FIXED_ADDRESS = 0x02,
|
||||
CMD_BLOCK_CONTROLLER = 0x04,
|
||||
CMD_COMPRESSED_TIME = 0x08,
|
||||
CMD_CYCLIC_PRIORITY = 0x10,
|
||||
CMD_EXTENDED_WRITE = 0x20,
|
||||
CMD_LOW_DREQ = 0x40,
|
||||
CMD_LOW_DACK = 0x80,
|
||||
CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
|
||||
| CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
|
||||
| CMD_LOW_DREQ | CMD_LOW_DACK
|
||||
|
||||
};
|
||||
|
||||
static void write_page (struct CPUX86State *env, uint32_t nport, uint32_t data)
|
||||
{
|
||||
int ichan;
|
||||
int ncont;
|
||||
static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
|
||||
|
||||
ncont = nport > 0x87;
|
||||
ichan = channels[nport - 0x80 - (ncont << 3)];
|
||||
|
||||
if (-1 == ichan) {
|
||||
log ("invalid channel %#x %#x\n", nport, data);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_controllers[ncont].regs[ichan].page = data;
|
||||
}
|
||||
|
||||
static void init_chan (int ncont, int ichan)
|
||||
{
|
||||
struct dma_regs *r;
|
||||
|
||||
r = dma_controllers[ncont].regs + ichan;
|
||||
r->now[ADDR] = r->base[0] << ncont;
|
||||
r->now[COUNT] = 0;
|
||||
}
|
||||
|
||||
static inline int getff (int ncont)
|
||||
{
|
||||
int ff;
|
||||
|
||||
ff = dma_controllers[ncont].flip_flop;
|
||||
dma_controllers[ncont].flip_flop = !ff;
|
||||
return ff;
|
||||
}
|
||||
|
||||
static uint32_t read_chan (struct CPUX86State *env, uint32_t nport)
|
||||
{
|
||||
int ff;
|
||||
int ncont, ichan, nreg;
|
||||
struct dma_regs *r;
|
||||
int val;
|
||||
|
||||
ncont = nport > 7;
|
||||
ichan = (nport >> (1 + ncont)) & 3;
|
||||
nreg = (nport >> ncont) & 1;
|
||||
r = dma_controllers[ncont].regs + ichan;
|
||||
|
||||
ff = getff (ncont);
|
||||
|
||||
if (nreg)
|
||||
val = (r->base[COUNT] << ncont) - r->now[COUNT];
|
||||
else
|
||||
val = r->now[ADDR] + r->now[COUNT];
|
||||
|
||||
return (val >> (ncont + (ff << 3))) & 0xff;
|
||||
}
|
||||
|
||||
static void write_chan (uint32_t nport, int size, uint32_t data)
|
||||
{
|
||||
int ncont, ichan, nreg;
|
||||
struct dma_regs *r;
|
||||
|
||||
ncont = nport > 7;
|
||||
ichan = (nport >> (1 + ncont)) & 3;
|
||||
nreg = (nport >> ncont) & 1;
|
||||
r = dma_controllers[ncont].regs + ichan;
|
||||
|
||||
if (2 == size) {
|
||||
r->base[nreg] = data;
|
||||
init_chan (ncont, ichan);
|
||||
}
|
||||
else {
|
||||
if (getff (ncont)) {
|
||||
r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
|
||||
init_chan (ncont, ichan);
|
||||
}
|
||||
else {
|
||||
r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void write_chanb (struct CPUX86State *env, uint32_t nport, uint32_t data)
|
||||
{
|
||||
write_chan (nport, 1, data);
|
||||
}
|
||||
|
||||
static void write_chanw (struct CPUX86State *env, uint32_t nport, uint32_t data)
|
||||
{
|
||||
write_chan (nport, 2, data);
|
||||
}
|
||||
|
||||
static void write_cont (struct CPUX86State *env, uint32_t nport, uint32_t data)
|
||||
{
|
||||
int iport, ichan, ncont;
|
||||
struct dma_cont *d;
|
||||
|
||||
ncont = nport > 0xf;
|
||||
ichan = -1;
|
||||
|
||||
d = dma_controllers + ncont;
|
||||
if (ncont) {
|
||||
iport = ((nport - 0xd0) >> 1) + 8;
|
||||
}
|
||||
else {
|
||||
iport = nport;
|
||||
}
|
||||
|
||||
switch (iport) {
|
||||
case 8: /* command */
|
||||
if (data && (data | CMD_NOT_SUPPORTED)) {
|
||||
log ("command %#x not supported\n", data);
|
||||
goto error;
|
||||
}
|
||||
d->command = data;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
ichan = data & 3;
|
||||
if (data & 4) {
|
||||
d->status |= 1 << (ichan + 4);
|
||||
}
|
||||
else {
|
||||
d->status &= ~(1 << (ichan + 4));
|
||||
}
|
||||
d->status &= ~(1 << ichan);
|
||||
break;
|
||||
|
||||
case 0xa: /* single mask */
|
||||
if (data & 4)
|
||||
d->mask |= 1 << (data & 3);
|
||||
else
|
||||
d->mask &= ~(1 << (data & 3));
|
||||
break;
|
||||
|
||||
case 0xb: /* mode */
|
||||
{
|
||||
#ifdef DMA_DEBUG
|
||||
int op;
|
||||
int ai;
|
||||
int dir;
|
||||
int opmode;
|
||||
|
||||
ichan = val & 3;
|
||||
op = (val >> 2) & 3;
|
||||
ai = (val >> 4) & 1;
|
||||
dir = (val >> 5) & 1;
|
||||
opmode = (val >> 6) & 3;
|
||||
|
||||
linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
|
||||
ichan, op, ai, dir, opmode);
|
||||
#endif
|
||||
|
||||
d->regs[ichan].mode = data;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc: /* clear flip flop */
|
||||
d->flip_flop = 0;
|
||||
break;
|
||||
|
||||
case 0xd: /* reset */
|
||||
d->flip_flop = 0;
|
||||
d->mask = ~0;
|
||||
d->status = 0;
|
||||
d->command = 0;
|
||||
break;
|
||||
|
||||
case 0xe: /* clear mask for all channels */
|
||||
d->mask = 0;
|
||||
break;
|
||||
|
||||
case 0xf: /* write mask for all channels */
|
||||
d->mask = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
log ("dma: unknown iport %#x\n", iport);
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef DMA_DEBUG
|
||||
if (0xc != iport) {
|
||||
linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n",
|
||||
nport, d != dma_controllers, ichan, data);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
|
||||
error:
|
||||
abort ();
|
||||
}
|
||||
|
||||
int DMA_get_channel_mode (int nchan)
|
||||
{
|
||||
return dma_controllers[nchan > 3].regs[nchan & 3].mode;
|
||||
}
|
||||
|
||||
void DMA_hold_DREQ (int nchan)
|
||||
{
|
||||
int ncont, ichan;
|
||||
|
||||
ncont = nchan > 3;
|
||||
ichan = nchan & 3;
|
||||
linfo ("held cont=%d chan=%d\n", ncont, ichan);
|
||||
dma_controllers[ncont].status |= 1 << (ichan + 4);
|
||||
}
|
||||
|
||||
void DMA_release_DREQ (int nchan)
|
||||
{
|
||||
int ncont, ichan;
|
||||
|
||||
ncont = nchan > 3;
|
||||
ichan = nchan & 3;
|
||||
linfo ("released cont=%d chan=%d\n", ncont, ichan);
|
||||
dma_controllers[ncont].status &= ~(1 << (ichan + 4));
|
||||
}
|
||||
|
||||
static void channel_run (int ncont, int ichan)
|
||||
{
|
||||
struct dma_regs *r;
|
||||
int n;
|
||||
int irq;
|
||||
uint32_t addr;
|
||||
/* int ai, dir; */
|
||||
|
||||
r = dma_controllers[ncont].regs + ichan;
|
||||
/* ai = r->mode & 16; */
|
||||
/* dir = r->mode & 32 ? -1 : 1; */
|
||||
|
||||
addr = MEM_REAL ((r->page << 16) | r->now[ADDR]);
|
||||
|
||||
irq = -1;
|
||||
n = r->read_handler (addr, (r->base[COUNT] << ncont) + (1 << ncont), &irq);
|
||||
r->now[COUNT] = n;
|
||||
|
||||
ldebug ("dma_pos %d irq %d size %d\n",
|
||||
n, irq, (r->base[1] << ncont) + (1 << ncont));
|
||||
|
||||
if (-1 != irq) {
|
||||
pic_set_irq (irq, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void DMA_run (void)
|
||||
{
|
||||
static int in_dma;
|
||||
struct dma_cont *d;
|
||||
int icont, ichan;
|
||||
|
||||
if (in_dma) {
|
||||
log ("attempt to re-enter dma\n");
|
||||
return;
|
||||
}
|
||||
|
||||
in_dma = 1;
|
||||
d = dma_controllers;
|
||||
|
||||
for (icont = 0; icont < 2; icont++, d++) {
|
||||
for (ichan = 0; ichan < 4; ichan++) {
|
||||
int mask;
|
||||
|
||||
mask = 1 << ichan;
|
||||
|
||||
if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
|
||||
channel_run (icont, ichan);
|
||||
}
|
||||
}
|
||||
in_dma = 0;
|
||||
}
|
||||
|
||||
void DMA_register_channel (int nchan,
|
||||
DMA_read_handler read_handler,
|
||||
DMA_misc_handler misc_handler)
|
||||
{
|
||||
struct dma_regs *r;
|
||||
int ichan, ncont;
|
||||
|
||||
ncont = nchan > 3;
|
||||
ichan = nchan & 3;
|
||||
|
||||
r = dma_controllers[ncont].regs + ichan;
|
||||
r->read_handler = read_handler;
|
||||
r->misc_handler = misc_handler;
|
||||
}
|
||||
|
||||
void DMA_init (void)
|
||||
{
|
||||
int i;
|
||||
int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
register_ioport_write (i, 1, write_chanb, 1);
|
||||
register_ioport_write (i, 1, write_chanw, 2);
|
||||
|
||||
register_ioport_write (0xc0 + (i << 1), 1, write_chanb, 1);
|
||||
register_ioport_write (0xc0 + (i << 1), 1, write_chanw, 2);
|
||||
|
||||
register_ioport_read (i, 1, read_chan, 1);
|
||||
register_ioport_read (0xc0 + (i << 1), 1, read_chan, 2);
|
||||
}
|
||||
|
||||
for (i = 0; i < LENOFA (page_port_list); i++) {
|
||||
register_ioport_write (page_port_list[i] + 0x80, 1, write_page, 1);
|
||||
register_ioport_write (page_port_list[i] + 0x88, 1, write_page, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
register_ioport_write (i + 8, 1, write_cont, 1);
|
||||
register_ioport_write (0xd0 + (i << 1), 1, write_cont, 1);
|
||||
}
|
||||
|
||||
write_cont (NULL, 0xd, 0);
|
||||
write_cont (NULL, 0xdd, 0);
|
||||
}
|
||||
@@ -0,0 +1,723 @@
|
||||
/*
|
||||
* QEMU Soundblaster 16 emulation
|
||||
*
|
||||
* Copyright (c) 2003 Vassili Karpov (malc)
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define MIN(a, b) ((a)>(b)?(b):(a))
|
||||
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
|
||||
|
||||
#define DEREF(x) (void)x
|
||||
#define log(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||
#define Fail(...) do { \
|
||||
fprintf (stderr, "sb16: " __VA_ARGS__); \
|
||||
abort (); \
|
||||
} while (0)
|
||||
|
||||
#ifdef DEBUG_SB16
|
||||
#define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||
#define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||
#define ldebug(...) fprintf (stderr, "sb16: " __VA_ARGS__)
|
||||
#else
|
||||
#define lwarn(...)
|
||||
#define linfo(...)
|
||||
#define ldebug(...)
|
||||
#endif
|
||||
|
||||
#define IO_READ_PROTO(name) \
|
||||
uint32_t name (struct CPUX86State *env, uint32_t nport)
|
||||
#define IO_WRITE_PROTO(name) \
|
||||
void name (struct CPUX86State *env, uint32_t nport, uint32_t val)
|
||||
|
||||
static struct {
|
||||
int ver_lo;
|
||||
int ver_hi;
|
||||
int irq;
|
||||
int dma;
|
||||
int hdma;
|
||||
int port;
|
||||
int mix_block;
|
||||
} sb = {4, 5, 5, 1, 5, 0x220, -1};
|
||||
|
||||
static int mix_block, noirq;
|
||||
|
||||
static struct mixer {
|
||||
int nreg;
|
||||
uint8_t regs[0x83];
|
||||
} mixer;
|
||||
|
||||
static struct dsp {
|
||||
int in_index;
|
||||
int out_data_len;
|
||||
int fmt_stereo;
|
||||
int fmt_signed;
|
||||
int fmt_bits;
|
||||
int dma_auto;
|
||||
int dma_buffer_size;
|
||||
int fifo;
|
||||
int freq;
|
||||
int time_const;
|
||||
int speaker;
|
||||
int needed_bytes;
|
||||
int cmd;
|
||||
int dma_pos;
|
||||
int use_hdma;
|
||||
|
||||
int v2x6;
|
||||
|
||||
uint8_t in_data[10];
|
||||
uint8_t out_data[10];
|
||||
|
||||
int left_till_irq;
|
||||
} dsp;
|
||||
|
||||
#define nocmd ~0
|
||||
|
||||
static void log_dsp (const char *cap)
|
||||
{
|
||||
DEREF (cap);
|
||||
|
||||
linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n",
|
||||
dsp.fmt_stereo ? 'S' : 'M',
|
||||
dsp.fmt_signed ? 'S' : 'U',
|
||||
dsp.fmt_bits,
|
||||
dsp.dma_auto ? 'a' : 's',
|
||||
dsp.dma_buffer_size,
|
||||
dsp.dma_pos,
|
||||
dsp.freq,
|
||||
dsp.time_const,
|
||||
dsp.speaker);
|
||||
}
|
||||
|
||||
static void control (int hold)
|
||||
{
|
||||
linfo ("%d high %d\n", hold, dsp.use_hdma);
|
||||
if (hold) {
|
||||
if (dsp.use_hdma)
|
||||
DMA_hold_DREQ (sb.hdma);
|
||||
else
|
||||
DMA_hold_DREQ (sb.dma);
|
||||
}
|
||||
else {
|
||||
if (dsp.use_hdma)
|
||||
DMA_release_DREQ (sb.hdma);
|
||||
else
|
||||
DMA_release_DREQ (sb.dma);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len)
|
||||
{
|
||||
int bps;
|
||||
audfmt_e fmt;
|
||||
|
||||
dsp.use_hdma = cmd < 0xc0;
|
||||
dsp.fifo = (cmd >> 1) & 1;
|
||||
dsp.dma_auto = (cmd >> 2) & 1;
|
||||
|
||||
switch (cmd >> 4) {
|
||||
case 11:
|
||||
dsp.fmt_bits = 16;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
dsp.fmt_bits = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
dsp.fmt_signed = (d0 >> 4) & 1;
|
||||
dsp.fmt_stereo = (d0 >> 5) & 1;
|
||||
|
||||
if (-1 != dsp.time_const) {
|
||||
int tmp;
|
||||
|
||||
tmp = 256 - dsp.time_const;
|
||||
dsp.freq = (1000000 + (tmp / 2)) / tmp;
|
||||
}
|
||||
bps = 1 << (16 == dsp.fmt_bits);
|
||||
|
||||
if (-1 != dma_len)
|
||||
dsp.dma_buffer_size = (dma_len + 1) * bps;
|
||||
|
||||
linfo ("frequency %d, stereo %d, signed %d, bits %d, size %d, auto %d\n",
|
||||
dsp.freq, dsp.fmt_stereo, dsp.fmt_signed, dsp.fmt_bits,
|
||||
dsp.dma_buffer_size, dsp.dma_auto);
|
||||
|
||||
if (16 == dsp.fmt_bits) {
|
||||
if (dsp.fmt_signed) {
|
||||
fmt = AUD_FMT_S16;
|
||||
}
|
||||
else {
|
||||
fmt = AUD_FMT_U16;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dsp.fmt_signed) {
|
||||
fmt = AUD_FMT_S8;
|
||||
}
|
||||
else {
|
||||
fmt = AUD_FMT_U8;
|
||||
}
|
||||
}
|
||||
|
||||
dsp.dma_pos = 0;
|
||||
dsp.left_till_irq = dsp.dma_buffer_size;
|
||||
|
||||
if (sb.mix_block) {
|
||||
mix_block = sb.mix_block;
|
||||
}
|
||||
else {
|
||||
int align;
|
||||
|
||||
align = bps << dsp.fmt_stereo;
|
||||
mix_block = ((dsp.freq * align) / 100) & ~(align - 1);
|
||||
}
|
||||
|
||||
AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt);
|
||||
control (1);
|
||||
dsp.speaker = 1;
|
||||
}
|
||||
|
||||
static void command (uint8_t cmd)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = (char *)-1;
|
||||
|
||||
linfo ("%#x\n", cmd);
|
||||
|
||||
if (cmd > 0xaf && cmd < 0xd0) {
|
||||
if (cmd & 8)
|
||||
goto error;
|
||||
|
||||
switch (cmd >> 4) {
|
||||
case 11:
|
||||
case 12:
|
||||
break;
|
||||
default:
|
||||
msg = "wrong bits";
|
||||
goto error;
|
||||
}
|
||||
dsp.needed_bytes = 3;
|
||||
}
|
||||
else {
|
||||
switch (cmd) {
|
||||
case 0x10:
|
||||
dsp.needed_bytes = 1;
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
dsp.needed_bytes = 2;
|
||||
dsp.dma_buffer_size = 0;
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
dsp.out_data[dsp.out_data_len++] = 0xff;
|
||||
break;
|
||||
|
||||
case 0x35:
|
||||
lwarn ("MIDI commands not implemented\n");
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
dsp.freq = -1;
|
||||
dsp.time_const = -1;
|
||||
dsp.needed_bytes = 1;
|
||||
break;
|
||||
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
dsp.freq = -1;
|
||||
dsp.time_const = -1;
|
||||
dsp.needed_bytes = 2;
|
||||
break;
|
||||
|
||||
case 0x47: /* Continue Auto-Initialize DMA 16bit */
|
||||
break;
|
||||
|
||||
case 0x48:
|
||||
dsp.needed_bytes = 2;
|
||||
break;
|
||||
|
||||
case 0x27: /* ????????? */
|
||||
case 0x4e:
|
||||
return;
|
||||
|
||||
case 0x80:
|
||||
cmd = nocmd;
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
{
|
||||
uint8_t d0;
|
||||
|
||||
d0 = 4;
|
||||
if (dsp.fmt_signed) d0 |= 16;
|
||||
if (dsp.fmt_stereo) d0 |= 32;
|
||||
dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1);
|
||||
cmd = nocmd;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd0: /* XXX */
|
||||
control (0);
|
||||
return;
|
||||
|
||||
case 0xd1:
|
||||
dsp.speaker = 1;
|
||||
break;
|
||||
|
||||
case 0xd3:
|
||||
dsp.speaker = 0;
|
||||
return;
|
||||
|
||||
case 0xd4:
|
||||
control (1);
|
||||
break;
|
||||
|
||||
case 0xd5:
|
||||
control (0);
|
||||
break;
|
||||
|
||||
case 0xd6:
|
||||
control (1);
|
||||
break;
|
||||
|
||||
case 0xd9:
|
||||
control (0);
|
||||
dsp.dma_auto = 0;
|
||||
return;
|
||||
|
||||
case 0xda:
|
||||
control (0);
|
||||
dsp.dma_auto = 0;
|
||||
break;
|
||||
|
||||
case 0xe0:
|
||||
dsp.needed_bytes = 1;
|
||||
break;
|
||||
|
||||
case 0xe1:
|
||||
dsp.out_data[dsp.out_data_len++] = sb.ver_lo;
|
||||
dsp.out_data[dsp.out_data_len++] = sb.ver_hi;
|
||||
return;
|
||||
|
||||
case 0xf2:
|
||||
dsp.out_data[dsp.out_data_len++] = 0xaa;
|
||||
mixer.regs[0x82] |= 1;
|
||||
pic_set_irq (sb.irq, 1);
|
||||
return;
|
||||
|
||||
default:
|
||||
msg = "is unknown";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
dsp.cmd = cmd;
|
||||
return;
|
||||
|
||||
error:
|
||||
Fail ("%#x %s", cmd, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
static void complete (void)
|
||||
{
|
||||
linfo ("complete command %#x, in_index %d, needed_bytes %d\n",
|
||||
dsp.cmd, dsp.in_index, dsp.needed_bytes);
|
||||
|
||||
if (dsp.cmd > 0xaf && dsp.cmd < 0xd0) {
|
||||
int d0, d1, d2;
|
||||
|
||||
d0 = dsp.in_data[0];
|
||||
d1 = dsp.in_data[1];
|
||||
d2 = dsp.in_data[2];
|
||||
|
||||
ldebug ("d0 = %d, d1 = %d, d2 = %d\n",
|
||||
d0, d1, d2);
|
||||
dma_cmd (dsp.cmd, d0, d1 + (d2 << 8));
|
||||
}
|
||||
else {
|
||||
switch (dsp.cmd) {
|
||||
|
||||
case 0x10:
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
{
|
||||
int d0, d1;
|
||||
int save_left;
|
||||
int save_pos;
|
||||
|
||||
d0 = dsp.in_data[0];
|
||||
d1 = dsp.in_data[1];
|
||||
|
||||
save_left = dsp.left_till_irq;
|
||||
save_pos = dsp.dma_pos;
|
||||
dma_cmd (0xc0, 0, d0 + (d1 << 8));
|
||||
dsp.left_till_irq = save_left;
|
||||
dsp.dma_pos = save_pos;
|
||||
|
||||
linfo ("set buffer size data[%d, %d] %d pos %d\n",
|
||||
d0, d1, dsp.dma_buffer_size, dsp.dma_pos);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x40:
|
||||
dsp.time_const = dsp.in_data[0];
|
||||
linfo ("set time const %d\n", dsp.time_const);
|
||||
break;
|
||||
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
dsp.freq = dsp.in_data[1] + (dsp.in_data[0] << 8);
|
||||
linfo ("set freq %#x, %#x = %d\n",
|
||||
dsp.in_data[1], dsp.in_data[0], dsp.freq);
|
||||
break;
|
||||
|
||||
case 0x48:
|
||||
dsp.dma_buffer_size = dsp.in_data[1] + (dsp.in_data[0] << 8);
|
||||
linfo ("set dma len %#x, %#x = %d\n",
|
||||
dsp.in_data[1], dsp.in_data[0], dsp.dma_buffer_size);
|
||||
break;
|
||||
|
||||
case 0xe0:
|
||||
dsp.out_data_len = 1;
|
||||
linfo ("data = %#x\n", dsp.in_data[0]);
|
||||
dsp.out_data[0] = dsp.in_data[0] ^ 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
dsp.cmd = -1;
|
||||
return;
|
||||
|
||||
error:
|
||||
Fail ("unrecognized command %#x", dsp.cmd);
|
||||
}
|
||||
|
||||
static IO_WRITE_PROTO (dsp_write)
|
||||
{
|
||||
int iport;
|
||||
|
||||
iport = nport - sb.port;
|
||||
|
||||
switch (iport) {
|
||||
case 0x6:
|
||||
if (0 == val)
|
||||
dsp.v2x6 = 0;
|
||||
else if ((1 == val) && (0 == dsp.v2x6)) {
|
||||
dsp.v2x6 = 1;
|
||||
dsp.out_data[dsp.out_data_len++] = 0xaa;
|
||||
}
|
||||
else
|
||||
dsp.v2x6 = ~0;
|
||||
break;
|
||||
|
||||
case 0xc: /* write data or command | write status */
|
||||
if (0 == dsp.needed_bytes) {
|
||||
command (val);
|
||||
if (0 == dsp.needed_bytes) {
|
||||
log_dsp (__func__);
|
||||
}
|
||||
}
|
||||
else {
|
||||
dsp.in_data[dsp.in_index++] = val;
|
||||
if (dsp.in_index == dsp.needed_bytes) {
|
||||
dsp.needed_bytes = 0;
|
||||
dsp.in_index = 0;
|
||||
complete ();
|
||||
log_dsp (__func__);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Fail ("(nport=%#x, val=%#x)", nport, val);
|
||||
}
|
||||
}
|
||||
|
||||
static IO_READ_PROTO (dsp_read)
|
||||
{
|
||||
char *msg;
|
||||
int iport, retval;
|
||||
|
||||
msg = (char *) -1;
|
||||
iport = nport - sb.port;
|
||||
|
||||
switch (iport) {
|
||||
|
||||
case 0x6: /* reset */
|
||||
return 0;
|
||||
|
||||
case 0xa: /* read data */
|
||||
if (dsp.out_data_len) {
|
||||
retval = dsp.out_data[--dsp.out_data_len];
|
||||
}
|
||||
else {
|
||||
#if 1
|
||||
lwarn ("empty output buffer\n");
|
||||
retval = 0;
|
||||
#else
|
||||
msg = "empty output buffer";
|
||||
goto error;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc: /* 0 can write */
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
case 0xd: /* timer interrupt clear */
|
||||
goto error;
|
||||
|
||||
case 0xe: /* data available status | irq 8 ack */
|
||||
retval = (0 == dsp.out_data_len) ? 0 : 0x80;
|
||||
break;
|
||||
|
||||
case 0xf: /* irq 16 ack */
|
||||
retval = 0xff;
|
||||
mixer.regs[0x82] &= ~2;
|
||||
ldebug ("16 ack\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((0xc != iport) && (0xe != iport)) {
|
||||
ldebug ("(nport=%#x, size=%d) iport %#x = %#x\n",
|
||||
nport, size, iport, retval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
error:
|
||||
Fail ("(nport=%#x) %s", nport, msg);
|
||||
}
|
||||
|
||||
static IO_WRITE_PROTO(mixer_write_indexb)
|
||||
{
|
||||
mixer.nreg = val & 0xff;
|
||||
}
|
||||
|
||||
static IO_WRITE_PROTO(mixer_write_datab)
|
||||
{
|
||||
mixer.regs[mixer.nreg] = val;
|
||||
}
|
||||
|
||||
static IO_WRITE_PROTO(mixer_write_indexw)
|
||||
{
|
||||
mixer_write_indexb (env, nport, val & 0xff);
|
||||
mixer_write_datab (env, nport, (val >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static IO_READ_PROTO(mixer_read)
|
||||
{
|
||||
return mixer.regs[mixer.nreg];
|
||||
}
|
||||
|
||||
void SB16_run (void)
|
||||
{
|
||||
if (0 == dsp.speaker)
|
||||
return;
|
||||
|
||||
AUD_run ();
|
||||
}
|
||||
|
||||
static int write_audio (uint32_t addr, int len, int size)
|
||||
{
|
||||
int temp, net;
|
||||
|
||||
temp = size;
|
||||
|
||||
net = 0;
|
||||
|
||||
while (temp) {
|
||||
int left_till_end;
|
||||
int to_copy;
|
||||
int copied;
|
||||
|
||||
left_till_end = len - dsp.dma_pos;
|
||||
|
||||
to_copy = MIN (temp, left_till_end);
|
||||
|
||||
copied = AUD_write ((void *) (addr + dsp.dma_pos), to_copy);
|
||||
|
||||
temp -= copied;
|
||||
dsp.dma_pos += copied;
|
||||
|
||||
if (dsp.dma_pos == len) {
|
||||
dsp.dma_pos = 0;
|
||||
}
|
||||
|
||||
net += copied;
|
||||
|
||||
if (copied != to_copy)
|
||||
return net;
|
||||
}
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
static int SB_read_DMA (uint32_t addr, int size, int *_irq)
|
||||
{
|
||||
int free, till, copy, written;
|
||||
|
||||
if (0 == dsp.speaker)
|
||||
return 0;
|
||||
|
||||
if (dsp.left_till_irq < 0) {
|
||||
dsp.left_till_irq += dsp.dma_buffer_size;
|
||||
return dsp.dma_pos;
|
||||
}
|
||||
|
||||
free = AUD_get_free ();
|
||||
|
||||
if ((free <= 0) || (0 == size)) {
|
||||
return dsp.dma_pos;
|
||||
}
|
||||
|
||||
if (mix_block > 0) {
|
||||
copy = MIN (free, mix_block);
|
||||
}
|
||||
else {
|
||||
copy = free;
|
||||
}
|
||||
|
||||
till = dsp.left_till_irq;
|
||||
|
||||
ldebug ("addr:%#010x free:%d till:%d size:%d\n",
|
||||
addr, free, till, size);
|
||||
/* linfo ("pos %d free %d size %d till %d copy %d auto %d noirq %d\n", */
|
||||
/* dsp.dma_pos, free, size, till, copy, dsp.dma_auto, noirq); */
|
||||
if (till <= copy) {
|
||||
if (0 == dsp.dma_auto) {
|
||||
copy = till;
|
||||
}
|
||||
}
|
||||
|
||||
written = write_audio (addr, size, copy);
|
||||
dsp.left_till_irq -= written;
|
||||
AUD_adjust_estimate (free - written);
|
||||
|
||||
if (dsp.left_till_irq <= 0) {
|
||||
mixer.regs[0x82] |= mixer.regs[0x80];
|
||||
if (0 == noirq)
|
||||
*_irq = sb.irq;
|
||||
|
||||
if (0 == dsp.dma_auto) {
|
||||
control (0);
|
||||
}
|
||||
}
|
||||
|
||||
ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n",
|
||||
dsp.dma_pos, free, size, dsp.left_till_irq, copy,
|
||||
dsp.dma_buffer_size);
|
||||
|
||||
if (dsp.left_till_irq <= 0) {
|
||||
dsp.left_till_irq += dsp.dma_buffer_size;
|
||||
}
|
||||
|
||||
return dsp.dma_pos;
|
||||
}
|
||||
|
||||
static int dma_misc_handler (int moo)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int magic_of_irq (int irq)
|
||||
{
|
||||
switch (irq) {
|
||||
case 2:
|
||||
return 1;
|
||||
case 5:
|
||||
return 2;
|
||||
case 7:
|
||||
return 4;
|
||||
case 10:
|
||||
return 8;
|
||||
default:
|
||||
log ("bad irq %d\n", irq);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int irq_of_magic (int magic)
|
||||
{
|
||||
switch (magic) {
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 5;
|
||||
case 4:
|
||||
return 7;
|
||||
case 8:
|
||||
return 10;
|
||||
default:
|
||||
log ("bad irq magic %d\n", magic);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
void SB16_init (void)
|
||||
{
|
||||
int i;
|
||||
static const uint8_t dsp_write_ports[] = {0x6, 0xc};
|
||||
static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
|
||||
|
||||
mixer.regs[0x0e] = ~0;
|
||||
mixer.regs[0x80] = magic_of_irq (sb.irq);
|
||||
mixer.regs[0x81] = 0x20 | (sb.dma << 1);
|
||||
|
||||
DEREF (irq_of_magic);
|
||||
|
||||
for (i = 0x30; i < 0x48; i++) {
|
||||
mixer.regs[i] = 0x20;
|
||||
}
|
||||
|
||||
for (i = 0; i < LENOFA (dsp_write_ports); i++) {
|
||||
register_ioport_write (sb.port + dsp_write_ports[i], 1, dsp_write, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < LENOFA (dsp_read_ports); i++) {
|
||||
register_ioport_read (sb.port + dsp_read_ports[i], 1, dsp_read, 1);
|
||||
}
|
||||
|
||||
register_ioport_write (sb.port + 0x4, 1, mixer_write_indexb, 1);
|
||||
register_ioport_write (sb.port + 0x4, 1, mixer_write_indexw, 2);
|
||||
register_ioport_read (sb.port + 0x5, 1, mixer_read, 1);
|
||||
register_ioport_write (sb.port + 0x5, 1, mixer_write_datab, 1);
|
||||
|
||||
DMA_register_channel (sb.hdma, SB_read_DMA, dma_misc_handler);
|
||||
DMA_register_channel (sb.dma, SB_read_DMA, dma_misc_handler);
|
||||
}
|
||||
@@ -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_raw((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_raw((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
|
||||
@@ -53,6 +53,16 @@ SECTIONS
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
. = 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 = .);
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
|
||||
@@ -25,3 +25,4 @@ struct target_pt_regs {
|
||||
#define ARM_r0 uregs[0]
|
||||
#define ARM_ORIG_r0 uregs[17]
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall ( 0)
|
||||
#define TARGET_NR_exit ( 1)
|
||||
#define TARGET_NR_fork ( 2)
|
||||
#define TARGET_NR_read ( 3)
|
||||
#define TARGET_NR_write ( 4)
|
||||
#define TARGET_NR_open ( 5)
|
||||
#define TARGET_NR_close ( 6)
|
||||
#define TARGET_NR_waitpid ( 7) /* removed */
|
||||
#define TARGET_NR_creat ( 8)
|
||||
#define TARGET_NR_link ( 9)
|
||||
#define TARGET_NR_unlink ( 10)
|
||||
#define TARGET_NR_execve ( 11)
|
||||
#define TARGET_NR_chdir ( 12)
|
||||
#define TARGET_NR_time ( 13)
|
||||
#define TARGET_NR_mknod ( 14)
|
||||
#define TARGET_NR_chmod ( 15)
|
||||
#define TARGET_NR_lchown ( 16)
|
||||
#define TARGET_NR_break ( 17) /* removed */
|
||||
/* 18 was sys_stat */
|
||||
#define TARGET_NR_lseek ( 19)
|
||||
#define TARGET_NR_getpid ( 20)
|
||||
#define TARGET_NR_mount ( 21)
|
||||
#define TARGET_NR_umount ( 22)
|
||||
#define TARGET_NR_setuid ( 23)
|
||||
#define TARGET_NR_getuid ( 24)
|
||||
#define TARGET_NR_stime ( 25)
|
||||
#define TARGET_NR_ptrace ( 26)
|
||||
#define TARGET_NR_alarm ( 27)
|
||||
|
||||
#define TARGET_NR_pause ( 29)
|
||||
#define TARGET_NR_utime ( 30)
|
||||
#define TARGET_NR_stty ( 31) /* removed */
|
||||
#define TARGET_NR_gtty ( 32) /* removed */
|
||||
#define TARGET_NR_access ( 33)
|
||||
#define TARGET_NR_nice ( 34)
|
||||
#define TARGET_NR_ftime ( 35) /* removed */
|
||||
#define TARGET_NR_sync ( 36)
|
||||
#define TARGET_NR_kill ( 37)
|
||||
#define TARGET_NR_rename ( 38)
|
||||
#define TARGET_NR_mkdir ( 39)
|
||||
#define TARGET_NR_rmdir ( 40)
|
||||
#define TARGET_NR_dup ( 41)
|
||||
#define TARGET_NR_pipe ( 42)
|
||||
#define TARGET_NR_times ( 43)
|
||||
#define TARGET_NR_prof ( 44) /* removed */
|
||||
#define TARGET_NR_brk ( 45)
|
||||
#define TARGET_NR_setgid ( 46)
|
||||
#define TARGET_NR_getgid ( 47)
|
||||
#define TARGET_NR_signal ( 48) /* removed */
|
||||
#define TARGET_NR_geteuid ( 49)
|
||||
#define TARGET_NR_getegid ( 50)
|
||||
#define TARGET_NR_acct ( 51)
|
||||
#define TARGET_NR_umount2 ( 52)
|
||||
#define TARGET_NR_lock ( 53) /* removed */
|
||||
#define TARGET_NR_ioctl ( 54)
|
||||
#define TARGET_NR_fcntl ( 55)
|
||||
#define TARGET_NR_mpx ( 56) /* removed */
|
||||
#define TARGET_NR_setpgid ( 57)
|
||||
#define TARGET_NR_ulimit ( 58) /* removed */
|
||||
/* 59 was sys_olduname */
|
||||
#define TARGET_NR_umask ( 60)
|
||||
#define TARGET_NR_chroot ( 61)
|
||||
#define TARGET_NR_ustat ( 62)
|
||||
#define TARGET_NR_dup2 ( 63)
|
||||
#define TARGET_NR_getppid ( 64)
|
||||
#define TARGET_NR_getpgrp ( 65)
|
||||
#define TARGET_NR_setsid ( 66)
|
||||
#define TARGET_NR_sigaction ( 67)
|
||||
#define TARGET_NR_sgetmask ( 68) /* removed */
|
||||
#define TARGET_NR_ssetmask ( 69) /* removed */
|
||||
#define TARGET_NR_setreuid ( 70)
|
||||
#define TARGET_NR_setregid ( 71)
|
||||
#define TARGET_NR_sigsuspend ( 72)
|
||||
#define TARGET_NR_sigpending ( 73)
|
||||
#define TARGET_NR_sethostname ( 74)
|
||||
#define TARGET_NR_setrlimit ( 75)
|
||||
#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */
|
||||
#define TARGET_NR_getrusage ( 77)
|
||||
#define TARGET_NR_gettimeofday ( 78)
|
||||
#define TARGET_NR_settimeofday ( 79)
|
||||
#define TARGET_NR_getgroups ( 80)
|
||||
#define TARGET_NR_setgroups ( 81)
|
||||
#define TARGET_NR_select ( 82)
|
||||
#define TARGET_NR_symlink ( 83)
|
||||
/* 84 was sys_lstat */
|
||||
#define TARGET_NR_readlink ( 85)
|
||||
#define TARGET_NR_uselib ( 86)
|
||||
#define TARGET_NR_swapon ( 87)
|
||||
#define TARGET_NR_reboot ( 88)
|
||||
#define TARGET_NR_readdir ( 89)
|
||||
#define TARGET_NR_mmap ( 90)
|
||||
#define TARGET_NR_munmap ( 91)
|
||||
#define TARGET_NR_truncate ( 92)
|
||||
#define TARGET_NR_ftruncate ( 93)
|
||||
#define TARGET_NR_fchmod ( 94)
|
||||
#define TARGET_NR_fchown ( 95)
|
||||
#define TARGET_NR_getpriority ( 96)
|
||||
#define TARGET_NR_setpriority ( 97)
|
||||
#define TARGET_NR_profil ( 98) /* removed */
|
||||
#define TARGET_NR_statfs ( 99)
|
||||
#define TARGET_NR_fstatfs (100)
|
||||
#define TARGET_NR_ioperm (101)
|
||||
#define TARGET_NR_socketcall (102)
|
||||
#define TARGET_NR_syslog (103)
|
||||
#define TARGET_NR_setitimer (104)
|
||||
#define TARGET_NR_getitimer (105)
|
||||
#define TARGET_NR_stat (106)
|
||||
#define TARGET_NR_lstat (107)
|
||||
#define TARGET_NR_fstat (108)
|
||||
/* 109 was sys_uname */
|
||||
/* 110 was sys_iopl */
|
||||
#define TARGET_NR_vhangup (111)
|
||||
#define TARGET_NR_idle (112)
|
||||
#define TARGET_NR_syscall (113) /* syscall to call a syscall! */
|
||||
#define TARGET_NR_wait4 (114)
|
||||
#define TARGET_NR_swapoff (115)
|
||||
#define TARGET_NR_sysinfo (116)
|
||||
#define TARGET_NR_ipc (117)
|
||||
#define TARGET_NR_fsync (118)
|
||||
#define TARGET_NR_sigreturn (119)
|
||||
#define TARGET_NR_clone (120)
|
||||
#define TARGET_NR_setdomainname (121)
|
||||
#define TARGET_NR_uname (122)
|
||||
#define TARGET_NR_modify_ldt (123)
|
||||
#define TARGET_NR_adjtimex (124)
|
||||
#define TARGET_NR_mprotect (125)
|
||||
#define TARGET_NR_sigprocmask (126)
|
||||
#define TARGET_NR_create_module (127) /* removed */
|
||||
#define TARGET_NR_init_module (128)
|
||||
#define TARGET_NR_delete_module (129)
|
||||
#define TARGET_NR_get_kernel_syms (130) /* removed */
|
||||
#define TARGET_NR_quotactl (131)
|
||||
#define TARGET_NR_getpgid (132)
|
||||
#define TARGET_NR_fchdir (133)
|
||||
#define TARGET_NR_bdflush (134)
|
||||
#define TARGET_NR_sysfs (135)
|
||||
#define TARGET_NR_personality (136)
|
||||
#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid (138)
|
||||
#define TARGET_NR_setfsgid (139)
|
||||
#define TARGET_NR__llseek (140)
|
||||
#define TARGET_NR_getdents (141)
|
||||
#define TARGET_NR__newselect (142)
|
||||
#define TARGET_NR_flock (143)
|
||||
#define TARGET_NR_msync (144)
|
||||
#define TARGET_NR_readv (145)
|
||||
#define TARGET_NR_writev (146)
|
||||
#define TARGET_NR_getsid (147)
|
||||
#define TARGET_NR_fdatasync (148)
|
||||
#define TARGET_NR__sysctl (149)
|
||||
#define TARGET_NR_mlock (150)
|
||||
#define TARGET_NR_munlock (151)
|
||||
#define TARGET_NR_mlockall (152)
|
||||
#define TARGET_NR_munlockall (153)
|
||||
#define TARGET_NR_sched_setparam (154)
|
||||
#define TARGET_NR_sched_getparam (155)
|
||||
#define TARGET_NR_sched_setscheduler (156)
|
||||
#define TARGET_NR_sched_getscheduler (157)
|
||||
#define TARGET_NR_sched_yield (158)
|
||||
#define TARGET_NR_sched_get_priority_max (159)
|
||||
#define TARGET_NR_sched_get_priority_min (160)
|
||||
#define TARGET_NR_sched_rr_get_interval (161)
|
||||
#define TARGET_NR_nanosleep (162)
|
||||
#define TARGET_NR_mremap (163)
|
||||
#define TARGET_NR_setresuid (164)
|
||||
#define TARGET_NR_getresuid (165)
|
||||
#define TARGET_NR_vm86 (166) /* removed */
|
||||
#define TARGET_NR_query_module (167) /* removed */
|
||||
#define TARGET_NR_poll (168)
|
||||
#define TARGET_NR_nfsservctl (169)
|
||||
#define TARGET_NR_setresgid (170)
|
||||
#define TARGET_NR_getresgid (171)
|
||||
#define TARGET_NR_prctl (172)
|
||||
#define TARGET_NR_rt_sigreturn (173)
|
||||
#define TARGET_NR_rt_sigaction (174)
|
||||
#define TARGET_NR_rt_sigprocmask (175)
|
||||
#define TARGET_NR_rt_sigpending (176)
|
||||
#define TARGET_NR_rt_sigtimedwait (177)
|
||||
#define TARGET_NR_rt_sigqueueinfo (178)
|
||||
#define TARGET_NR_rt_sigsuspend (179)
|
||||
#define TARGET_NR_pread (180)
|
||||
#define TARGET_NR_pwrite (181)
|
||||
#define TARGET_NR_chown (182)
|
||||
#define TARGET_NR_getcwd (183)
|
||||
#define TARGET_NR_capget (184)
|
||||
#define TARGET_NR_capset (185)
|
||||
#define TARGET_NR_sigaltstack (186)
|
||||
#define TARGET_NR_sendfile (187)
|
||||
/* 188 reserved */
|
||||
/* 189 reserved */
|
||||
#define TARGET_NR_vfork (190)
|
||||
#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 (192)
|
||||
#define TARGET_NR_truncate64 (193)
|
||||
#define TARGET_NR_ftruncate64 (194)
|
||||
#define TARGET_NR_stat64 (195)
|
||||
#define TARGET_NR_lstat64 (196)
|
||||
#define TARGET_NR_fstat64 (197)
|
||||
#define TARGET_NR_lchown32 (198)
|
||||
#define TARGET_NR_getuid32 (199)
|
||||
#define TARGET_NR_getgid32 (200)
|
||||
#define TARGET_NR_geteuid32 (201)
|
||||
#define TARGET_NR_getegid32 (202)
|
||||
#define TARGET_NR_setreuid32 (203)
|
||||
#define TARGET_NR_setregid32 (204)
|
||||
#define TARGET_NR_getgroups32 (205)
|
||||
#define TARGET_NR_setgroups32 (206)
|
||||
#define TARGET_NR_fchown32 (207)
|
||||
#define TARGET_NR_setresuid32 (208)
|
||||
#define TARGET_NR_getresuid32 (209)
|
||||
#define TARGET_NR_setresgid32 (210)
|
||||
#define TARGET_NR_getresgid32 (211)
|
||||
#define TARGET_NR_chown32 (212)
|
||||
#define TARGET_NR_setuid32 (213)
|
||||
#define TARGET_NR_setgid32 (214)
|
||||
#define TARGET_NR_setfsuid32 (215)
|
||||
#define TARGET_NR_setfsgid32 (216)
|
||||
#define TARGET_NR_getdents64 (217)
|
||||
#define TARGET_NR_pivot_root (218)
|
||||
#define TARGET_NR_mincore (219)
|
||||
#define TARGET_NR_madvise (220)
|
||||
#define TARGET_NR_fcntl64 (221)
|
||||
/* 222 for tux */
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid (224)
|
||||
#define TARGET_NR_readahead (225)
|
||||
#define TARGET_NR_setxattr (226)
|
||||
#define TARGET_NR_lsetxattr (227)
|
||||
#define TARGET_NR_fsetxattr (228)
|
||||
#define TARGET_NR_getxattr (229)
|
||||
#define TARGET_NR_lgetxattr (230)
|
||||
#define TARGET_NR_fgetxattr (231)
|
||||
#define TARGET_NR_listxattr (232)
|
||||
#define TARGET_NR_llistxattr (233)
|
||||
#define TARGET_NR_flistxattr (234)
|
||||
#define TARGET_NR_removexattr (235)
|
||||
#define TARGET_NR_lremovexattr (236)
|
||||
#define TARGET_NR_fremovexattr (237)
|
||||
#define TARGET_NR_tkill (238)
|
||||
#define TARGET_NR_sendfile64 (239)
|
||||
#define TARGET_NR_futex (240)
|
||||
#define TARGET_NR_sched_setaffinity (241)
|
||||
#define TARGET_NR_sched_getaffinity (242)
|
||||
#define TARGET_NR_io_setup (243)
|
||||
#define TARGET_NR_io_destroy (244)
|
||||
#define TARGET_NR_io_getevents (245)
|
||||
#define TARGET_NR_io_submit (246)
|
||||
#define TARGET_NR_io_cancel (247)
|
||||
#define TARGET_NR_exit_group (248)
|
||||
#define TARGET_NR_lookup_dcookie (249)
|
||||
#define TARGET_NR_epoll_create (250)
|
||||
#define TARGET_NR_epoll_ctl (251)
|
||||
#define TARGET_NR_epoll_wait (252)
|
||||
#define TARGET_NR_remap_file_pages (253)
|
||||
/* 254 for set_thread_area */
|
||||
/* 255 for get_thread_area */
|
||||
/* 256 for set_tid_address */
|
||||
@@ -0,0 +1,215 @@
|
||||
/* from asm/termbits.h */
|
||||
/* NOTE: exactly the same as i386 */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
|
||||
/* ioctls */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
+166
-38
@@ -74,7 +74,105 @@ 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
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_SPARC )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->psr = 0;
|
||||
regs->pc = infop->entry;
|
||||
regs->npc = regs->pc + 4;
|
||||
regs->y = 0;
|
||||
regs->u_regs[14] = infop->start_stack - 16 * 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PPC
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_PPC )
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#else
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#endif
|
||||
#define ELF_ARCH EM_PPC
|
||||
|
||||
/* Note that isn't exactly what regular kernel does
|
||||
* but this is what the ABI wants and is needed to allow
|
||||
* execution of PPC BSD programs.
|
||||
*/
|
||||
#define ELF_PLAT_INIT(_r) \
|
||||
do { \
|
||||
unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \
|
||||
_r->gpr[3] = bprm->argc; \
|
||||
_r->gpr[4] = (unsigned long)++pos; \
|
||||
for (; tmp != 0; pos++) \
|
||||
tmp = *pos; \
|
||||
_r->gpr[5] = (unsigned long)pos; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* We need to put in some extra aux table entries to tell glibc what
|
||||
* the cache block size is, so it can use the dcbz instruction safely.
|
||||
*/
|
||||
#define AT_DCACHEBSIZE 19
|
||||
#define AT_ICACHEBSIZE 20
|
||||
#define AT_UCACHEBSIZE 21
|
||||
/* A special ignored type value for PPC, for glibc compatibility. */
|
||||
#define AT_IGNOREPPC 22
|
||||
/*
|
||||
* The requirements here are:
|
||||
* - keep the final alignment of sp (sp & 0xf)
|
||||
* - make sure the 32-bit value at the first 16 byte aligned position of
|
||||
* AUXV is greater than 16 for glibc compatibility.
|
||||
* AT_IGNOREPPC is used for that.
|
||||
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
|
||||
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
|
||||
*/
|
||||
#define DLINFO_ARCH_ITEMS 3
|
||||
#define ARCH_DLINFO \
|
||||
do { \
|
||||
sp -= DLINFO_ARCH_ITEMS * 2; \
|
||||
NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \
|
||||
NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \
|
||||
NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \
|
||||
/* \
|
||||
* Now handle glibc compatibility. \
|
||||
*/ \
|
||||
sp -= 2*2; \
|
||||
NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \
|
||||
NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \
|
||||
} while (0)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
|
||||
{
|
||||
_regs->msr = 1 << MSR_PR; /* Set user mode */
|
||||
_regs->gpr[1] = infop->start_stack;
|
||||
_regs->nip = infop->entry;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -163,7 +261,7 @@ struct exec
|
||||
#define INTERPRETER_AOUT 1
|
||||
#define INTERPRETER_ELF 2
|
||||
|
||||
#define DLINFO_ITEMS 12
|
||||
#define DLINFO_ITEMS 11
|
||||
|
||||
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
|
||||
#define get_user(ptr) (typeof(*ptr))(*(ptr))
|
||||
@@ -455,18 +553,32 @@ static void set_brk(unsigned long start, unsigned long end)
|
||||
}
|
||||
|
||||
|
||||
/* We need to explicitly zero any fractional pages
|
||||
after the data section (i.e. bss). This would
|
||||
contain the junk from the file that should not
|
||||
be in memory */
|
||||
|
||||
|
||||
/* We need to explicitly zero any fractional pages after the data
|
||||
section (i.e. bss). This would contain the junk from the file that
|
||||
should not be in memory. */
|
||||
static void padzero(unsigned long elf_bss)
|
||||
{
|
||||
unsigned long nbyte;
|
||||
char * fpnt;
|
||||
|
||||
nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */
|
||||
/* XXX: this is really a hack : if the real host page size is
|
||||
smaller than the target page size, some pages after the end
|
||||
of the file may not be mapped. A better fix would be to
|
||||
patch target_mmap(), but it is more complicated as the file
|
||||
size must be known */
|
||||
if (real_host_page_size < host_page_size) {
|
||||
unsigned long end_addr, end_addr1;
|
||||
end_addr1 = (elf_bss + real_host_page_size - 1) &
|
||||
~(real_host_page_size - 1);
|
||||
end_addr = HOST_PAGE_ALIGN(elf_bss);
|
||||
if (end_addr1 < end_addr) {
|
||||
mmap((void *)end_addr1, end_addr - end_addr1,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
nbyte = elf_bss & (host_page_size-1);
|
||||
if (nbyte) {
|
||||
nbyte = host_page_size - nbyte;
|
||||
fpnt = (char *) elf_bss;
|
||||
@@ -483,15 +595,51 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
target_ulong *argv, *envp, *dlinfo;
|
||||
target_ulong *sp;
|
||||
|
||||
/*
|
||||
* Force 16 byte alignment here for generality.
|
||||
*/
|
||||
target_ulong *argv, *envp;
|
||||
target_ulong *sp, *csp;
|
||||
|
||||
/*
|
||||
* Force 16 byte _final_ alignment here for generality.
|
||||
*/
|
||||
sp = (unsigned int *) (~15UL & (unsigned long) p);
|
||||
sp -= exec ? DLINFO_ITEMS*2 : 2;
|
||||
dlinfo = sp;
|
||||
csp = sp;
|
||||
csp -= (DLINFO_ITEMS + 1) * 2;
|
||||
#ifdef DLINFO_ARCH_ITEMS
|
||||
csp -= DLINFO_ARCH_ITEMS*2;
|
||||
#endif
|
||||
csp -= envc+1;
|
||||
csp -= argc+1;
|
||||
csp -= (!ibcs ? 3 : 1); /* argc itself */
|
||||
if ((unsigned long)csp & 15UL)
|
||||
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
|
||||
|
||||
#define NEW_AUX_ENT(nr, id, val) \
|
||||
put_user (tswapl(id), sp + (nr * 2)); \
|
||||
put_user (tswapl(val), sp + (nr * 2 + 1))
|
||||
sp -= 2;
|
||||
NEW_AUX_ENT (0, AT_NULL, 0);
|
||||
|
||||
sp -= DLINFO_ITEMS*2;
|
||||
NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||
NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||
NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||
NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
|
||||
NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr));
|
||||
NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0);
|
||||
NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry);
|
||||
NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid());
|
||||
NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid());
|
||||
NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid());
|
||||
NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid());
|
||||
#ifdef ARCH_DLINFO
|
||||
/*
|
||||
* ARCH_DLINFO must come last so platform specific code can enforce
|
||||
* special alignment requirements on the AUXV if necessary (eg. PPC).
|
||||
*/
|
||||
ARCH_DLINFO;
|
||||
#endif
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
sp -= envc+1;
|
||||
envp = sp;
|
||||
sp -= argc+1;
|
||||
@@ -500,26 +648,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||
put_user(tswapl((target_ulong)envp),--sp);
|
||||
put_user(tswapl((target_ulong)argv),--sp);
|
||||
}
|
||||
|
||||
#define NEW_AUX_ENT(id, val) \
|
||||
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_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 +1215,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),
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
/* 223 is unused */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
|
||||
/* ioctls */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
+285
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* qemu main
|
||||
* qemu user main
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
@@ -28,17 +28,15 @@
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
FILE *logfile = NULL;
|
||||
int loglevel;
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
|
||||
#ifdef __i386__
|
||||
#if defined(__i386__) && !defined(CONFIG_STATIC)
|
||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||
object ! */
|
||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
|
||||
/* for recent libc, we add these dummies symbol which are not declared
|
||||
/* for recent libc, we add these dummy symbols which are not declared
|
||||
when generating a linked object (bug in ld ?) */
|
||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||
long __init_array_start[0];
|
||||
@@ -246,8 +244,6 @@ void cpu_loop(CPUX86State *env)
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define ARM_SYSCALL_BASE 0x900000
|
||||
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
int trapnr;
|
||||
@@ -285,6 +281,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",
|
||||
@@ -298,10 +297,258 @@ void cpu_loop(CPUARMState *env)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
||||
//#define DEBUG_WIN
|
||||
|
||||
/* WARNING: dealing with register windows _is_ complicated */
|
||||
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
|
||||
{
|
||||
index = (index + cwp * 16) & (16 * NWINDOWS - 1);
|
||||
/* wrap handling : if cwp is on the last window, then we use the
|
||||
registers 'after' the end */
|
||||
if (index < 8 && env->cwp == (NWINDOWS - 1))
|
||||
index += (16 * NWINDOWS);
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline void save_window_offset(CPUSPARCState *env, int offset)
|
||||
{
|
||||
unsigned int new_wim, i, cwp1;
|
||||
uint32_t *sp_ptr;
|
||||
|
||||
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
|
||||
((1LL << NWINDOWS) - 1);
|
||||
/* save the window */
|
||||
cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
|
||||
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
|
||||
(int)sp_ptr, cwp1);
|
||||
#endif
|
||||
for(i = 0; i < 16; i++)
|
||||
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
|
||||
env->wim = new_wim;
|
||||
}
|
||||
|
||||
static void save_window(CPUSPARCState *env)
|
||||
{
|
||||
save_window_offset(env, 2);
|
||||
}
|
||||
|
||||
static void restore_window(CPUSPARCState *env)
|
||||
{
|
||||
unsigned int new_wim, i, cwp1;
|
||||
uint32_t *sp_ptr;
|
||||
|
||||
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
|
||||
((1LL << NWINDOWS) - 1);
|
||||
|
||||
/* restore the invalid window */
|
||||
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
|
||||
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
|
||||
(int)sp_ptr, cwp1);
|
||||
#endif
|
||||
for(i = 0; i < 16; i++)
|
||||
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i);
|
||||
env->wim = new_wim;
|
||||
}
|
||||
|
||||
static void flush_windows(CPUSPARCState *env)
|
||||
{
|
||||
int offset, cwp1;
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("flush_windows:\n");
|
||||
#endif
|
||||
offset = 2;
|
||||
for(;;) {
|
||||
/* if restore would invoke restore_window(), then we can stop */
|
||||
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
|
||||
if (env->wim & (1 << cwp1))
|
||||
break;
|
||||
#if defined(DEBUG_WIN)
|
||||
printf("offset=%d: ", offset);
|
||||
#endif
|
||||
save_window_offset(env, offset);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_loop (CPUSPARCState *env)
|
||||
{
|
||||
int trapnr, ret;
|
||||
|
||||
while (1) {
|
||||
trapnr = cpu_sparc_exec (env);
|
||||
|
||||
switch (trapnr) {
|
||||
case 0x88:
|
||||
case 0x90:
|
||||
ret = do_syscall (env, env->gregs[1],
|
||||
env->regwptr[0], env->regwptr[1],
|
||||
env->regwptr[2], env->regwptr[3],
|
||||
env->regwptr[4], env->regwptr[5]);
|
||||
if ((unsigned int)ret >= (unsigned int)(-515)) {
|
||||
env->psr |= PSR_CARRY;
|
||||
ret = -ret;
|
||||
} else {
|
||||
env->psr &= ~PSR_CARRY;
|
||||
}
|
||||
env->regwptr[0] = ret;
|
||||
/* next instruction */
|
||||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
break;
|
||||
case 0x83: /* flush windows */
|
||||
// flush_windows(env);
|
||||
/* next instruction */
|
||||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
break;
|
||||
case TT_WIN_OVF: /* window overflow */
|
||||
save_window(env);
|
||||
break;
|
||||
case TT_WIN_UNF: /* window underflow */
|
||||
restore_window(env);
|
||||
break;
|
||||
default:
|
||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||
cpu_sparc_dump_state(env, stderr, 0);
|
||||
exit (1);
|
||||
}
|
||||
process_pending_signals (env);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PPC
|
||||
|
||||
void cpu_loop(CPUPPCState *env)
|
||||
{
|
||||
int trapnr;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_ppc_exec(env);
|
||||
switch(trapnr) {
|
||||
case EXCP_NONE:
|
||||
case EXCP_INTERRUPT:
|
||||
case EXCP_MTMSR: /* mtmsr instruction: */
|
||||
case EXCP_BRANCH: /* branch instruction */
|
||||
/* Single step mode */
|
||||
break;
|
||||
#if 0
|
||||
case EXCP_RESET: /* System reset */
|
||||
fprintf(stderr, "RESET asked... Stop emulation\n");
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
#endif
|
||||
case EXCP_MACHINE_CHECK: /* Machine check exception */
|
||||
fprintf(stderr, "Machine check exeption... "
|
||||
"See you in kernel code !\n");
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
case EXCP_DSI: /* Impossible memory access */
|
||||
fprintf(stderr, "Invalid memory access\n");
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_ISI: /* Impossible instruction fetch */
|
||||
fprintf(stderr, "Invalid instruction fetch\n");
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_EXTERNAL: /* External interruption */
|
||||
fprintf(stderr, "External access exeption\n");
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
case EXCP_ALIGN: /* Alignment exception */
|
||||
fprintf(stderr, "Alignment exception\n");
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
case EXCP_PROGRAM: /* Program exception */
|
||||
fprintf(stderr, "Program exception\n");
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
break;
|
||||
/* Trap */
|
||||
case EXCP_TRAP: /* Trap */
|
||||
case EXCP_TRACE: /* Trace exception (optional) */
|
||||
info.si_signo = SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
/* Invalid instruction */
|
||||
case EXCP_INVAL:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
/* Privileged instruction */
|
||||
case EXCP_PRIV: /* Privileged instruction */
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_NO_FP: /* No floating point */
|
||||
case EXCP_DECR: /* Decrementer exception */
|
||||
case EXCP_RESA: /* Implementation specific */
|
||||
case EXCP_RESB: /* Implementation specific */
|
||||
case EXCP_FP_ASSIST: /* Floating-point assist (optional) */
|
||||
fprintf(stderr, "Misc expt...\n");
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
|
||||
case EXCP_SYSCALL:
|
||||
{
|
||||
uint32_t ret;
|
||||
/* system call */
|
||||
/* WARNING:
|
||||
* PPC ABI uses overflow flag in cr0 to signal an error
|
||||
* in syscalls.
|
||||
*/
|
||||
env->crf[0] &= ~0x1;
|
||||
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||
env->gpr[8]);
|
||||
if (ret > (uint32_t)(-515)) {
|
||||
env->crf[0] |= 0x1;
|
||||
ret = -ret;
|
||||
}
|
||||
env->gpr[3] = ret;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// error:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
cpu_ppc_dump_state(env, stderr, 0);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: qemu-" TARGET_ARCH " [-h] [-d] [-L path] [-s size] program [arguments...]\n"
|
||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
@@ -339,7 +586,9 @@ int main(int argc, char **argv)
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
loglevel = 0;
|
||||
/* init debug */
|
||||
cpu_set_log_filename(DEBUG_LOGFILE);
|
||||
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
if (optind >= argc)
|
||||
@@ -352,7 +601,7 @@ int main(int argc, char **argv)
|
||||
if (!strcmp(r, "-")) {
|
||||
break;
|
||||
} else if (!strcmp(r, "d")) {
|
||||
loglevel = 1;
|
||||
cpu_set_log(CPU_LOG_ALL);
|
||||
} else if (!strcmp(r, "s")) {
|
||||
r = argv[optind++];
|
||||
x86_stack_size = strtol(r, (char **)&r, 0);
|
||||
@@ -379,16 +628,6 @@ int main(int argc, char **argv)
|
||||
usage();
|
||||
filename = argv[optind];
|
||||
|
||||
/* init debug */
|
||||
if (loglevel) {
|
||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||
if (!logfile) {
|
||||
perror(DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
/* Zero out regs */
|
||||
memset(regs, 0, sizeof(struct target_pt_regs));
|
||||
|
||||
@@ -432,6 +671,10 @@ int main(int argc, char **argv)
|
||||
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;
|
||||
@@ -492,6 +735,27 @@ int main(int argc, char **argv)
|
||||
}
|
||||
env->cpsr = regs->uregs[16];
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
{
|
||||
int i;
|
||||
env->pc = regs->pc;
|
||||
env->npc = regs->npc;
|
||||
env->y = regs->y;
|
||||
for(i = 0; i < 8; i++)
|
||||
env->gregs[i] = regs->u_regs[i];
|
||||
for(i = 0; i < 8; i++)
|
||||
env->regwptr[i] = regs->u_regs[i + 8];
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 32; i++)
|
||||
env->msr[i] = (regs->msr >> i) & 1;
|
||||
env->nip = regs->nip;
|
||||
for(i = 0; i < 32; i++) {
|
||||
env->gpr[i] = regs->gpr[i];
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* PPC emulation for qemu: syscall definitions.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* XXX: ABSOLUTELY BUGGY:
|
||||
* for now, this is quite just a cut-and-paste from i386 target...
|
||||
*/
|
||||
|
||||
/* default linux values for the selectors */
|
||||
#define __USER_DS (1)
|
||||
|
||||
struct target_pt_regs {
|
||||
unsigned long gpr[32];
|
||||
unsigned long nip;
|
||||
unsigned long msr;
|
||||
unsigned long orig_gpr3; /* Used for restarting system calls */
|
||||
unsigned long ctr;
|
||||
unsigned long link;
|
||||
unsigned long xer;
|
||||
unsigned long ccr;
|
||||
unsigned long mq; /* 601 only (not used at present) */
|
||||
/* Used on APUS to hold IPL value. */
|
||||
unsigned long trap; /* Reason for being here */
|
||||
unsigned long dar; /* Fault registers */
|
||||
unsigned long dsisr;
|
||||
unsigned long result; /* Result of a system call */
|
||||
};
|
||||
|
||||
/* ioctls */
|
||||
struct target_revectored_struct {
|
||||
target_ulong __map[8]; /* 256 bits */
|
||||
};
|
||||
|
||||
/*
|
||||
* flags masks
|
||||
*/
|
||||
|
||||
/* ipcs */
|
||||
|
||||
#define TARGET_SEMOP 1
|
||||
#define TARGET_SEMGET 2
|
||||
#define TARGET_SEMCTL 3
|
||||
#define TARGET_MSGSND 11
|
||||
#define TARGET_MSGRCV 12
|
||||
#define TARGET_MSGGET 13
|
||||
#define TARGET_MSGCTL 14
|
||||
#define TARGET_SHMAT 21
|
||||
#define TARGET_SHMDT 22
|
||||
#define TARGET_SHMGET 23
|
||||
#define TARGET_SHMCTL 24
|
||||
|
||||
struct target_msgbuf {
|
||||
int mtype;
|
||||
char mtext[1];
|
||||
};
|
||||
|
||||
struct target_ipc_kludge {
|
||||
unsigned int msgp; /* Really (struct msgbuf *) */
|
||||
int msgtyp;
|
||||
};
|
||||
|
||||
struct target_ipc_perm {
|
||||
int key;
|
||||
unsigned short uid;
|
||||
unsigned short gid;
|
||||
unsigned short cuid;
|
||||
unsigned short cgid;
|
||||
unsigned short mode;
|
||||
unsigned short seq;
|
||||
};
|
||||
|
||||
struct target_msqid_ds {
|
||||
struct target_ipc_perm msg_perm;
|
||||
unsigned int msg_first; /* really struct target_msg* */
|
||||
unsigned int msg_last; /* really struct target_msg* */
|
||||
unsigned int msg_stime; /* really target_time_t */
|
||||
unsigned int msg_rtime; /* really target_time_t */
|
||||
unsigned int msg_ctime; /* really target_time_t */
|
||||
unsigned int wwait; /* really struct wait_queue* */
|
||||
unsigned int rwait; /* really struct wait_queue* */
|
||||
unsigned short msg_cbytes;
|
||||
unsigned short msg_qnum;
|
||||
unsigned short msg_qbytes;
|
||||
unsigned short msg_lspid;
|
||||
unsigned short msg_lrpid;
|
||||
};
|
||||
|
||||
struct target_shmid_ds {
|
||||
struct target_ipc_perm shm_perm;
|
||||
int shm_segsz;
|
||||
unsigned int shm_atime; /* really target_time_t */
|
||||
unsigned int shm_dtime; /* really target_time_t */
|
||||
unsigned int shm_ctime; /* really target_time_t */
|
||||
unsigned short shm_cpid;
|
||||
unsigned short shm_lpid;
|
||||
short shm_nattch;
|
||||
unsigned short shm_npages;
|
||||
unsigned long *shm_pages;
|
||||
void *attaches; /* really struct shm_desc * */
|
||||
};
|
||||
|
||||
#define TARGET_IPC_RMID 0
|
||||
#define TARGET_IPC_SET 1
|
||||
#define TARGET_IPC_STAT 2
|
||||
|
||||
union target_semun {
|
||||
int val;
|
||||
unsigned int buf; /* really struct semid_ds * */
|
||||
unsigned int array; /* really unsigned short * */
|
||||
unsigned int __buf; /* really struct seminfo * */
|
||||
unsigned int __pad; /* really void* */
|
||||
};
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown32 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid32 23
|
||||
#define TARGET_NR_getuid32 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid32 46
|
||||
#define TARGET_NR_getgid32 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid32 49
|
||||
#define TARGET_NR_getegid32 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid32 70
|
||||
#define TARGET_NR_setregid32 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups32 80
|
||||
#define TARGET_NR_setgroups32 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown32 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid32 138
|
||||
#define TARGET_NR_setfsgid32 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid32 164
|
||||
#define TARGET_NR_getresuid32 165
|
||||
#define TARGET_NR_query_module 166
|
||||
#define TARGET_NR_poll 167
|
||||
#define TARGET_NR_nfsservctl 168
|
||||
#define TARGET_NR_setresgid32 169
|
||||
#define TARGET_NR_getresgid32 170
|
||||
#define TARGET_NR_prctl 171
|
||||
#define TARGET_NR_rt_sigreturn 172
|
||||
#define TARGET_NR_rt_sigaction 173
|
||||
#define TARGET_NR_rt_sigprocmask 174
|
||||
#define TARGET_NR_rt_sigpending 175
|
||||
#define TARGET_NR_rt_sigtimedwait 176
|
||||
#define TARGET_NR_rt_sigqueueinfo 177
|
||||
#define TARGET_NR_rt_sigsuspend 178
|
||||
#define TARGET_NR_pread64 179
|
||||
#define TARGET_NR_pwrite64 180
|
||||
#define TARGET_NR_chown32 181
|
||||
#define TARGET_NR_getcwd 182
|
||||
#define TARGET_NR_capget 183
|
||||
#define TARGET_NR_capset 184
|
||||
#define TARGET_NR_sigaltstack 185
|
||||
#define TARGET_NR_sendfile 186
|
||||
#define TARGET_NR_getpmsg 187 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 189
|
||||
#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_readahead 191
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_pciconfig_read 198
|
||||
#define TARGET_NR_pciconfig_write 199
|
||||
#define TARGET_NR_pciconfig_iobase 200
|
||||
#define TARGET_NR_multiplexer 201
|
||||
#define TARGET_NR_getdents64 202
|
||||
#define TARGET_NR_pivot_root 203
|
||||
#define TARGET_NR_fcntl64 204
|
||||
#define TARGET_NR_madvise 205
|
||||
#define TARGET_NR_mincore 206
|
||||
#define TARGET_NR_gettid 207
|
||||
#define TARGET_NR_tkill 208
|
||||
#define TARGET_NR_setxattr 209
|
||||
#define TARGET_NR_lsetxattr 210
|
||||
#define TARGET_NR_fsetxattr 211
|
||||
#define TARGET_NR_getxattr 212
|
||||
#define TARGET_NR_lgetxattr 213
|
||||
#define TARGET_NR_fgetxattr 214
|
||||
#define TARGET_NR_listxattr 215
|
||||
#define TARGET_NR_llistxattr 216
|
||||
#define TARGET_NR_flistxattr 217
|
||||
#define TARGET_NR_removexattr 218
|
||||
#define TARGET_NR_lremovexattr 219
|
||||
#define TARGET_NR_fremovexattr 220
|
||||
#define TARGET_NR_futex 221
|
||||
#define TARGET_NR_sched_setaffinity 222
|
||||
#define TARGET_NR_sched_getaffinity 223
|
||||
/* 224 currently unused */
|
||||
#define TARGET_NR_tuxcall 225
|
||||
#define TARGET_NR_sendfile64 226
|
||||
#define TARGET_NR_io_setup 227
|
||||
#define TARGET_NR_io_destroy 228
|
||||
#define TARGET_NR_io_getevents 229
|
||||
#define TARGET_NR_io_submit 230
|
||||
#define TARGET_NR_io_cancel 231
|
||||
#define TARGET_NR_set_tid_address 232
|
||||
#define TARGET_NR_fadvise64 233
|
||||
#define TARGET_NR_exit_group 234
|
||||
#define TARGET_NR_lookup_dcookie 235
|
||||
#define TARGET_NR_epoll_create 236
|
||||
#define TARGET_NR_epoll_ctl 237
|
||||
#define TARGET_NR_epoll_wait 238
|
||||
#define TARGET_NR_remap_file_pages 239
|
||||
#define TARGET_NR_timer_create 240
|
||||
#define TARGET_NR_timer_settime 241
|
||||
#define TARGET_NR_timer_gettime 242
|
||||
#define TARGET_NR_timer_getoverrun 243
|
||||
#define TARGET_NR_timer_delete 244
|
||||
#define TARGET_NR_clock_settime 245
|
||||
#define TARGET_NR_clock_gettime 246
|
||||
#define TARGET_NR_clock_getres 247
|
||||
#define TARGET_NR_clock_nanosleep 248
|
||||
#define TARGET_NR_swapcontext 249
|
||||
#define TARGET_NR_tgkill 250
|
||||
#define TARGET_NR_utimes 251
|
||||
#define TARGET_NR_statfs64 252
|
||||
#define TARGET_NR_fstatfs64 253
|
||||
#define TARGET_NR_fadvise64_64 254
|
||||
@@ -0,0 +1,235 @@
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
unsigned int c_ispeed; /* input speed */
|
||||
unsigned int c_ospeed; /* output speed */
|
||||
};
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VMIN 5
|
||||
#define TARGET_VEOL 6
|
||||
#define TARGET_VTIME 7
|
||||
#define TARGET_VEOL2 8
|
||||
#define TARGET_VSWTC 9
|
||||
|
||||
#define TARGET_VWERASE 10
|
||||
#define TARGET_VREPRINT 11
|
||||
#define TARGET_VSUSP 12
|
||||
#define TARGET_VSTART 13
|
||||
#define TARGET_VSTOP 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VDISCARD 16
|
||||
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IXON 0001000
|
||||
#define TARGET_IXOFF 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IUCLC 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_ONLCR 0000002
|
||||
#define TARGET_OLCUC 0000004
|
||||
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
|
||||
#define TARGET_OFILL 00000100
|
||||
#define TARGET_OFDEL 00000200
|
||||
#define TARGET_NLDLY 00001400
|
||||
#define TARGET_NL0 00000000
|
||||
#define TARGET_NL1 00000400
|
||||
#define TARGET_NL2 00001000
|
||||
#define TARGET_NL3 00001400
|
||||
#define TARGET_TABDLY 00006000
|
||||
#define TARGET_TAB0 00000000
|
||||
#define TARGET_TAB1 00002000
|
||||
#define TARGET_TAB2 00004000
|
||||
#define TARGET_TAB3 00006000
|
||||
#define TARGET_CRDLY 00030000
|
||||
#define TARGET_CR0 00000000
|
||||
#define TARGET_CR1 00010000
|
||||
#define TARGET_CR2 00020000
|
||||
#define TARGET_CR3 00030000
|
||||
#define TARGET_FFDLY 00040000
|
||||
#define TARGET_FF0 00000000
|
||||
#define TARGET_FF1 00040000
|
||||
#define TARGET_BSDLY 00100000
|
||||
#define TARGET_BS0 00000000
|
||||
#define TARGET_BS1 00100000
|
||||
#define TARGET_VTDLY 00200000
|
||||
#define TARGET_VT0 00000000
|
||||
#define TARGET_VT1 00200000
|
||||
#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0000377
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CBAUDEX 0000000
|
||||
#define TARGET_B57600 00020
|
||||
#define TARGET_B115200 00021
|
||||
#define TARGET_B230400 00022
|
||||
#define TARGET_B460800 00023
|
||||
#define TARGET_B500000 00024
|
||||
#define TARGET_B576000 00025
|
||||
#define TARGET_B921600 00026
|
||||
#define TARGET_B1000000 00027
|
||||
#define TARGET_B1152000 00030
|
||||
#define TARGET_B1500000 00031
|
||||
#define TARGET_B2000000 00032
|
||||
#define TARGET_B2500000 00033
|
||||
#define TARGET_B3000000 00034
|
||||
#define TARGET_B3500000 00035
|
||||
#define TARGET_B4000000 00036
|
||||
|
||||
#define TARGET_CSIZE 00001400
|
||||
#define TARGET_CS5 00000000
|
||||
#define TARGET_CS6 00000400
|
||||
#define TARGET_CS7 00001000
|
||||
#define TARGET_CS8 00001400
|
||||
|
||||
#define TARGET_CSTOPB 00002000
|
||||
#define TARGET_CREAD 00004000
|
||||
#define TARGET_PARENB 00010000
|
||||
#define TARGET_PARODD 00020000
|
||||
#define TARGET_HUPCL 00040000
|
||||
|
||||
#define TARGET_CLOCAL 00100000
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0x00000080
|
||||
#define TARGET_ICANON 0x00000100
|
||||
#define TARGET_XCASE 0x00004000
|
||||
#define TARGET_ECHO 0x00000008
|
||||
#define TARGET_ECHOE 0x00000002
|
||||
#define TARGET_ECHOK 0x00000004
|
||||
#define TARGET_ECHONL 0x00000010
|
||||
#define TARGET_NOFLSH 0x80000000
|
||||
#define TARGET_TOSTOP 0x00400000
|
||||
#define TARGET_ECHOCTL 0x00000040
|
||||
#define TARGET_ECHOPRT 0x00000020
|
||||
#define TARGET_ECHOKE 0x00000001
|
||||
#define TARGET_FLUSHO 0x00800000
|
||||
#define TARGET_PENDIN 0x20000000
|
||||
#define TARGET_IEXTEN 0x00000400
|
||||
|
||||
/* ioctls */
|
||||
|
||||
#define TARGET_FIOCLEX TARGET_IO('f', 1)
|
||||
#define TARGET_FIONCLEX TARGET_IO('f', 2)
|
||||
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
|
||||
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
|
||||
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
|
||||
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||
//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t)
|
||||
|
||||
#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios)
|
||||
#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios)
|
||||
#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios)
|
||||
#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios)
|
||||
|
||||
#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio)
|
||||
#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio)
|
||||
#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio)
|
||||
#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio)
|
||||
|
||||
#define TARGET_TCSBRK TARGET_IO('t', 29)
|
||||
#define TARGET_TCXONC TARGET_IO('t', 30)
|
||||
#define TARGET_TCFLSH TARGET_IO('t', 31)
|
||||
|
||||
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize)
|
||||
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize)
|
||||
#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */
|
||||
#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */
|
||||
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */
|
||||
|
||||
#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars)
|
||||
#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars)
|
||||
#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int)
|
||||
#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int)
|
||||
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
|
||||
# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
|
||||
+2
-9
@@ -6,15 +6,8 @@
|
||||
#include <signal.h>
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#include "syscall-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#include "cpu.h"
|
||||
#include "syscall.h"
|
||||
|
||||
/* This struct is used to hold certain information about the image.
|
||||
* Basically, it replicates in user space what would be certain
|
||||
|
||||
+544
-49
@@ -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);
|
||||
@@ -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,
|
||||
@@ -825,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,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
struct target_pt_regs {
|
||||
target_ulong psr;
|
||||
target_ulong pc;
|
||||
target_ulong npc;
|
||||
target_ulong y;
|
||||
target_ulong u_regs[16];
|
||||
};
|
||||
@@ -0,0 +1,220 @@
|
||||
#define TARGET_NR_exit 1 /* Common */
|
||||
#define TARGET_NR_fork 2 /* Common */
|
||||
#define TARGET_NR_read 3 /* Common */
|
||||
#define TARGET_NR_write 4 /* Common */
|
||||
#define TARGET_NR_open 5 /* Common */
|
||||
#define TARGET_NR_close 6 /* Common */
|
||||
#define TARGET_NR_wait4 7 /* Common */
|
||||
#define TARGET_NR_creat 8 /* Common */
|
||||
#define TARGET_NR_link 9 /* Common */
|
||||
#define TARGET_NR_unlink 10 /* Common */
|
||||
#define TARGET_NR_execv 11 /* SunOS Specific */
|
||||
#define TARGET_NR_chdir 12 /* Common */
|
||||
#define TARGET_NR_chown 13 /* Common */
|
||||
#define TARGET_NR_mknod 14 /* Common */
|
||||
#define TARGET_NR_chmod 15 /* Common */
|
||||
#define TARGET_NR_lchown 16 /* Common */
|
||||
#define TARGET_NR_brk 17 /* Common */
|
||||
#define TARGET_NR_perfctr 18 /* Performance counter operations */
|
||||
#define TARGET_NR_lseek 19 /* Common */
|
||||
#define TARGET_NR_getpid 20 /* Common */
|
||||
#define TARGET_NR_capget 21 /* Linux Specific */
|
||||
#define TARGET_NR_capset 22 /* Linux Specific */
|
||||
#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */
|
||||
#define TARGET_NR_getuid 24 /* Common */
|
||||
#define TARGET_NR_ptrace 26 /* Common */
|
||||
#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */
|
||||
#define TARGET_NR_sigaltstack 28 /* Common */
|
||||
#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
|
||||
#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */
|
||||
#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_access 33 /* Common */
|
||||
#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */
|
||||
#define TARGET_NR_chown32 35 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_sync 36 /* Common */
|
||||
#define TARGET_NR_kill 37 /* Common */
|
||||
#define TARGET_NR_stat 38 /* Common */
|
||||
#define TARGET_NR_sendfile 39 /* Linux Specific */
|
||||
#define TARGET_NR_lstat 40 /* Common */
|
||||
#define TARGET_NR_dup 41 /* Common */
|
||||
#define TARGET_NR_pipe 42 /* Common */
|
||||
#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */
|
||||
#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_umount2 45 /* Linux Specific */
|
||||
#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */
|
||||
#define TARGET_NR_getgid 47 /* Common */
|
||||
#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */
|
||||
#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */
|
||||
#define TARGET_NR_getegid 50 /* SunOS calls getgid() */
|
||||
#define TARGET_NR_acct 51 /* Common */
|
||||
#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */
|
||||
#define TARGET_NR_ioctl 54 /* Common */
|
||||
#define TARGET_NR_reboot 55 /* Common */
|
||||
#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_symlink 57 /* Common */
|
||||
#define TARGET_NR_readlink 58 /* Common */
|
||||
#define TARGET_NR_execve 59 /* Common */
|
||||
#define TARGET_NR_umask 60 /* Common */
|
||||
#define TARGET_NR_chroot 61 /* Common */
|
||||
#define TARGET_NR_fstat 62 /* Common */
|
||||
#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_getpagesize 64 /* Common */
|
||||
#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */
|
||||
#define TARGET_NR_vfork 66 /* Common */
|
||||
#define TARGET_NR_pread 67 /* Linux Specific */
|
||||
#define TARGET_NR_pwrite 68 /* Linux Specific */
|
||||
#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
|
||||
#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
|
||||
#define TARGET_NR_mmap 71 /* Common */
|
||||
#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
|
||||
#define TARGET_NR_munmap 73 /* Common */
|
||||
#define TARGET_NR_mprotect 74 /* Common */
|
||||
#define TARGET_NR_madvise 75 /* Common */
|
||||
#define TARGET_NR_vhangup 76 /* Common */
|
||||
#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_mincore 78 /* Common */
|
||||
#define TARGET_NR_getgroups 79 /* Common */
|
||||
#define TARGET_NR_setgroups 80 /* Common */
|
||||
#define TARGET_NR_getpgrp 81 /* Common */
|
||||
#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
|
||||
#define TARGET_NR_setitimer 83 /* Common */
|
||||
#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_swapon 85 /* Common */
|
||||
#define TARGET_NR_getitimer 86 /* Common */
|
||||
#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
|
||||
#define TARGET_NR_sethostname 88 /* Common */
|
||||
#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
|
||||
#define TARGET_NR_dup2 90 /* Common */
|
||||
#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
|
||||
#define TARGET_NR_fcntl 92 /* Common */
|
||||
#define TARGET_NR_select 93 /* Common */
|
||||
#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
|
||||
#define TARGET_NR_fsync 95 /* Common */
|
||||
#define TARGET_NR_setpriority 96 /* Common */
|
||||
#define TARGET_NR_socket 97 /* Common */
|
||||
#define TARGET_NR_connect 98 /* Common */
|
||||
#define TARGET_NR_accept 99 /* Common */
|
||||
#define TARGET_NR_getpriority 100 /* Common */
|
||||
#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigaction 102 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigpending 104 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */
|
||||
#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */
|
||||
#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
|
||||
#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
|
||||
#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
|
||||
#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
|
||||
#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
|
||||
#define TARGET_NR_recvmsg 113 /* Common */
|
||||
#define TARGET_NR_sendmsg 114 /* Common */
|
||||
#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
|
||||
#define TARGET_NR_gettimeofday 116 /* Common */
|
||||
#define TARGET_NR_getrusage 117 /* Common */
|
||||
#define TARGET_NR_getsockopt 118 /* Common */
|
||||
#define TARGET_NR_getcwd 119 /* Linux Specific */
|
||||
#define TARGET_NR_readv 120 /* Common */
|
||||
#define TARGET_NR_writev 121 /* Common */
|
||||
#define TARGET_NR_settimeofday 122 /* Common */
|
||||
#define TARGET_NR_fchown 123 /* Common */
|
||||
#define TARGET_NR_fchmod 124 /* Common */
|
||||
#define TARGET_NR_recvfrom 125 /* Common */
|
||||
#define TARGET_NR_setreuid 126 /* Common */
|
||||
#define TARGET_NR_setregid 127 /* Common */
|
||||
#define TARGET_NR_rename 128 /* Common */
|
||||
#define TARGET_NR_truncate 129 /* Common */
|
||||
#define TARGET_NR_ftruncate 130 /* Common */
|
||||
#define TARGET_NR_flock 131 /* Common */
|
||||
#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_sendto 133 /* Common */
|
||||
#define TARGET_NR_shutdown 134 /* Common */
|
||||
#define TARGET_NR_socketpair 135 /* Common */
|
||||
#define TARGET_NR_mkdir 136 /* Common */
|
||||
#define TARGET_NR_rmdir 137 /* Common */
|
||||
#define TARGET_NR_utimes 138 /* SunOS Specific */
|
||||
#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_getpeername 141 /* Common */
|
||||
#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_getrlimit 144 /* Common */
|
||||
#define TARGET_NR_setrlimit 145 /* Common */
|
||||
#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
|
||||
#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */
|
||||
#define TARGET_NR_getsockname 150 /* Common */
|
||||
#define TARGET_NR_poll 153 /* Common */
|
||||
#define TARGET_NR_getdents64 154 /* Linux specific */
|
||||
#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */
|
||||
#define TARGET_NR_statfs 157 /* Common */
|
||||
#define TARGET_NR_fstatfs 158 /* Common */
|
||||
#define TARGET_NR_umount 159 /* Common */
|
||||
#define TARGET_NR_getdomainname 162 /* SunOS Specific */
|
||||
#define TARGET_NR_setdomainname 163 /* Common */
|
||||
#define TARGET_NR_quotactl 165 /* Common */
|
||||
#define TARGET_NR_mount 167 /* Common */
|
||||
#define TARGET_NR_ustat 168 /* Common */
|
||||
#define TARGET_NR_getdents 174 /* Common */
|
||||
#define TARGET_NR_setsid 175 /* Common */
|
||||
#define TARGET_NR_fchdir 176 /* Common */
|
||||
#define TARGET_NR_sigpending 183 /* Common */
|
||||
#define TARGET_NR_query_module 184 /* Linux Specific */
|
||||
#define TARGET_NR_setpgid 185 /* Common */
|
||||
#define TARGET_NR_tkill 187 /* SunOS: fpathconf */
|
||||
#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
|
||||
#define TARGET_NR_uname 189 /* Linux Specific */
|
||||
#define TARGET_NR_init_module 190 /* Linux Specific */
|
||||
#define TARGET_NR_personality 191 /* Linux Specific */
|
||||
#define TARGET_NR_getppid 197 /* Linux Specific */
|
||||
#define TARGET_NR_sigaction 198 /* Linux Specific */
|
||||
#define TARGET_NR_sgetmask 199 /* Linux Specific */
|
||||
#define TARGET_NR_ssetmask 200 /* Linux Specific */
|
||||
#define TARGET_NR_sigsuspend 201 /* Linux Specific */
|
||||
#define TARGET_NR_oldlstat 202 /* Linux Specific */
|
||||
#define TARGET_NR_uselib 203 /* Linux Specific */
|
||||
#define TARGET_NR_readdir 204 /* Linux Specific */
|
||||
#define TARGET_NR_readahead 205 /* Linux Specific */
|
||||
#define TARGET_NR_socketcall 206 /* Linux Specific */
|
||||
#define TARGET_NR_syslog 207 /* Linux Specific */
|
||||
#define TARGET_NR_waitpid 212 /* Linux Specific */
|
||||
#define TARGET_NR_swapoff 213 /* Linux Specific */
|
||||
#define TARGET_NR_sysinfo 214 /* Linux Specific */
|
||||
#define TARGET_NR_ipc 215 /* Linux Specific */
|
||||
#define TARGET_NR_sigreturn 216 /* Linux Specific */
|
||||
#define TARGET_NR_clone 217 /* Linux Specific */
|
||||
#define TARGET_NR_adjtimex 219 /* Linux Specific */
|
||||
#define TARGET_NR_sigprocmask 220 /* Linux Specific */
|
||||
#define TARGET_NR_create_module 221 /* Linux Specific */
|
||||
#define TARGET_NR_delete_module 222 /* Linux Specific */
|
||||
#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */
|
||||
#define TARGET_NR_getpgid 224 /* Linux Specific */
|
||||
#define TARGET_NR_bdflush 225 /* Linux Specific */
|
||||
#define TARGET_NR_sysfs 226 /* Linux Specific */
|
||||
#define TARGET_NR_afs_syscall 227 /* Linux Specific */
|
||||
#define TARGET_NR_setfsuid 228 /* Linux Specific */
|
||||
#define TARGET_NR_setfsgid 229 /* Linux Specific */
|
||||
#define TARGET_NR__newselect 230 /* Linux Specific */
|
||||
#define TARGET_NR_time 231 /* Linux Specific */
|
||||
#define TARGET_NR_stime 233 /* Linux Specific */
|
||||
#define TARGET_NR__llseek 236 /* Linux Specific */
|
||||
#define TARGET_NR_mlock 237
|
||||
#define TARGET_NR_munlock 238
|
||||
#define TARGET_NR_mlockall 239
|
||||
#define TARGET_NR_munlockall 240
|
||||
#define TARGET_NR_sched_setparam 241
|
||||
#define TARGET_NR_sched_getparam 242
|
||||
#define TARGET_NR_sched_setscheduler 243
|
||||
#define TARGET_NR_sched_getscheduler 244
|
||||
#define TARGET_NR_sched_yield 245
|
||||
#define TARGET_NR_sched_get_priority_max 246
|
||||
#define TARGET_NR_sched_get_priority_min 247
|
||||
#define TARGET_NR_sched_rr_get_interval 248
|
||||
#define TARGET_NR_nanosleep 249
|
||||
#define TARGET_NR_mremap 250
|
||||
#define TARGET_NR__sysctl 251
|
||||
#define TARGET_NR_getsid 252
|
||||
#define TARGET_NR_fdatasync 253
|
||||
#define TARGET_NR_nfsservctl 254
|
||||
#define TARGET_NR_aplib 255
|
||||
#define TARGET_NR__exit TARGET_NR_exit
|
||||
@@ -0,0 +1,279 @@
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_cc characters */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VEOL 5
|
||||
#define TARGET_VEOL2 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
|
||||
/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
|
||||
* shared with eof/eol
|
||||
*/
|
||||
#define TARGET_VMIN TARGET_VEOF
|
||||
#define TARGET_VTIME TARGET_VEOL
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0x00000001
|
||||
#define TARGET_BRKINT 0x00000002
|
||||
#define TARGET_IGNPAR 0x00000004
|
||||
#define TARGET_PARMRK 0x00000008
|
||||
#define TARGET_INPCK 0x00000010
|
||||
#define TARGET_ISTRIP 0x00000020
|
||||
#define TARGET_INLCR 0x00000040
|
||||
#define TARGET_IGNCR 0x00000080
|
||||
#define TARGET_ICRNL 0x00000100
|
||||
#define TARGET_IUCLC 0x00000200
|
||||
#define TARGET_IXON 0x00000400
|
||||
#define TARGET_IXANY 0x00000800
|
||||
#define TARGET_IXOFF 0x00001000
|
||||
#define TARGET_IMAXBEL 0x00002000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0x00000001
|
||||
#define TARGET_OLCUC 0x00000002
|
||||
#define TARGET_ONLCR 0x00000004
|
||||
#define TARGET_OCRNL 0x00000008
|
||||
#define TARGET_ONOCR 0x00000010
|
||||
#define TARGET_ONLRET 0x00000020
|
||||
#define TARGET_OFILL 0x00000040
|
||||
#define TARGET_OFDEL 0x00000080
|
||||
#define TARGET_NLDLY 0x00000100
|
||||
#define TARGET_NL0 0x00000000
|
||||
#define TARGET_NL1 0x00000100
|
||||
#define TARGET_CRDLY 0x00000600
|
||||
#define TARGET_CR0 0x00000000
|
||||
#define TARGET_CR1 0x00000200
|
||||
#define TARGET_CR2 0x00000400
|
||||
#define TARGET_CR3 0x00000600
|
||||
#define TARGET_TABDLY 0x00001800
|
||||
#define TARGET_TAB0 0x00000000
|
||||
#define TARGET_TAB1 0x00000800
|
||||
#define TARGET_TAB2 0x00001000
|
||||
#define TARGET_TAB3 0x00001800
|
||||
#define TARGET_XTABS 0x00001800
|
||||
#define TARGET_BSDLY 0x00002000
|
||||
#define TARGET_BS0 0x00000000
|
||||
#define TARGET_BS1 0x00002000
|
||||
#define TARGET_VTDLY 0x00004000
|
||||
#define TARGET_VT0 0x00000000
|
||||
#define TARGET_VT1 0x00004000
|
||||
#define TARGET_FFDLY 0x00008000
|
||||
#define TARGET_FF0 0x00000000
|
||||
#define TARGET_FF1 0x00008000
|
||||
#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */
|
||||
#define TARGET_WRAP 0x00020000 /* SUNOS specific */
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0x0000100f
|
||||
#define TARGET_B0 0x00000000 /* hang up */
|
||||
#define TARGET_B50 0x00000001
|
||||
#define TARGET_B75 0x00000002
|
||||
#define TARGET_B110 0x00000003
|
||||
#define TARGET_B134 0x00000004
|
||||
#define TARGET_B150 0x00000005
|
||||
#define TARGET_B200 0x00000006
|
||||
#define TARGET_B300 0x00000007
|
||||
#define TARGET_B600 0x00000008
|
||||
#define TARGET_B1200 0x00000009
|
||||
#define TARGET_B1800 0x0000000a
|
||||
#define TARGET_B2400 0x0000000b
|
||||
#define TARGET_B4800 0x0000000c
|
||||
#define TARGET_B9600 0x0000000d
|
||||
#define TARGET_B19200 0x0000000e
|
||||
#define TARGET_B38400 0x0000000f
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0x00000030
|
||||
#define TARGET_CS5 0x00000000
|
||||
#define TARGET_CS6 0x00000010
|
||||
#define TARGET_CS7 0x00000020
|
||||
#define TARGET_CS8 0x00000030
|
||||
#define TARGET_CSTOPB 0x00000040
|
||||
#define TARGET_CREAD 0x00000080
|
||||
#define TARGET_PARENB 0x00000100
|
||||
#define TARGET_PARODD 0x00000200
|
||||
#define TARGET_HUPCL 0x00000400
|
||||
#define TARGET_CLOCAL 0x00000800
|
||||
#define TARGET_CBAUDEX 0x00001000
|
||||
/* We'll never see these speeds with the Zilogs, but for completeness... */
|
||||
#define TARGET_B57600 0x00001001
|
||||
#define TARGET_B115200 0x00001002
|
||||
#define TARGET_B230400 0x00001003
|
||||
#define TARGET_B460800 0x00001004
|
||||
/* This is what we can do with the Zilogs. */
|
||||
#define TARGET_B76800 0x00001005
|
||||
/* This is what we can do with the SAB82532. */
|
||||
#define TARGET_B153600 0x00001006
|
||||
#define TARGET_B307200 0x00001007
|
||||
#define TARGET_B614400 0x00001008
|
||||
#define TARGET_B921600 0x00001009
|
||||
/* And these are the rest... */
|
||||
#define TARGET_B500000 0x0000100a
|
||||
#define TARGET_B576000 0x0000100b
|
||||
#define TARGET_B1000000 0x0000100c
|
||||
#define TARGET_B1152000 0x0000100d
|
||||
#define TARGET_B1500000 0x0000100e
|
||||
#define TARGET_B2000000 0x0000100f
|
||||
/* These have totally bogus values and nobody uses them
|
||||
so far. Later on we'd have to use say 0x10000x and
|
||||
adjust CBAUD constant and drivers accordingly.
|
||||
#define B2500000 0x00001010
|
||||
#define B3000000 0x00001011
|
||||
#define B3500000 0x00001012
|
||||
#define B4000000 0x00001013 */
|
||||
#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */
|
||||
#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */
|
||||
#define TARGET_CRTSCTS 0x80000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0x00000001
|
||||
#define TARGET_ICANON 0x00000002
|
||||
#define TARGET_XCASE 0x00000004
|
||||
#define TARGET_ECHO 0x00000008
|
||||
#define TARGET_ECHOE 0x00000010
|
||||
#define TARGET_ECHOK 0x00000020
|
||||
#define TARGET_ECHONL 0x00000040
|
||||
#define TARGET_NOFLSH 0x00000080
|
||||
#define TARGET_TOSTOP 0x00000100
|
||||
#define TARGET_ECHOCTL 0x00000200
|
||||
#define TARGET_ECHOPRT 0x00000400
|
||||
#define TARGET_ECHOKE 0x00000800
|
||||
#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */
|
||||
#define TARGET_FLUSHO 0x00002000
|
||||
#define TARGET_PENDIN 0x00004000
|
||||
#define TARGET_IEXTEN 0x00008000
|
||||
|
||||
/* ioctls */
|
||||
|
||||
/* Big T */
|
||||
#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio)
|
||||
#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio)
|
||||
#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio)
|
||||
#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio)
|
||||
#define TARGET_TCSBRK TARGET_IO('T', 5)
|
||||
#define TARGET_TCXONC TARGET_IO('T', 6)
|
||||
#define TARGET_TCFLSH TARGET_IO('T', 7)
|
||||
#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios)
|
||||
#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios)
|
||||
#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios)
|
||||
#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios)
|
||||
|
||||
/* Note that all the ioctls that are not available in Linux have a
|
||||
* double underscore on the front to: a) avoid some programs to
|
||||
* thing we support some ioctls under Linux (autoconfiguration stuff)
|
||||
*/
|
||||
/* Little t */
|
||||
#define TARGET_TIOCGETD TARGET_IOR('t', 0, int)
|
||||
#define TARGET_TIOCSETD TARGET_IOW('t', 1, int)
|
||||
//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
|
||||
//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
|
||||
//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
|
||||
//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
|
||||
//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
|
||||
//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
|
||||
#define TARGET_TIOCEXCL TARGET_IO('t', 13)
|
||||
#define TARGET_TIOCNXCL TARGET_IO('t', 14)
|
||||
//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
|
||||
//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
|
||||
//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
|
||||
//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
|
||||
//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
|
||||
//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
|
||||
//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
|
||||
#define TARGET_TIOCCONS TARGET_IO('t', 36)
|
||||
//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
|
||||
//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
|
||||
#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int)
|
||||
#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int)
|
||||
//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
|
||||
#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
|
||||
#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize)
|
||||
//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
|
||||
#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
|
||||
#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int)
|
||||
#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int)
|
||||
#define TARGET_TIOCMSET TARGET_IOW('t', 109, int)
|
||||
#define TARGET_TIOCSTART TARGET_IO('t', 110)
|
||||
#define TARGET_TIOCSTOP TARGET_IO('t', 111)
|
||||
#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
|
||||
#define TARGET_TIOCNOTTY TARGET_IO('t', 113)
|
||||
#define TARGET_TIOCSTI TARGET_IOW('t', 114, char)
|
||||
#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)
|
||||
//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
|
||||
//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
|
||||
/* 118 is the non-posix setpgrp tty ioctl */
|
||||
/* 119 is the non-posix getpgrp tty ioctl */
|
||||
//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */
|
||||
//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */
|
||||
#define TARGET_TIOCCBRK TARGET_IO('t', 122)
|
||||
#define TARGET_TIOCSBRK TARGET_IO('t', 123)
|
||||
//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */
|
||||
//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */
|
||||
//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */
|
||||
//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */
|
||||
//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */
|
||||
//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */
|
||||
#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int)
|
||||
#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int)
|
||||
#define TARGET_TIOCSCTTY TARGET_IO('t', 132)
|
||||
#define TARGET_TIOCGSID TARGET_IOR('t', 133, int)
|
||||
/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
|
||||
|
||||
/* Little f */
|
||||
#define TARGET_FIOCLEX TARGET_IO('f', 1)
|
||||
#define TARGET_FIONCLEX TARGET_IO('f', 2)
|
||||
#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
|
||||
#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
|
||||
#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
|
||||
#define TARGET_TIOCINQ TARGET_FIONREAD
|
||||
|
||||
/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
|
||||
* someday. This is completely bogus, I know...
|
||||
*/
|
||||
//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */
|
||||
//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */
|
||||
|
||||
/* Linux specific, no SunOS equivalent. */
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TCSBRKP 0x5425
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* Wait input */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
|
||||
|
||||
+440
-134
@@ -41,6 +41,7 @@
|
||||
#include <sys/uio.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/times.h>
|
||||
#include <utime.h>
|
||||
//#include <sys/user.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
@@ -64,10 +65,138 @@
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
/* 16 bit uid wrappers emulation */
|
||||
#define USE_UID16
|
||||
#endif
|
||||
|
||||
//#include <linux/msdos_fs.h>
|
||||
#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
|
||||
@@ -110,6 +239,27 @@ extern int setresgid(gid_t, gid_t, gid_t);
|
||||
extern int getresgid(gid_t *, gid_t *, gid_t *);
|
||||
extern int setgroups(int, gid_t *);
|
||||
|
||||
#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;\
|
||||
})
|
||||
static inline long get_errno(long ret)
|
||||
{
|
||||
if (ret == -1)
|
||||
@@ -210,6 +360,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)
|
||||
{
|
||||
@@ -1124,6 +1289,17 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
|
||||
newsp = env->regs[13];
|
||||
new_env->regs[13] = newsp;
|
||||
new_env->regs[0] = 0;
|
||||
#elif defined(TARGET_SPARC)
|
||||
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
|
||||
#elif defined(TARGET_PPC)
|
||||
if (!newsp)
|
||||
newsp = env->gpr[1];
|
||||
new_env->gpr[1] = newsp;
|
||||
{
|
||||
int i;
|
||||
for (i = 7; i < 32; i++)
|
||||
new_env->gpr[i] = 0;
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -1184,11 +1360,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_UID16
|
||||
|
||||
#define high2lowuid(x) (x)
|
||||
#define high2lowgid(x) (x)
|
||||
#define low2highuid(x) (x)
|
||||
#define low2highgid(x) (x)
|
||||
static inline int high2lowuid(int uid)
|
||||
{
|
||||
if (uid > 65535)
|
||||
return 65534;
|
||||
else
|
||||
return uid;
|
||||
}
|
||||
|
||||
static inline int high2lowgid(int gid)
|
||||
{
|
||||
if (gid > 65535)
|
||||
return 65534;
|
||||
else
|
||||
return gid;
|
||||
}
|
||||
|
||||
static inline int low2highuid(int uid)
|
||||
{
|
||||
if ((int16_t)uid == -1)
|
||||
return -1;
|
||||
else
|
||||
return uid;
|
||||
}
|
||||
|
||||
static inline int low2highgid(int gid)
|
||||
{
|
||||
if ((int16_t)gid == -1)
|
||||
return -1;
|
||||
else
|
||||
return gid;
|
||||
}
|
||||
|
||||
#endif /* USE_UID16 */
|
||||
|
||||
void syscall_init(void)
|
||||
{
|
||||
@@ -1230,7 +1436,7 @@ void syscall_init(void)
|
||||
ie++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6)
|
||||
{
|
||||
@@ -1239,7 +1445,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
struct kernel_statfs *stfs;
|
||||
|
||||
#ifdef DEBUG
|
||||
gemu_log("syscall %d\n", num);
|
||||
gemu_log("syscall %d", num);
|
||||
#endif
|
||||
switch(num) {
|
||||
case TARGET_NR_exit:
|
||||
@@ -1331,13 +1537,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_chmod:
|
||||
ret = get_errno(chmod((const char *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_lchown:
|
||||
ret = get_errno(chown((const char *)arg1, arg2, arg3));
|
||||
break;
|
||||
#ifdef TARGET_NR_break
|
||||
case TARGET_NR_break:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_oldstat
|
||||
case TARGET_NR_oldstat:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_lseek:
|
||||
ret = get_errno(lseek(arg1, arg2, arg3));
|
||||
break;
|
||||
@@ -1350,12 +1557,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_umount:
|
||||
ret = get_errno(umount((const char *)arg1));
|
||||
break;
|
||||
case TARGET_NR_setuid:
|
||||
ret = get_errno(setuid(low2highuid(arg1)));
|
||||
break;
|
||||
case TARGET_NR_getuid:
|
||||
ret = get_errno(getuid());
|
||||
break;
|
||||
case TARGET_NR_stime:
|
||||
{
|
||||
int *time_ptr = (int *)arg1;
|
||||
@@ -1369,25 +1570,40 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_alarm:
|
||||
ret = alarm(arg1);
|
||||
break;
|
||||
#ifdef TARGET_NR_oldfstat
|
||||
case TARGET_NR_oldfstat:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_pause:
|
||||
ret = get_errno(pause());
|
||||
break;
|
||||
case TARGET_NR_utime:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct utimbuf tbuf;
|
||||
struct target_utimbuf *target_tbuf = (void *)arg2;
|
||||
tbuf.actime = tswapl(target_tbuf->actime);
|
||||
tbuf.modtime = tswapl(target_tbuf->modtime);
|
||||
ret = get_errno(utime((const char *)arg1, &tbuf));
|
||||
}
|
||||
break;
|
||||
#ifdef TARGET_NR_stty
|
||||
case TARGET_NR_stty:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_gtty
|
||||
case TARGET_NR_gtty:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_access:
|
||||
ret = get_errno(access((const char *)arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_nice:
|
||||
ret = get_errno(nice(arg1));
|
||||
break;
|
||||
#ifdef TARGET_NR_ftime
|
||||
case TARGET_NR_ftime:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_sync:
|
||||
sync();
|
||||
ret = 0;
|
||||
@@ -1423,51 +1639,52 @@ 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;
|
||||
#ifdef TARGET_NR_prof
|
||||
case TARGET_NR_prof:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_setgid:
|
||||
ret = get_errno(setgid(low2highgid(arg1)));
|
||||
break;
|
||||
case TARGET_NR_getgid:
|
||||
ret = get_errno(getgid());
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_signal:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_geteuid:
|
||||
ret = get_errno(geteuid());
|
||||
break;
|
||||
case TARGET_NR_getegid:
|
||||
ret = get_errno(getegid());
|
||||
break;
|
||||
|
||||
case TARGET_NR_acct:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_umount2:
|
||||
ret = get_errno(umount2((const char *)arg1, arg2));
|
||||
break;
|
||||
#ifdef TARGET_NR_lock
|
||||
case TARGET_NR_lock:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_ioctl:
|
||||
ret = do_ioctl(arg1, arg2, arg3);
|
||||
break;
|
||||
case TARGET_NR_fcntl:
|
||||
ret = get_errno(do_fcntl(arg1, arg2, arg3));
|
||||
break;
|
||||
#ifdef TARGET_NR_mpx
|
||||
case TARGET_NR_mpx:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_setpgid:
|
||||
ret = get_errno(setpgid(arg1, arg2));
|
||||
break;
|
||||
#ifdef TARGET_NR_ulimit
|
||||
case TARGET_NR_ulimit:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_oldolduname
|
||||
case TARGET_NR_oldolduname:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_umask:
|
||||
ret = get_errno(umask(arg1));
|
||||
break;
|
||||
@@ -1672,12 +1889,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
/* NOTE: ret is eax, so not transcoding must be done */
|
||||
ret = do_rt_sigreturn(cpu_env);
|
||||
break;
|
||||
case TARGET_NR_setreuid:
|
||||
ret = get_errno(setreuid(arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_setregid:
|
||||
ret = get_errno(setregid(arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_sethostname:
|
||||
ret = get_errno(sethostname((const char *)arg1, arg2));
|
||||
break;
|
||||
@@ -1734,41 +1945,25 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
ret = get_errno(settimeofday(&tv, NULL));
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_getgroups:
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint16_t *target_grouplist = (void *)arg2;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (!is_error(ret)) {
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
target_grouplist[i] = tswap16(grouplist[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_setgroups:
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint16_t *target_grouplist = (void *)arg2;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
grouplist[i] = tswap16(target_grouplist[i]);
|
||||
ret = get_errno(setgroups(gidsetsize, grouplist));
|
||||
}
|
||||
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;
|
||||
#ifdef TARGET_NR_oldlstat
|
||||
case TARGET_NR_oldlstat:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_readlink:
|
||||
ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3));
|
||||
break;
|
||||
@@ -1781,8 +1976,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,17 +1991,23 @@ 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:
|
||||
#if defined(TARGET_SPARC)
|
||||
#define MMAP_SHIFT 12
|
||||
#else
|
||||
#define MMAP_SHIFT TARGET_PAGE_BITS
|
||||
#endif
|
||||
ret = get_errno(target_mmap(arg1, arg2, arg3,
|
||||
target_to_host_bitmask(arg4, mmap_flags_tbl),
|
||||
arg5,
|
||||
arg6 << TARGET_PAGE_BITS));
|
||||
arg6 << MMAP_SHIFT));
|
||||
break;
|
||||
case TARGET_NR_munmap:
|
||||
ret = get_errno(target_munmap(arg1, arg2));
|
||||
@@ -1841,17 +2042,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_fchmod:
|
||||
ret = get_errno(fchmod(arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_fchown:
|
||||
ret = get_errno(fchown(arg1, arg2, arg3));
|
||||
break;
|
||||
case TARGET_NR_getpriority:
|
||||
ret = get_errno(getpriority(arg1, arg2));
|
||||
break;
|
||||
case TARGET_NR_setpriority:
|
||||
ret = get_errno(setpriority(arg1, arg2, arg3));
|
||||
break;
|
||||
#ifdef TARGET_NR_profil
|
||||
case TARGET_NR_profil:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_statfs:
|
||||
stfs = (void *)arg2;
|
||||
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
|
||||
@@ -1873,8 +2073,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
stfs = (void *)arg2;
|
||||
ret = get_errno(sys_fstatfs(arg1, stfs));
|
||||
goto convert_statfs;
|
||||
#ifdef TARGET_NR_ioperm
|
||||
case TARGET_NR_ioperm:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_socketcall:
|
||||
ret = do_socketcall(arg1, (int32_t *)arg2);
|
||||
break;
|
||||
@@ -1932,10 +2134,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
struct target_stat *target_st = (void *)arg2;
|
||||
target_st->st_dev = tswap16(st.st_dev);
|
||||
target_st->st_ino = tswapl(st.st_ino);
|
||||
#if defined(TARGET_PPC)
|
||||
target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
|
||||
target_st->st_uid = tswap32(st.st_uid);
|
||||
target_st->st_gid = tswap32(st.st_gid);
|
||||
#else
|
||||
target_st->st_mode = tswap16(st.st_mode);
|
||||
target_st->st_nlink = tswap16(st.st_nlink);
|
||||
target_st->st_uid = tswap16(st.st_uid);
|
||||
target_st->st_gid = tswap16(st.st_gid);
|
||||
#endif
|
||||
target_st->st_nlink = tswap16(st.st_nlink);
|
||||
target_st->st_rdev = tswap16(st.st_rdev);
|
||||
target_st->st_size = tswapl(st.st_size);
|
||||
target_st->st_blksize = tswapl(st.st_blksize);
|
||||
@@ -1946,15 +2154,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifdef TARGET_NR_olduname
|
||||
case TARGET_NR_olduname:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_iopl
|
||||
case TARGET_NR_iopl:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_vhangup:
|
||||
ret = get_errno(vhangup());
|
||||
break;
|
||||
#ifdef TARGET_NR_idle
|
||||
case TARGET_NR_idle:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_wait4:
|
||||
{
|
||||
int status;
|
||||
@@ -2035,12 +2249,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
break;
|
||||
case TARGET_NR_afs_syscall:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_setfsuid:
|
||||
ret = get_errno(setfsuid(arg1));
|
||||
break;
|
||||
case TARGET_NR_setfsgid:
|
||||
ret = get_errno(setfsgid(arg1));
|
||||
break;
|
||||
case TARGET_NR__llseek:
|
||||
{
|
||||
int64_t res;
|
||||
@@ -2264,50 +2472,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
req.tv_sec = tswapl(target_req->tv_sec);
|
||||
req.tv_nsec = tswapl(target_req->tv_nsec);
|
||||
ret = get_errno(nanosleep(&req, &rem));
|
||||
if (target_rem) {
|
||||
if (is_error(ret) && target_rem) {
|
||||
target_rem->tv_sec = tswapl(rem.tv_sec);
|
||||
target_rem->tv_nsec = tswapl(rem.tv_nsec);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_setresuid:
|
||||
ret = get_errno(setresuid(low2highuid(arg1),
|
||||
low2highuid(arg2),
|
||||
low2highuid(arg3)));
|
||||
break;
|
||||
case TARGET_NR_getresuid:
|
||||
{
|
||||
int ruid, euid, suid;
|
||||
ret = get_errno(getresuid(&ruid, &euid, &suid));
|
||||
if (!is_error(ret)) {
|
||||
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
|
||||
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
|
||||
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_setresgid:
|
||||
ret = get_errno(setresgid(low2highgid(arg1),
|
||||
low2highgid(arg2),
|
||||
low2highgid(arg3)));
|
||||
break;
|
||||
case TARGET_NR_getresgid:
|
||||
{
|
||||
int rgid, egid, sgid;
|
||||
ret = get_errno(getresgid(&rgid, &egid, &sgid));
|
||||
if (!is_error(ret)) {
|
||||
*(uint16_t *)arg1 = high2lowgid(tswap16(rgid));
|
||||
*(uint16_t *)arg2 = high2lowgid(tswap16(egid));
|
||||
*(uint16_t *)arg3 = high2lowgid(tswap16(sgid));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_query_module:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_nfsservctl:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_prctl:
|
||||
goto unimplemented;
|
||||
#ifdef TARGET_NR_pread
|
||||
case TARGET_NR_pread:
|
||||
page_unprotect_range((void *)arg2, arg3);
|
||||
ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
|
||||
@@ -2315,9 +2492,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_pwrite:
|
||||
ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
|
||||
break;
|
||||
case TARGET_NR_chown:
|
||||
ret = get_errno(chown((const char *)arg1, arg2, arg3));
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_getcwd:
|
||||
ret = get_errno(sys_getcwd1((char *)arg1, arg2));
|
||||
break;
|
||||
@@ -2329,13 +2504,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
goto unimplemented;
|
||||
case TARGET_NR_sendfile:
|
||||
goto unimplemented;
|
||||
#ifdef TARGET_NR_getpmsg
|
||||
case TARGET_NR_getpmsg:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_putpmsg
|
||||
case TARGET_NR_putpmsg:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
case TARGET_NR_vfork:
|
||||
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
|
||||
break;
|
||||
#ifdef TARGET_NR_ugetrlimit
|
||||
case TARGET_NR_ugetrlimit:
|
||||
{
|
||||
struct rlimit rlim;
|
||||
@@ -2347,6 +2527,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TARGET_NR_truncate64:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_ftruncate64:
|
||||
@@ -2364,27 +2545,137 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
if (!is_error(ret)) {
|
||||
struct target_stat64 *target_st = (void *)arg2;
|
||||
memset(target_st, 0, sizeof(struct target_stat64));
|
||||
target_st->st_dev = tswap16(st.st_dev);
|
||||
target_st->st_ino = tswap64(st.st_ino);
|
||||
put_user(st.st_dev, &target_st->st_dev);
|
||||
put_user(st.st_ino, &target_st->st_ino);
|
||||
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
|
||||
target_st->__st_ino = tswapl(st.st_ino);
|
||||
put_user(st.st_ino, &target_st->__st_ino);
|
||||
#endif
|
||||
target_st->st_mode = tswap32(st.st_mode);
|
||||
target_st->st_nlink = tswap32(st.st_nlink);
|
||||
target_st->st_uid = tswapl(st.st_uid);
|
||||
target_st->st_gid = tswapl(st.st_gid);
|
||||
target_st->st_rdev = tswap16(st.st_rdev);
|
||||
put_user(st.st_mode, &target_st->st_mode);
|
||||
put_user(st.st_nlink, &target_st->st_nlink);
|
||||
put_user(st.st_uid, &target_st->st_uid);
|
||||
put_user(st.st_gid, &target_st->st_gid);
|
||||
put_user(st.st_rdev, &target_st->st_rdev);
|
||||
/* XXX: better use of kernel struct */
|
||||
target_st->st_size = tswap64(st.st_size);
|
||||
target_st->st_blksize = tswapl(st.st_blksize);
|
||||
target_st->st_blocks = tswapl(st.st_blocks);
|
||||
target_st->target_st_atime = tswapl(st.st_atime);
|
||||
target_st->target_st_mtime = tswapl(st.st_mtime);
|
||||
target_st->target_st_ctime = tswapl(st.st_ctime);
|
||||
put_user(st.st_size, &target_st->st_size);
|
||||
put_user(st.st_blksize, &target_st->st_blksize);
|
||||
put_user(st.st_blocks, &target_st->st_blocks);
|
||||
put_user(st.st_atime, &target_st->target_st_atime);
|
||||
put_user(st.st_mtime, &target_st->target_st_mtime);
|
||||
put_user(st.st_ctime, &target_st->target_st_ctime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_UID16
|
||||
case TARGET_NR_lchown:
|
||||
ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
|
||||
break;
|
||||
case TARGET_NR_getuid:
|
||||
ret = get_errno(high2lowuid(getuid()));
|
||||
break;
|
||||
case TARGET_NR_getgid:
|
||||
ret = get_errno(high2lowgid(getgid()));
|
||||
break;
|
||||
case TARGET_NR_geteuid:
|
||||
ret = get_errno(high2lowuid(geteuid()));
|
||||
break;
|
||||
case TARGET_NR_getegid:
|
||||
ret = get_errno(high2lowgid(getegid()));
|
||||
break;
|
||||
case TARGET_NR_setreuid:
|
||||
ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
|
||||
break;
|
||||
case TARGET_NR_setregid:
|
||||
ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
|
||||
break;
|
||||
case TARGET_NR_getgroups:
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint16_t *target_grouplist = (void *)arg2;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (!is_error(ret)) {
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
target_grouplist[i] = tswap16(grouplist[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_setgroups:
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint16_t *target_grouplist = (void *)arg2;
|
||||
gid_t *grouplist;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
grouplist[i] = tswap16(target_grouplist[i]);
|
||||
ret = get_errno(setgroups(gidsetsize, grouplist));
|
||||
}
|
||||
break;
|
||||
case TARGET_NR_fchown:
|
||||
ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
|
||||
break;
|
||||
#ifdef TARGET_NR_setresuid
|
||||
case TARGET_NR_setresuid:
|
||||
ret = get_errno(setresuid(low2highuid(arg1),
|
||||
low2highuid(arg2),
|
||||
low2highuid(arg3)));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresuid
|
||||
case TARGET_NR_getresuid:
|
||||
{
|
||||
int ruid, euid, suid;
|
||||
ret = get_errno(getresuid(&ruid, &euid, &suid));
|
||||
if (!is_error(ret)) {
|
||||
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
|
||||
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
|
||||
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresgid
|
||||
case TARGET_NR_setresgid:
|
||||
ret = get_errno(setresgid(low2highgid(arg1),
|
||||
low2highgid(arg2),
|
||||
low2highgid(arg3)));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getresgid
|
||||
case TARGET_NR_getresgid:
|
||||
{
|
||||
int rgid, egid, sgid;
|
||||
ret = get_errno(getresgid(&rgid, &egid, &sgid));
|
||||
if (!is_error(ret)) {
|
||||
*(uint16_t *)arg1 = tswap16(high2lowgid(rgid));
|
||||
*(uint16_t *)arg2 = tswap16(high2lowgid(egid));
|
||||
*(uint16_t *)arg3 = tswap16(high2lowgid(sgid));
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_chown:
|
||||
ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3)));
|
||||
break;
|
||||
case TARGET_NR_setuid:
|
||||
ret = get_errno(setuid(low2highuid(arg1)));
|
||||
break;
|
||||
case TARGET_NR_setgid:
|
||||
ret = get_errno(setgid(low2highgid(arg1)));
|
||||
break;
|
||||
case TARGET_NR_setfsuid:
|
||||
ret = get_errno(setfsuid(arg1));
|
||||
break;
|
||||
case TARGET_NR_setfsgid:
|
||||
ret = get_errno(setfsgid(arg1));
|
||||
break;
|
||||
#endif /* USE_UID16 */
|
||||
|
||||
case TARGET_NR_lchown32:
|
||||
ret = get_errno(lchown((const char *)arg1, arg2, arg3));
|
||||
break;
|
||||
@@ -2456,6 +2747,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_setfsgid32:
|
||||
ret = get_errno(setfsgid(arg1));
|
||||
break;
|
||||
|
||||
case TARGET_NR_pivot_root:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_mincore:
|
||||
@@ -2496,13 +2788,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef TARGET_NR_security
|
||||
case TARGET_NR_security:
|
||||
goto unimplemented;
|
||||
#endif
|
||||
#ifdef TARGET_NR_getpagesize
|
||||
case TARGET_NR_getpagesize:
|
||||
ret = TARGET_PAGE_SIZE;
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_gettid:
|
||||
ret = get_errno(gettid());
|
||||
break;
|
||||
case TARGET_NR_readahead:
|
||||
goto unimplemented;
|
||||
#ifdef TARGET_NR_setxattr
|
||||
case TARGET_NR_setxattr:
|
||||
case TARGET_NR_lsetxattr:
|
||||
case TARGET_NR_fsetxattr:
|
||||
@@ -2516,9 +2816,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
case TARGET_NR_lremovexattr:
|
||||
case TARGET_NR_fremovexattr:
|
||||
goto unimplemented_nowarn;
|
||||
#endif
|
||||
#ifdef TARGET_NR_set_thread_area
|
||||
case TARGET_NR_set_thread_area:
|
||||
case TARGET_NR_get_thread_area:
|
||||
goto unimplemented_nowarn;
|
||||
#endif
|
||||
default:
|
||||
unimplemented:
|
||||
gemu_log("qemu: Unsupported syscall: %d\n", num);
|
||||
@@ -2527,6 +2830,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
#ifdef DEBUG
|
||||
gemu_log(" = %ld\n", ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
+141
-492
@@ -4,284 +4,7 @@
|
||||
most of them stay the same, so we handle it by puting ifdefs if
|
||||
necessary */
|
||||
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
#define TARGET_NR_getdents64 217
|
||||
#define TARGET_NR_pivot_root 218
|
||||
#define TARGET_NR_mincore 219
|
||||
#define TARGET_NR_madvise 220
|
||||
#endif
|
||||
|
||||
#define TARGET_NR_fcntl64 221
|
||||
#define TARGET_NR_security 223 /* syscall for security modules */
|
||||
#define TARGET_NR_gettid 224
|
||||
#define TARGET_NR_readahead 225
|
||||
#define TARGET_NR_setxattr 226
|
||||
#define TARGET_NR_lsetxattr 227
|
||||
#define TARGET_NR_fsetxattr 228
|
||||
#define TARGET_NR_getxattr 229
|
||||
#define TARGET_NR_lgetxattr 230
|
||||
#define TARGET_NR_fgetxattr 231
|
||||
#define TARGET_NR_listxattr 232
|
||||
#define TARGET_NR_llistxattr 233
|
||||
#define TARGET_NR_flistxattr 234
|
||||
#define TARGET_NR_removexattr 235
|
||||
#define TARGET_NR_lremovexattr 236
|
||||
#define TARGET_NR_fremovexattr 237
|
||||
#define TARGET_NR_tkill 238
|
||||
#define TARGET_NR_sendfile64 239
|
||||
#define TARGET_NR_futex 240
|
||||
#define TARGET_NR_sched_setaffinity 241
|
||||
#define TARGET_NR_sched_getaffinity 242
|
||||
#define TARGET_NR_set_thread_area 243
|
||||
#define TARGET_NR_get_thread_area 244
|
||||
#define TARGET_NR_io_setup 245
|
||||
#define TARGET_NR_io_destroy 246
|
||||
#define TARGET_NR_io_getevents 247
|
||||
#define TARGET_NR_io_submit 248
|
||||
#define TARGET_NR_io_cancel 249
|
||||
#define TARGET_NR_fadvise64 250
|
||||
|
||||
#define TARGET_NR_exit_group 252
|
||||
#define TARGET_NR_lookup_dcookie 253
|
||||
#define TARGET_NR_epoll_create 254
|
||||
#define TARGET_NR_epoll_ctl 255
|
||||
#define TARGET_NR_epoll_wait 256
|
||||
#define TARGET_NR_remap_file_pages 257
|
||||
#define TARGET_NR_set_tid_address 258
|
||||
#define TARGET_NR_timer_create 259
|
||||
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
|
||||
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
|
||||
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
|
||||
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
|
||||
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
|
||||
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
|
||||
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
|
||||
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
|
||||
#include "syscall_nr.h"
|
||||
|
||||
#define SOCKOP_socket 1
|
||||
#define SOCKOP_bind 2
|
||||
@@ -321,7 +44,7 @@
|
||||
#define TARGET_IOC_WRITE 1U
|
||||
#define TARGET_IOC_READ 2U
|
||||
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC)
|
||||
|
||||
#define TARGET_IOC_SIZEBITS 13
|
||||
#define TARGET_IOC_DIRBITS 3
|
||||
@@ -383,6 +106,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 +115,17 @@ struct target_tms {
|
||||
target_clock_t tms_cstime;
|
||||
};
|
||||
|
||||
struct target_utimbuf {
|
||||
target_long actime;
|
||||
target_long modtime;
|
||||
};
|
||||
|
||||
struct target_sel_arg_struct {
|
||||
target_long n;
|
||||
target_long inp, outp, exp;
|
||||
target_long tvp;
|
||||
};
|
||||
|
||||
struct target_iovec {
|
||||
target_long iov_base; /* Starting address */
|
||||
target_long iov_len; /* Number of bytes */
|
||||
@@ -533,8 +269,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,
|
||||
@@ -543,7 +279,7 @@ struct target_sigaction;
|
||||
int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
struct target_sigaction *oact);
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
|
||||
|
||||
#define TARGET_SA_NOCLDSTOP 0x00000001
|
||||
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
|
||||
@@ -584,6 +320,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 */
|
||||
@@ -926,220 +664,26 @@ struct target_pollfd {
|
||||
#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
|
||||
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
|
||||
/* 0x54 is just a magic number to make these relatively unique ('T') */
|
||||
|
||||
#define TARGET_TCGETS 0x5401
|
||||
#define TARGET_TCSETS 0x5402
|
||||
#define TARGET_TCSETSW 0x5403
|
||||
#define TARGET_TCSETSF 0x5404
|
||||
#define TARGET_TCGETA 0x5405
|
||||
#define TARGET_TCSETA 0x5406
|
||||
#define TARGET_TCSETAW 0x5407
|
||||
#define TARGET_TCSETAF 0x5408
|
||||
#define TARGET_TCSBRK 0x5409
|
||||
#define TARGET_TCXONC 0x540A
|
||||
#define TARGET_TCFLSH 0x540B
|
||||
#define TARGET_TIOCEXCL 0x540C
|
||||
#define TARGET_TIOCNXCL 0x540D
|
||||
#define TARGET_TIOCSCTTY 0x540E
|
||||
#define TARGET_TIOCGPGRP 0x540F
|
||||
#define TARGET_TIOCSPGRP 0x5410
|
||||
#define TARGET_TIOCOUTQ 0x5411
|
||||
#define TARGET_TIOCSTI 0x5412
|
||||
#define TARGET_TIOCGWINSZ 0x5413
|
||||
#define TARGET_TIOCSWINSZ 0x5414
|
||||
#define TARGET_TIOCMGET 0x5415
|
||||
#define TARGET_TIOCMBIS 0x5416
|
||||
#define TARGET_TIOCMBIC 0x5417
|
||||
#define TARGET_TIOCMSET 0x5418
|
||||
#define TARGET_TIOCGSOFTCAR 0x5419
|
||||
#define TARGET_TIOCSSOFTCAR 0x541A
|
||||
#define TARGET_FIONREAD 0x541B
|
||||
#define TARGET_TIOCINQ FIONREAD
|
||||
#define TARGET_TIOCLINUX 0x541C
|
||||
#define TARGET_TIOCCONS 0x541D
|
||||
#define TARGET_TIOCGSERIAL 0x541E
|
||||
#define TARGET_TIOCSSERIAL 0x541F
|
||||
#define TARGET_TIOCPKT 0x5420
|
||||
#define TARGET_FIONBIO 0x5421
|
||||
#define TARGET_TIOCNOTTY 0x5422
|
||||
#define TARGET_TIOCSETD 0x5423
|
||||
#define TARGET_TIOCGETD 0x5424
|
||||
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
|
||||
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
|
||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||
|
||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define TARGET_FIOCLEX 0x5451
|
||||
#define TARGET_FIOASYNC 0x5452
|
||||
#define TARGET_TIOCSERCONFIG 0x5453
|
||||
#define TARGET_TIOCSERGWILD 0x5454
|
||||
#define TARGET_TIOCSERSWILD 0x5455
|
||||
#define TARGET_TIOCGLCKTRMIOS 0x5456
|
||||
#define TARGET_TIOCSLCKTRMIOS 0x5457
|
||||
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
|
||||
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
|
||||
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
|
||||
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
|
||||
|
||||
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
|
||||
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
|
||||
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
|
||||
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TARGET_TIOCPKT_DATA 0
|
||||
#define TARGET_TIOCPKT_FLUSHREAD 1
|
||||
#define TARGET_TIOCPKT_FLUSHWRITE 2
|
||||
#define TARGET_TIOCPKT_STOP 4
|
||||
#define TARGET_TIOCPKT_START 8
|
||||
#define TARGET_TIOCPKT_NOSTOP 16
|
||||
#define TARGET_TIOCPKT_DOSTOP 32
|
||||
|
||||
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
|
||||
|
||||
/* from asm/termbits.h */
|
||||
|
||||
#define TARGET_NCCS 19
|
||||
|
||||
struct target_termios {
|
||||
unsigned int c_iflag; /* input mode flags */
|
||||
unsigned int c_oflag; /* output mode flags */
|
||||
unsigned int c_cflag; /* control mode flags */
|
||||
unsigned int c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCCS]; /* control characters */
|
||||
#define TARGET_NCC 8
|
||||
struct target_termio {
|
||||
unsigned short c_iflag; /* input mode flags */
|
||||
unsigned short c_oflag; /* output mode flags */
|
||||
unsigned short c_cflag; /* control mode flags */
|
||||
unsigned short c_lflag; /* local mode flags */
|
||||
unsigned char c_line; /* line discipline */
|
||||
unsigned char c_cc[TARGET_NCC]; /* control characters */
|
||||
};
|
||||
|
||||
/* c_iflag bits */
|
||||
#define TARGET_IGNBRK 0000001
|
||||
#define TARGET_BRKINT 0000002
|
||||
#define TARGET_IGNPAR 0000004
|
||||
#define TARGET_PARMRK 0000010
|
||||
#define TARGET_INPCK 0000020
|
||||
#define TARGET_ISTRIP 0000040
|
||||
#define TARGET_INLCR 0000100
|
||||
#define TARGET_IGNCR 0000200
|
||||
#define TARGET_ICRNL 0000400
|
||||
#define TARGET_IUCLC 0001000
|
||||
#define TARGET_IXON 0002000
|
||||
#define TARGET_IXANY 0004000
|
||||
#define TARGET_IXOFF 0010000
|
||||
#define TARGET_IMAXBEL 0020000
|
||||
struct target_winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
|
||||
/* c_oflag bits */
|
||||
#define TARGET_OPOST 0000001
|
||||
#define TARGET_OLCUC 0000002
|
||||
#define TARGET_ONLCR 0000004
|
||||
#define TARGET_OCRNL 0000010
|
||||
#define TARGET_ONOCR 0000020
|
||||
#define TARGET_ONLRET 0000040
|
||||
#define TARGET_OFILL 0000100
|
||||
#define TARGET_OFDEL 0000200
|
||||
#define TARGET_NLDLY 0000400
|
||||
#define TARGET_NL0 0000000
|
||||
#define TARGET_NL1 0000400
|
||||
#define TARGET_CRDLY 0003000
|
||||
#define TARGET_CR0 0000000
|
||||
#define TARGET_CR1 0001000
|
||||
#define TARGET_CR2 0002000
|
||||
#define TARGET_CR3 0003000
|
||||
#define TARGET_TABDLY 0014000
|
||||
#define TARGET_TAB0 0000000
|
||||
#define TARGET_TAB1 0004000
|
||||
#define TARGET_TAB2 0010000
|
||||
#define TARGET_TAB3 0014000
|
||||
#define TARGET_XTABS 0014000
|
||||
#define TARGET_BSDLY 0020000
|
||||
#define TARGET_BS0 0000000
|
||||
#define TARGET_BS1 0020000
|
||||
#define TARGET_VTDLY 0040000
|
||||
#define TARGET_VT0 0000000
|
||||
#define TARGET_VT1 0040000
|
||||
#define TARGET_FFDLY 0100000
|
||||
#define TARGET_FF0 0000000
|
||||
#define TARGET_FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define TARGET_CBAUD 0010017
|
||||
#define TARGET_B0 0000000 /* hang up */
|
||||
#define TARGET_B50 0000001
|
||||
#define TARGET_B75 0000002
|
||||
#define TARGET_B110 0000003
|
||||
#define TARGET_B134 0000004
|
||||
#define TARGET_B150 0000005
|
||||
#define TARGET_B200 0000006
|
||||
#define TARGET_B300 0000007
|
||||
#define TARGET_B600 0000010
|
||||
#define TARGET_B1200 0000011
|
||||
#define TARGET_B1800 0000012
|
||||
#define TARGET_B2400 0000013
|
||||
#define TARGET_B4800 0000014
|
||||
#define TARGET_B9600 0000015
|
||||
#define TARGET_B19200 0000016
|
||||
#define TARGET_B38400 0000017
|
||||
#define TARGET_EXTA B19200
|
||||
#define TARGET_EXTB B38400
|
||||
#define TARGET_CSIZE 0000060
|
||||
#define TARGET_CS5 0000000
|
||||
#define TARGET_CS6 0000020
|
||||
#define TARGET_CS7 0000040
|
||||
#define TARGET_CS8 0000060
|
||||
#define TARGET_CSTOPB 0000100
|
||||
#define TARGET_CREAD 0000200
|
||||
#define TARGET_PARENB 0000400
|
||||
#define TARGET_PARODD 0001000
|
||||
#define TARGET_HUPCL 0002000
|
||||
#define TARGET_CLOCAL 0004000
|
||||
#define TARGET_CBAUDEX 0010000
|
||||
#define TARGET_B57600 0010001
|
||||
#define TARGET_B115200 0010002
|
||||
#define TARGET_B230400 0010003
|
||||
#define TARGET_B460800 0010004
|
||||
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
#define TARGET_CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define TARGET_ISIG 0000001
|
||||
#define TARGET_ICANON 0000002
|
||||
#define TARGET_XCASE 0000004
|
||||
#define TARGET_ECHO 0000010
|
||||
#define TARGET_ECHOE 0000020
|
||||
#define TARGET_ECHOK 0000040
|
||||
#define TARGET_ECHONL 0000100
|
||||
#define TARGET_NOFLSH 0000200
|
||||
#define TARGET_TOSTOP 0000400
|
||||
#define TARGET_ECHOCTL 0001000
|
||||
#define TARGET_ECHOPRT 0002000
|
||||
#define TARGET_ECHOKE 0004000
|
||||
#define TARGET_FLUSHO 0010000
|
||||
#define TARGET_PENDIN 0040000
|
||||
#define TARGET_IEXTEN 0100000
|
||||
|
||||
/* c_cc character offsets */
|
||||
#define TARGET_VINTR 0
|
||||
#define TARGET_VQUIT 1
|
||||
#define TARGET_VERASE 2
|
||||
#define TARGET_VKILL 3
|
||||
#define TARGET_VEOF 4
|
||||
#define TARGET_VTIME 5
|
||||
#define TARGET_VMIN 6
|
||||
#define TARGET_VSWTC 7
|
||||
#define TARGET_VSTART 8
|
||||
#define TARGET_VSTOP 9
|
||||
#define TARGET_VSUSP 10
|
||||
#define TARGET_VEOL 11
|
||||
#define TARGET_VREPRINT 12
|
||||
#define TARGET_VDISCARD 13
|
||||
#define TARGET_VWERASE 14
|
||||
#define TARGET_VLNEXT 15
|
||||
#define TARGET_VEOL2 16
|
||||
#include "termbits.h"
|
||||
|
||||
#define TARGET_MAP_SHARED 0x01 /* Share changes */
|
||||
#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
|
||||
@@ -1153,6 +697,7 @@ struct target_termios {
|
||||
#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
|
||||
#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM)
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
unsigned short __pad1;
|
||||
@@ -1213,7 +758,111 @@ struct target_stat64 {
|
||||
unsigned long long st_ino;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
target_ulong st_ino;
|
||||
unsigned short st_mode;
|
||||
short st_nlink;
|
||||
unsigned short st_uid;
|
||||
unsigned short st_gid;
|
||||
unsigned short st_rdev;
|
||||
target_long st_size;
|
||||
target_long target_st_atime;
|
||||
target_ulong __unused1;
|
||||
target_long target_st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_long target_st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_long st_blksize;
|
||||
target_long st_blocks;
|
||||
target_ulong __unused4[2];
|
||||
};
|
||||
|
||||
struct target_stat64 {
|
||||
unsigned char __pad0[6];
|
||||
unsigned short st_dev;
|
||||
|
||||
uint64_t st_ino;
|
||||
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
|
||||
unsigned char __pad2[6];
|
||||
unsigned short st_rdev;
|
||||
|
||||
unsigned char __pad3[8];
|
||||
|
||||
int64_t st_size;
|
||||
unsigned int st_blksize;
|
||||
|
||||
unsigned char __pad4[8];
|
||||
unsigned int st_blocks;
|
||||
|
||||
unsigned int target_st_atime;
|
||||
unsigned int __unused1;
|
||||
|
||||
unsigned int target_st_mtime;
|
||||
unsigned int __unused2;
|
||||
|
||||
unsigned int target_st_ctime;
|
||||
unsigned int __unused3;
|
||||
|
||||
unsigned int __unused4;
|
||||
unsigned int __unused5;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
struct target_stat {
|
||||
unsigned short st_dev;
|
||||
target_ulong st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned short st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned short st_rdev;
|
||||
target_ulong st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong st_blocks;
|
||||
target_ulong target_st_atime;
|
||||
target_ulong __unused1;
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong __unused2;
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong __unused3;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
struct target_stat64 {
|
||||
unsigned long long st_dev;
|
||||
unsigned long long st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned long long st_rdev;
|
||||
long long pad0;
|
||||
long long st_size;
|
||||
target_ulong st_blksize;
|
||||
target_ulong pad1;
|
||||
long long st_blocks; /* Number 512-byte blocks allocated. */
|
||||
target_ulong target_st_atime;
|
||||
target_ulong target_st_atime_nsec;
|
||||
target_ulong target_st_mtime;
|
||||
target_ulong target_st_mtime_nsec;
|
||||
target_ulong target_st_ctime;
|
||||
target_ulong target_st_ctime_nsec;
|
||||
target_ulong __unused4;
|
||||
target_ulong __unused5;
|
||||
};
|
||||
|
||||
#endif /* defined(TARGET_PPC) */
|
||||
|
||||
#define TARGET_F_DUPFD 0 /* dup */
|
||||
#define TARGET_F_GETFD 1 /* get close_on_exec */
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
-244
@@ -1,244 +0,0 @@
|
||||
|
||||
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
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 = v;
|
||||
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 = v2;
|
||||
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 = v2;
|
||||
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 = v2;
|
||||
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 = v2;
|
||||
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 = v2;
|
||||
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
|
||||
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* QEMU OSS Audio output driver
|
||||
*
|
||||
* Copyright (c) 2003 Vassili Karpov (malc)
|
||||
*
|
||||
* 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 <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
|
||||
/* http://www.multi-platforms.com/Tips/PopCount.htm */
|
||||
static inline uint32_t popcount (uint32_t u)
|
||||
{
|
||||
u = ((u&0x55555555) + ((u>>1)&0x55555555));
|
||||
u = ((u&0x33333333) + ((u>>2)&0x33333333));
|
||||
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
|
||||
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
|
||||
u = ( u&0x0000ffff) + (u>>16);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline uint32_t lsbindex (uint32_t u)
|
||||
{
|
||||
return popcount ((u&-u)-1);
|
||||
}
|
||||
|
||||
#define MIN(a, b) ((a)>(b)?(b):(a))
|
||||
#define MAX(a, b) ((a)<(b)?(b):(a))
|
||||
|
||||
#define DEREF(x) (void)x
|
||||
#define log(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||
#define ERRFail(...) do { \
|
||||
int _errno = errno; \
|
||||
fprintf (stderr, "oss: " __VA_ARGS__); \
|
||||
fprintf (stderr, "system error: %s\n", strerror (_errno)); \
|
||||
abort (); \
|
||||
} while (0)
|
||||
#define Fail(...) do { \
|
||||
fprintf (stderr, "oss: " __VA_ARGS__); \
|
||||
fprintf (stderr, "\n"); \
|
||||
abort (); \
|
||||
} while (0)
|
||||
|
||||
#ifdef DEBUG_OSS
|
||||
#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||
#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||
#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__)
|
||||
#else
|
||||
#define lwarn(...)
|
||||
#define linfo(...)
|
||||
#define ldebug(...)
|
||||
#endif
|
||||
|
||||
|
||||
#define IOCTL(args) do { \
|
||||
int ret = ioctl args; \
|
||||
if (-1 == ret) { \
|
||||
ERRFail (#args); \
|
||||
} \
|
||||
ldebug ("ioctl " #args " = %d\n", ret); \
|
||||
} while (0)
|
||||
|
||||
static int audio_fd = -1;
|
||||
static int freq;
|
||||
static int conf_nfrags = 4;
|
||||
static int conf_fragsize;
|
||||
static int nfrags;
|
||||
static int fragsize;
|
||||
static int bufsize;
|
||||
static int nchannels;
|
||||
static int fmt;
|
||||
static int rpos;
|
||||
static int wpos;
|
||||
static int atom;
|
||||
static int live;
|
||||
static int leftover;
|
||||
static int bytes_per_second;
|
||||
static void *buf;
|
||||
static enum {DONT, DSP, TID} estimate = TID;
|
||||
|
||||
static void (*copy_fn)(void *, void *, int);
|
||||
|
||||
static void copy_no_conversion (void *dst, void *src, int size)
|
||||
{
|
||||
memcpy (dst, src, size);
|
||||
}
|
||||
|
||||
static void copy_u16_to_s16 (void *dst, void *src, int size)
|
||||
{
|
||||
int i;
|
||||
uint16_t *out, *in;
|
||||
|
||||
out = dst;
|
||||
in = src;
|
||||
|
||||
for (i = 0; i < size / 2; i++) {
|
||||
out[i] = in[i] + 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
static void pab (struct audio_buf_info *abinfo)
|
||||
{
|
||||
DEREF (abinfo);
|
||||
|
||||
ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
|
||||
"rpos %d, wpos %d, live %d\n",
|
||||
abinfo->fragments,
|
||||
abinfo->fragstotal,
|
||||
abinfo->fragsize,
|
||||
abinfo->bytes,
|
||||
rpos, wpos, live);
|
||||
}
|
||||
|
||||
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt)
|
||||
{
|
||||
int fmt_;
|
||||
int bits16;
|
||||
|
||||
if (-1 == audio_fd) {
|
||||
AUD_open (rfreq, rnchannels, rfmt);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rfmt) {
|
||||
case AUD_FMT_U8:
|
||||
bits16 = 0;
|
||||
fmt_ = AFMT_U8;
|
||||
copy_fn = copy_no_conversion;
|
||||
atom = 1;
|
||||
break;
|
||||
|
||||
case AUD_FMT_S8:
|
||||
Fail ("can not play 8bit signed");
|
||||
|
||||
case AUD_FMT_S16:
|
||||
bits16 = 1;
|
||||
fmt_ = AFMT_S16_LE;
|
||||
copy_fn = copy_no_conversion;
|
||||
atom = 2;
|
||||
break;
|
||||
|
||||
case AUD_FMT_U16:
|
||||
bits16 = 1;
|
||||
fmt_ = AFMT_S16_LE;
|
||||
copy_fn = copy_u16_to_s16;
|
||||
atom = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq))
|
||||
return;
|
||||
else {
|
||||
AUD_open (rfreq, rnchannels, rfmt);
|
||||
}
|
||||
}
|
||||
|
||||
void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt)
|
||||
{
|
||||
int fmt_;
|
||||
int mmmmssss;
|
||||
struct audio_buf_info abinfo;
|
||||
int _fmt;
|
||||
int _freq;
|
||||
int _nchannels;
|
||||
int bits16;
|
||||
|
||||
bits16 = 0;
|
||||
|
||||
switch (rfmt) {
|
||||
case AUD_FMT_U8:
|
||||
bits16 = 0;
|
||||
fmt_ = AFMT_U8;
|
||||
copy_fn = copy_no_conversion;
|
||||
atom = 1;
|
||||
break;
|
||||
|
||||
case AUD_FMT_S8:
|
||||
Fail ("can not play 8bit signed");
|
||||
|
||||
case AUD_FMT_S16:
|
||||
bits16 = 1;
|
||||
fmt_ = AFMT_S16_LE;
|
||||
copy_fn = copy_no_conversion;
|
||||
atom = 2;
|
||||
break;
|
||||
|
||||
case AUD_FMT_U16:
|
||||
bits16 = 1;
|
||||
fmt_ = AFMT_S16_LE;
|
||||
copy_fn = copy_u16_to_s16;
|
||||
atom = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
free (buf);
|
||||
buf = 0;
|
||||
}
|
||||
|
||||
if (-1 != audio_fd)
|
||||
close (audio_fd);
|
||||
|
||||
audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK);
|
||||
if (-1 == audio_fd) {
|
||||
ERRFail ("can not open /dev/dsp");
|
||||
}
|
||||
|
||||
_fmt = fmt_;
|
||||
_freq = rfreq;
|
||||
_nchannels = rnchannels;
|
||||
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1));
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt));
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels));
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq));
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK));
|
||||
|
||||
/* from oss.pdf:
|
||||
|
||||
The argument to this call is an integer encoded as 0xMMMMSSSS (in
|
||||
hex). The 16 least significant bits determine the fragment
|
||||
size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment
|
||||
size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the
|
||||
maximum is total_buffer_size/2. Some devices or processor
|
||||
architectures may require larger fragments - in this case the
|
||||
requested fragment size is automatically increased.
|
||||
|
||||
So ahem... 4096 = 2^12, and grand total 0x0004000c
|
||||
*/
|
||||
|
||||
mmmmssss = (conf_nfrags << 16) | conf_fragsize;
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss));
|
||||
|
||||
linfo ("_fmt = %d, fmt = %d\n"
|
||||
"_channels = %d, rnchannels = %d\n"
|
||||
"_freq = %d, freq = %d\n",
|
||||
_fmt, fmt_,
|
||||
_nchannels, rnchannels,
|
||||
_freq, rfreq);
|
||||
|
||||
if (_fmt != fmt_) {
|
||||
Fail ("format %d != %d", _fmt, fmt_);
|
||||
}
|
||||
|
||||
if (_nchannels != rnchannels) {
|
||||
Fail ("channels %d != %d", _nchannels, rnchannels);
|
||||
}
|
||||
|
||||
if (_freq != rfreq) {
|
||||
Fail ("freq %d != %d", _freq, rfreq);
|
||||
}
|
||||
|
||||
IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo));
|
||||
|
||||
nfrags = abinfo.fragstotal;
|
||||
fragsize = abinfo.fragsize;
|
||||
freq = _freq;
|
||||
fmt = _fmt;
|
||||
nchannels = rnchannels;
|
||||
atom <<= nchannels >> 1;
|
||||
bufsize = nfrags * fragsize;
|
||||
|
||||
bytes_per_second = (freq << (nchannels >> 1)) << bits16;
|
||||
|
||||
linfo ("bytes per second %d\n", bytes_per_second);
|
||||
|
||||
linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
|
||||
abinfo.fragments,
|
||||
abinfo.fragstotal,
|
||||
abinfo.fragsize,
|
||||
abinfo.bytes,
|
||||
bufsize);
|
||||
|
||||
if (NULL == buf) {
|
||||
buf = malloc (bufsize);
|
||||
if (NULL == buf) {
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
rpos = 0;
|
||||
wpos = 0;
|
||||
live = 0;
|
||||
}
|
||||
|
||||
int AUD_write (void *in_buf, int size)
|
||||
{
|
||||
int to_copy, temp;
|
||||
uint8_t *in, *out;
|
||||
|
||||
to_copy = MIN (bufsize - live, size);
|
||||
|
||||
temp = to_copy;
|
||||
|
||||
in = in_buf;
|
||||
out = buf;
|
||||
|
||||
while (temp) {
|
||||
int copy;
|
||||
|
||||
copy = MIN (temp, bufsize - wpos);
|
||||
copy_fn (out + wpos, in, copy);
|
||||
|
||||
wpos += copy;
|
||||
if (wpos == bufsize) {
|
||||
wpos = 0;
|
||||
}
|
||||
|
||||
temp -= copy;
|
||||
in += copy;
|
||||
live += copy;
|
||||
}
|
||||
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
void AUD_run (void)
|
||||
{
|
||||
int res;
|
||||
int bytes;
|
||||
struct audio_buf_info abinfo;
|
||||
|
||||
if (0 == live)
|
||||
return;
|
||||
|
||||
res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo);
|
||||
|
||||
if (-1 == res) {
|
||||
int err;
|
||||
|
||||
err = errno;
|
||||
lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
|
||||
}
|
||||
|
||||
bytes = abinfo.bytes;
|
||||
bytes = MIN (live, bytes);
|
||||
#if 0
|
||||
bytes = (bytes / fragsize) * fragsize;
|
||||
#endif
|
||||
|
||||
while (bytes) {
|
||||
int left, play, written;
|
||||
|
||||
left = bufsize - rpos;
|
||||
play = MIN (left, bytes);
|
||||
written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play);
|
||||
|
||||
if (-1 == written) {
|
||||
if (EAGAIN == errno || EINTR == errno) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
ERRFail ("write audio");
|
||||
}
|
||||
}
|
||||
|
||||
play = written;
|
||||
live -= play;
|
||||
rpos += play;
|
||||
bytes -= play;
|
||||
|
||||
if (rpos == bufsize) {
|
||||
rpos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_dsp_bytes (void)
|
||||
{
|
||||
int res;
|
||||
struct count_info info;
|
||||
|
||||
res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info);
|
||||
if (-1 == res) {
|
||||
int err;
|
||||
|
||||
err = errno;
|
||||
lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
ldebug ("bytes %d\n", info.bytes);
|
||||
return info.bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void AUD_adjust_estimate (int _leftover)
|
||||
{
|
||||
leftover = _leftover;
|
||||
}
|
||||
|
||||
int AUD_get_free (void)
|
||||
{
|
||||
int free, elapsed;
|
||||
|
||||
free = bufsize - live;
|
||||
|
||||
if (0 == free)
|
||||
return 0;
|
||||
|
||||
elapsed = free;
|
||||
switch (estimate) {
|
||||
case DONT:
|
||||
break;
|
||||
|
||||
case DSP:
|
||||
{
|
||||
static int old_bytes;
|
||||
int bytes;
|
||||
|
||||
bytes = get_dsp_bytes ();
|
||||
if (bytes <= 0)
|
||||
return free;
|
||||
|
||||
elapsed = bytes - old_bytes;
|
||||
old_bytes = bytes;
|
||||
ldebug ("dsp elapsed %d bytes\n", elapsed);
|
||||
break;
|
||||
}
|
||||
|
||||
case TID:
|
||||
{
|
||||
static uint64_t old_ticks;
|
||||
uint64_t ticks, delta;
|
||||
uint64_t ua_elapsed;
|
||||
uint64_t al_elapsed;
|
||||
|
||||
ticks = cpu_get_ticks ();
|
||||
delta = ticks - old_ticks;
|
||||
old_ticks = ticks;
|
||||
|
||||
ua_elapsed = (delta * bytes_per_second) / ticks_per_sec;
|
||||
al_elapsed = ua_elapsed & ~3ULL;
|
||||
|
||||
ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
|
||||
|
||||
if (al_elapsed > (uint64_t) INT_MAX)
|
||||
elapsed = INT_MAX;
|
||||
else
|
||||
elapsed = al_elapsed;
|
||||
|
||||
elapsed += leftover;
|
||||
}
|
||||
}
|
||||
|
||||
if (elapsed > free) {
|
||||
lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
|
||||
return free;
|
||||
}
|
||||
else {
|
||||
return elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
int AUD_get_live (void)
|
||||
{
|
||||
return live;
|
||||
}
|
||||
|
||||
int AUD_get_buffer_size (void)
|
||||
{
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
void AUD_init (void)
|
||||
{
|
||||
int fsp;
|
||||
int _fragsize = 4096;
|
||||
|
||||
DEREF (pab);
|
||||
|
||||
fsp = _fragsize;
|
||||
if (0 != (fsp & (fsp - 1))) {
|
||||
Fail ("fragment size %d is not power of 2", fsp);
|
||||
}
|
||||
|
||||
conf_fragsize = lsbindex (fsp);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
- The PC BIOS comes from the Bochs project
|
||||
(http://bochs.sourceforge.net/).
|
||||
- The VGA BIOS comes from the LGPL VGA bios project
|
||||
(http://www.nongnu.org/vgabios/).
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
# enable automatic i386 program execution by the kernel (must enable binfmt_misc)
|
||||
echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
|
||||
echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
|
||||
+247
-108
@@ -1,11 +1,13 @@
|
||||
\input texinfo @c -*- texinfo -*-
|
||||
|
||||
@iftex
|
||||
@settitle QEMU CPU Emulator Reference Documentation
|
||||
@titlepage
|
||||
@sp 7
|
||||
@center @titlefont{QEMU CPU Emulator Reference Documentation}
|
||||
@sp 3
|
||||
@end titlepage
|
||||
@end iftex
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
@@ -16,14 +18,18 @@ achieves a reasonnable speed while being easy to port on new host
|
||||
CPUs.
|
||||
|
||||
QEMU has two operating modes:
|
||||
@itemize
|
||||
@item User mode emulation. In this mode, QEMU can launch Linux processes
|
||||
|
||||
@itemize @minus
|
||||
|
||||
@item
|
||||
User mode emulation. In this mode, QEMU can launch Linux processes
|
||||
compiled for one CPU on another CPU. Linux system calls are converted
|
||||
because of endianness and 32/64 bit mismatches. The Wine Windows API
|
||||
emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator
|
||||
(@url{www.dosemu.org}) are the main targets for QEMU.
|
||||
|
||||
@item Full system emulation. In this mode, QEMU emulates a full
|
||||
@item
|
||||
Full system emulation. In this mode, QEMU emulates a full
|
||||
system, including a processor and various peripherials. Currently, it
|
||||
is only used to launch an x86 Linux kernel on an x86 Linux system. It
|
||||
enables easier testing and debugging of system code. It can also be
|
||||
@@ -66,7 +72,7 @@ QEMU user mode emulation features:
|
||||
|
||||
QEMU full system emulation features:
|
||||
@itemize
|
||||
@item Using mmap() system calls to simulate the MMU
|
||||
@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU.
|
||||
@end itemize
|
||||
|
||||
@section x86 emulation
|
||||
@@ -104,14 +110,7 @@ memory access.
|
||||
10 byte @code{long double}s of x86 for floating point emulation to get
|
||||
maximum performances.
|
||||
|
||||
@item Full system emulation only works if no data are mapped above the virtual address
|
||||
0xc0000000 (yet).
|
||||
|
||||
@item Some priviledged instructions or behaviors are missing. Only the ones
|
||||
needed for proper Linux kernel operation are emulated.
|
||||
|
||||
@item No memory separation between the kernel and the user processes is done.
|
||||
It will be implemented very soon.
|
||||
@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet).
|
||||
|
||||
@end itemize
|
||||
|
||||
@@ -128,13 +127,27 @@ generic dynamic code generation architecture of QEMU.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section SPARC emulation
|
||||
|
||||
The SPARC emulation is currently in development.
|
||||
|
||||
@chapter Installation
|
||||
|
||||
If you want to compile QEMU, please read the @file{README} which gives
|
||||
the related information. Otherwise just download the binary
|
||||
distribution (@file{qemu-XXX-i386.tar.gz}) and untar it as root in
|
||||
@file{/}:
|
||||
|
||||
@example
|
||||
su
|
||||
cd /
|
||||
tar zxvf /tmp/qemu-XXX-i386.tar.gz
|
||||
@end example
|
||||
|
||||
@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.
|
||||
|
||||
@@ -144,20 +157,20 @@ itself and all the target (x86) dynamic libraries used by it.
|
||||
libraries:
|
||||
|
||||
@example
|
||||
qemu -L / /bin/ls
|
||||
qemu-i386 -L / /bin/ls
|
||||
@end example
|
||||
|
||||
@code{-L /} tells that the x86 dynamic linker must be searched with a
|
||||
@file{/} prefix.
|
||||
|
||||
@item Since QEMU is also a linux process, you can launch qemu with qemu:
|
||||
@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources):
|
||||
|
||||
@example
|
||||
qemu -L / qemu -L / /bin/ls
|
||||
qemu-i386 -L / qemu-i386 -L / /bin/ls
|
||||
@end example
|
||||
|
||||
@item On non x86 CPUs, you need first to download at least an x86 glibc
|
||||
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
||||
(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that
|
||||
@code{LD_LIBRARY_PATH} is not set:
|
||||
|
||||
@example
|
||||
@@ -167,16 +180,16 @@ unset LD_LIBRARY_PATH
|
||||
Then you can launch the precompiled @file{ls} x86 executable:
|
||||
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
qemu-i386 tests/i386/ls
|
||||
@end example
|
||||
You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that
|
||||
You can look at @file{qemu-binfmt-conf.sh} so that
|
||||
QEMU is automatically launched by the Linux kernel when you try to
|
||||
launch x86 executables. It requires the @code{binfmt_misc} module in the
|
||||
Linux kernel.
|
||||
|
||||
@item The x86 version of QEMU is also included. You can try weird things such as:
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
@@ -190,7 +203,7 @@ distribution (see previous section). In order to verify it, you must be
|
||||
able to do:
|
||||
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||
@end example
|
||||
|
||||
@item Download the binary x86 Wine install
|
||||
@@ -203,7 +216,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386
|
||||
@item Then you can try the example @file{putty.exe}:
|
||||
|
||||
@example
|
||||
qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
|
||||
qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
@@ -211,7 +224,7 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil
|
||||
@section Command line options
|
||||
|
||||
@example
|
||||
usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]
|
||||
usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
|
||||
@end example
|
||||
|
||||
@table @option
|
||||
@@ -234,20 +247,82 @@ Act as if the host page size was 'pagesize' bytes
|
||||
|
||||
@chapter QEMU System emulator invocation
|
||||
|
||||
@section Introduction
|
||||
|
||||
@c man begin DESCRIPTION
|
||||
|
||||
The QEMU System emulator simulates a complete PC. It can either boot
|
||||
directly a Linux kernel (without any BIOS or boot loader) or boot like a
|
||||
real PC with the included BIOS.
|
||||
|
||||
In order to meet specific user needs, two versions of QEMU are
|
||||
available:
|
||||
|
||||
@enumerate
|
||||
|
||||
@item
|
||||
@code{qemu-fast} uses the host Memory Management Unit (MMU) to simulate
|
||||
the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB
|
||||
address space cannot be used and some memory mapped peripherials
|
||||
cannot be emulated accurately yet. Therefore, a specific Linux kernel
|
||||
must be used (@xref{linux_compile}).
|
||||
|
||||
@item
|
||||
@code{qemu} uses a software MMU. It is about @emph{two times
|
||||
slower} but gives a more accurate emulation.
|
||||
|
||||
@end enumerate
|
||||
|
||||
QEMU emulates the following PC peripherials:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
VGA (hardware level, including all non standard modes)
|
||||
@item
|
||||
PS/2 mouse and keyboard
|
||||
@item
|
||||
2 IDE interfaces with hard disk and CD-ROM support
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
Serial port
|
||||
@item
|
||||
Soundblaster 16 card
|
||||
@item
|
||||
PIC (interrupt controler)
|
||||
@item
|
||||
PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@end itemize
|
||||
|
||||
@c man end
|
||||
|
||||
@section Quick Start
|
||||
|
||||
This section explains how to launch a Linux kernel inside QEMU.
|
||||
Download and uncompress the linux image (@file{linux.img}) and type:
|
||||
|
||||
@example
|
||||
qemu linux.img
|
||||
@end example
|
||||
|
||||
Linux should boot and give you a prompt.
|
||||
|
||||
@section Direct Linux Boot and Network emulation
|
||||
|
||||
This section explains how to launch a Linux kernel inside QEMU without
|
||||
having to make a full bootable image. It is very useful for fast Linux
|
||||
kernel testing. The QEMU network configuration is also explained.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image. The archive also contains a precompiled
|
||||
version of @file{vl}, the QEMU System emulator.
|
||||
Download the archive @file{linux-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image.
|
||||
|
||||
@item Optional: If you want network support (for example to launch X11 examples), you
|
||||
must copy the script @file{vl-ifup} in @file{/etc} and configure
|
||||
must copy the script @file{qemu-ifup} in @file{/etc} and configure
|
||||
properly @code{sudo} so that the command @code{ifconfig} contained in
|
||||
@file{vl-ifup} can be executed as root. You must verify that your host
|
||||
@file{qemu-ifup} can be executed as root. You must verify that your host
|
||||
kernel supports the TUN/TAP network interfaces: the device
|
||||
@file{/dev/net/tun} must be present.
|
||||
|
||||
@@ -256,13 +331,12 @@ the host kernel and the emulated kernel. The emulated kernel is seen
|
||||
from the host kernel at IP address 172.20.0.2 and the host kernel is
|
||||
seen from the emulated kernel at IP address 172.20.0.1.
|
||||
|
||||
@item Launch @code{vl.sh}. You should have the following output:
|
||||
@item Launch @code{qemu.sh}. You should have the following output:
|
||||
|
||||
@example
|
||||
> ./vl.sh
|
||||
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
|
||||
> ./qemu.sh
|
||||
Connected to host network interface: tun0
|
||||
Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
|
||||
BIOS-provided physical RAM map:
|
||||
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
|
||||
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
|
||||
@@ -271,19 +345,19 @@ 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
|
||||
Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0
|
||||
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)
|
||||
Detected 2399.621 MHz processor.
|
||||
Console: colour EGA 80x25
|
||||
Calibrating delay loop... 4744.80 BogoMIPS
|
||||
Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k 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)
|
||||
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
|
||||
@@ -295,21 +369,24 @@ Initializing RT netlink socket
|
||||
apm: BIOS not found.
|
||||
Starting kswapd
|
||||
Journalled Block Device driver loaded
|
||||
Detected PS/2 Mouse Port.
|
||||
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
|
||||
Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4
|
||||
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: attached ide-disk driver.
|
||||
hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63
|
||||
Partition check:
|
||||
hda:
|
||||
Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996
|
||||
NET4: Linux TCP/IP 1.0 for NET4.0
|
||||
IP Protocols: ICMP, UDP, TCP, IGMP
|
||||
IP: routing cache hash table of 512 buckets, 4Kbytes
|
||||
@@ -317,9 +394,15 @@ 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
|
||||
#
|
||||
Freeing unused kernel memory: 64k freed
|
||||
|
||||
Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
|
||||
|
||||
QEMU Linux test distribution (based on Redhat 9)
|
||||
|
||||
Type 'exit' to halt the system
|
||||
|
||||
sh-2.05b#
|
||||
@end example
|
||||
|
||||
@item
|
||||
@@ -349,18 +432,18 @@ a real Virtual Linux system !
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
A 2.5.74 kernel is also included in the vl-test archive. Just
|
||||
replace the bzImage in vl.sh to try it.
|
||||
A 2.5.74 kernel is also included in the archive. Just
|
||||
replace the bzImage in qemu.sh to try it.
|
||||
|
||||
@item
|
||||
vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the
|
||||
qemu creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the
|
||||
default) containing all the simulated PC memory. If possible, try to use
|
||||
a temporary directory using the tmpfs filesystem to avoid too many
|
||||
unnecessary disk accesses.
|
||||
|
||||
@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.
|
||||
In order to exit cleanly from qemu, you can do a @emph{shutdown} inside
|
||||
qemu. qemu will automatically exit when the Linux shutdown is done.
|
||||
|
||||
@item
|
||||
You can boot slightly faster by disabling the probe of non present IDE
|
||||
@@ -379,19 +462,30 @@ Lawton for the plex86 Project (@url{www.plex86.org}).
|
||||
@section Invocation
|
||||
|
||||
@example
|
||||
usage: vl [options] bzImage [kernel parameters...]
|
||||
@c man begin SYNOPSIS
|
||||
usage: qemu [options] [disk_image]
|
||||
@c man end
|
||||
@end example
|
||||
|
||||
@file{bzImage} is a Linux kernel image.
|
||||
@c man begin OPTIONS
|
||||
@var{disk_image} is a raw hard disk image for IDE hard disk 0.
|
||||
|
||||
General options:
|
||||
@table @option
|
||||
@item -hda file
|
||||
@item -hdb file
|
||||
Use 'file' as hard disk 0 or 1 image (@xref{disk_images}).
|
||||
@item -hdc file
|
||||
@item -hdd file
|
||||
Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}).
|
||||
|
||||
@item -cdrom file
|
||||
Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
|
||||
@option{-cdrom} at the same time).
|
||||
|
||||
@item -boot [c|d]
|
||||
Boot on hard disk (c) or CD-ROM (d). Hard disk boot is the default.
|
||||
|
||||
@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}).
|
||||
@@ -400,22 +494,50 @@ the write back by pressing @key{C-a s} (@xref{disk_images}).
|
||||
Set virtual RAM size to @var{megs} megabytes.
|
||||
|
||||
@item -n script
|
||||
Set network init script [default=/etc/vl-ifup]. This script is
|
||||
Set network init script [default=/etc/qemu-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.
|
||||
Use @var{file} as initial ram disk.
|
||||
|
||||
@item -tun-fd fd
|
||||
Assumes @var{fd} talks to tap/tun and use it. Read
|
||||
@url{http://bellard.org/qemu/tetrinet.html} to have an example of its
|
||||
use.
|
||||
|
||||
@item -nographic
|
||||
|
||||
Normally, QEMU uses SDL to display the VGA output. With this option,
|
||||
you can totally disable graphical output so that QEMU is a simple
|
||||
command line application. The emulated serial port is redirected on
|
||||
the console. Therefore, you can still use QEMU to debug a Linux kernel
|
||||
with a serial console.
|
||||
|
||||
@end table
|
||||
|
||||
Linux boot specific (does not require a full PC boot with a BIOS):
|
||||
@table @option
|
||||
|
||||
@item -kernel bzImage
|
||||
Use @var{bzImage} as kernel image.
|
||||
|
||||
@item -append cmdline
|
||||
Use @var{cmdline} as kernel command line
|
||||
|
||||
@item -initrd file
|
||||
Use @var{file} as initial ram disk.
|
||||
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
@table @option
|
||||
@item -s
|
||||
Wait gdb connection to port 1234.
|
||||
Wait gdb connection to port 1234 (@xref{gdb_usage}).
|
||||
@item -p port
|
||||
Change gdb connection port.
|
||||
@item -d
|
||||
Output log in /tmp/vl.log
|
||||
Output log in /tmp/qemu.log
|
||||
@end table
|
||||
|
||||
During emulation, use @key{C-a h} to get terminal commands:
|
||||
@@ -432,7 +554,25 @@ Send break (magic sysrq)
|
||||
@item C-a C-a
|
||||
Send C-a
|
||||
@end table
|
||||
@c man end
|
||||
|
||||
@ignore
|
||||
|
||||
@setfilename qemu
|
||||
@settitle QEMU System Emulator
|
||||
|
||||
@c man begin SEEALSO
|
||||
The HTML documentation of QEMU for more precise information and Linux
|
||||
user mode emulator invocation.
|
||||
@c man end
|
||||
|
||||
@c man begin AUTHOR
|
||||
Fabrice Bellard
|
||||
@c man end
|
||||
|
||||
@end ignore
|
||||
|
||||
@end ignore
|
||||
@node disk_images
|
||||
@section Disk Images
|
||||
|
||||
@@ -466,30 +606,30 @@ same disk image template for many users.
|
||||
To create a COW disk images, use the command:
|
||||
|
||||
@example
|
||||
vlmkcow -f myrawimage.bin mycowimage.cow
|
||||
qemu-mkcow -f myrawimage.bin mycowimage.cow
|
||||
@end example
|
||||
|
||||
@file{myrawimage.bin} is a raw image you want to use as original disk
|
||||
image. It will never be written to.
|
||||
|
||||
@file{mycowimage.cow} is the COW disk image which is created by
|
||||
@code{vlmkcow}. You can use it directly with the @option{-hdx}
|
||||
@code{qemu-mkcow}. You can use it directly with the @option{-hdx}
|
||||
options. You must not modify the original raw disk image if you use
|
||||
COW images, as COW images only store the modified sectors from the raw
|
||||
disk image. QEMU stores the original raw disk image name and its
|
||||
modified time in the COW disk image so that chances of mistakes are
|
||||
reduced.
|
||||
|
||||
If 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.
|
||||
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
|
||||
qemu-mkcow mycowimage.cow 1024
|
||||
@end example
|
||||
|
||||
to create a 1 gigabyte empty COW disk image.
|
||||
@@ -504,10 +644,13 @@ Since holes are used, the displayed size of the COW disk image is not
|
||||
the real one. To know it, use the @code{ls -ls} command.
|
||||
@end enumerate
|
||||
|
||||
@node linux_compile
|
||||
@section Linux Kernel Compilation
|
||||
|
||||
You should be able to use any kernel with QEMU provided you make the
|
||||
following changes (only 2.4.x and 2.5.x were tested):
|
||||
You can use any linux kernel with QEMU. However, if you want to use
|
||||
@code{qemu-fast} to get maximum performances, you should make the
|
||||
following changes to the Linux kernel (only 2.4.x and 2.5.x were
|
||||
tested):
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
@@ -573,36 +716,16 @@ As you would do to make a real kernel. Then you can use with QEMU
|
||||
exactly the same kernel as you would boot on your PC (in
|
||||
@file{arch/i386/boot/bzImage}).
|
||||
|
||||
@section PC Emulation
|
||||
|
||||
QEMU emulates the following PC peripherials:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
PIC (interrupt controler)
|
||||
@item
|
||||
PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@item
|
||||
Dumb VGA (to print the @code{Uncompressing Linux} message)
|
||||
@item
|
||||
Serial port (port=0x3f8, irq=4)
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
IDE disk interface (port=0x1f0, irq=14)
|
||||
@end itemize
|
||||
|
||||
@node gdb_usage
|
||||
@section GDB usage
|
||||
|
||||
QEMU has a primitive support to work with gdb, so that you can do
|
||||
'Ctrl-C' while the kernel is running and inspect its state.
|
||||
'Ctrl-C' while the virtual machine is running and inspect its state.
|
||||
|
||||
In order to use gdb, launch vl with the '-s' option. It will wait for a
|
||||
In order to use gdb, launch qemu with the '-s' option. It will wait for a
|
||||
gdb connection:
|
||||
@example
|
||||
> vl -s arch/i386/boot/bzImage initrd-2.4.20.img root=/dev/ram0 ramdisk_size=6144
|
||||
> qemu -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
|
||||
@@ -622,7 +745,17 @@ Then you can use gdb normally. For example, type 'c' to launch the kernel:
|
||||
(gdb) c
|
||||
@end example
|
||||
|
||||
WARNING: breakpoints and single stepping are not yet supported.
|
||||
Here are some useful tips in order to use gdb on system code:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Use @code{info reg} to display all the CPU registers.
|
||||
@item
|
||||
Use @code{x/10i $eip} to display the code at the PC position.
|
||||
@item
|
||||
Use @code{set architecture i8086} to dump 16 bit code. Then use
|
||||
@code{x/10i $cs*16+*eip} to dump the code at the PC position.
|
||||
@end enumerate
|
||||
|
||||
@chapter QEMU Internals
|
||||
|
||||
@@ -906,16 +1039,6 @@ The new Plex86 project.
|
||||
In the directory @file{tests/}, various interesting testing programs
|
||||
are available. There are used for regression testing.
|
||||
|
||||
@section @file{hello-i386}
|
||||
|
||||
Very simple statically linked x86 program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{hello-arm}
|
||||
|
||||
Very simple statically linked ARM program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{test-i386}
|
||||
|
||||
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||
@@ -931,6 +1054,22 @@ The Linux system call @code{vm86()} is used to test vm86 emulation.
|
||||
Various exceptions are raised to test most of the x86 user space
|
||||
exception reporting.
|
||||
|
||||
@section @file{linux-test}
|
||||
|
||||
This program tests various Linux system calls. It is used to verify
|
||||
that the system call parameters are correctly converted between target
|
||||
and host CPUs.
|
||||
|
||||
@section @file{hello-i386}
|
||||
|
||||
Very simple statically linked x86 program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{hello-arm}
|
||||
|
||||
Very simple statically linked ARM program, just to test QEMU during a
|
||||
port to a new host CPU.
|
||||
|
||||
@section @file{sha1}
|
||||
|
||||
It is a simple benchmark. Care must be taken to interpret the results
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
#include "bswap.h"
|
||||
|
||||
int cow_create(int cow_fd, const char *image_filename,
|
||||
int64_t image_sectors)
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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.h"
|
||||
#include "exec-all.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);
|
||||
}
|
||||
/* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGQUIT, SIG_DFL);
|
||||
|
||||
ds->dpy_update = sdl_update;
|
||||
ds->dpy_resize = sdl_resize;
|
||||
ds->dpy_refresh = sdl_refresh;
|
||||
|
||||
sdl_resize(ds, 640, 400);
|
||||
SDL_WM_SetCaption("QEMU", "QEMU");
|
||||
SDL_EnableKeyRepeat(250, 50);
|
||||
gui_grab = 0;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 USUFFIX q
|
||||
#define DATA_TYPE uint64_t
|
||||
#elif DATA_SIZE == 4
|
||||
#define SUFFIX l
|
||||
#define USUFFIX l
|
||||
#define DATA_TYPE uint32_t
|
||||
#elif DATA_SIZE == 2
|
||||
#define SUFFIX w
|
||||
#define USUFFIX uw
|
||||
#define DATA_TYPE uint16_t
|
||||
#define DATA_STYPE int16_t
|
||||
#elif DATA_SIZE == 1
|
||||
#define SUFFIX b
|
||||
#define USUFFIX ub
|
||||
#define DATA_TYPE uint8_t
|
||||
#define DATA_STYPE int8_t
|
||||
#else
|
||||
#error unsupported data size
|
||||
#endif
|
||||
|
||||
#if ACCESS_TYPE == 0
|
||||
|
||||
#define CPU_MEM_INDEX 0
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#elif ACCESS_TYPE == 1
|
||||
|
||||
#define CPU_MEM_INDEX 1
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#elif ACCESS_TYPE == 2
|
||||
|
||||
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#elif ACCESS_TYPE == 3
|
||||
|
||||
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
||||
#define MMUSUFFIX _cmmu
|
||||
|
||||
#else
|
||||
#error invalid ACCESS_TYPE
|
||||
#endif
|
||||
|
||||
#if DATA_SIZE == 8
|
||||
#define RES_TYPE uint64_t
|
||||
#else
|
||||
#define RES_TYPE int
|
||||
#endif
|
||||
|
||||
|
||||
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user);
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user);
|
||||
|
||||
static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr)
|
||||
{
|
||||
int index;
|
||||
RES_TYPE res;
|
||||
unsigned long addr, physaddr;
|
||||
int is_user;
|
||||
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
is_user = CPU_MEM_INDEX;
|
||||
if (__builtin_expect(env->tlb_read[is_user][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_read[is_user][index].addend;
|
||||
res = glue(glue(ld, USUFFIX), _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;
|
||||
int is_user;
|
||||
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
is_user = CPU_MEM_INDEX;
|
||||
if (__builtin_expect(env->tlb_read[is_user][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_read[is_user][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;
|
||||
int is_user;
|
||||
|
||||
addr = (unsigned long)ptr;
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
is_user = CPU_MEM_INDEX;
|
||||
if (__builtin_expect(env->tlb_write[is_user][index].address !=
|
||||
(addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
|
||||
glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user);
|
||||
} else {
|
||||
physaddr = addr + env->tlb_write[is_user][index].addend;
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
|
||||
}
|
||||
}
|
||||
|
||||
#undef RES_TYPE
|
||||
#undef DATA_TYPE
|
||||
#undef DATA_STYPE
|
||||
#undef SUFFIX
|
||||
#undef USUFFIX
|
||||
#undef DATA_SIZE
|
||||
#undef CPU_MEM_INDEX
|
||||
#undef MMUSUFFIX
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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 USUFFIX q
|
||||
#define DATA_TYPE uint64_t
|
||||
#elif DATA_SIZE == 4
|
||||
#define SUFFIX l
|
||||
#define USUFFIX l
|
||||
#define DATA_TYPE uint32_t
|
||||
#elif DATA_SIZE == 2
|
||||
#define SUFFIX w
|
||||
#define USUFFIX uw
|
||||
#define DATA_TYPE uint16_t
|
||||
#elif DATA_SIZE == 1
|
||||
#define SUFFIX b
|
||||
#define USUFFIX ub
|
||||
#define DATA_TYPE uint8_t
|
||||
#else
|
||||
#error unsupported data size
|
||||
#endif
|
||||
|
||||
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user,
|
||||
void *retaddr);
|
||||
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
DATA_TYPE val,
|
||||
int is_user,
|
||||
void *retaddr);
|
||||
|
||||
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
|
||||
unsigned long tlb_addr)
|
||||
{
|
||||
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), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user)
|
||||
{
|
||||
DATA_TYPE res;
|
||||
int index;
|
||||
unsigned long physaddr, tlb_addr;
|
||||
void *retaddr;
|
||||
|
||||
/* test if there is match for unaligned or IO access */
|
||||
/* XXX: could done more in memory macro in a non portable way */
|
||||
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 = GETPC();
|
||||
res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
|
||||
is_user, retaddr);
|
||||
} else {
|
||||
/* unaligned access in the same page */
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = GETPC();
|
||||
tlb_fill(addr, 0, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* handle all unaligned cases */
|
||||
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
int is_user,
|
||||
void *retaddr)
|
||||
{
|
||||
DATA_TYPE res, res1, res2;
|
||||
int index, shift;
|
||||
unsigned long physaddr, tlb_addr, addr1, addr2;
|
||||
|
||||
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(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
|
||||
is_user, retaddr);
|
||||
res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
|
||||
is_user, retaddr);
|
||||
shift = (addr & (DATA_SIZE - 1)) * 8;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
|
||||
#else
|
||||
res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
|
||||
#endif
|
||||
} else {
|
||||
/* unaligned/aligned access in the same page */
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
tlb_fill(addr, 0, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
DATA_TYPE val,
|
||||
int is_user)
|
||||
{
|
||||
unsigned long physaddr, tlb_addr;
|
||||
void *retaddr;
|
||||
int index;
|
||||
|
||||
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_write[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 = GETPC();
|
||||
glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
|
||||
is_user, retaddr);
|
||||
} else {
|
||||
/* aligned/unaligned access in the same page */
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = GETPC();
|
||||
tlb_fill(addr, 1, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
||||
/* handles all unaligned cases */
|
||||
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
|
||||
DATA_TYPE val,
|
||||
int is_user,
|
||||
void *retaddr)
|
||||
{
|
||||
unsigned long physaddr, tlb_addr;
|
||||
int index, i;
|
||||
|
||||
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_write[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
|
||||
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
|
||||
is_user, retaddr);
|
||||
#else
|
||||
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
|
||||
is_user, 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, is_user, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SHIFT
|
||||
#undef DATA_TYPE
|
||||
#undef SUFFIX
|
||||
#undef USUFFIX
|
||||
#undef DATA_SIZE
|
||||
@@ -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];
|
||||
@@ -24,9 +24,17 @@ register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
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);
|
||||
}
|
||||
+56
-48
@@ -17,71 +17,71 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-arm.h"
|
||||
#include "exec.h"
|
||||
|
||||
#define REGNAME r0
|
||||
#define REG (env->regs[0])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r1
|
||||
#define REG (env->regs[1])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r2
|
||||
#define REG (env->regs[2])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r3
|
||||
#define REG (env->regs[3])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r4
|
||||
#define REG (env->regs[4])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r5
|
||||
#define REG (env->regs[5])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r6
|
||||
#define REG (env->regs[6])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r7
|
||||
#define REG (env->regs[7])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r8
|
||||
#define REG (env->regs[8])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r9
|
||||
#define REG (env->regs[9])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r10
|
||||
#define REG (env->regs[10])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r11
|
||||
#define REG (env->regs[11])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r12
|
||||
#define REG (env->regs[12])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r13
|
||||
#define REG (env->regs[13])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r14
|
||||
#define REG (env->regs[14])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
#define REGNAME r15
|
||||
#define REG (env->regs[15])
|
||||
#include "op-arm-template.h"
|
||||
#include "op_template.h"
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
@@ -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 */
|
||||
@@ -360,7 +368,7 @@ void OPPROTO op_mul_T0_T1(void)
|
||||
void OPPROTO op_mull_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = T0 * T1;
|
||||
res = (uint64_t)T0 * (uint64_t)T1;
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
@@ -369,7 +377,7 @@ void OPPROTO op_mull_T0_T1(void)
|
||||
void OPPROTO op_imull_T0_T1(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = (int32_t)T0 * (int32_t)T1;
|
||||
res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
|
||||
T1 = res >> 32;
|
||||
T0 = res;
|
||||
}
|
||||
File renamed without changes.
@@ -23,8 +23,8 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu-arm.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
/* internal defines */
|
||||
@@ -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;
|
||||
@@ -42,12 +44,12 @@ extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc-arm.h"
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op-arm.h"
|
||||
#include "gen-op.h"
|
||||
|
||||
typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
||||
@@ -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,16 +509,16 @@ 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 */
|
||||
gen_movl_T0_reg(s, rs);
|
||||
gen_movl_T1_reg(s, rm);
|
||||
if (insn & (1 << 22))
|
||||
gen_op_mull_T0_T1();
|
||||
else
|
||||
gen_op_imull_T0_T1();
|
||||
else
|
||||
gen_op_mull_T0_T1();
|
||||
if (insn & (1 << 21))
|
||||
gen_op_addq_T0_T1(rn, rd);
|
||||
if (insn & (1 << 20))
|
||||
@@ -531,8 +546,7 @@ static void disas_arm_insn(DisasContext *s)
|
||||
rn = (insn >> 16) & 0xf;
|
||||
rd = (insn >> 12) & 0xf;
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (insn & (1 << 25))
|
||||
gen_add_datah_offset(s, insn);
|
||||
gen_add_datah_offset(s, insn);
|
||||
if (insn & (1 << 20)) {
|
||||
/* load */
|
||||
switch(sh) {
|
||||
@@ -547,14 +561,18 @@ static void disas_arm_insn(DisasContext *s)
|
||||
gen_op_ldsw_T0_T1();
|
||||
break;
|
||||
}
|
||||
gen_movl_reg_T0(s, rd);
|
||||
} else {
|
||||
/* store */
|
||||
gen_movl_T0_reg(s, rd);
|
||||
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 +600,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 +713,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 +787,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. */
|
||||
static inline int gen_intermediate_code_internal(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 +815,27 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
|
||||
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,14 +856,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen_intermediate_code(TranslationBlock *tb)
|
||||
int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 0);
|
||||
return gen_intermediate_code_internal(env, tb, 0);
|
||||
}
|
||||
|
||||
int gen_intermediate_code_pc(TranslationBlock *tb)
|
||||
int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 1);
|
||||
return gen_intermediate_code_internal(env, tb, 1);
|
||||
}
|
||||
|
||||
CPUARMState *cpu_arm_init(void)
|
||||
@@ -756,5 +895,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' : '-');
|
||||
}
|
||||
+104
-15
@@ -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
|
||||
@@ -59,12 +58,14 @@
|
||||
#define DESC_TYPE_SHIFT 8
|
||||
#define DESC_A_MASK (1 << 8)
|
||||
|
||||
#define DESC_CS_MASK (1 << 11)
|
||||
#define DESC_C_MASK (1 << 10)
|
||||
#define DESC_R_MASK (1 << 9)
|
||||
#define DESC_CS_MASK (1 << 11) /* 1=code segment 0=data segment */
|
||||
#define DESC_C_MASK (1 << 10) /* code: conforming */
|
||||
#define DESC_R_MASK (1 << 9) /* code: readable */
|
||||
|
||||
#define DESC_E_MASK (1 << 10)
|
||||
#define DESC_W_MASK (1 << 9)
|
||||
#define DESC_E_MASK (1 << 10) /* data: expansion direction */
|
||||
#define DESC_W_MASK (1 << 9) /* data: writable */
|
||||
|
||||
#define DESC_TSS_BUSY_MASK (1 << 9)
|
||||
|
||||
/* eflags masks */
|
||||
#define CC_C 0x0001
|
||||
@@ -74,6 +75,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
|
||||
@@ -86,6 +91,29 @@
|
||||
#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)
|
||||
@@ -153,13 +181,13 @@
|
||||
#define EXCP11_ALGN 17
|
||||
#define EXCP12_MCHK 18
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
||||
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
|
||||
CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
|
||||
|
||||
CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
|
||||
CC_OP_MULW,
|
||||
CC_OP_MULL,
|
||||
|
||||
CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
|
||||
CC_OP_ADDW,
|
||||
@@ -230,6 +258,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 */
|
||||
@@ -253,7 +282,7 @@ typedef struct CPUX86State {
|
||||
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;
|
||||
@@ -270,7 +299,17 @@ typedef struct CPUX86State {
|
||||
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;
|
||||
} CPUX86State;
|
||||
@@ -289,10 +328,57 @@ int cpu_x86_exec(CPUX86State *s);
|
||||
void cpu_x86_close(CPUX86State *s);
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *s);
|
||||
|
||||
/* needed to load some predefinied segment registers */
|
||||
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
|
||||
/* 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;
|
||||
|
||||
/* simulate fsave/frstor */
|
||||
/* 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);
|
||||
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
|
||||
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
|
||||
|
||||
@@ -308,6 +394,9 @@ void cpu_x86_init_mmu(CPUX86State *env);
|
||||
extern int phys_ram_size;
|
||||
extern int phys_ram_fd;
|
||||
extern uint8_t *phys_ram_base;
|
||||
extern int a20_enabled;
|
||||
|
||||
void cpu_x86_set_a20(CPUX86State *env, int a20_state);
|
||||
|
||||
/* used to debug */
|
||||
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
|
||||
@@ -112,8 +112,8 @@ extern int loglevel;
|
||||
#define FP_CONVERT (env->fp_convert)
|
||||
#endif
|
||||
|
||||
#include "cpu-i386.h"
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
typedef struct CCTable {
|
||||
int (*compute_all)(void); /* return all the flags */
|
||||
@@ -122,9 +122,13 @@ typedef struct CCTable {
|
||||
|
||||
extern CCTable cc_table[];
|
||||
|
||||
void load_seg(int seg_reg, int selector, unsigned cur_eip);
|
||||
void jmp_seg(int selector, unsigned int new_eip);
|
||||
void load_seg(int seg_reg, int selector);
|
||||
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);
|
||||
@@ -133,11 +137,14 @@ 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);
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr,
|
||||
int is_write, int is_user, int is_softmmu);
|
||||
void tlb_fill(unsigned long addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
void __hidden cpu_lock(void);
|
||||
void __hidden cpu_unlock(void);
|
||||
void do_interrupt(int intno, int is_int, int error_code,
|
||||
unsigned int next_eip);
|
||||
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,
|
||||
@@ -163,6 +170,124 @@ void helper_rdmsr(void);
|
||||
void helper_wrmsr(void);
|
||||
void helper_lsl(void);
|
||||
void helper_lar(void);
|
||||
void helper_verr(void);
|
||||
void helper_verw(void);
|
||||
|
||||
void check_iob_T0(void);
|
||||
void check_iow_T0(void);
|
||||
void check_iol_T0(void);
|
||||
void check_iob_DX(void);
|
||||
void check_iow_DX(void);
|
||||
void check_iol_DX(void);
|
||||
|
||||
/* XXX: move that to a generic header */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define ldul_user ldl_user
|
||||
#define ldul_kernel ldl_kernel
|
||||
|
||||
#define ACCESS_TYPE 0
|
||||
#define MEMSUFFIX _kernel
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define ACCESS_TYPE 1
|
||||
#define MEMSUFFIX _user
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
/* these access are slower, they must be as rare as possible */
|
||||
#define ACCESS_TYPE 2
|
||||
#define MEMSUFFIX _data
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define ldub(p) ldub_data(p)
|
||||
#define ldsb(p) ldsb_data(p)
|
||||
#define lduw(p) lduw_data(p)
|
||||
#define ldsw(p) ldsw_data(p)
|
||||
#define ldl(p) ldl_data(p)
|
||||
#define ldq(p) ldq_data(p)
|
||||
|
||||
#define stb(p, v) stb_data(p, v)
|
||||
#define stw(p, v) stw_data(p, v)
|
||||
#define stl(p, v) stl_data(p, v)
|
||||
#define stq(p, v) stq_data(p, v)
|
||||
|
||||
static inline double ldfq(void *ptr)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.i = ldq(ptr);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static inline void stfq(void *ptr, double v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} u;
|
||||
u.d = v;
|
||||
stq(ptr, u.i);
|
||||
}
|
||||
|
||||
static inline float ldfl(void *ptr)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.i = ldl(ptr);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void stfl(void *ptr, float v)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} u;
|
||||
u.f = v;
|
||||
stl(ptr, u.i);
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
/* use long double functions */
|
||||
@@ -310,7 +435,47 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
|
||||
e |= SIGND(temp) >> 16;
|
||||
stw(ptr + 8, e);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
|
||||
/* XXX: same endianness assumed */
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
||||
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
|
||||
{
|
||||
return *(CPU86_LDouble *)ptr;
|
||||
}
|
||||
|
||||
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
|
||||
{
|
||||
*(CPU86_LDouble *)ptr = f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* we use memory access macros */
|
||||
|
||||
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
|
||||
temp.l.lower = ldq(ptr);
|
||||
temp.l.upper = lduw(ptr + 8);
|
||||
return temp.d;
|
||||
}
|
||||
|
||||
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
|
||||
{
|
||||
CPU86_LDoubleU temp;
|
||||
|
||||
temp.d = f;
|
||||
stq(ptr, temp.l.lower);
|
||||
stw(ptr + 8, temp.l.upper);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
#endif /* USE_X86LDOUBLE */
|
||||
|
||||
const CPU86_LDouble f15rk[7];
|
||||
|
||||
@@ -347,11 +512,6 @@ 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)
|
||||
{
|
||||
@@ -360,3 +520,4 @@ static inline void load_eflags(int eflags, int update_mask)
|
||||
env->eflags = (env->eflags & ~update_mask) |
|
||||
(eflags & update_mask);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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.h"
|
||||
#include "exec-all.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",
|
||||
"MULB",
|
||||
"MULW",
|
||||
"MULL",
|
||||
"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, i;
|
||||
char cc_op_name[32];
|
||||
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
|
||||
|
||||
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] CPL=%d II=%d\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' : '-',
|
||||
env->hflags & HF_CPL_MASK,
|
||||
(env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1);
|
||||
for(i = 0; i < 6; i++) {
|
||||
SegmentCache *sc = &env->segs[i];
|
||||
fprintf(f, "%s =%04x %08x %08x %08x\n",
|
||||
seg_name[i],
|
||||
sc->selector,
|
||||
(int)sc->base,
|
||||
sc->limit,
|
||||
sc->flags);
|
||||
}
|
||||
fprintf(f, "LDT=%04x %08x %08x %08x\n",
|
||||
env->ldt.selector,
|
||||
(int)env->ldt.base,
|
||||
env->ldt.limit,
|
||||
env->ldt.flags);
|
||||
fprintf(f, "TR =%04x %08x %08x %08x\n",
|
||||
env->tr.selector,
|
||||
(int)env->tr.base,
|
||||
env->tr.limit,
|
||||
env->tr.flags);
|
||||
fprintf(f, "GDT= %08x %08x\n",
|
||||
(int)env->gdt.base, env->gdt.limit);
|
||||
fprintf(f, "IDT= %08x %08x\n",
|
||||
(int)env->idt.base, env->idt.limit);
|
||||
fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
|
||||
env->cr[0], env->cr[2], env->cr[3], env->cr[4]);
|
||||
|
||||
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;
|
||||
static uint32_t a20_mask;
|
||||
int a20_enabled;
|
||||
|
||||
int phys_ram_size;
|
||||
int phys_ram_fd;
|
||||
uint8_t *phys_ram_base;
|
||||
|
||||
void cpu_x86_set_a20(CPUX86State *env, int a20_state)
|
||||
{
|
||||
a20_state = (a20_state != 0);
|
||||
if (a20_state != a20_enabled) {
|
||||
#if defined(DEBUG_MMU)
|
||||
printf("A20 update: a20=%d\n", a20_state);
|
||||
#endif
|
||||
/* if the cpu is currently executing code, we must unlink it and
|
||||
all the potentially executing TB */
|
||||
cpu_interrupt(env, 0);
|
||||
|
||||
/* when a20 is changed, all the MMU mappings are invalid, so
|
||||
we must flush everything */
|
||||
tlb_flush(env);
|
||||
a20_enabled = a20_state;
|
||||
if (a20_enabled)
|
||||
a20_mask = 0xffffffff;
|
||||
else
|
||||
a20_mask = 0xffefffff;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_x86_update_cr0(CPUX86State *env)
|
||||
{
|
||||
int pg_state, pe_state;
|
||||
|
||||
#if defined(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) {
|
||||
tlb_flush(env);
|
||||
last_pg_state = pg_state;
|
||||
}
|
||||
pe_state = env->cr[0] & CR0_PE_MASK;
|
||||
if (last_pe_state != pe_state) {
|
||||
tb_flush(env);
|
||||
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
|
||||
tlb_flush(env);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_x86_init_mmu(CPUX86State *env)
|
||||
{
|
||||
a20_enabled = 1;
|
||||
a20_mask = 0xffffffff;
|
||||
|
||||
last_pg_state = -1;
|
||||
cpu_x86_update_cr0(env);
|
||||
}
|
||||
|
||||
/* XXX: also flush 4MB pages */
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
|
||||
{
|
||||
tlb_flush_page(env, addr);
|
||||
}
|
||||
|
||||
/* 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, int is_user, int is_softmmu)
|
||||
{
|
||||
uint8_t *pde_ptr, *pte_ptr;
|
||||
uint32_t pde, pte, virt_addr;
|
||||
int error_code, is_dirty, prot, page_size, ret;
|
||||
unsigned long pd;
|
||||
|
||||
#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 & TARGET_PAGE_MASK;
|
||||
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)) & a20_mask);
|
||||
pde = ldl_raw(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_raw(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_raw(pde_ptr, pde);
|
||||
}
|
||||
|
||||
/* page directory entry */
|
||||
pte_ptr = phys_ram_base +
|
||||
(((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask);
|
||||
pte = ldl_raw(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_raw(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:
|
||||
pte = pte & a20_mask;
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
if (is_softmmu)
|
||||
#endif
|
||||
{
|
||||
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 & TARGET_PAGE_MASK) & (page_size - 1);
|
||||
paddr = (pte & TARGET_PAGE_MASK) + 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;
|
||||
} else {
|
||||
env->tlb_write[is_user][index].address = -1;
|
||||
env->tlb_write[is_user][index].addend = -1;
|
||||
}
|
||||
page_set_flags(vaddr, vaddr + TARGET_PAGE_SIZE,
|
||||
PAGE_VALID | PAGE_EXEC | prot);
|
||||
ret = 0;
|
||||
}
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
else {
|
||||
ret = 0;
|
||||
/* XXX: incorrect for 4MB pages */
|
||||
pd = physpage_find(pte & ~0xfff);
|
||||
if ((pd & 0xfff) != 0) {
|
||||
/* IO access: no mapping is done as it will be handled by the
|
||||
soft MMU */
|
||||
if (!(env->hflags & HF_SOFTMMU_MASK))
|
||||
ret = 2;
|
||||
} else {
|
||||
void *map_addr;
|
||||
map_addr = mmap((void *)virt_addr, page_size, prot,
|
||||
MAP_SHARED | MAP_FIXED, phys_ram_fd, pd);
|
||||
if (map_addr == MAP_FAILED) {
|
||||
fprintf(stderr,
|
||||
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
|
||||
pte & ~0xfff, virt_addr);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
|
||||
pte & ~0xfff, virt_addr, (page_size != 4096));
|
||||
#endif
|
||||
page_set_flags(virt_addr, virt_addr + page_size,
|
||||
PAGE_VALID | PAGE_EXEC | prot);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
do_fault_protect:
|
||||
error_code = PG_ERROR_P_MASK;
|
||||
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;
|
||||
}
|
||||
+168
-127
@@ -17,7 +17,7 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec-i386.h"
|
||||
#include "exec.h"
|
||||
|
||||
/* n must be a constant to be efficient */
|
||||
static inline int lshift(int x, int n)
|
||||
@@ -169,11 +169,16 @@ void OPPROTO op_bswapl_T0(void)
|
||||
}
|
||||
|
||||
/* multiply/divide */
|
||||
|
||||
/* XXX: add eflags optimizations */
|
||||
/* XXX: add non P4 style flags */
|
||||
|
||||
void OPPROTO op_mulb_AL_T0(void)
|
||||
{
|
||||
unsigned int res;
|
||||
res = (uint8_t)EAX * (uint8_t)T0;
|
||||
EAX = (EAX & 0xffff0000) | res;
|
||||
CC_DST = res;
|
||||
CC_SRC = (res & 0xff00);
|
||||
}
|
||||
|
||||
@@ -182,6 +187,7 @@ void OPPROTO op_imulb_AL_T0(void)
|
||||
int res;
|
||||
res = (int8_t)EAX * (int8_t)T0;
|
||||
EAX = (EAX & 0xffff0000) | (res & 0xffff);
|
||||
CC_DST = res;
|
||||
CC_SRC = (res != (int8_t)res);
|
||||
}
|
||||
|
||||
@@ -191,6 +197,7 @@ void OPPROTO op_mulw_AX_T0(void)
|
||||
res = (uint16_t)EAX * (uint16_t)T0;
|
||||
EAX = (EAX & 0xffff0000) | (res & 0xffff);
|
||||
EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff);
|
||||
CC_DST = res;
|
||||
CC_SRC = res >> 16;
|
||||
}
|
||||
|
||||
@@ -200,6 +207,7 @@ void OPPROTO op_imulw_AX_T0(void)
|
||||
res = (int16_t)EAX * (int16_t)T0;
|
||||
EAX = (EAX & 0xffff0000) | (res & 0xffff);
|
||||
EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff);
|
||||
CC_DST = res;
|
||||
CC_SRC = (res != (int16_t)res);
|
||||
}
|
||||
|
||||
@@ -209,6 +217,7 @@ void OPPROTO op_mull_EAX_T0(void)
|
||||
res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0);
|
||||
EAX = res;
|
||||
EDX = res >> 32;
|
||||
CC_DST = res;
|
||||
CC_SRC = res >> 32;
|
||||
}
|
||||
|
||||
@@ -218,6 +227,7 @@ void OPPROTO op_imull_EAX_T0(void)
|
||||
res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0);
|
||||
EAX = res;
|
||||
EDX = res >> 32;
|
||||
CC_DST = res;
|
||||
CC_SRC = (res != (int32_t)res);
|
||||
}
|
||||
|
||||
@@ -226,6 +236,7 @@ void OPPROTO op_imulw_T0_T1(void)
|
||||
int res;
|
||||
res = (int16_t)T0 * (int16_t)T1;
|
||||
T0 = res;
|
||||
CC_DST = res;
|
||||
CC_SRC = (res != (int16_t)res);
|
||||
}
|
||||
|
||||
@@ -234,6 +245,7 @@ void OPPROTO op_imull_T0_T1(void)
|
||||
int64_t res;
|
||||
res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
|
||||
T0 = res;
|
||||
CC_DST = res;
|
||||
CC_SRC = (res != (int32_t)res);
|
||||
}
|
||||
|
||||
@@ -376,70 +388,16 @@ void OPPROTO op_andl_A0_ffff(void)
|
||||
|
||||
/* memory access */
|
||||
|
||||
void OPPROTO op_ldub_T0_A0(void)
|
||||
{
|
||||
T0 = ldub((uint8_t *)A0);
|
||||
}
|
||||
#define MEMSUFFIX _raw
|
||||
#include "ops_mem.h"
|
||||
|
||||
void OPPROTO op_ldsb_T0_A0(void)
|
||||
{
|
||||
T0 = ldsb((int8_t *)A0);
|
||||
}
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#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"
|
||||
#endif
|
||||
|
||||
/* used for bit operations */
|
||||
|
||||
@@ -471,6 +429,12 @@ void OPPROTO op_hlt(void)
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_debug(void)
|
||||
{
|
||||
env->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_raise_interrupt(void)
|
||||
{
|
||||
int intno;
|
||||
@@ -507,6 +471,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)
|
||||
@@ -556,9 +530,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)
|
||||
@@ -566,6 +540,11 @@ void OPPROTO op_movl_T0_0(void)
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
/* multiple size ops */
|
||||
|
||||
#define ldul ldl
|
||||
@@ -624,6 +603,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)
|
||||
@@ -893,9 +904,10 @@ 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);
|
||||
load_seg(PARAM1, T0);
|
||||
}
|
||||
|
||||
/* faster VM86 version */
|
||||
@@ -936,10 +948,54 @@ void OPPROTO op_lar(void)
|
||||
helper_lar();
|
||||
}
|
||||
|
||||
/* T0: segment, T1:eip */
|
||||
void OPPROTO op_ljmp_T0_T1(void)
|
||||
void OPPROTO op_verr(void)
|
||||
{
|
||||
jmp_seg(T0 & 0xffff, T1);
|
||||
helper_verr();
|
||||
}
|
||||
|
||||
void OPPROTO op_verw(void)
|
||||
{
|
||||
helper_verw();
|
||||
}
|
||||
|
||||
void OPPROTO op_arpl(void)
|
||||
{
|
||||
if ((T0 & 3) < (T1 & 3)) {
|
||||
/* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */
|
||||
T0 = (T0 & ~3) | (T1 & 3);
|
||||
T1 = CC_Z;
|
||||
} else {
|
||||
T1 = 0;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_arpl_update(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
CC_SRC = (eflags & ~CC_Z) | T1;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
@@ -947,6 +1003,11 @@ 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();
|
||||
@@ -1009,9 +1070,18 @@ void OPPROTO op_clts(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();
|
||||
}
|
||||
|
||||
@@ -1080,38 +1150,36 @@ void OPPROTO op_set_cc_op(void)
|
||||
CC_OP = PARAM1;
|
||||
}
|
||||
|
||||
#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff)
|
||||
/* XXX: clear VIF/VIP in all ops ? */
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = T0;
|
||||
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);
|
||||
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK));
|
||||
}
|
||||
|
||||
void OPPROTO op_movw_eflags_T0(void)
|
||||
{
|
||||
int eflags;
|
||||
eflags = T0;
|
||||
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);
|
||||
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK) & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_eflags_T0_io(void)
|
||||
{
|
||||
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK));
|
||||
}
|
||||
|
||||
void OPPROTO op_movw_eflags_T0_io(void)
|
||||
{
|
||||
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK) & 0xffff);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_eflags_T0_cpl0(void)
|
||||
{
|
||||
load_eflags(T0, FL_UPDATE_CPL0_MASK);
|
||||
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK));
|
||||
}
|
||||
|
||||
void OPPROTO op_movw_eflags_T0_cpl0(void)
|
||||
{
|
||||
load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff);
|
||||
load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK) & 0xffff);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -1237,31 +1305,14 @@ static int compute_c_eflags(void)
|
||||
return CC_SRC & CC_C;
|
||||
}
|
||||
|
||||
static int compute_c_mul(void)
|
||||
{
|
||||
int cf;
|
||||
cf = (CC_SRC != 0);
|
||||
return cf;
|
||||
}
|
||||
|
||||
static int compute_all_mul(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
cf = (CC_SRC != 0);
|
||||
pf = 0; /* undefined */
|
||||
af = 0; /* undefined */
|
||||
zf = 0; /* undefined */
|
||||
sf = 0; /* undefined */
|
||||
of = cf << 11;
|
||||
return cf | pf | af | zf | sf | of;
|
||||
}
|
||||
|
||||
CCTable cc_table[CC_OP_NB] = {
|
||||
[CC_OP_DYNAMIC] = { /* should never happen */ },
|
||||
|
||||
[CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
|
||||
|
||||
[CC_OP_MUL] = { compute_all_mul, compute_c_mul },
|
||||
[CC_OP_MULB] = { compute_all_mulb, compute_c_mull },
|
||||
[CC_OP_MULW] = { compute_all_mulw, compute_c_mull },
|
||||
[CC_OP_MULL] = { compute_all_mull, compute_c_mull },
|
||||
|
||||
[CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
|
||||
[CC_OP_ADDW] = { compute_all_addw, compute_c_addw },
|
||||
@@ -1442,21 +1493,10 @@ void OPPROTO op_fldl_ST0_A0(void)
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
void OPPROTO op_fldt_ST0_A0(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
helper_fldt_ST0_A0();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* helpers are needed to avoid static constant reference. XXX: find a better way */
|
||||
#ifdef USE_INT_TO_FLOAT_HELPERS
|
||||
@@ -1566,17 +1606,10 @@ void OPPROTO op_fstl_ST0_A0(void)
|
||||
stfq((void *)A0, (double)ST0);
|
||||
}
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
void OPPROTO op_fstt_ST0_A0(void)
|
||||
{
|
||||
*(long double *)A0 = ST0;
|
||||
}
|
||||
#else
|
||||
void OPPROTO op_fstt_ST0_A0(void)
|
||||
{
|
||||
helper_fstt_ST0_A0();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_fist_ST0_A0(void)
|
||||
{
|
||||
@@ -1736,6 +1769,14 @@ void OPPROTO op_fucomi_ST0_FT0(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmov_ST0_STN_T0(void)
|
||||
{
|
||||
if (T0) {
|
||||
ST0 = ST(PARAM1);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_fadd_ST0_FT0(void)
|
||||
{
|
||||
ST0 += FT0;
|
||||
@@ -1855,7 +1896,7 @@ void OPPROTO op_fldz_ST0(void)
|
||||
|
||||
void OPPROTO op_fldz_FT0(void)
|
||||
{
|
||||
ST0 = f15rk[0];
|
||||
FT0 = f15rk[0];
|
||||
}
|
||||
|
||||
/* associated heplers to reduce generated code length and to simplify
|
||||
@@ -83,12 +83,14 @@ void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
|
||||
{
|
||||
if (T0)
|
||||
REG = (REG & 0xffff0000) | (T1 & 0xffff);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
|
||||
{
|
||||
if (T0)
|
||||
REG = T1;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
@@ -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
|
||||
@@ -229,6 +229,29 @@ static int glue(compute_all_sar, SUFFIX)(void)
|
||||
return cf | pf | af | zf | sf | of;
|
||||
}
|
||||
|
||||
#if DATA_BITS == 32
|
||||
static int glue(compute_c_mul, SUFFIX)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = (CC_SRC != 0);
|
||||
return cf;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
|
||||
CF are modified and it is slower to do that. */
|
||||
static int glue(compute_all_mul, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
cf = (CC_SRC != 0);
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = 0; /* undefined */
|
||||
zf = ((DATA_TYPE)CC_DST == 0) << 6;
|
||||
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
|
||||
of = cf << 11;
|
||||
return cf | pf | af | zf | sf | of;
|
||||
}
|
||||
|
||||
/* various optimized jumps cases */
|
||||
|
||||
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
|
||||
@@ -238,18 +261,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void)
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -260,18 +283,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -282,9 +305,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -295,9 +318,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void)
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -518,34 +541,73 @@ void OPPROTO op_update_bt_cc(void)
|
||||
#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->segs[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->segs[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 */
|
||||
|
||||
@@ -559,6 +621,26 @@ 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);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void)
|
||||
{
|
||||
glue(glue(check_io, SUFFIX), _T0)();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void)
|
||||
{
|
||||
glue(glue(check_io, SUFFIX), _DX)();
|
||||
}
|
||||
|
||||
#undef DATA_BITS
|
||||
#undef SHIFT_MASK
|
||||
#undef SIGN_MASK
|
||||
@@ -44,6 +44,9 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
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) |
|
||||
@@ -63,6 +66,9 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
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) |
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* PPC emulation cpu definitions for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
*
|
||||
* 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 !defined (__CPU_PPC_H__)
|
||||
#define __CPU_PPC_H__
|
||||
|
||||
#include <endian.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "cpu-defs.h"
|
||||
|
||||
/*** Sign extend constants ***/
|
||||
/* 8 to 32 bits */
|
||||
static inline int32_t s_ext8 (uint8_t value)
|
||||
{
|
||||
int8_t *tmp = &value;
|
||||
|
||||
return *tmp;
|
||||
}
|
||||
|
||||
/* 16 to 32 bits */
|
||||
static inline int32_t s_ext16 (uint16_t value)
|
||||
{
|
||||
int16_t *tmp = &value;
|
||||
|
||||
return *tmp;
|
||||
}
|
||||
|
||||
/* 24 to 32 bits */
|
||||
static inline int32_t s_ext24 (uint32_t value)
|
||||
{
|
||||
uint16_t utmp = (value >> 8) & 0xFFFF;
|
||||
int16_t *tmp = &utmp;
|
||||
|
||||
return (*tmp << 8) | (value & 0xFF);
|
||||
}
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
/* Floting point status and control register */
|
||||
#define FPSCR_FX 31
|
||||
#define FPSCR_FEX 30
|
||||
#define FPSCR_VX 29
|
||||
#define FPSCR_OX 28
|
||||
#define FPSCR_UX 27
|
||||
#define FPSCR_ZX 26
|
||||
#define FPSCR_XX 25
|
||||
#define FPSCR_VXSNAN 24
|
||||
#define FPSCR_VXISI 26
|
||||
#define FPSCR_VXIDI 25
|
||||
#define FPSCR_VXZDZ 21
|
||||
#define FPSCR_VXIMZ 20
|
||||
|
||||
#define FPSCR_VXVC 18
|
||||
#define FPSCR_FR 17
|
||||
#define FPSCR_FI 16
|
||||
#define FPSCR_FPRF 11
|
||||
#define FPSCR_VXSOFT 9
|
||||
#define FPSCR_VXSQRT 8
|
||||
#define FPSCR_VXCVI 7
|
||||
#define FPSCR_OE 6
|
||||
#define FPSCR_UE 5
|
||||
#define FPSCR_ZE 4
|
||||
#define FPSCR_XE 3
|
||||
#define FPSCR_NI 2
|
||||
#define FPSCR_RN 0
|
||||
#define fpscr_fx env->fpscr[FPSCR_FX]
|
||||
#define fpscr_fex env->fpscr[FPSCR_FEX]
|
||||
#define fpscr_vx env->fpscr[FPSCR_VX]
|
||||
#define fpscr_ox env->fpscr[FPSCR_OX]
|
||||
#define fpscr_ux env->fpscr[FPSCR_UX]
|
||||
#define fpscr_zx env->fpscr[FPSCR_ZX]
|
||||
#define fpscr_xx env->fpscr[FPSCR_XX]
|
||||
#define fpscr_vsxnan env->fpscr[FPSCR_VXSNAN]
|
||||
#define fpscr_vxisi env->fpscr[FPSCR_VXISI]
|
||||
#define fpscr_vxidi env->fpscr[FPSCR_VXIDI]
|
||||
#define fpscr_vxzdz env->fpscr[FPSCR_VXZDZ]
|
||||
#define fpscr_vximz env->fpscr[FPSCR_VXIMZ]
|
||||
#define fpscr_fr env->fpscr[FPSCR_FR]
|
||||
#define fpscr_fi env->fpscr[FPSCR_FI]
|
||||
#define fpscr_fprf env->fpscr[FPSCR_FPRF]
|
||||
#define fpscr_vxsoft env->fpscr[FPSCR_VXSOFT]
|
||||
#define fpscr_vxsqrt env->fpscr[FPSCR_VXSQRT]
|
||||
#define fpscr_oe env->fpscr[FPSCR_OE]
|
||||
#define fpscr_ue env->fpscr[FPSCR_UE]
|
||||
#define fpscr_ze env->fpscr[FPSCR_ZE]
|
||||
#define fpscr_xe env->fpscr[FPSCR_XE]
|
||||
#define fpscr_ni env->fpscr[FPSCR_NI]
|
||||
#define fpscr_rn env->fpscr[FPSCR_RN]
|
||||
|
||||
/* Supervisor mode registers */
|
||||
/* Machine state register */
|
||||
#define MSR_POW 18
|
||||
#define MSR_ILE 16
|
||||
#define MSR_EE 15
|
||||
#define MSR_PR 14
|
||||
#define MSR_FP 13
|
||||
#define MSR_ME 12
|
||||
#define MSR_FE0 11
|
||||
#define MSR_SE 10
|
||||
#define MSR_BE 9
|
||||
#define MSR_FE1 8
|
||||
#define MSR_IP 6
|
||||
#define MSR_IR 5
|
||||
#define MSR_DR 4
|
||||
#define MSR_RI 1
|
||||
#define MSR_LE 0
|
||||
#define msr_pow env->msr[MSR_POW]
|
||||
#define msr_ile env->msr[MSR_ILE]
|
||||
#define msr_ee env->msr[MSR_EE]
|
||||
#define msr_pr env->msr[MSR_PR]
|
||||
#define msr_fp env->msr[MSR_FP]
|
||||
#define msr_me env->msr[MSR_ME]
|
||||
#define msr_fe0 env->msr[MSR_FE0]
|
||||
#define msr_se env->msr[MSR_SE]
|
||||
#define msr_be env->msr[MSR_BE]
|
||||
#define msr_fe1 env->msr[MSR_FE1]
|
||||
#define msr_ip env->msr[MSR_IP]
|
||||
#define msr_ir env->msr[MSR_IR]
|
||||
#define msr_dr env->msr[MSR_DR]
|
||||
#define msr_ri env->msr[MSR_RI]
|
||||
#define msr_le env->msr[MSR_LE]
|
||||
|
||||
/* Segment registers */
|
||||
typedef struct ppc_sr_t {
|
||||
uint32_t t:1;
|
||||
uint32_t ks:1;
|
||||
uint32_t kp:1;
|
||||
uint32_t n:1;
|
||||
uint32_t res:4;
|
||||
uint32_t vsid:24;
|
||||
} ppc_sr_t;
|
||||
|
||||
typedef struct CPUPPCState {
|
||||
/* general purpose registers */
|
||||
uint32_t gpr[32];
|
||||
/* floating point registers */
|
||||
double fpr[32];
|
||||
/* segment registers */
|
||||
ppc_sr_t sr[16];
|
||||
/* special purpose registers */
|
||||
uint32_t spr[1024];
|
||||
/* XER */
|
||||
uint8_t xer[32];
|
||||
/* Reservation address */
|
||||
uint32_t reserve;
|
||||
/* machine state register */
|
||||
uint8_t msr[32];
|
||||
/* condition register */
|
||||
uint8_t crf[8];
|
||||
/* floating point status and control register */
|
||||
uint8_t fpscr[32];
|
||||
uint32_t nip;
|
||||
/* CPU exception code */
|
||||
uint32_t exception;
|
||||
|
||||
/* qemu dedicated */
|
||||
/* temporary float registers */
|
||||
double ft0;
|
||||
double ft1;
|
||||
double ft2;
|
||||
int interrupt_request;
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int error_code;
|
||||
int user_mode_only; /* user mode only simulation */
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
} CPUPPCState;
|
||||
|
||||
CPUPPCState *cpu_ppc_init(void);
|
||||
int cpu_ppc_exec(CPUPPCState *s);
|
||||
void cpu_ppc_close(CPUPPCState *s);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
struct siginfo;
|
||||
int cpu_ppc_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
|
||||
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#include "cpu-all.h"
|
||||
|
||||
#define ugpr(n) (env->gpr[n])
|
||||
#define fpr(n) (env->fpr[n])
|
||||
|
||||
#define SPR_ENCODE(sprn) \
|
||||
(((sprn) >> 5) | (((sprn) & 0x1F) << 5))
|
||||
|
||||
/* User mode SPR */
|
||||
#define spr(n) env->spr[n]
|
||||
//#define XER spr[1]
|
||||
#define XER env->xer
|
||||
#define XER_SO 31
|
||||
#define XER_OV 30
|
||||
#define XER_CA 29
|
||||
#define XER_BC 0
|
||||
#define xer_so env->xer[XER_SO]
|
||||
#define xer_ov env->xer[XER_OV]
|
||||
#define xer_ca env->xer[XER_CA]
|
||||
#define xer_bc env->xer[XER_BC]
|
||||
|
||||
#define LR spr[SPR_ENCODE(8)]
|
||||
#define CTR spr[SPR_ENCODE(9)]
|
||||
/* VEA mode SPR */
|
||||
#define V_TBL spr[SPR_ENCODE(268)]
|
||||
#define V_TBU spr[SPR_ENCODE(269)]
|
||||
/* supervisor mode SPR */
|
||||
#define DSISR spr[SPR_ENCODE(18)]
|
||||
#define DAR spr[SPR_ENCODE(19)]
|
||||
#define DEC spr[SPR_ENCODE(22)]
|
||||
#define SDR1 spr[SPR_ENCODE(25)]
|
||||
typedef struct ppc_sdr1_t {
|
||||
uint32_t htaborg:16;
|
||||
uint32_t res:7;
|
||||
uint32_t htabmask:9;
|
||||
} ppc_sdr1_t;
|
||||
#define SRR0 spr[SPR_ENCODE(26)]
|
||||
#define SRR0_MASK 0xFFFFFFFC
|
||||
#define SRR1 spr[SPR_ENCODE(27)]
|
||||
#define SPRG0 spr[SPR_ENCODE(272)]
|
||||
#define SPRG1 spr[SPR_ENCODE(273)]
|
||||
#define SPRG2 spr[SPR_ENCODE(274)]
|
||||
#define SPRG3 spr[SPR_ENCODE(275)]
|
||||
#define EAR spr[SPR_ENCODE(282)]
|
||||
typedef struct ppc_ear_t {
|
||||
uint32_t e:1;
|
||||
uint32_t res:25;
|
||||
uint32_t rid:6;
|
||||
} ppc_ear_t;
|
||||
#define TBL spr[SPR_ENCODE(284)]
|
||||
#define TBU spr[SPR_ENCODE(285)]
|
||||
#define PVR spr[SPR_ENCODE(287)]
|
||||
typedef struct ppc_pvr_t {
|
||||
uint32_t version:16;
|
||||
uint32_t revision:16;
|
||||
} ppc_pvr_t;
|
||||
#define IBAT0U spr[SPR_ENCODE(528)]
|
||||
#define IBAT0L spr[SPR_ENCODE(529)]
|
||||
#define IBAT1U spr[SPR_ENCODE(530)]
|
||||
#define IBAT1L spr[SPR_ENCODE(531)]
|
||||
#define IBAT2U spr[SPR_ENCODE(532)]
|
||||
#define IBAT2L spr[SPR_ENCODE(533)]
|
||||
#define IBAT3U spr[SPR_ENCODE(534)]
|
||||
#define IBAT3L spr[SPR_ENCODE(535)]
|
||||
#define DBAT0U spr[SPR_ENCODE(536)]
|
||||
#define DBAT0L spr[SPR_ENCODE(537)]
|
||||
#define DBAT1U spr[SPR_ENCODE(538)]
|
||||
#define DBAT1L spr[SPR_ENCODE(539)]
|
||||
#define DBAT2U spr[SPR_ENCODE(540)]
|
||||
#define DBAT2L spr[SPR_ENCODE(541)]
|
||||
#define DBAT3U spr[SPR_ENCODE(542)]
|
||||
#define DBAT3L spr[SPR_ENCODE(543)]
|
||||
typedef struct ppc_ubat_t {
|
||||
uint32_t bepi:15;
|
||||
uint32_t res:4;
|
||||
uint32_t bl:11;
|
||||
uint32_t vs:1;
|
||||
uint32_t vp:1;
|
||||
} ppc_ubat_t;
|
||||
typedef struct ppc_lbat_t {
|
||||
uint32_t brpn:15;
|
||||
uint32_t res0:10;
|
||||
uint32_t w:1;
|
||||
uint32_t i:1;
|
||||
uint32_t m:1;
|
||||
uint32_t g:1;
|
||||
uint32_t res1:1;
|
||||
uint32_t pp:2;
|
||||
} ppc_lbat_t;
|
||||
#define DABR spr[SPR_ENCODE(1013)]
|
||||
#define DABR_MASK 0xFFFFFFF8
|
||||
typedef struct ppc_dabr_t {
|
||||
uint32_t dab:29;
|
||||
uint32_t bt:1;
|
||||
uint32_t dw:1;
|
||||
uint32_t dr:1;
|
||||
} ppc_dabr_t;
|
||||
#define FPECR spr[SPR_ENCODE(1022)]
|
||||
#define PIR spr[SPR_ENCODE(1023)]
|
||||
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#include "cpu-all.h"
|
||||
|
||||
CPUPPCState *cpu_ppc_init(void);
|
||||
int cpu_ppc_exec(CPUPPCState *s);
|
||||
void cpu_ppc_close(CPUPPCState *s);
|
||||
void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
|
||||
|
||||
/* Exeptions */
|
||||
enum {
|
||||
EXCP_NONE = 0x00,
|
||||
/* PPC hardware exceptions : exception vector / 0x100 */
|
||||
EXCP_RESET = 0x01, /* System reset */
|
||||
EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */
|
||||
EXCP_DSI = 0x03, /* Impossible memory access */
|
||||
EXCP_ISI = 0x04, /* Impossible instruction fetch */
|
||||
EXCP_EXTERNAL = 0x05, /* External interruption */
|
||||
EXCP_ALIGN = 0x06, /* Alignment exception */
|
||||
EXCP_PROGRAM = 0x07, /* Program exception */
|
||||
EXCP_NO_FP = 0x08, /* No floating point */
|
||||
EXCP_DECR = 0x09, /* Decrementer exception */
|
||||
EXCP_RESA = 0x0A, /* Implementation specific */
|
||||
EXCP_RESB = 0x0B, /* Implementation specific */
|
||||
EXCP_SYSCALL = 0x0C, /* System call */
|
||||
EXCP_TRACE = 0x0D, /* Trace exception (optional) */
|
||||
EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */
|
||||
#if 0
|
||||
/* Exeption subtypes for EXCP_DSI */
|
||||
EXCP_DSI_TRANSLATE = 0x10301, /* Data address can't be translated */
|
||||
EXCP_DSI_NOTSUP = 0x10302, /* Access type not supported */
|
||||
EXCP_DSI_PROT = 0x10303, /* Memory protection violation */
|
||||
EXCP_DSI_EXTERNAL = 0x10304, /* External access disabled */
|
||||
EXCP_DSI_DABR = 0x10305, /* Data address breakpoint */
|
||||
/* Exeption subtypes for EXCP_ISI */
|
||||
EXCP_ISI_TRANSLATE = 0x10401, /* Code address can't be translated */
|
||||
EXCP_ISI_NOTSUP = 0x10402, /* Access type not supported */
|
||||
EXCP_ISI_PROT = 0x10403, /* Memory protection violation */
|
||||
EXCP_ISI_GUARD = 0x10404, /* Fetch into guarded memory */
|
||||
/* Exeption subtypes for EXCP_ALIGN */
|
||||
EXCP_ALIGN_FP = 0x10601, /* FP alignment exception */
|
||||
EXCP_ALIGN_LST = 0x10602, /* Unaligned memory load/store */
|
||||
EXCP_ALIGN_LE = 0x10603, /* Unaligned little-endian access */
|
||||
EXCP_ALIGN_PROT = 0x10604, /* Access cross protection boundary */
|
||||
EXCP_ALIGN_BAT = 0x10605, /* Access cross a BAT/seg boundary */
|
||||
EXCP_ALIGN_CACHE = 0x10606, /* Impossible dcbz access */
|
||||
/* Exeption subtypes for EXCP_PROGRAM */
|
||||
/* FP exceptions */
|
||||
EXCP_FP_OX = 0x10701, /* FP overflow */
|
||||
EXCP_FP_UX = 0x10702, /* FP underflow */
|
||||
EXCP_FP_ZX = 0x10703, /* FP divide by zero */
|
||||
EXCP_FP_XX = 0x10704, /* FP inexact */
|
||||
EXCP_FP_VXNAN = 0x10705, /* FP invalid SNaN op */
|
||||
EXCP_FP_VXISI = 0x10706, /* FP invalid infinite substraction */
|
||||
EXCP_FP_VXIDI = 0x10707, /* FP invalid infinite divide */
|
||||
EXCP_FP_VXZDZ = 0x10708, /* FP invalid zero divide */
|
||||
EXCP_FP_VXIMZ = 0x10709, /* FP invalid infinite * zero */
|
||||
EXCP_FP_VXVC = 0x1070A, /* FP invalid compare */
|
||||
EXCP_FP_VXSOFT = 0x1070B, /* FP invalid operation */
|
||||
EXCP_FP_VXSQRT = 0x1070C, /* FP invalid square root */
|
||||
EXCP_FP_VXCVI = 0x1070D, /* FP invalid integer conversion */
|
||||
/* Invalid instruction */
|
||||
EXCP_INVAL_INVAL = 0x10711, /* Invalid instruction */
|
||||
EXCP_INVAL_LSWX = 0x10712, /* Invalid lswx instruction */
|
||||
EXCP_INVAL_SPR = 0x10713, /* Invalid SPR access */
|
||||
EXCP_INVAL_FP = 0x10714, /* Unimplemented mandatory fp instr */
|
||||
#endif
|
||||
EXCP_INVAL = 0x70, /* Invalid instruction */
|
||||
/* Privileged instruction */
|
||||
EXCP_PRIV = 0x71, /* Privileged instruction */
|
||||
/* Trap */
|
||||
EXCP_TRAP = 0x72, /* Trap */
|
||||
/* Special cases where we want to stop translation */
|
||||
EXCP_MTMSR = 0x103, /* mtmsr instruction: */
|
||||
/* may change privilege level */
|
||||
EXCP_BRANCH = 0x104, /* branch instruction */
|
||||
};
|
||||
|
||||
#endif /* !defined (__CPU_PPC_H__) */
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* PPC emulation definitions for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
*
|
||||
* 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 !defined (__PPC_H__)
|
||||
#define __PPC_H__
|
||||
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
register struct CPUPPCState *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#define PARAM(n) ((uint32_t)PARAM##n)
|
||||
#define SPARAM(n) ((int32_t)PARAM##n)
|
||||
#define FT0 (env->ft0)
|
||||
#define FT1 (env->ft1)
|
||||
#define FT2 (env->ft2)
|
||||
#define FTS0 ((float)env->ft0)
|
||||
#define FTS1 ((float)env->ft1)
|
||||
#define FTS2 ((float)env->ft2)
|
||||
|
||||
#define RETURN() __asm__ __volatile__("");
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
static inline uint8_t ld8 (uint32_t EA)
|
||||
{
|
||||
return *((uint8_t *)EA);
|
||||
}
|
||||
|
||||
static inline uint16_t ld16 (uint32_t EA)
|
||||
{
|
||||
return __be16_to_cpu(*((uint16_t *)EA));
|
||||
}
|
||||
|
||||
static inline uint16_t ld16r (uint32_t EA)
|
||||
{
|
||||
return __le16_to_cpu(*((uint16_t *)EA));
|
||||
}
|
||||
|
||||
static inline uint32_t ld32 (uint32_t EA)
|
||||
{
|
||||
return __be32_to_cpu(*((uint32_t *)EA));
|
||||
}
|
||||
|
||||
static inline uint32_t ld32r (uint32_t EA)
|
||||
{
|
||||
return __le32_to_cpu(*((uint32_t *)EA));
|
||||
}
|
||||
|
||||
static inline uint64_t ld64 (uint32_t EA)
|
||||
{
|
||||
return __be64_to_cpu(*((uint64_t *)EA));
|
||||
}
|
||||
|
||||
static inline uint64_t ld64r (uint32_t EA)
|
||||
{
|
||||
return __le64_to_cpu(*((uint64_t *)EA));
|
||||
}
|
||||
|
||||
static inline void st8 (uint32_t EA, uint8_t data)
|
||||
{
|
||||
*((uint8_t *)EA) = data;
|
||||
}
|
||||
|
||||
static inline void st16 (uint32_t EA, uint16_t data)
|
||||
{
|
||||
*((uint16_t *)EA) = __cpu_to_be16(data);
|
||||
}
|
||||
|
||||
static inline void st16r (uint32_t EA, uint16_t data)
|
||||
{
|
||||
*((uint16_t *)EA) = __cpu_to_le16(data);
|
||||
}
|
||||
|
||||
static inline void st32 (uint32_t EA, uint32_t data)
|
||||
{
|
||||
*((uint32_t *)EA) = __cpu_to_be32(data);
|
||||
}
|
||||
|
||||
static inline void st32r (uint32_t EA, uint32_t data)
|
||||
{
|
||||
*((uint32_t *)EA) = __cpu_to_le32(data);
|
||||
}
|
||||
|
||||
static inline void st64 (uint32_t EA, uint64_t data)
|
||||
{
|
||||
*((uint64_t *)EA) = __cpu_to_be64(data);
|
||||
}
|
||||
|
||||
static inline void st64r (uint32_t EA, uint64_t data)
|
||||
{
|
||||
*((uint64_t *)EA) = __cpu_to_le64(data);
|
||||
}
|
||||
|
||||
static inline void set_CRn(int n, uint8_t value)
|
||||
{
|
||||
env->crf[n] = value;
|
||||
}
|
||||
|
||||
static inline void set_carry (void)
|
||||
{
|
||||
xer_ca = 1;
|
||||
}
|
||||
|
||||
static inline void reset_carry (void)
|
||||
{
|
||||
xer_ca = 0;
|
||||
}
|
||||
|
||||
static inline void set_overflow (void)
|
||||
{
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
|
||||
static inline void reset_overflow (void)
|
||||
{
|
||||
xer_ov = 0;
|
||||
}
|
||||
|
||||
static inline uint32_t rotl (uint32_t i, int n)
|
||||
{
|
||||
return ((i << n) | (i >> (32 - n)));
|
||||
}
|
||||
|
||||
void raise_exception (int exception_index);
|
||||
void raise_exception_err (int exception_index, int error_code);
|
||||
|
||||
uint32_t do_load_cr (void);
|
||||
void do_store_cr (uint32_t crn, uint32_t value);
|
||||
uint32_t do_load_xer (void);
|
||||
void do_store_xer (uint32_t value);
|
||||
uint32_t do_load_msr (void);
|
||||
void do_store_msr (uint32_t msr_value);
|
||||
void do_load_fpscr (void);
|
||||
void do_store_fpscr (uint32_t mask);
|
||||
|
||||
int32_t do_sraw(int32_t Ta, uint32_t Tb);
|
||||
void do_lmw (int reg, uint32_t src);
|
||||
void do_stmw (int reg, uint32_t dest);
|
||||
void do_lsw (uint32_t reg, int count, uint32_t src);
|
||||
void do_stsw (uint32_t reg, int count, uint32_t dest);
|
||||
|
||||
void do_dcbz (void);
|
||||
void do_icbi (void);
|
||||
|
||||
#endif /* !defined (__PPC_H__) */
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* PPC emulation helpers for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "exec.h"
|
||||
|
||||
extern FILE *logfile;
|
||||
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
/* shortcuts to generate exceptions */
|
||||
void raise_exception_err (int exception_index, int error_code)
|
||||
{
|
||||
env->exception_index = exception_index;
|
||||
env->error_code = error_code;
|
||||
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void raise_exception (int exception_index)
|
||||
{
|
||||
env->exception_index = exception_index;
|
||||
env->error_code = 0;
|
||||
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
/* Helpers for "fat" micro operations */
|
||||
uint32_t do_load_cr (void)
|
||||
{
|
||||
return (env->crf[0] << 28) |
|
||||
(env->crf[1] << 24) |
|
||||
(env->crf[2] << 20) |
|
||||
(env->crf[3] << 16) |
|
||||
(env->crf[4] << 12) |
|
||||
(env->crf[5] << 8) |
|
||||
(env->crf[6] << 4) |
|
||||
(env->crf[7] << 0);
|
||||
}
|
||||
|
||||
void do_store_cr (uint32_t crn, uint32_t value)
|
||||
{
|
||||
int i, sh;
|
||||
|
||||
for (i = 0, sh = 7; i < 8; i++, sh --) {
|
||||
if (crn & (1 << sh))
|
||||
env->crf[i] = (value >> (sh * 4)) & 0xF;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t do_load_xer (void)
|
||||
{
|
||||
return (xer_so << XER_SO) |
|
||||
(xer_ov << XER_OV) |
|
||||
(xer_ca << XER_CA) |
|
||||
(xer_bc << XER_BC);
|
||||
}
|
||||
|
||||
void do_store_xer (uint32_t value)
|
||||
{
|
||||
xer_so = (value >> XER_SO) & 0x01;
|
||||
xer_ov = (value >> XER_OV) & 0x01;
|
||||
xer_ca = (value >> XER_CA) & 0x01;
|
||||
xer_bc = (value >> XER_BC) & 0x1f;
|
||||
}
|
||||
|
||||
uint32_t do_load_msr (void)
|
||||
{
|
||||
return (msr_pow << MSR_POW) |
|
||||
(msr_ile << MSR_ILE) |
|
||||
(msr_ee << MSR_EE) |
|
||||
(msr_pr << MSR_PR) |
|
||||
(msr_fp << MSR_FP) |
|
||||
(msr_me << MSR_ME) |
|
||||
(msr_fe0 << MSR_FE0) |
|
||||
(msr_se << MSR_SE) |
|
||||
(msr_be << MSR_BE) |
|
||||
(msr_fe1 << MSR_FE1) |
|
||||
(msr_ip << MSR_IP) |
|
||||
(msr_ir << MSR_IR) |
|
||||
(msr_dr << MSR_DR) |
|
||||
(msr_ri << MSR_RI) |
|
||||
(msr_le << MSR_LE);
|
||||
}
|
||||
|
||||
void do_store_msr (uint32_t msr_value)
|
||||
{
|
||||
msr_pow = (msr_value >> MSR_POW) & 0x03;
|
||||
msr_ile = (msr_value >> MSR_ILE) & 0x01;
|
||||
msr_ee = (msr_value >> MSR_EE) & 0x01;
|
||||
msr_pr = (msr_value >> MSR_PR) & 0x01;
|
||||
msr_fp = (msr_value >> MSR_FP) & 0x01;
|
||||
msr_me = (msr_value >> MSR_ME) & 0x01;
|
||||
msr_fe0 = (msr_value >> MSR_FE0) & 0x01;
|
||||
msr_se = (msr_value >> MSR_SE) & 0x01;
|
||||
msr_be = (msr_value >> MSR_BE) & 0x01;
|
||||
msr_fe1 = (msr_value >> MSR_FE1) & 0x01;
|
||||
msr_ip = (msr_value >> MSR_IP) & 0x01;
|
||||
msr_ir = (msr_value >> MSR_IR) & 0x01;
|
||||
msr_dr = (msr_value >> MSR_DR) & 0x01;
|
||||
msr_ri = (msr_value >> MSR_RI) & 0x01;
|
||||
msr_le = (msr_value >> MSR_LE) & 0x01;
|
||||
}
|
||||
|
||||
/* The 32 MSB of the target fpr are undefined. They'll be zero... */
|
||||
/* Floating point operations helpers */
|
||||
void do_load_fpscr (void)
|
||||
{
|
||||
/* The 32 MSB of the target fpr are undefined.
|
||||
* They'll be zero...
|
||||
*/
|
||||
union {
|
||||
double d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
int i;
|
||||
|
||||
u.s.u[0] = 0;
|
||||
u.s.u[1] = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
u.s.u[1] |= env->fpscr[i] << (4 * i);
|
||||
FT0 = u.d;
|
||||
}
|
||||
|
||||
void do_store_fpscr (uint32_t mask)
|
||||
{
|
||||
/*
|
||||
* We use only the 32 LSB of the incoming fpr
|
||||
*/
|
||||
union {
|
||||
double d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
int i;
|
||||
|
||||
u.d = FT0;
|
||||
if (mask & 0x80)
|
||||
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[1] >> 28) & ~0x9);
|
||||
for (i = 1; i < 7; i++) {
|
||||
if (mask & (1 << (7 - i)))
|
||||
env->fpscr[i] = (u.s.u[1] >> (4 * (7 - i))) & 0xF;
|
||||
}
|
||||
/* TODO: update FEX & VX */
|
||||
/* Set rounding mode */
|
||||
switch (env->fpscr[0] & 0x3) {
|
||||
case 0:
|
||||
/* Best approximation (round to nearest) */
|
||||
fesetround(FE_TONEAREST);
|
||||
break;
|
||||
case 1:
|
||||
/* Smaller magnitude (round toward zero) */
|
||||
fesetround(FE_TOWARDZERO);
|
||||
break;
|
||||
case 2:
|
||||
/* Round toward +infinite */
|
||||
fesetround(FE_UPWARD);
|
||||
break;
|
||||
case 3:
|
||||
/* Round toward -infinite */
|
||||
fesetround(FE_DOWNWARD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t do_sraw(int32_t value, uint32_t shift)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
xer_ca = 0;
|
||||
if (shift & 0x20) {
|
||||
ret = (-1) * ((uint32_t)value >> 31);
|
||||
if (ret < 0)
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
ret = value >> (shift & 0x1f);
|
||||
if (ret < 0 && (value & ((1 << shift) - 1)) != 0)
|
||||
xer_ca = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void do_lmw (int reg, uint32_t src)
|
||||
{
|
||||
for (; reg <= 31; reg++, src += 4)
|
||||
ugpr(reg) = ld32(src);
|
||||
}
|
||||
|
||||
void do_stmw (int reg, uint32_t dest)
|
||||
{
|
||||
for (; reg <= 31; reg++, dest += 4)
|
||||
st32(dest, ugpr(reg));
|
||||
}
|
||||
|
||||
void do_lsw (uint32_t reg, int count, uint32_t src)
|
||||
{
|
||||
uint32_t tmp;
|
||||
int sh;
|
||||
|
||||
for (; count > 3; count -= 4, src += 4) {
|
||||
ugpr(reg++) = ld32(src);
|
||||
if (T2 == 32)
|
||||
T2 = 0;
|
||||
}
|
||||
if (count > 0) {
|
||||
tmp = 0;
|
||||
for (sh = 24; count > 0; count--, src++, sh -= 8) {
|
||||
tmp |= ld8(src) << sh;
|
||||
}
|
||||
ugpr(reg) = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void do_stsw (uint32_t reg, int count, uint32_t dest)
|
||||
{
|
||||
int sh;
|
||||
|
||||
for (; count > 3; count -= 4, dest += 4) {
|
||||
st32(dest, ugpr(reg++));
|
||||
if (reg == 32)
|
||||
reg = 0;
|
||||
}
|
||||
if (count > 0) {
|
||||
for (sh = 24; count > 0; count--, dest++, sh -= 8) {
|
||||
st8(dest, (ugpr(reg) >> sh) & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_dcbz (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Assume cache line size is 32 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
st32(T0, 0);
|
||||
T0 += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Instruction cache invalidation helper */
|
||||
void do_icbi (void)
|
||||
{
|
||||
tb_invalidate_page(T0);
|
||||
}
|
||||
+1418
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* PPC emulation micro-operations for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
|
||||
{
|
||||
T0 = regs->gpr[REG];
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
|
||||
{
|
||||
T1 = regs->gpr[REG];
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
|
||||
{
|
||||
T2 = regs->gpr[REG];
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
|
||||
{
|
||||
regs->gpr[REG] = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
|
||||
{
|
||||
regs->gpr[REG] = T1;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
|
||||
{
|
||||
regs->gpr[REG] = T2;
|
||||
}
|
||||
|
||||
#if REG <= 7
|
||||
|
||||
void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
|
||||
{
|
||||
T0 = regs->crf[REG];
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
|
||||
{
|
||||
T1 = regs->crf[REG];
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
|
||||
{
|
||||
regs->crf[REG] = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
|
||||
{
|
||||
regs->crf[REG] = T1;
|
||||
}
|
||||
|
||||
/* Floating point condition and status register moves */
|
||||
void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void)
|
||||
{
|
||||
T0 = regs->fpscr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
#if REG == 0
|
||||
void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
|
||||
{
|
||||
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
|
||||
{
|
||||
regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
|
||||
{
|
||||
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9);
|
||||
RETURN();
|
||||
}
|
||||
#else
|
||||
void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
|
||||
{
|
||||
regs->fpscr[REG] = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
|
||||
{
|
||||
regs->fpscr[REG] = PARAM(1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
|
||||
{
|
||||
regs->fpscr[REG] = 0x0;
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* REG <= 7 */
|
||||
|
||||
/* float moves */
|
||||
|
||||
/* floating point registers moves */
|
||||
void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void)
|
||||
{
|
||||
FT0 = env->fpr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void)
|
||||
{
|
||||
env->fpr[REG] = FT0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void)
|
||||
{
|
||||
FT1 = env->fpr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void)
|
||||
{
|
||||
env->fpr[REG] = FT1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void)
|
||||
{
|
||||
FT2 = env->fpr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void)
|
||||
{
|
||||
env->fpr[REG] = FT2;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
#undef REG
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,59 @@
|
||||
#ifndef CPU_SPARC_H
|
||||
#define CPU_SPARC_H
|
||||
|
||||
#include <setjmp.h>
|
||||
#include "config.h"
|
||||
#include "cpu-defs.h"
|
||||
|
||||
/*#define EXCP_INTERRUPT 0x100*/
|
||||
|
||||
/* trap definitions */
|
||||
#define TT_ILL_INSN 0x02
|
||||
#define TT_WIN_OVF 0x05
|
||||
#define TT_WIN_UNF 0x06
|
||||
#define TT_DIV_ZERO 0x2a
|
||||
#define TT_TRAP 0x80
|
||||
|
||||
#define PSR_NEG (1<<23)
|
||||
#define PSR_ZERO (1<<22)
|
||||
#define PSR_OVF (1<<21)
|
||||
#define PSR_CARRY (1<<20)
|
||||
|
||||
#define NWINDOWS 32
|
||||
|
||||
typedef struct CPUSPARCState {
|
||||
uint32_t gregs[8]; /* general registers */
|
||||
uint32_t *regwptr; /* pointer to current register window */
|
||||
double *regfptr; /* floating point registers */
|
||||
uint32_t pc; /* program counter */
|
||||
uint32_t npc; /* next program counter */
|
||||
uint32_t sp; /* stack pointer */
|
||||
uint32_t y; /* multiply/divide register */
|
||||
uint32_t psr; /* processor state register */
|
||||
uint32_t T2;
|
||||
uint32_t cwp; /* index of current register window (extracted
|
||||
from PSR) */
|
||||
uint32_t wim; /* window invalid mask */
|
||||
jmp_buf jmp_env;
|
||||
int user_mode_only;
|
||||
int exception_index;
|
||||
int interrupt_index;
|
||||
int interrupt_request;
|
||||
struct TranslationBlock *current_tb;
|
||||
void *opaque;
|
||||
/* NOTE: we allow 8 more registers to handle wrapping */
|
||||
uint32_t regbase[NWINDOWS * 16 + 8];
|
||||
} CPUSPARCState;
|
||||
|
||||
CPUSPARCState *cpu_sparc_init(void);
|
||||
int cpu_sparc_exec(CPUSPARCState *s);
|
||||
int cpu_sparc_close(CPUSPARCState *s);
|
||||
|
||||
struct siginfo;
|
||||
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
|
||||
void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags);
|
||||
|
||||
#define TARGET_PAGE_BITS 13
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef EXEC_SPARC_H
|
||||
#define EXEC_SPARC_H 1
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
register struct CPUSPARCState *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void cpu_loop_exit(void);
|
||||
#endif
|
||||
@@ -0,0 +1,661 @@
|
||||
/*
|
||||
SPARC micro operations
|
||||
|
||||
Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
/*XXX*/
|
||||
#define REGNAME g0
|
||||
#define REG (env->gregs[0])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g1
|
||||
#define REG (env->gregs[1])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g2
|
||||
#define REG (env->gregs[2])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g3
|
||||
#define REG (env->gregs[3])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g4
|
||||
#define REG (env->gregs[4])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g5
|
||||
#define REG (env->gregs[5])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g6
|
||||
#define REG (env->gregs[6])
|
||||
#include "op_template.h"
|
||||
#define REGNAME g7
|
||||
#define REG (env->gregs[7])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i0
|
||||
#define REG (env->regwptr[16])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i1
|
||||
#define REG (env->regwptr[17])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i2
|
||||
#define REG (env->regwptr[18])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i3
|
||||
#define REG (env->regwptr[19])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i4
|
||||
#define REG (env->regwptr[20])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i5
|
||||
#define REG (env->regwptr[21])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i6
|
||||
#define REG (env->regwptr[22])
|
||||
#include "op_template.h"
|
||||
#define REGNAME i7
|
||||
#define REG (env->regwptr[23])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l0
|
||||
#define REG (env->regwptr[8])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l1
|
||||
#define REG (env->regwptr[9])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l2
|
||||
#define REG (env->regwptr[10])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l3
|
||||
#define REG (env->regwptr[11])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l4
|
||||
#define REG (env->regwptr[12])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l5
|
||||
#define REG (env->regwptr[13])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l6
|
||||
#define REG (env->regwptr[14])
|
||||
#include "op_template.h"
|
||||
#define REGNAME l7
|
||||
#define REG (env->regwptr[15])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o0
|
||||
#define REG (env->regwptr[0])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o1
|
||||
#define REG (env->regwptr[1])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o2
|
||||
#define REG (env->regwptr[2])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o3
|
||||
#define REG (env->regwptr[3])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o4
|
||||
#define REG (env->regwptr[4])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o5
|
||||
#define REG (env->regwptr[5])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o6
|
||||
#define REG (env->regwptr[6])
|
||||
#include "op_template.h"
|
||||
#define REGNAME o7
|
||||
#define REG (env->regwptr[7])
|
||||
#include "op_template.h"
|
||||
#define EIP (env->pc)
|
||||
|
||||
#define FLAG_SET(x) (env->psr&x)?1:0
|
||||
#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY)
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_1(void)
|
||||
{
|
||||
T0 = 1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_im(void)
|
||||
{
|
||||
T0 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T1_im(void)
|
||||
{
|
||||
T1 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T2_im(void)
|
||||
{
|
||||
T2 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_im(void)
|
||||
{
|
||||
T1 += PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_T2(void)
|
||||
{
|
||||
T1 += T2;
|
||||
}
|
||||
|
||||
void OPPROTO op_subl_T1_T2(void)
|
||||
{
|
||||
T1 -= T2;
|
||||
}
|
||||
|
||||
void OPPROTO op_add_T1_T0(void)
|
||||
{
|
||||
T0 += T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_add_T1_T0_cc(void)
|
||||
{
|
||||
unsigned int src1;
|
||||
src1 = T0;
|
||||
T0 += T1;
|
||||
env->psr = 0;
|
||||
if (!T0)
|
||||
env->psr |= PSR_ZERO;
|
||||
if ((int) T0 < 0)
|
||||
env->psr |= PSR_NEG;
|
||||
if (T0 < src1)
|
||||
env->psr |= PSR_CARRY;
|
||||
if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
|
||||
env->psr |= PSR_OVF;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sub_T1_T0(void)
|
||||
{
|
||||
T0 -= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sub_T1_T0_cc(void)
|
||||
{
|
||||
unsigned int src1;
|
||||
|
||||
src1 = T0;
|
||||
T0 -= T1;
|
||||
env->psr = 0;
|
||||
if (!T0)
|
||||
env->psr |= PSR_ZERO;
|
||||
if ((int) T0 < 0)
|
||||
env->psr |= PSR_NEG;
|
||||
if (src1 < T1)
|
||||
env->psr |= PSR_CARRY;
|
||||
if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
|
||||
env->psr |= PSR_OVF;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_and_T1_T0(void)
|
||||
{
|
||||
T0 &= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_or_T1_T0(void)
|
||||
{
|
||||
T0 |= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xor_T1_T0(void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_andn_T1_T0(void)
|
||||
{
|
||||
T0 &= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_orn_T1_T0(void)
|
||||
{
|
||||
T0 |= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xnor_T1_T0(void)
|
||||
{
|
||||
T0 ^= ~T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addx_T1_T0(void)
|
||||
{
|
||||
T0 += T1 + ((env->psr & PSR_CARRY) ? 1 : 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_umul_T1_T0(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = (uint64_t) T0 *(uint64_t) T1;
|
||||
T0 = res & 0xffffffff;
|
||||
env->y = res >> 32;
|
||||
}
|
||||
|
||||
void OPPROTO op_smul_T1_T0(void)
|
||||
{
|
||||
uint64_t res;
|
||||
res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1);
|
||||
T0 = res & 0xffffffff;
|
||||
env->y = res >> 32;
|
||||
}
|
||||
|
||||
void OPPROTO op_mulscc_T1_T0(void)
|
||||
{
|
||||
unsigned int b1, C, V, b2, src1;
|
||||
C = FLAG_SET(PSR_CARRY);
|
||||
V = FLAG_SET(PSR_OVF);
|
||||
b1 = C ^ V;
|
||||
b2 = T0 & 1;
|
||||
T0 = (b1 << 31) | (T0 >> 1);
|
||||
if (!(env->y & 1))
|
||||
T1 = 0;
|
||||
/* do addition and update flags */
|
||||
src1 = T0;
|
||||
T0 += T1;
|
||||
env->psr = 0;
|
||||
if (!T0)
|
||||
env->psr |= PSR_ZERO;
|
||||
if ((int) T0 < 0)
|
||||
env->psr |= PSR_NEG;
|
||||
if (T0 < src1)
|
||||
env->psr |= PSR_CARRY;
|
||||
if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
|
||||
env->psr |= PSR_OVF;
|
||||
env->y = (b2 << 31) | (env->y >> 1);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_udiv_T1_T0(void)
|
||||
{
|
||||
uint64_t x0;
|
||||
uint32_t x1;
|
||||
|
||||
x0 = T0 | ((uint64_t) (env->y) << 32);
|
||||
x1 = T1;
|
||||
x0 = x0 / x1;
|
||||
if (x0 > 0xffffffff) {
|
||||
T0 = 0xffffffff;
|
||||
T1 = 1;
|
||||
} else {
|
||||
T0 = x0;
|
||||
T1 = 0;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sdiv_T1_T0(void)
|
||||
{
|
||||
int64_t x0;
|
||||
int32_t x1;
|
||||
|
||||
x0 = T0 | ((uint64_t) (env->y) << 32);
|
||||
x1 = T1;
|
||||
x0 = x0 / x1;
|
||||
if ((int32_t) x0 != x0) {
|
||||
T0 = x0 >> 63;
|
||||
T1 = 1;
|
||||
} else {
|
||||
T0 = x0;
|
||||
T1 = 0;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_div_cc(void)
|
||||
{
|
||||
env->psr = 0;
|
||||
if (!T0)
|
||||
env->psr |= PSR_ZERO;
|
||||
if ((int) T0 < 0)
|
||||
env->psr |= PSR_NEG;
|
||||
if (T1)
|
||||
env->psr |= PSR_OVF;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_subx_T1_T0(void)
|
||||
{
|
||||
T0 -= T1 + ((env->psr & PSR_CARRY) ? 1 : 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_logic_T0_cc(void)
|
||||
{
|
||||
env->psr = 0;
|
||||
if (!T0)
|
||||
env->psr |= PSR_ZERO;
|
||||
if ((int) T0 < 0)
|
||||
env->psr |= PSR_NEG;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_set_flags(void)
|
||||
{
|
||||
env->psr = 0;
|
||||
if (!T0)
|
||||
env->psr |= PSR_ZERO;
|
||||
if ((unsigned int) T0 < (unsigned int) T1)
|
||||
env->psr |= PSR_CARRY;
|
||||
if ((int) T0 < (int) T1)
|
||||
env->psr |= PSR_OVF;
|
||||
if ((int) T0 < 0)
|
||||
env->psr |= PSR_NEG;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_sll(void)
|
||||
{
|
||||
T0 <<= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_srl(void)
|
||||
{
|
||||
T0 >>= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sra(void)
|
||||
{
|
||||
T0 = ((int32_t) T0) >> T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_st(void)
|
||||
{
|
||||
stl((void *) T0, T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_stb(void)
|
||||
{
|
||||
stb((void *) T0, T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_sth(void)
|
||||
{
|
||||
stw((void *) T0, T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_std(void)
|
||||
{
|
||||
stl((void *) T0, T1);
|
||||
stl((void *) (T0 + 4), T2);
|
||||
}
|
||||
|
||||
void OPPROTO op_ld(void)
|
||||
{
|
||||
T1 = ldl((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldub(void)
|
||||
{
|
||||
T1 = ldub((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_lduh(void)
|
||||
{
|
||||
T1 = lduw((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsb(void)
|
||||
{
|
||||
T1 = ldsb((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsh(void)
|
||||
{
|
||||
T1 = ldsw((void *) T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldstub(void)
|
||||
{
|
||||
T1 = ldub((void *) T0);
|
||||
stb((void *) T0, 0xff); /* XXX: Should be Atomically */
|
||||
}
|
||||
|
||||
void OPPROTO op_swap(void)
|
||||
{
|
||||
unsigned int tmp = ldl((void *) T0);
|
||||
stl((void *) T0, T1); /* XXX: Should be Atomically */
|
||||
T1 = tmp;
|
||||
}
|
||||
|
||||
void OPPROTO op_ldd(void)
|
||||
{
|
||||
T1 = ldl((void *) T0);
|
||||
T0 = ldl((void *) (T0 + 4));
|
||||
}
|
||||
|
||||
void OPPROTO op_wry(void)
|
||||
{
|
||||
env->y = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_rdy(void)
|
||||
{
|
||||
T0 = env->y;
|
||||
}
|
||||
|
||||
void raise_exception(int tt)
|
||||
{
|
||||
env->exception_index = tt;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void memcpy32(uint32_t *dst, const uint32_t *src)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
dst[4] = src[4];
|
||||
dst[5] = src[5];
|
||||
dst[6] = src[6];
|
||||
dst[7] = src[7];
|
||||
}
|
||||
|
||||
static inline void set_cwp(int new_cwp)
|
||||
{
|
||||
/* put the modified wrap registers at their proper location */
|
||||
if (env->cwp == (NWINDOWS - 1))
|
||||
memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
|
||||
env->cwp = new_cwp;
|
||||
/* put the wrap registers at their temporary location */
|
||||
if (new_cwp == (NWINDOWS - 1))
|
||||
memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
|
||||
env->regwptr = env->regbase + (new_cwp * 16);
|
||||
}
|
||||
|
||||
/* XXX: use another pointer for %iN registers to avoid slow wrapping
|
||||
handling ? */
|
||||
void OPPROTO op_save(void)
|
||||
{
|
||||
int cwp;
|
||||
cwp = (env->cwp - 1) & (NWINDOWS - 1);
|
||||
if (env->wim & (1 << cwp)) {
|
||||
raise_exception(TT_WIN_OVF);
|
||||
}
|
||||
set_cwp(cwp);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_restore(void)
|
||||
{
|
||||
int cwp;
|
||||
cwp = (env->cwp + 1) & (NWINDOWS - 1);
|
||||
if (env->wim & (1 << cwp)) {
|
||||
raise_exception(TT_WIN_UNF);
|
||||
}
|
||||
set_cwp(cwp);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_exception(void)
|
||||
{
|
||||
env->exception_index = PARAM1;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_trap_T0(void)
|
||||
{
|
||||
env->exception_index = TT_TRAP + (T0 & 0x7f);
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void OPPROTO op_trapcc_T0(void)
|
||||
{
|
||||
if (T2) {
|
||||
env->exception_index = TT_TRAP + (T0 & 0x7f);
|
||||
cpu_loop_exit();
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_be(void)
|
||||
{
|
||||
T2 = (env->psr & PSR_ZERO);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_ble(void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T2 = Z | (N ^ V);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bl(void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T2 = N ^ V;
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bleu(void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T2 = C | Z;
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bcs(void)
|
||||
{
|
||||
T2 = (env->psr & PSR_CARRY);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bvs(void)
|
||||
{
|
||||
T2 = (env->psr & PSR_OVF);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bneg(void)
|
||||
{
|
||||
T2 = (env->psr & PSR_NEG);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bne(void)
|
||||
{
|
||||
T2 = !(env->psr & PSR_ZERO);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bg(void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T2 = !(Z | (N ^ V));
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bge(void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T2 = !(N ^ V);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bgu(void)
|
||||
{
|
||||
GET_FLAGS;
|
||||
T2 = !(C | Z);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bcc(void)
|
||||
{
|
||||
T2 = !(env->psr & PSR_CARRY);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bpos(void)
|
||||
{
|
||||
T2 = !(env->psr & PSR_NEG);
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_bvc(void)
|
||||
{
|
||||
T2 = !(env->psr & PSR_OVF);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T2_0(void)
|
||||
{
|
||||
T2 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T2_1(void)
|
||||
{
|
||||
T2 = 1;
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp_im(void)
|
||||
{
|
||||
env->pc = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_npc_im(void)
|
||||
{
|
||||
env->npc = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_npc_T0(void)
|
||||
{
|
||||
env->npc = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_next_insn(void)
|
||||
{
|
||||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
}
|
||||
|
||||
void OPPROTO op_generic_branch(void)
|
||||
{
|
||||
if (T2) {
|
||||
env->npc = PARAM1;
|
||||
} else {
|
||||
env->npc = PARAM2;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_generic_branch_a(void)
|
||||
{
|
||||
if (T2) {
|
||||
env->pc = PARAM2;
|
||||
env->npc = PARAM1;
|
||||
} else {
|
||||
env->pc = PARAM2 + 4;
|
||||
env->npc = PARAM2 + 8;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPARC micro operations (templates for various register related
|
||||
* operations)
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
void OPPROTO glue(op_movl_T0_, REGNAME)(void)
|
||||
{
|
||||
T0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T1_, REGNAME)(void)
|
||||
{
|
||||
T1 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T2_, REGNAME)(void)
|
||||
{
|
||||
T2 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
|
||||
{
|
||||
REG = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
|
||||
{
|
||||
REG = T1;
|
||||
}
|
||||
|
||||
#undef REG
|
||||
#undef REGNAME
|
||||
@@ -0,0 +1,865 @@
|
||||
/*
|
||||
SPARC translation
|
||||
|
||||
Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
SPARC has two pitfalls: Delay slots and (a)nullification.
|
||||
This is currently solved as follows:
|
||||
|
||||
'call' instructions simply execute the delay slot before the actual
|
||||
control transfer instructions.
|
||||
|
||||
'jmpl' instructions execute calculate the destination, then execute
|
||||
the delay slot and then do the control transfer.
|
||||
|
||||
(conditional) branch instructions are the most difficult ones, as the
|
||||
delay slot may be nullified (ie. not executed). This happens when a
|
||||
conditional branch is not executed (thus no control transfer happens)
|
||||
and the 'anull' bit in the branch instruction opcode is set. This is
|
||||
currently solved by doing a jump after the delay slot instruction.
|
||||
|
||||
TODO-list:
|
||||
|
||||
Register window overflow/underflow check
|
||||
FPU-Instructions
|
||||
Coprocessor-Instructions
|
||||
Check signedness issues
|
||||
Privileged instructions
|
||||
Optimize synthetic instructions
|
||||
Optional alignment and privileged instruction check
|
||||
|
||||
-- TMO, 09/03/03
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
#define DEBUG_DISAS
|
||||
|
||||
typedef struct DisasContext {
|
||||
uint8_t *pc; /* NULL means dynamic value */
|
||||
uint8_t *npc; /* NULL means dynamic value */
|
||||
int is_br;
|
||||
struct TranslationBlock *tb;
|
||||
} DisasContext;
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s,n,copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS
|
||||
};
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
#define GET_FIELD(X, FROM, TO) \
|
||||
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
|
||||
|
||||
#define IS_IMM (insn & (1<<13))
|
||||
|
||||
static void disas_sparc_insn(DisasContext * dc);
|
||||
|
||||
typedef void (GenOpFunc) (void);
|
||||
typedef void (GenOpFunc1) (long);
|
||||
typedef void (GenOpFunc2) (long, long);
|
||||
typedef void (GenOpFunc3) (long, long, long);
|
||||
|
||||
static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
|
||||
{
|
||||
gen_op_movl_g0_T0,
|
||||
gen_op_movl_g1_T0,
|
||||
gen_op_movl_g2_T0,
|
||||
gen_op_movl_g3_T0,
|
||||
gen_op_movl_g4_T0,
|
||||
gen_op_movl_g5_T0,
|
||||
gen_op_movl_g6_T0,
|
||||
gen_op_movl_g7_T0,
|
||||
gen_op_movl_o0_T0,
|
||||
gen_op_movl_o1_T0,
|
||||
gen_op_movl_o2_T0,
|
||||
gen_op_movl_o3_T0,
|
||||
gen_op_movl_o4_T0,
|
||||
gen_op_movl_o5_T0,
|
||||
gen_op_movl_o6_T0,
|
||||
gen_op_movl_o7_T0,
|
||||
gen_op_movl_l0_T0,
|
||||
gen_op_movl_l1_T0,
|
||||
gen_op_movl_l2_T0,
|
||||
gen_op_movl_l3_T0,
|
||||
gen_op_movl_l4_T0,
|
||||
gen_op_movl_l5_T0,
|
||||
gen_op_movl_l6_T0,
|
||||
gen_op_movl_l7_T0,
|
||||
gen_op_movl_i0_T0,
|
||||
gen_op_movl_i1_T0,
|
||||
gen_op_movl_i2_T0,
|
||||
gen_op_movl_i3_T0,
|
||||
gen_op_movl_i4_T0,
|
||||
gen_op_movl_i5_T0,
|
||||
gen_op_movl_i6_T0,
|
||||
gen_op_movl_i7_T0,
|
||||
},
|
||||
{
|
||||
gen_op_movl_g0_T1,
|
||||
gen_op_movl_g1_T1,
|
||||
gen_op_movl_g2_T1,
|
||||
gen_op_movl_g3_T1,
|
||||
gen_op_movl_g4_T1,
|
||||
gen_op_movl_g5_T1,
|
||||
gen_op_movl_g6_T1,
|
||||
gen_op_movl_g7_T1,
|
||||
gen_op_movl_o0_T1,
|
||||
gen_op_movl_o1_T1,
|
||||
gen_op_movl_o2_T1,
|
||||
gen_op_movl_o3_T1,
|
||||
gen_op_movl_o4_T1,
|
||||
gen_op_movl_o5_T1,
|
||||
gen_op_movl_o6_T1,
|
||||
gen_op_movl_o7_T1,
|
||||
gen_op_movl_l0_T1,
|
||||
gen_op_movl_l1_T1,
|
||||
gen_op_movl_l2_T1,
|
||||
gen_op_movl_l3_T1,
|
||||
gen_op_movl_l4_T1,
|
||||
gen_op_movl_l5_T1,
|
||||
gen_op_movl_l6_T1,
|
||||
gen_op_movl_l7_T1,
|
||||
gen_op_movl_i0_T1,
|
||||
gen_op_movl_i1_T1,
|
||||
gen_op_movl_i2_T1,
|
||||
gen_op_movl_i3_T1,
|
||||
gen_op_movl_i4_T1,
|
||||
gen_op_movl_i5_T1,
|
||||
gen_op_movl_i6_T1,
|
||||
gen_op_movl_i7_T1,
|
||||
}
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
|
||||
{
|
||||
gen_op_movl_T0_g0,
|
||||
gen_op_movl_T0_g1,
|
||||
gen_op_movl_T0_g2,
|
||||
gen_op_movl_T0_g3,
|
||||
gen_op_movl_T0_g4,
|
||||
gen_op_movl_T0_g5,
|
||||
gen_op_movl_T0_g6,
|
||||
gen_op_movl_T0_g7,
|
||||
gen_op_movl_T0_o0,
|
||||
gen_op_movl_T0_o1,
|
||||
gen_op_movl_T0_o2,
|
||||
gen_op_movl_T0_o3,
|
||||
gen_op_movl_T0_o4,
|
||||
gen_op_movl_T0_o5,
|
||||
gen_op_movl_T0_o6,
|
||||
gen_op_movl_T0_o7,
|
||||
gen_op_movl_T0_l0,
|
||||
gen_op_movl_T0_l1,
|
||||
gen_op_movl_T0_l2,
|
||||
gen_op_movl_T0_l3,
|
||||
gen_op_movl_T0_l4,
|
||||
gen_op_movl_T0_l5,
|
||||
gen_op_movl_T0_l6,
|
||||
gen_op_movl_T0_l7,
|
||||
gen_op_movl_T0_i0,
|
||||
gen_op_movl_T0_i1,
|
||||
gen_op_movl_T0_i2,
|
||||
gen_op_movl_T0_i3,
|
||||
gen_op_movl_T0_i4,
|
||||
gen_op_movl_T0_i5,
|
||||
gen_op_movl_T0_i6,
|
||||
gen_op_movl_T0_i7,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T1_g0,
|
||||
gen_op_movl_T1_g1,
|
||||
gen_op_movl_T1_g2,
|
||||
gen_op_movl_T1_g3,
|
||||
gen_op_movl_T1_g4,
|
||||
gen_op_movl_T1_g5,
|
||||
gen_op_movl_T1_g6,
|
||||
gen_op_movl_T1_g7,
|
||||
gen_op_movl_T1_o0,
|
||||
gen_op_movl_T1_o1,
|
||||
gen_op_movl_T1_o2,
|
||||
gen_op_movl_T1_o3,
|
||||
gen_op_movl_T1_o4,
|
||||
gen_op_movl_T1_o5,
|
||||
gen_op_movl_T1_o6,
|
||||
gen_op_movl_T1_o7,
|
||||
gen_op_movl_T1_l0,
|
||||
gen_op_movl_T1_l1,
|
||||
gen_op_movl_T1_l2,
|
||||
gen_op_movl_T1_l3,
|
||||
gen_op_movl_T1_l4,
|
||||
gen_op_movl_T1_l5,
|
||||
gen_op_movl_T1_l6,
|
||||
gen_op_movl_T1_l7,
|
||||
gen_op_movl_T1_i0,
|
||||
gen_op_movl_T1_i1,
|
||||
gen_op_movl_T1_i2,
|
||||
gen_op_movl_T1_i3,
|
||||
gen_op_movl_T1_i4,
|
||||
gen_op_movl_T1_i5,
|
||||
gen_op_movl_T1_i6,
|
||||
gen_op_movl_T1_i7,
|
||||
},
|
||||
{
|
||||
gen_op_movl_T2_g0,
|
||||
gen_op_movl_T2_g1,
|
||||
gen_op_movl_T2_g2,
|
||||
gen_op_movl_T2_g3,
|
||||
gen_op_movl_T2_g4,
|
||||
gen_op_movl_T2_g5,
|
||||
gen_op_movl_T2_g6,
|
||||
gen_op_movl_T2_g7,
|
||||
gen_op_movl_T2_o0,
|
||||
gen_op_movl_T2_o1,
|
||||
gen_op_movl_T2_o2,
|
||||
gen_op_movl_T2_o3,
|
||||
gen_op_movl_T2_o4,
|
||||
gen_op_movl_T2_o5,
|
||||
gen_op_movl_T2_o6,
|
||||
gen_op_movl_T2_o7,
|
||||
gen_op_movl_T2_l0,
|
||||
gen_op_movl_T2_l1,
|
||||
gen_op_movl_T2_l2,
|
||||
gen_op_movl_T2_l3,
|
||||
gen_op_movl_T2_l4,
|
||||
gen_op_movl_T2_l5,
|
||||
gen_op_movl_T2_l6,
|
||||
gen_op_movl_T2_l7,
|
||||
gen_op_movl_T2_i0,
|
||||
gen_op_movl_T2_i1,
|
||||
gen_op_movl_T2_i2,
|
||||
gen_op_movl_T2_i3,
|
||||
gen_op_movl_T2_i4,
|
||||
gen_op_movl_T2_i5,
|
||||
gen_op_movl_T2_i6,
|
||||
gen_op_movl_T2_i7,
|
||||
}
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
|
||||
gen_op_movl_T0_im,
|
||||
gen_op_movl_T1_im,
|
||||
gen_op_movl_T2_im
|
||||
};
|
||||
|
||||
static inline void gen_movl_imm_TN(int reg, int imm)
|
||||
{
|
||||
gen_op_movl_TN_im[reg] (imm);
|
||||
}
|
||||
|
||||
static inline void gen_movl_imm_T1(int val)
|
||||
{
|
||||
gen_movl_imm_TN(1, val);
|
||||
}
|
||||
|
||||
static inline void gen_movl_imm_T0(int val)
|
||||
{
|
||||
gen_movl_imm_TN(0, val);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_TN(int reg, int t)
|
||||
{
|
||||
if (reg)
|
||||
gen_op_movl_reg_TN[t][reg] ();
|
||||
else
|
||||
gen_movl_imm_TN(t, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T0(int reg)
|
||||
{
|
||||
gen_movl_reg_TN(reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T1(int reg)
|
||||
{
|
||||
gen_movl_reg_TN(reg, 1);
|
||||
}
|
||||
|
||||
static inline void gen_movl_reg_T2(int reg)
|
||||
{
|
||||
gen_movl_reg_TN(reg, 2);
|
||||
}
|
||||
|
||||
static inline void gen_movl_TN_reg(int reg, int t)
|
||||
{
|
||||
if (reg)
|
||||
gen_op_movl_TN_reg[t][reg] ();
|
||||
}
|
||||
|
||||
static inline void gen_movl_T0_reg(int reg)
|
||||
{
|
||||
gen_movl_TN_reg(reg, 0);
|
||||
}
|
||||
|
||||
static inline void gen_movl_T1_reg(int reg)
|
||||
{
|
||||
gen_movl_TN_reg(reg, 1);
|
||||
}
|
||||
|
||||
static void gen_cond(int cond)
|
||||
{
|
||||
switch (cond) {
|
||||
case 0x0:
|
||||
gen_op_movl_T2_0();
|
||||
break;
|
||||
case 0x1:
|
||||
gen_op_eval_be();
|
||||
break;
|
||||
case 0x2:
|
||||
gen_op_eval_ble();
|
||||
break;
|
||||
case 0x3:
|
||||
gen_op_eval_bl();
|
||||
break;
|
||||
case 0x4:
|
||||
gen_op_eval_bleu();
|
||||
break;
|
||||
case 0x5:
|
||||
gen_op_eval_bcs();
|
||||
break;
|
||||
case 0x6:
|
||||
gen_op_eval_bneg();
|
||||
break;
|
||||
case 0x7:
|
||||
gen_op_eval_bvs();
|
||||
break;
|
||||
case 0x8:
|
||||
gen_op_movl_T2_1();
|
||||
break;
|
||||
case 0x9:
|
||||
gen_op_eval_bne();
|
||||
break;
|
||||
case 0xa:
|
||||
gen_op_eval_bg();
|
||||
break;
|
||||
case 0xb:
|
||||
gen_op_eval_bge();
|
||||
break;
|
||||
case 0xc:
|
||||
gen_op_eval_bgu();
|
||||
break;
|
||||
case 0xd:
|
||||
gen_op_eval_bcc();
|
||||
break;
|
||||
case 0xe:
|
||||
gen_op_eval_bpos();
|
||||
break;
|
||||
default:
|
||||
case 0xf:
|
||||
gen_op_eval_bvc();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
|
||||
{
|
||||
unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
|
||||
target += (uint32_t) dc->pc;
|
||||
if (cond == 0x0) {
|
||||
/* unconditional not taken */
|
||||
if (a) {
|
||||
dc->pc = dc->npc + 4;
|
||||
dc->npc = dc->pc + 4;
|
||||
} else {
|
||||
dc->pc = dc->npc;
|
||||
dc->npc = dc->pc + 4;
|
||||
}
|
||||
} else if (cond == 0x8) {
|
||||
/* unconditional taken */
|
||||
if (a) {
|
||||
dc->pc = (uint8_t *) target;
|
||||
dc->npc = dc->pc + 4;
|
||||
} else {
|
||||
dc->pc = dc->npc;
|
||||
dc->npc = (uint8_t *) target;
|
||||
}
|
||||
} else {
|
||||
gen_cond(cond);
|
||||
if (a) {
|
||||
gen_op_generic_branch_a((uint32_t) target,
|
||||
(uint32_t) (dc->npc));
|
||||
dc->is_br = 1;
|
||||
dc->pc = NULL;
|
||||
dc->npc = NULL;
|
||||
} else {
|
||||
dc->pc = dc->npc;
|
||||
gen_op_generic_branch((uint32_t) target,
|
||||
(uint32_t) (dc->npc + 4));
|
||||
dc->npc = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
|
||||
|
||||
static int sign_extend(int x, int len)
|
||||
{
|
||||
len = 32 - len;
|
||||
return (x << len) >> len;
|
||||
}
|
||||
|
||||
static inline void save_state(DisasContext * dc)
|
||||
{
|
||||
gen_op_jmp_im((uint32_t)dc->pc);
|
||||
if (dc->npc != NULL)
|
||||
gen_op_movl_npc_im((long) dc->npc);
|
||||
}
|
||||
|
||||
static void disas_sparc_insn(DisasContext * dc)
|
||||
{
|
||||
unsigned int insn, opc, rs1, rs2, rd;
|
||||
|
||||
insn = ldl_code(dc->pc);
|
||||
opc = GET_FIELD(insn, 0, 1);
|
||||
|
||||
rd = GET_FIELD(insn, 2, 6);
|
||||
switch (opc) {
|
||||
case 0: /* branches/sethi */
|
||||
{
|
||||
unsigned int xop = GET_FIELD(insn, 7, 9);
|
||||
int target;
|
||||
target = GET_FIELD(insn, 10, 31);
|
||||
switch (xop) {
|
||||
case 0x0:
|
||||
case 0x1: /* UNIMPL */
|
||||
goto illegal_insn;
|
||||
case 0x2: /* BN+x */
|
||||
{
|
||||
target <<= 2;
|
||||
target = sign_extend(target, 22);
|
||||
do_branch(dc, target, insn);
|
||||
goto jmp_insn;
|
||||
}
|
||||
case 0x3: /* FBN+x */
|
||||
break;
|
||||
case 0x4: /* SETHI */
|
||||
gen_movl_imm_T0(target << 10);
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
case 0x5: /*CBN+x */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
/*CALL*/ {
|
||||
unsigned int target = GET_FIELDs(insn, 2, 31) << 2;
|
||||
|
||||
gen_op_movl_T0_im((long) (dc->pc));
|
||||
gen_movl_T0_reg(15);
|
||||
target = (long) dc->pc + target;
|
||||
dc->pc = dc->npc;
|
||||
dc->npc = (uint8_t *) target;
|
||||
}
|
||||
goto jmp_insn;
|
||||
case 2: /* FPU & Logical Operations */
|
||||
{
|
||||
unsigned int xop = GET_FIELD(insn, 7, 12);
|
||||
if (xop == 0x3a) { /* generate trap */
|
||||
int cond;
|
||||
rs1 = GET_FIELD(insn, 13, 17);
|
||||
gen_movl_reg_T0(rs1);
|
||||
if (IS_IMM) {
|
||||
gen_movl_imm_T1(GET_FIELD(insn, 25, 31));
|
||||
} else {
|
||||
rs2 = GET_FIELD(insn, 27, 31);
|
||||
gen_movl_reg_T1(rs2);
|
||||
}
|
||||
gen_op_add_T1_T0();
|
||||
save_state(dc);
|
||||
cond = GET_FIELD(insn, 3, 6);
|
||||
if (cond == 0x8) {
|
||||
gen_op_trap_T0();
|
||||
dc->is_br = 1;
|
||||
goto jmp_insn;
|
||||
} else {
|
||||
gen_op_trapcc_T0();
|
||||
}
|
||||
} else if (xop == 0x28) {
|
||||
rs1 = GET_FIELD(insn, 13, 17);
|
||||
switch(rs1) {
|
||||
case 0: /* rdy */
|
||||
gen_op_rdy();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
default:
|
||||
goto illegal_insn;
|
||||
}
|
||||
} else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
|
||||
goto illegal_insn;
|
||||
} else {
|
||||
rs1 = GET_FIELD(insn, 13, 17);
|
||||
gen_movl_reg_T0(rs1);
|
||||
if (IS_IMM) { /* immediate */
|
||||
rs2 = GET_FIELDs(insn, 19, 31);
|
||||
gen_movl_imm_T1(rs2);
|
||||
} else { /* register */
|
||||
rs2 = GET_FIELD(insn, 27, 31);
|
||||
gen_movl_reg_T1(rs2);
|
||||
}
|
||||
if (xop < 0x20) {
|
||||
switch (xop & ~0x10) {
|
||||
case 0x0:
|
||||
if (xop & 0x10)
|
||||
gen_op_add_T1_T0_cc();
|
||||
else
|
||||
gen_op_add_T1_T0();
|
||||
break;
|
||||
case 0x1:
|
||||
gen_op_and_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x2:
|
||||
gen_op_or_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x3:
|
||||
gen_op_xor_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x4:
|
||||
if (xop & 0x10)
|
||||
gen_op_sub_T1_T0_cc();
|
||||
else
|
||||
gen_op_sub_T1_T0();
|
||||
break;
|
||||
case 0x5:
|
||||
gen_op_andn_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x6:
|
||||
gen_op_orn_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x7:
|
||||
gen_op_xnor_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0x8:
|
||||
gen_op_addx_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_set_flags();
|
||||
break;
|
||||
case 0xa:
|
||||
gen_op_umul_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0xb:
|
||||
gen_op_smul_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_logic_T0_cc();
|
||||
break;
|
||||
case 0xc:
|
||||
gen_op_subx_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_set_flags();
|
||||
break;
|
||||
case 0xe:
|
||||
gen_op_udiv_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_div_cc();
|
||||
break;
|
||||
case 0xf:
|
||||
gen_op_sdiv_T1_T0();
|
||||
if (xop & 0x10)
|
||||
gen_op_div_cc();
|
||||
break;
|
||||
default:
|
||||
goto illegal_insn;
|
||||
}
|
||||
gen_movl_T0_reg(rd);
|
||||
} else {
|
||||
switch (xop) {
|
||||
case 0x24: /* mulscc */
|
||||
gen_op_mulscc_T1_T0();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
case 0x25: /* SLL */
|
||||
gen_op_sll();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
case 0x26:
|
||||
gen_op_srl();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
case 0x27:
|
||||
gen_op_sra();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
case 0x30:
|
||||
{
|
||||
gen_op_xor_T1_T0();
|
||||
switch(rd) {
|
||||
case 0:
|
||||
gen_op_wry();
|
||||
break;
|
||||
default:
|
||||
goto illegal_insn;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x38: /* jmpl */
|
||||
{
|
||||
gen_op_add_T1_T0();
|
||||
gen_op_movl_npc_T0();
|
||||
if (rd != 0) {
|
||||
gen_op_movl_T0_im((long) (dc->pc));
|
||||
gen_movl_T0_reg(rd);
|
||||
}
|
||||
dc->pc = dc->npc;
|
||||
dc->npc = NULL;
|
||||
}
|
||||
goto jmp_insn;
|
||||
case 0x3b: /* flush */
|
||||
/* nothing to do */
|
||||
break;
|
||||
case 0x3c: /* save */
|
||||
save_state(dc);
|
||||
gen_op_add_T1_T0();
|
||||
gen_op_save();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
case 0x3d: /* restore */
|
||||
save_state(dc);
|
||||
gen_op_add_T1_T0();
|
||||
gen_op_restore();
|
||||
gen_movl_T0_reg(rd);
|
||||
break;
|
||||
default:
|
||||
goto illegal_insn;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: /* load/store instructions */
|
||||
{
|
||||
unsigned int xop = GET_FIELD(insn, 7, 12);
|
||||
rs1 = GET_FIELD(insn, 13, 17);
|
||||
gen_movl_reg_T0(rs1);
|
||||
if (IS_IMM) { /* immediate */
|
||||
rs2 = GET_FIELDs(insn, 19, 31);
|
||||
gen_movl_imm_T1(rs2);
|
||||
} else { /* register */
|
||||
rs2 = GET_FIELD(insn, 27, 31);
|
||||
gen_movl_reg_T1(rs2);
|
||||
}
|
||||
gen_op_add_T1_T0();
|
||||
if (xop < 4 || xop > 7) {
|
||||
switch (xop) {
|
||||
case 0x0: /* load word */
|
||||
gen_op_ld();
|
||||
break;
|
||||
case 0x1: /* load unsigned byte */
|
||||
gen_op_ldub();
|
||||
break;
|
||||
case 0x2: /* load unsigned halfword */
|
||||
gen_op_lduh();
|
||||
break;
|
||||
case 0x3: /* load double word */
|
||||
gen_op_ldd();
|
||||
gen_movl_T0_reg(rd + 1);
|
||||
break;
|
||||
case 0x9: /* load signed byte */
|
||||
gen_op_ldsb();
|
||||
break;
|
||||
case 0xa: /* load signed halfword */
|
||||
gen_op_ldsh();
|
||||
break;
|
||||
case 0xd: /* ldstub -- XXX: should be atomically */
|
||||
gen_op_ldstub();
|
||||
break;
|
||||
case 0x0f: /* swap register with memory. Also atomically */
|
||||
gen_op_swap();
|
||||
break;
|
||||
}
|
||||
gen_movl_T1_reg(rd);
|
||||
} else if (xop < 8) {
|
||||
gen_movl_reg_T1(rd);
|
||||
switch (xop) {
|
||||
case 0x4:
|
||||
gen_op_st();
|
||||
break;
|
||||
case 0x5:
|
||||
gen_op_stb();
|
||||
break;
|
||||
case 0x6:
|
||||
gen_op_sth();
|
||||
break;
|
||||
case 0x7:
|
||||
gen_movl_reg_T2(rd + 1);
|
||||
gen_op_std();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* default case for non jump instructions */
|
||||
if (dc->npc != NULL) {
|
||||
dc->pc = dc->npc;
|
||||
dc->npc = dc->npc + 4;
|
||||
} else {
|
||||
dc->pc = NULL;
|
||||
gen_op_next_insn();
|
||||
}
|
||||
jmp_insn:;
|
||||
return;
|
||||
illegal_insn:
|
||||
gen_op_jmp_im((uint32_t)dc->pc);
|
||||
if (dc->npc != NULL)
|
||||
gen_op_movl_npc_im((long) dc->npc);
|
||||
gen_op_exception(TT_ILL_INSN);
|
||||
dc->is_br = 1;
|
||||
}
|
||||
|
||||
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||
int spc)
|
||||
{
|
||||
uint8_t *pc_start, *last_pc;
|
||||
uint16_t *gen_opc_end;
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
|
||||
memset(dc, 0, sizeof(DisasContext));
|
||||
if (spc) {
|
||||
printf("SearchPC not yet supported\n");
|
||||
exit(0);
|
||||
}
|
||||
dc->tb = tb;
|
||||
pc_start = (uint8_t *) tb->pc;
|
||||
dc->pc = pc_start;
|
||||
dc->npc = (uint8_t *) tb->cs_base;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
do {
|
||||
last_pc = dc->pc;
|
||||
disas_sparc_insn(dc);
|
||||
if (dc->is_br)
|
||||
break;
|
||||
/* if the next PC is different, we abort now */
|
||||
if (dc->pc != (last_pc + 4))
|
||||
break;
|
||||
} while ((gen_opc_ptr < gen_opc_end) &&
|
||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
if (dc->pc != NULL)
|
||||
gen_op_jmp_im((long) dc->pc);
|
||||
if (dc->npc != NULL)
|
||||
gen_op_movl_npc_im((long) dc->npc);
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "--------------\n");
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||
disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0);
|
||||
fprintf(logfile, "\n");
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 0);
|
||||
}
|
||||
|
||||
int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
|
||||
{
|
||||
return gen_intermediate_code_internal(tb, 1);
|
||||
}
|
||||
|
||||
CPUSPARCState *cpu_sparc_init(void)
|
||||
{
|
||||
CPUSPARCState *env;
|
||||
|
||||
cpu_exec_init();
|
||||
|
||||
if (!(env = malloc(sizeof(CPUSPARCState))))
|
||||
return (NULL);
|
||||
memset(env, 0, sizeof(*env));
|
||||
env->cwp = 0;
|
||||
env->wim = 1;
|
||||
env->regwptr = env->regbase + (env->cwp * 16);
|
||||
env->user_mode_only = 1;
|
||||
return (env);
|
||||
}
|
||||
|
||||
#define GET_FLAG(a,b) ((env->psr & a)?b:'-')
|
||||
|
||||
void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc);
|
||||
fprintf(f, "General Registers:\n");
|
||||
for (i = 0; i < 4; i++)
|
||||
fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
|
||||
fprintf(f, "\n");
|
||||
for (; i < 8; i++)
|
||||
fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
|
||||
fprintf(f, "\nCurrent Register Window:\n");
|
||||
for (x = 0; x < 3; x++) {
|
||||
for (i = 0; i < 4; i++)
|
||||
fprintf(f, "%%%c%d: 0x%08x\t",
|
||||
(x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
|
||||
env->regwptr[i + x * 8]);
|
||||
fprintf(f, "\n");
|
||||
for (; i < 8; i++)
|
||||
fprintf(f, "%%%c%d: 0x%08x\t",
|
||||
(x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
|
||||
env->regwptr[i + x * 8]);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp,
|
||||
GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
|
||||
GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
|
||||
env->wim);
|
||||
}
|
||||
+16
-11
@@ -1,14 +1,15 @@
|
||||
include ../config.mak
|
||||
include ../config-host.mak
|
||||
|
||||
CFLAGS=-Wall -O2 -g
|
||||
LDFLAGS=
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
||||
TESTS=linux-test testthread sha1-i386 test-i386 runcom
|
||||
endif
|
||||
TESTS+=sha1 test_path
|
||||
TESTS+=sha1# test_path
|
||||
#TESTS+=test_path
|
||||
|
||||
QEMU=../qemu
|
||||
QEMU=../i386-user/qemu-i386
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
@@ -16,12 +17,6 @@ hello-i386: hello-i386.c
|
||||
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
|
||||
strip $@
|
||||
|
||||
testclone: testclone.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
testsig: testsig.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
testthread: testthread.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
||||
|
||||
@@ -32,7 +27,7 @@ test_path: test_path.c
|
||||
# i386 emulation test (test various opcodes) */
|
||||
test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
|
||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c \
|
||||
test-i386-code16.S test-i386-vm86.S -lm
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
@@ -44,6 +39,10 @@ endif
|
||||
$(QEMU) test-i386 > test-i386.out
|
||||
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
|
||||
|
||||
# generic Linux and CPU test
|
||||
linux-test: linux-test.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm
|
||||
|
||||
# speed test
|
||||
sha1-i386: sha1.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||
@@ -66,5 +65,11 @@ hello-arm: hello-arm.o
|
||||
hello-arm.o: hello-arm.c
|
||||
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
|
||||
|
||||
# XXX: find a way to compile easily a test for each arch
|
||||
test2:
|
||||
@for arch in i386 arm sparc ppc; do \
|
||||
../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o $(TESTS)
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* linux and CPU test
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <utime.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sched.h>
|
||||
#include <dirent.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#define TESTPATH "/tmp/linux-test.tmp"
|
||||
#define TESTPORT 7654
|
||||
#define STACK_SIZE 16384
|
||||
|
||||
void error1(const char *filename, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "%s:%d: ", filename, line);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int __chk_error(const char *filename, int line, int ret)
|
||||
{
|
||||
if (ret < 0) {
|
||||
error1(filename, line, "%m (ret=%d, errno=%d)",
|
||||
ret, errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define error(fmt, args...) error1(__FILE__, __LINE__, fmt, ##args)
|
||||
|
||||
#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret))
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
#define FILE_BUF_SIZE 300
|
||||
|
||||
void test_file(void)
|
||||
{
|
||||
int fd, i, len, ret;
|
||||
uint8_t buf[FILE_BUF_SIZE];
|
||||
uint8_t buf2[FILE_BUF_SIZE];
|
||||
uint8_t buf3[FILE_BUF_SIZE];
|
||||
char cur_dir[1024];
|
||||
struct stat st;
|
||||
struct utimbuf tbuf;
|
||||
struct iovec vecs[2];
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
|
||||
/* clean up, just in case */
|
||||
unlink(TESTPATH "/file1");
|
||||
unlink(TESTPATH "/file2");
|
||||
unlink(TESTPATH "/file3");
|
||||
rmdir(TESTPATH);
|
||||
|
||||
if (getcwd(cur_dir, sizeof(cur_dir)) == NULL)
|
||||
error("getcwd");
|
||||
|
||||
chk_error(mkdir(TESTPATH, 0755));
|
||||
|
||||
chk_error(chdir(TESTPATH));
|
||||
|
||||
/* open/read/write/close/readv/writev/lseek */
|
||||
|
||||
fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644));
|
||||
for(i=0;i < FILE_BUF_SIZE; i++)
|
||||
buf[i] = i;
|
||||
len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2));
|
||||
if (len != (FILE_BUF_SIZE / 2))
|
||||
error("write");
|
||||
vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2);
|
||||
vecs[0].iov_len = 16;
|
||||
vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16;
|
||||
vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16;
|
||||
len = chk_error(writev(fd, vecs, 2));
|
||||
if (len != (FILE_BUF_SIZE / 2))
|
||||
error("writev");
|
||||
chk_error(close(fd));
|
||||
|
||||
chk_error(rename("file1", "file2"));
|
||||
|
||||
fd = chk_error(open("file2", O_RDONLY));
|
||||
|
||||
len = chk_error(read(fd, buf2, FILE_BUF_SIZE));
|
||||
if (len != FILE_BUF_SIZE)
|
||||
error("read");
|
||||
if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0)
|
||||
error("memcmp");
|
||||
|
||||
#define FOFFSET 16
|
||||
ret = chk_error(lseek(fd, FOFFSET, SEEK_SET));
|
||||
if (ret != 16)
|
||||
error("lseek");
|
||||
vecs[0].iov_base = buf3;
|
||||
vecs[0].iov_len = 32;
|
||||
vecs[1].iov_base = buf3 + 32;
|
||||
vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32;
|
||||
len = chk_error(readv(fd, vecs, 2));
|
||||
if (len != FILE_BUF_SIZE - FOFFSET)
|
||||
error("readv");
|
||||
if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0)
|
||||
error("memcmp");
|
||||
|
||||
chk_error(close(fd));
|
||||
|
||||
/* access */
|
||||
chk_error(access("file2", R_OK));
|
||||
|
||||
/* stat/chmod/utime/truncate */
|
||||
|
||||
chk_error(chmod("file2", 0600));
|
||||
tbuf.actime = 1001;
|
||||
tbuf.modtime = 1000;
|
||||
chk_error(truncate("file2", 100));
|
||||
chk_error(utime("file2", &tbuf));
|
||||
chk_error(stat("file2", &st));
|
||||
if (st.st_size != 100)
|
||||
error("stat size");
|
||||
if (!S_ISREG(st.st_mode))
|
||||
error("stat mode");
|
||||
if ((st.st_mode & 0777) != 0600)
|
||||
error("stat mode2");
|
||||
if (st.st_atime != 1001 ||
|
||||
st.st_mtime != 1000)
|
||||
error("stat time");
|
||||
|
||||
chk_error(stat(TESTPATH, &st));
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
error("stat mode");
|
||||
|
||||
/* fstat */
|
||||
fd = chk_error(open("file2", O_RDWR));
|
||||
chk_error(ftruncate(fd, 50));
|
||||
chk_error(fstat(fd, &st));
|
||||
chk_error(close(fd));
|
||||
|
||||
if (st.st_size != 50)
|
||||
error("stat size");
|
||||
if (!S_ISREG(st.st_mode))
|
||||
error("stat mode");
|
||||
|
||||
/* symlink/lstat */
|
||||
chk_error(symlink("file2", "file3"));
|
||||
chk_error(lstat("file3", &st));
|
||||
if (!S_ISLNK(st.st_mode))
|
||||
error("stat mode");
|
||||
|
||||
/* getdents */
|
||||
dir = opendir(TESTPATH);
|
||||
if (!dir)
|
||||
error("opendir");
|
||||
len = 0;
|
||||
for(;;) {
|
||||
de = readdir(dir);
|
||||
if (!de)
|
||||
break;
|
||||
if (strcmp(de->d_name, ".") != 0 &&
|
||||
strcmp(de->d_name, "..") != 0 &&
|
||||
strcmp(de->d_name, "file2") != 0 &&
|
||||
strcmp(de->d_name, "file3") != 0)
|
||||
error("readdir");
|
||||
len++;
|
||||
}
|
||||
closedir(dir);
|
||||
if (len != 4)
|
||||
error("readdir");
|
||||
|
||||
chk_error(unlink("file3"));
|
||||
chk_error(unlink("file2"));
|
||||
chk_error(chdir(cur_dir));
|
||||
chk_error(rmdir(TESTPATH));
|
||||
}
|
||||
|
||||
void test_fork(void)
|
||||
{
|
||||
int pid, status;
|
||||
|
||||
pid = chk_error(fork());
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
exit(2);
|
||||
}
|
||||
chk_error(waitpid(pid, &status, 0));
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 2)
|
||||
error("waitpid status=0x%x", status);
|
||||
}
|
||||
|
||||
void test_time(void)
|
||||
{
|
||||
struct timeval tv, tv2;
|
||||
struct timespec ts, rem;
|
||||
struct rusage rusg1, rusg2;
|
||||
int ti, i;
|
||||
|
||||
chk_error(gettimeofday(&tv, NULL));
|
||||
rem.tv_sec = 1;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 20 * 1000000;
|
||||
chk_error(nanosleep(&ts, &rem));
|
||||
if (rem.tv_sec != 1)
|
||||
error("nanosleep");
|
||||
chk_error(gettimeofday(&tv2, NULL));
|
||||
ti = tv2.tv_sec - tv.tv_sec;
|
||||
if (ti >= 2)
|
||||
error("gettimeofday");
|
||||
|
||||
chk_error(getrusage(RUSAGE_SELF, &rusg1));
|
||||
for(i = 0;i < 10000; i++);
|
||||
chk_error(getrusage(RUSAGE_SELF, &rusg2));
|
||||
if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 ||
|
||||
(rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0)
|
||||
error("getrusage");
|
||||
}
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int server_socket(void)
|
||||
{
|
||||
int val, fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
|
||||
/* server socket */
|
||||
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
|
||||
|
||||
val = 1;
|
||||
chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(TESTPORT);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
|
||||
chk_error(listen(fd, 0));
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
int client_socket(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
|
||||
/* server socket */
|
||||
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(TESTPORT);
|
||||
inet_aton("127.0.0.1", &sockaddr.sin_addr);
|
||||
chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)));
|
||||
return fd;
|
||||
}
|
||||
|
||||
const char socket_msg[] = "hello socket\n";
|
||||
|
||||
void test_socket(void)
|
||||
{
|
||||
int server_fd, client_fd, fd, pid, ret;
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
char buf[512];
|
||||
|
||||
server_fd = server_socket();
|
||||
pid = chk_error(fork());
|
||||
if (pid == 0) {
|
||||
client_fd = client_socket();
|
||||
send(client_fd, socket_msg, sizeof(socket_msg), 0);
|
||||
close(client_fd);
|
||||
exit(0);
|
||||
}
|
||||
len = sizeof(sockaddr);
|
||||
fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len));
|
||||
|
||||
ret = chk_error(recv(fd, buf, sizeof(buf), 0));
|
||||
if (ret != sizeof(socket_msg))
|
||||
error("recv");
|
||||
if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0)
|
||||
error("socket_msg");
|
||||
chk_error(close(fd));
|
||||
chk_error(close(server_fd));
|
||||
}
|
||||
|
||||
#define WCOUNT_MAX 512
|
||||
|
||||
void test_pipe(void)
|
||||
{
|
||||
fd_set rfds, wfds;
|
||||
int fds[2], fd_max, ret;
|
||||
uint8_t ch;
|
||||
int wcount, rcount;
|
||||
|
||||
chk_error(pipe(fds));
|
||||
chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK));
|
||||
chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK));
|
||||
wcount = 0;
|
||||
rcount = 0;
|
||||
for(;;) {
|
||||
FD_ZERO(&rfds);
|
||||
fd_max = fds[0];
|
||||
FD_SET(fds[0], &rfds);
|
||||
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(fds[1], &wfds);
|
||||
if (fds[1] > fd_max)
|
||||
fd_max = fds[1];
|
||||
|
||||
ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL));
|
||||
if (ret > 0) {
|
||||
if (FD_ISSET(fds[0], &rfds)) {
|
||||
chk_error(read(fds[0], &ch, 1));
|
||||
rcount++;
|
||||
if (rcount >= WCOUNT_MAX)
|
||||
break;
|
||||
}
|
||||
if (FD_ISSET(fds[1], &wfds)) {
|
||||
ch = 'a';
|
||||
chk_error(write(fds[0], &ch, 1));
|
||||
wcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
chk_error(close(fds[0]));
|
||||
chk_error(close(fds[1]));
|
||||
}
|
||||
|
||||
int thread1_res;
|
||||
int thread2_res;
|
||||
|
||||
int thread1_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<5;i++) {
|
||||
thread1_res++;
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread2_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<6;i++) {
|
||||
thread2_res++;
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_clone(void)
|
||||
{
|
||||
uint8_t *stack1, *stack2;
|
||||
int pid1, pid2, status1, status2;
|
||||
|
||||
stack1 = malloc(STACK_SIZE);
|
||||
pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"));
|
||||
|
||||
stack2 = malloc(STACK_SIZE);
|
||||
pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"));
|
||||
|
||||
while (waitpid(pid1, &status1, 0) != pid1);
|
||||
while (waitpid(pid2, &status2, 0) != pid2);
|
||||
if (thread1_res != 5 ||
|
||||
thread2_res != 6)
|
||||
error("clone");
|
||||
}
|
||||
|
||||
/***********************************/
|
||||
|
||||
volatile int alarm_count;
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void sig_alarm(int sig)
|
||||
{
|
||||
if (sig != SIGALRM)
|
||||
error("signal");
|
||||
alarm_count++;
|
||||
}
|
||||
|
||||
void sig_segv(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
if (sig != SIGSEGV)
|
||||
error("signal");
|
||||
longjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
void test_signal(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
struct itimerval it, oit;
|
||||
|
||||
/* timer test */
|
||||
|
||||
alarm_count = 0;
|
||||
|
||||
act.sa_handler = sig_alarm;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
chk_error(sigaction(SIGALRM, &act, NULL));
|
||||
|
||||
it.it_interval.tv_sec = 0;
|
||||
it.it_interval.tv_usec = 10 * 1000;
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = 10 * 1000;
|
||||
chk_error(setitimer(ITIMER_REAL, &it, NULL));
|
||||
chk_error(getitimer(ITIMER_REAL, &oit));
|
||||
if (oit.it_value.tv_sec != it.it_value.tv_sec ||
|
||||
oit.it_value.tv_usec != it.it_value.tv_usec)
|
||||
error("itimer");
|
||||
|
||||
while (alarm_count < 5) {
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
|
||||
it.it_interval.tv_sec = 0;
|
||||
it.it_interval.tv_usec = 0;
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = 0;
|
||||
memset(&oit, 0xff, sizeof(oit));
|
||||
chk_error(setitimer(ITIMER_REAL, &it, &oit));
|
||||
if (oit.it_value.tv_sec != 0 ||
|
||||
oit.it_value.tv_usec != 10 * 1000)
|
||||
error("setitimer");
|
||||
|
||||
/* SIGSEGV test */
|
||||
act.sa_sigaction = sig_segv;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
chk_error(sigaction(SIGSEGV, &act, NULL));
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
*(uint8_t *)0 = 0;
|
||||
}
|
||||
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
chk_error(sigaction(SIGSEGV, &act, NULL));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_file();
|
||||
test_fork();
|
||||
test_time();
|
||||
test_socket();
|
||||
test_clone();
|
||||
test_signal();
|
||||
return 0;
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
|
||||
/* from valgrind tests */
|
||||
|
||||
/* ================ sha1.c ================ */
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
|
||||
Test Vectors (from FIPS PUB 180-1)
|
||||
"abc"
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
A million repetitions of "a"
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
||||
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||
|
||||
#define SHA1HANDSOFF
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h> /* for u_int*_t */
|
||||
|
||||
/* ================ sha1.h ================ */
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u_int32_t state[5];
|
||||
u_int32_t count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]);
|
||||
void SHA1Init(SHA1_CTX* context);
|
||||
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len);
|
||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
||||
/* ================ end of sha1.h ================ */
|
||||
#include <endian.h>
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
#define blk0(i) block->l[i]
|
||||
#else
|
||||
#error "Endianness not defined!"
|
||||
#endif
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
|
||||
{
|
||||
u_int32_t a, b, c, d, e;
|
||||
typedef union {
|
||||
unsigned char c[64];
|
||||
u_int32_t l[16];
|
||||
} CHAR64LONG16;
|
||||
#ifdef SHA1HANDSOFF
|
||||
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
|
||||
memcpy(block, buffer, 64);
|
||||
#else
|
||||
/* The following had better never be used because it causes the
|
||||
* pointer-to-const buffer to be cast into a pointer to non-const.
|
||||
* And the result is written through. I threw a "const" in, hoping
|
||||
* this will cause a diagnostic.
|
||||
*/
|
||||
CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
|
||||
#endif
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
#ifdef SHA1HANDSOFF
|
||||
memset(block, '\0', sizeof(block));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
void SHA1Init(SHA1_CTX* context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len)
|
||||
{
|
||||
u_int32_t i;
|
||||
u_int32_t j;
|
||||
|
||||
j = context->count[0];
|
||||
if ((context->count[0] += len << 3) < j)
|
||||
context->count[1]++;
|
||||
context->count[1] += (len>>29);
|
||||
j = (j >> 3) & 63;
|
||||
if ((j + len) > 63) {
|
||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(context->state, context->buffer);
|
||||
for ( ; i + 63 < len; i += 64) {
|
||||
SHA1Transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned char finalcount[8];
|
||||
unsigned char c;
|
||||
|
||||
#if 0 /* untested "improvement" by DHR */
|
||||
/* Convert context->count to a sequence of bytes
|
||||
* in finalcount. Second element first, but
|
||||
* big-endian order within element.
|
||||
* But we do it all backwards.
|
||||
*/
|
||||
unsigned char *fcp = &finalcount[8];
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
u_int32_t t = context->count[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; t >>= 8, j++)
|
||||
*--fcp = (unsigned char) t
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
#endif
|
||||
c = 0200;
|
||||
SHA1Update(context, &c, 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
c = 0000;
|
||||
SHA1Update(context, &c, 1);
|
||||
}
|
||||
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++) {
|
||||
digest[i] = (unsigned char)
|
||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
/* Wipe variables */
|
||||
memset(context, '\0', sizeof(*context));
|
||||
memset(&finalcount, '\0', sizeof(finalcount));
|
||||
}
|
||||
/* ================ end of sha1.c ================ */
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
SHA1_CTX ctx;
|
||||
unsigned char hash[20], buf[BUFSIZE];
|
||||
int i;
|
||||
|
||||
for(i=0;i<BUFSIZE;i++)
|
||||
buf[i] = i;
|
||||
|
||||
SHA1Init(&ctx);
|
||||
for(i=0;i<1000;i++)
|
||||
SHA1Update(&ctx, buf, BUFSIZE);
|
||||
SHA1Final(hash, &ctx);
|
||||
|
||||
printf("SHA1=");
|
||||
for(i=0;i<20;i++)
|
||||
printf("%02x", hash[i]);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+182
-14
@@ -1,3 +1,22 @@
|
||||
/*
|
||||
* x86 CPU test
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -6,12 +25,15 @@
|
||||
#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 TEST_P4_FLAGS
|
||||
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
@@ -331,7 +353,11 @@ void test_jcc(void)
|
||||
}
|
||||
|
||||
#undef CC_MASK
|
||||
#ifdef TEST_P4_FLAGS
|
||||
#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
|
||||
#else
|
||||
#define CC_MASK (CC_O | CC_C)
|
||||
#endif
|
||||
|
||||
#define OP mul
|
||||
#include "test-i386-muldiv.h"
|
||||
@@ -339,15 +365,6 @@ void test_jcc(void)
|
||||
#define OP imul
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
#undef CC_MASK
|
||||
#define CC_MASK (0)
|
||||
|
||||
#define OP div
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
#define OP idiv
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
void test_imulw2(int op0, int op1)
|
||||
{
|
||||
int res, s1, s0, flags;
|
||||
@@ -384,6 +401,15 @@ void test_imull2(int op0, int op1)
|
||||
"imull", s0, s1, res, flags & CC_MASK);
|
||||
}
|
||||
|
||||
#undef CC_MASK
|
||||
#define CC_MASK (0)
|
||||
|
||||
#define OP div
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
#define OP idiv
|
||||
#include "test-i386-muldiv.h"
|
||||
|
||||
void test_mul(void)
|
||||
{
|
||||
test_imulb(0x1234561d, 4);
|
||||
@@ -637,6 +663,45 @@ void test_fenv(void)
|
||||
TEST_ENV(&float_env32, "");
|
||||
}
|
||||
|
||||
|
||||
#define TEST_FCMOV(a, b, eflags, CC)\
|
||||
{\
|
||||
double res;\
|
||||
asm("push %3\n"\
|
||||
"popf\n"\
|
||||
"fcmov" CC " %2, %0\n"\
|
||||
: "=t" (res)\
|
||||
: "0" (a), "u" (b), "g" (eflags));\
|
||||
printf("fcmov%s eflags=0x%04x-> %f\n", \
|
||||
CC, eflags, res);\
|
||||
}
|
||||
|
||||
void test_fcmov(void)
|
||||
{
|
||||
double a, b;
|
||||
int eflags, i;
|
||||
|
||||
a = 1.0;
|
||||
b = 2.0;
|
||||
for(i = 0; i < 4; i++) {
|
||||
eflags = 0;
|
||||
if (i & 1)
|
||||
eflags |= CC_C;
|
||||
if (i & 2)
|
||||
eflags |= CC_Z;
|
||||
TEST_FCMOV(a, b, eflags, "b");
|
||||
TEST_FCMOV(a, b, eflags, "e");
|
||||
TEST_FCMOV(a, b, eflags, "be");
|
||||
TEST_FCMOV(a, b, eflags, "nb");
|
||||
TEST_FCMOV(a, b, eflags, "ne");
|
||||
TEST_FCMOV(a, b, eflags, "nbe");
|
||||
}
|
||||
TEST_FCMOV(a, b, 0, "u");
|
||||
TEST_FCMOV(a, b, CC_P, "u");
|
||||
TEST_FCMOV(a, b, 0, "nu");
|
||||
TEST_FCMOV(a, b, CC_P, "nu");
|
||||
}
|
||||
|
||||
void test_floats(void)
|
||||
{
|
||||
test_fops(2, 3);
|
||||
@@ -654,6 +719,9 @@ void test_floats(void)
|
||||
test_fbcd(1234567890123456);
|
||||
test_fbcd(-123451234567890);
|
||||
test_fenv();
|
||||
if (TEST_CMOV) {
|
||||
test_fcmov();
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
@@ -855,7 +923,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;
|
||||
@@ -863,7 +930,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) */
|
||||
@@ -965,6 +1037,11 @@ void test_misc(void)
|
||||
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];
|
||||
@@ -1096,7 +1173,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)
|
||||
@@ -1124,8 +1201,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:
|
||||
@@ -1250,6 +1331,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;
|
||||
}
|
||||
@@ -1344,6 +1427,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 */
|
||||
@@ -1390,5 +1557,6 @@ int main(int argc, char **argv)
|
||||
test_vm86();
|
||||
test_exceptions();
|
||||
test_self_modifying_code();
|
||||
test_single_step();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sched.h>
|
||||
|
||||
int thread1_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
|
||||
for(i=0;i<10;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thread2_func(void *arg)
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
for(i=0;i<20;i++) {
|
||||
snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
|
||||
write(1, buf, strlen(buf));
|
||||
usleep(120 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STACK_SIZE 16384
|
||||
|
||||
void test_clone(void)
|
||||
{
|
||||
uint8_t *stack1, *stack2;
|
||||
int pid1, pid2, status1, status2;
|
||||
|
||||
stack1 = malloc(STACK_SIZE);
|
||||
pid1 = clone(thread1_func, stack1 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
|
||||
|
||||
stack2 = malloc(STACK_SIZE);
|
||||
pid2 = clone(thread2_func, stack2 + STACK_SIZE,
|
||||
CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
|
||||
|
||||
while (waitpid(pid1, &status1, 0) != pid1);
|
||||
while (waitpid(pid2, &status2, 0) != pid2);
|
||||
printf("status1=0x%x\n", status1);
|
||||
printf("status2=0x%x\n", status2);
|
||||
printf("End of clone test.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_clone();
|
||||
return 0;
|
||||
}
|
||||
-194
@@ -1,194 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void alarm_handler(int sig)
|
||||
{
|
||||
printf("alarm signal=%d\n", sig);
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
#ifndef REG_EAX
|
||||
#define REG_EAX EAX
|
||||
#define REG_EBX EBX
|
||||
#define REG_ECX ECX
|
||||
#define REG_EDX EDX
|
||||
#define REG_ESI ESI
|
||||
#define REG_EDI EDI
|
||||
#define REG_EBP EBP
|
||||
#define REG_ESP ESP
|
||||
#define REG_EIP EIP
|
||||
#define REG_EFL EFL
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#define REG_ERR ERR
|
||||
#endif
|
||||
|
||||
void dump_regs(struct ucontext *uc)
|
||||
{
|
||||
printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"EFL=%08x EIP=%08x trapno=%02x err=%08x\n",
|
||||
uc->uc_mcontext.gregs[REG_EAX],
|
||||
uc->uc_mcontext.gregs[REG_EBX],
|
||||
uc->uc_mcontext.gregs[REG_ECX],
|
||||
uc->uc_mcontext.gregs[REG_EDX],
|
||||
uc->uc_mcontext.gregs[REG_ESI],
|
||||
uc->uc_mcontext.gregs[REG_EDI],
|
||||
uc->uc_mcontext.gregs[REG_EBP],
|
||||
uc->uc_mcontext.gregs[REG_ESP],
|
||||
uc->uc_mcontext.gregs[REG_EFL],
|
||||
uc->uc_mcontext.gregs[REG_EIP],
|
||||
uc->uc_mcontext.gregs[REG_TRAPNO],
|
||||
uc->uc_mcontext.gregs[REG_ERR]);
|
||||
}
|
||||
|
||||
void sig_handler(int sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
|
||||
printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n",
|
||||
strsignal(info->si_signo),
|
||||
info->si_signo, info->si_errno, info->si_code,
|
||||
(unsigned long)info->si_addr);
|
||||
dump_regs(uc);
|
||||
longjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
int v1;
|
||||
int tab[2];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act;
|
||||
volatile int val;
|
||||
|
||||
act.sa_sigaction = sig_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGTRAP, &act, NULL);
|
||||
|
||||
/* test division by zero reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now divide by zero */
|
||||
v1 = 0;
|
||||
v1 = 2 / v1;
|
||||
}
|
||||
|
||||
/* test illegal instruction reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now execute an invalid instruction */
|
||||
asm volatile("ud2");
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* now store in an invalid address */
|
||||
*(char *)0x1234 = 1;
|
||||
}
|
||||
|
||||
/* test SEGV reporting */
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* read from an invalid address */
|
||||
v1 = *(char *)0x1234;
|
||||
}
|
||||
|
||||
printf("segment GPF exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* load an invalid segment */
|
||||
asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0));
|
||||
}
|
||||
|
||||
printf("INT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int $0xfd");
|
||||
}
|
||||
|
||||
printf("INT3 exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("int3");
|
||||
}
|
||||
|
||||
printf("CLI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("STI exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("cli");
|
||||
}
|
||||
|
||||
printf("INTO exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* overflow exception */
|
||||
asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff));
|
||||
}
|
||||
|
||||
printf("BOUND exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
/* bound exception */
|
||||
tab[0] = 1;
|
||||
tab[1] = 10;
|
||||
asm volatile ("bound %0, %1" : : "r" (11), "m" (tab));
|
||||
}
|
||||
|
||||
printf("OUTB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0));
|
||||
}
|
||||
|
||||
printf("INB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321));
|
||||
}
|
||||
|
||||
printf("REP OUTSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("REP INSB exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1));
|
||||
}
|
||||
|
||||
printf("HLT exception:\n");
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
|
||||
printf("single step exception:\n");
|
||||
val = 0;
|
||||
if (setjmp(jmp_env) == 0) {
|
||||
asm volatile ("pushf\n"
|
||||
"orl $0x00100, (%%esp)\n"
|
||||
"popf\n"
|
||||
"movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory");
|
||||
}
|
||||
printf("val=0x%x\n", val);
|
||||
|
||||
#if 1
|
||||
{
|
||||
int i;
|
||||
act.sa_handler = alarm_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
alarm(1);
|
||||
for(i = 0;i < 2; i++) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
Executable
+428
@@ -0,0 +1,428 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GNU CC.
|
||||
|
||||
# GNU CC is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GNU CC is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU CC; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
# Boston MA 02111-1307, USA.
|
||||
|
||||
# This does trivial (and I mean _trivial_) conversion of Texinfo
|
||||
# markup to Perl POD format. It's intended to be used to extract
|
||||
# something suitable for a manpage from a Texinfo document.
|
||||
|
||||
$output = 0;
|
||||
$skipping = 0;
|
||||
%sects = ();
|
||||
$section = "";
|
||||
@icstack = ();
|
||||
@endwstack = ();
|
||||
@skstack = ();
|
||||
@instack = ();
|
||||
$shift = "";
|
||||
%defs = ();
|
||||
$fnno = 1;
|
||||
$inf = "";
|
||||
$ibase = "";
|
||||
|
||||
while ($_ = shift) {
|
||||
if (/^-D(.*)$/) {
|
||||
if ($1 ne "") {
|
||||
$flag = $1;
|
||||
} else {
|
||||
$flag = shift;
|
||||
}
|
||||
$value = "";
|
||||
($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
|
||||
die "no flag specified for -D\n"
|
||||
unless $flag ne "";
|
||||
die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
|
||||
unless $flag =~ /^[a-zA-Z0-9_-]+$/;
|
||||
$defs{$flag} = $value;
|
||||
} elsif (/^-/) {
|
||||
usage();
|
||||
} else {
|
||||
$in = $_, next unless defined $in;
|
||||
$out = $_, next unless defined $out;
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $in) {
|
||||
$inf = gensym();
|
||||
open($inf, "<$in") or die "opening \"$in\": $!\n";
|
||||
$ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
|
||||
} else {
|
||||
$inf = \*STDIN;
|
||||
}
|
||||
|
||||
if (defined $out) {
|
||||
open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
|
||||
}
|
||||
|
||||
while(defined $inf) {
|
||||
while(<$inf>) {
|
||||
# Certain commands are discarded without further processing.
|
||||
/^\@(?:
|
||||
[a-z]+index # @*index: useful only in complete manual
|
||||
|need # @need: useful only in printed manual
|
||||
|(?:end\s+)?group # @group .. @end group: ditto
|
||||
|page # @page: ditto
|
||||
|node # @node: useful only in .info file
|
||||
|(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents
|
||||
)\b/x and next;
|
||||
|
||||
chomp;
|
||||
|
||||
# Look for filename and title markers.
|
||||
/^\@setfilename\s+([^.]+)/ and $fn = $1, next;
|
||||
/^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
|
||||
|
||||
# Identify a man title but keep only the one we are interested in.
|
||||
/^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
|
||||
if (exists $defs{$1}) {
|
||||
$fn = $1;
|
||||
$tl = postprocess($2);
|
||||
}
|
||||
next;
|
||||
};
|
||||
|
||||
# Look for blocks surrounded by @c man begin SECTION ... @c man end.
|
||||
# This really oughta be @ifman ... @end ifman and the like, but such
|
||||
# would require rev'ing all other Texinfo translators.
|
||||
/^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
|
||||
$output = 1 if exists $defs{$2};
|
||||
$sect = $1;
|
||||
next;
|
||||
};
|
||||
/^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
|
||||
/^\@c\s+man\s+end/ and do {
|
||||
$sects{$sect} = "" unless exists $sects{$sect};
|
||||
$sects{$sect} .= postprocess($section);
|
||||
$section = "";
|
||||
$output = 0;
|
||||
next;
|
||||
};
|
||||
|
||||
# handle variables
|
||||
/^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
|
||||
$defs{$1} = $2;
|
||||
next;
|
||||
};
|
||||
/^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
delete $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
next unless $output;
|
||||
|
||||
# Discard comments. (Can't do it above, because then we'd never see
|
||||
# @c man lines.)
|
||||
/^\@c\b/ and next;
|
||||
|
||||
# End-block handler goes up here because it needs to operate even
|
||||
# if we are skipping.
|
||||
/^\@end\s+([a-z]+)/ and do {
|
||||
# Ignore @end foo, where foo is not an operation which may
|
||||
# cause us to skip, if we are presently skipping.
|
||||
my $ended = $1;
|
||||
next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/;
|
||||
|
||||
die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
|
||||
die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
|
||||
|
||||
$endw = pop @endwstack;
|
||||
|
||||
if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
|
||||
$skipping = pop @skstack;
|
||||
next;
|
||||
} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
|
||||
$shift = "";
|
||||
$_ = ""; # need a paragraph break
|
||||
} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
|
||||
$_ = "\n=back\n";
|
||||
$ic = pop @icstack;
|
||||
} else {
|
||||
die "unknown command \@end $ended at line $.\n";
|
||||
}
|
||||
};
|
||||
|
||||
# We must handle commands which can cause skipping even while we
|
||||
# are skipping, otherwise we will not process nested conditionals
|
||||
# correctly.
|
||||
/^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = "ifset";
|
||||
$skipping = 1 unless exists $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = "ifclear";
|
||||
$skipping = 1 if exists $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@(ignore|menu|iftex)\b/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = $1;
|
||||
$skipping = 1;
|
||||
next;
|
||||
};
|
||||
|
||||
next if $skipping;
|
||||
|
||||
# Character entities. First the ones that can be replaced by raw text
|
||||
# or discarded outright:
|
||||
s/\@copyright\{\}/(c)/g;
|
||||
s/\@dots\{\}/.../g;
|
||||
s/\@enddots\{\}/..../g;
|
||||
s/\@([.!? ])/$1/g;
|
||||
s/\@[:-]//g;
|
||||
s/\@bullet(?:\{\})?/*/g;
|
||||
s/\@TeX\{\}/TeX/g;
|
||||
s/\@pounds\{\}/\#/g;
|
||||
s/\@minus(?:\{\})?/-/g;
|
||||
s/\\,/,/g;
|
||||
|
||||
# Now the ones that have to be replaced by special escapes
|
||||
# (which will be turned back into text by unmunge())
|
||||
s/&/&/g;
|
||||
s/\@\{/{/g;
|
||||
s/\@\}/}/g;
|
||||
s/\@\@/&at;/g;
|
||||
|
||||
# Inside a verbatim block, handle @var specially.
|
||||
if ($shift ne "") {
|
||||
s/\@var\{([^\}]*)\}/<$1>/g;
|
||||
}
|
||||
|
||||
# POD doesn't interpret E<> inside a verbatim block.
|
||||
if ($shift eq "") {
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
} else {
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
}
|
||||
|
||||
# Single line command handlers.
|
||||
|
||||
/^\@include\s+(.+)$/ and do {
|
||||
push @instack, $inf;
|
||||
$inf = gensym();
|
||||
|
||||
# Try cwd and $ibase.
|
||||
open($inf, "<" . $1)
|
||||
or open($inf, "<" . $ibase . "/" . $1)
|
||||
or die "cannot open $1 or $ibase/$1: $!\n";
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
|
||||
and $_ = "\n=head2 $1\n";
|
||||
/^\@subsection\s+(.+)$/
|
||||
and $_ = "\n=head3 $1\n";
|
||||
|
||||
# Block command handlers:
|
||||
/^\@itemize\s+(\@[a-z]+|\*|-)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
$ic = $1;
|
||||
$_ = "\n=over 4\n";
|
||||
$endw = "itemize";
|
||||
};
|
||||
|
||||
/^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
if (defined $1) {
|
||||
$ic = $1 . ".";
|
||||
} else {
|
||||
$ic = "1.";
|
||||
}
|
||||
$_ = "\n=over 4\n";
|
||||
$endw = "enumerate";
|
||||
};
|
||||
|
||||
/^\@([fv]?table)\s+(\@[a-z]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
$endw = $1;
|
||||
$ic = $2;
|
||||
$ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
|
||||
$ic =~ s/\@(?:code|kbd)/C/;
|
||||
$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
|
||||
$ic =~ s/\@(?:file)/F/;
|
||||
$_ = "\n=over 4\n";
|
||||
};
|
||||
|
||||
/^\@((?:small)?example|display)/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = $1;
|
||||
$shift = "\t";
|
||||
$_ = ""; # need a paragraph break
|
||||
};
|
||||
|
||||
/^\@itemx?\s*(.+)?$/ and do {
|
||||
if (defined $1) {
|
||||
# Entity escapes prevent munging by the <> processing below.
|
||||
# print "$ic\n";
|
||||
$_ = "\n=item $ic\<$1\>\n";
|
||||
} else {
|
||||
$_ = "\n=item $ic\n";
|
||||
$ic =~ y/A-Ya-y/B-Zb-z/;
|
||||
$ic =~ s/(\d+)/$1 + 1/eg;
|
||||
}
|
||||
};
|
||||
|
||||
$section .= $shift.$_."\n";
|
||||
}
|
||||
# End of current file.
|
||||
close($inf);
|
||||
$inf = pop @instack;
|
||||
}
|
||||
|
||||
die "No filename or title\n" unless defined $fn && defined $tl;
|
||||
|
||||
$sects{NAME} = "$fn \- $tl\n";
|
||||
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
|
||||
|
||||
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
|
||||
BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
|
||||
if(exists $sects{$sect}) {
|
||||
$head = $sect;
|
||||
$head =~ s/SEEALSO/SEE ALSO/;
|
||||
print "=head1 $head\n\n";
|
||||
print scalar unmunge ($sects{$sect});
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die "usage: $0 [-D toggle...] [infile [outfile]]\n";
|
||||
}
|
||||
|
||||
sub postprocess
|
||||
{
|
||||
local $_ = $_[0];
|
||||
|
||||
# @value{foo} is replaced by whatever 'foo' is defined as.
|
||||
while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
|
||||
if (! exists $defs{$2}) {
|
||||
print STDERR "Option $2 not defined\n";
|
||||
s/\Q$1\E//;
|
||||
} else {
|
||||
$value = $defs{$2};
|
||||
s/\Q$1\E/$value/;
|
||||
}
|
||||
}
|
||||
|
||||
# Formatting commands.
|
||||
# Temporary escape for @r.
|
||||
s/\@r\{([^\}]*)\}/R<$1>/g;
|
||||
s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
|
||||
s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
|
||||
s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
|
||||
s/\@sc\{([^\}]*)\}/\U$1/g;
|
||||
s/\@file\{([^\}]*)\}/F<$1>/g;
|
||||
s/\@w\{([^\}]*)\}/S<$1>/g;
|
||||
s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
|
||||
|
||||
# Cross references are thrown away, as are @noindent and @refill.
|
||||
# (@noindent is impossible in .pod, and @refill is unnecessary.)
|
||||
# @* is also impossible in .pod; we discard it and any newline that
|
||||
# follows it. Similarly, our macro @gol must be discarded.
|
||||
|
||||
s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
|
||||
s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
|
||||
s/;\s+\@pxref\{(?:[^\}]*)\}//g;
|
||||
s/\@noindent\s*//g;
|
||||
s/\@refill//g;
|
||||
s/\@gol//g;
|
||||
s/\@\*\s*\n?//g;
|
||||
|
||||
# @uref can take one, two, or three arguments, with different
|
||||
# semantics each time. @url and @email are just like @uref with
|
||||
# one argument, for our purposes.
|
||||
s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g;
|
||||
s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
|
||||
s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
|
||||
|
||||
# Turn B<blah I<blah> blah> into B<blah> I<blah> B<blah> to
|
||||
# match Texinfo semantics of @emph inside @samp. Also handle @r
|
||||
# inside bold.
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B</g;
|
||||
1 while (s/B<([^<>]*)I<([^>]+)>/B<$1>I<$2>B</g);
|
||||
1 while (s/I<([^<>]*)B<([^>]+)>/I<$1>B<$2>I</g);
|
||||
s/[BI]<>//g;
|
||||
s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
|
||||
s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
|
||||
|
||||
# Extract footnotes. This has to be done after all other
|
||||
# processing because otherwise the regexp will choke on formatting
|
||||
# inside @footnote.
|
||||
while (/\@footnote/g) {
|
||||
s/\@footnote\{([^\}]+)\}/[$fnno]/;
|
||||
add_footnote($1, $fnno);
|
||||
$fnno++;
|
||||
}
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub unmunge
|
||||
{
|
||||
# Replace escaped symbols with their equivalents.
|
||||
local $_ = $_[0];
|
||||
|
||||
s/</E<lt>/g;
|
||||
s/>/E<gt>/g;
|
||||
s/{/\{/g;
|
||||
s/}/\}/g;
|
||||
s/&at;/\@/g;
|
||||
s/&/&/g;
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub add_footnote
|
||||
{
|
||||
unless (exists $sects{FOOTNOTES}) {
|
||||
$sects{FOOTNOTES} = "\n=over 4\n\n";
|
||||
}
|
||||
|
||||
$sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
|
||||
$sects{FOOTNOTES} .= $_[0];
|
||||
$sects{FOOTNOTES} .= "\n\n";
|
||||
}
|
||||
|
||||
# stolen from Symbol.pm
|
||||
{
|
||||
my $genseq = 0;
|
||||
sub gensym
|
||||
{
|
||||
my $name = "GEN" . $genseq++;
|
||||
my $ref = \*{$name};
|
||||
delete $::{$name};
|
||||
return $ref;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -26,34 +26,19 @@
|
||||
#include "config.h"
|
||||
|
||||
#define IN_OP_I386
|
||||
#if defined(TARGET_I386)
|
||||
#include "cpu-i386.h"
|
||||
#define OPC_CPU_H "opc-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "cpu-arm.h"
|
||||
#define OPC_CPU_H "opc-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
#include "exec.h"
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "dyngen.h"
|
||||
#if defined(TARGET_I386)
|
||||
#include "op-i386.h"
|
||||
#elif defined(TARGET_ARM)
|
||||
#include "op-arm.h"
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
#include "op.h"
|
||||
|
||||
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
@@ -66,13 +51,13 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
@@ -107,19 +92,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)
|
||||
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,
|
||||
@@ -141,7 +131,7 @@ int cpu_gen_code(TranslationBlock *tb,
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include OPC_CPU_H
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
@@ -154,7 +144,7 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
unsigned long tc_ptr;
|
||||
uint16_t *opc_ptr;
|
||||
|
||||
if (gen_intermediate_code_pc(tb) < 0)
|
||||
if (gen_intermediate_code_pc(env, tb) < 0)
|
||||
return -1;
|
||||
|
||||
/* find opc index corresponding to search_pc */
|
||||
@@ -182,13 +172,14 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
#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", i, gen_opc_pc[i]);
|
||||
fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]);
|
||||
}
|
||||
}
|
||||
fprintf(logfile, "j=0x%x eip=0x%lx cs_base=%lx\n",
|
||||
j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
|
||||
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;
|
||||
@@ -198,8 +189,10 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
env->regs[15] = gen_opc_pc[j];
|
||||
#elif defined(TARGET_SPARC)
|
||||
env->pc = gen_opc_pc[j];
|
||||
#elif defined(TARGET_PPC)
|
||||
env->nip = gen_opc_pc[j];
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,25 @@
|
||||
#define VL_H
|
||||
|
||||
/* vl.c */
|
||||
struct CPUX86State;
|
||||
extern int reset_requested;
|
||||
extern int64_t ticks_per_sec;
|
||||
|
||||
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 pic_set_irq(int irq, int level);
|
||||
int64_t cpu_get_ticks(void);
|
||||
|
||||
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;
|
||||
@@ -45,11 +63,85 @@ int bdrv_commit(BlockDriverState *bs);
|
||||
|
||||
struct cow_header_v2 {
|
||||
uint32_t magic;
|
||||
uint32_t long version;
|
||||
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);
|
||||
|
||||
/* ide.c */
|
||||
#define MAX_DISKS 4
|
||||
|
||||
extern BlockDriverState *bs_table[MAX_DISKS];
|
||||
|
||||
void ide_init(void);
|
||||
void ide_set_geometry(int n, int cyls, int heads, int secs);
|
||||
void ide_set_cdrom(int n, int is_cdrom);
|
||||
|
||||
/* oss.c */
|
||||
typedef enum {
|
||||
AUD_FMT_U8,
|
||||
AUD_FMT_S8,
|
||||
AUD_FMT_U16,
|
||||
AUD_FMT_S16
|
||||
} audfmt_e;
|
||||
|
||||
void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt);
|
||||
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt);
|
||||
int AUD_write (void *in_buf, int size);
|
||||
void AUD_run (void);
|
||||
void AUD_adjust_estimate (int _leftover);
|
||||
int AUD_get_free (void);
|
||||
int AUD_get_live (void);
|
||||
int AUD_get_buffer_size (void);
|
||||
void AUD_init (void);
|
||||
|
||||
/* dma.c */
|
||||
typedef int (*DMA_read_handler) (uint32_t addr, int size, int *irq);
|
||||
typedef int (*DMA_misc_handler) (int);
|
||||
|
||||
int DMA_get_channel_mode (int nchan);
|
||||
void DMA_hold_DREQ (int nchan);
|
||||
void DMA_release_DREQ (int nchan);
|
||||
void DMA_run (void);
|
||||
void DMA_init (void);
|
||||
void DMA_register_channel (int nchan,
|
||||
DMA_read_handler read_handler,
|
||||
DMA_misc_handler misc_handler);
|
||||
|
||||
/* sb16.c */
|
||||
void SB16_run (void);
|
||||
void SB16_init (void);
|
||||
|
||||
#endif /* VL_H */
|
||||
Reference in new issue
Block a user