Compare commits
333
Commits
release_0_8_2
...
v0.9.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efb602cda3 | ||
|
|
26a16623b8 | ||
|
|
d8ecc0b913 | ||
|
|
19c80e50ee | ||
|
|
a0f51eadc6 | ||
|
|
b6aaab3b86 | ||
|
|
df517cec51 | ||
|
|
2afbeee757 | ||
|
|
7b9c30c5ee | ||
|
|
c636bb66cc | ||
|
|
84f2e8ef05 | ||
|
|
a9ce859052 | ||
|
|
564c337efd | ||
|
|
2a2528266e | ||
|
|
263466f53a | ||
|
|
1e2bed4f7e | ||
|
|
831952376e | ||
|
|
4fe8b87a7c | ||
|
|
1057eaa709 | ||
|
|
d96372efaa | ||
|
|
fa2948167f | ||
|
|
b49d07ba03 | ||
|
|
33ef55bd96 | ||
|
|
3fffc2234f | ||
|
|
4a109bfbca | ||
|
|
01d6a890b4 | ||
|
|
6a1cbf68b7 | ||
|
|
c4e27dd441 | ||
|
|
d80c7d1c47 | ||
|
|
0499e4a02a | ||
|
|
0dcece76f0 | ||
|
|
01feaa058e | ||
|
|
bf53ca0190 | ||
|
|
5a7b542bbd | ||
|
|
fd6776422b | ||
|
|
46ea33974d | ||
|
|
90e950d17f | ||
|
|
3ddd00658e | ||
|
|
a2d1ebaf89 | ||
|
|
4046d9130e | ||
|
|
f749998939 | ||
|
|
e5b0bc445e | ||
|
|
dff5efc848 | ||
|
|
64423fb206 | ||
|
|
6c3675cac3 | ||
|
|
71c2fd5cdf | ||
|
|
df5cf72160 | ||
|
|
44cbbf18b9 | ||
|
|
6070dd07e9 | ||
|
|
e6a71ae327 | ||
|
|
5f4da8c0f3 | ||
|
|
b29a0341d7 | ||
|
|
4de9b249d3 | ||
|
|
30c4bbace1 | ||
|
|
9c2149c8e0 | ||
|
|
17c275d9ce | ||
|
|
81e1e20979 | ||
|
|
3b1c8be4f4 | ||
|
|
c281868e26 | ||
|
|
3c07f8e894 | ||
|
|
72f341ed1e | ||
|
|
bc814401c2 | ||
|
|
8e71621f78 | ||
|
|
57be54bb3e | ||
|
|
5f12ab4b10 | ||
|
|
af23902bd9 | ||
|
|
472c5273e2 | ||
|
|
15dcf5aa86 | ||
|
|
7f1c9da998 | ||
|
|
284ec167e7 | ||
|
|
831b78254c | ||
|
|
54421cb17b | ||
|
|
0da75eb135 | ||
|
|
605686cd7a | ||
|
|
8182266352 | ||
|
|
54fd9cdfb4 | ||
|
|
9dbd25e664 | ||
|
|
2c52c8169a | ||
|
|
f1770b3e1f | ||
|
|
72742c8626 | ||
|
|
adb4796796 | ||
|
|
dabd98ddf5 | ||
|
|
daf90626be | ||
|
|
5856de800d | ||
|
|
fde7d5bd73 | ||
|
|
5c2b87e34d | ||
|
|
567daa491f | ||
|
|
8f1c91d801 | ||
|
|
abcebc7e80 | ||
|
|
f158755072 | ||
|
|
bf8c534200 | ||
|
|
0178196398 | ||
|
|
18607dcb7c | ||
|
|
96d30e4801 | ||
|
|
2f67a0d55a | ||
|
|
21664424ed | ||
|
|
3b39528c15 | ||
|
|
3b9f94e1a8 | ||
|
|
f5e25d7007 | ||
|
|
2909b29aee | ||
|
|
f7bcd4e373 | ||
|
|
43c1b7e4c3 | ||
|
|
86e94dea5b | ||
|
|
8f28f3fbbe | ||
|
|
43f238d7b6 | ||
|
|
4dbb0f5006 | ||
|
|
6850dd945e | ||
|
|
b92090309e | ||
|
|
2e9671daee | ||
|
|
eec85c2a0d | ||
|
|
9ae0255520 | ||
|
|
a0ae05aa63 | ||
|
|
455204eb1a | ||
|
|
6f30fa853b | ||
|
|
b371dc594b | ||
|
|
2ee4aed86f | ||
|
|
df628ff14e | ||
|
|
240f24e013 | ||
|
|
0feef828e1 | ||
|
|
3a3f24fce8 | ||
|
|
7495fd0f4a | ||
|
|
f8c6ff6c3c | ||
|
|
04e897efdd | ||
|
|
388c45084d | ||
|
|
fa1fb14cd2 | ||
|
|
1f95844967 | ||
|
|
a14d6c8c65 | ||
|
|
04d4b0c33f | ||
|
|
9042c0e20d | ||
|
|
70ead43412 | ||
|
|
5bf089345b | ||
|
|
eddbd288a0 | ||
|
|
28d657fc0b | ||
|
|
4258b780af | ||
|
|
52f61fdeec | ||
|
|
c26c1c4b3d | ||
|
|
c032e2a98c | ||
|
|
42550fde7e | ||
|
|
62ee021121 | ||
|
|
fef3074347 | ||
|
|
bd491d6a4e | ||
|
|
71e3ceb800 | ||
|
|
73fc97427b | ||
|
|
ffd843bcdc | ||
|
|
1cb6c3fd38 | ||
|
|
eaf7e70b01 | ||
|
|
8bdc2159db | ||
|
|
416b5d366d | ||
|
|
d8b20157fc | ||
|
|
92190c648a | ||
|
|
a86c8f29de | ||
|
|
5dc4b74480 | ||
|
|
c570fd169c | ||
|
|
328a42406d | ||
|
|
67d3b957e6 | ||
|
|
179e32bbcc | ||
|
|
e4630047e1 | ||
|
|
73e14b623f | ||
|
|
768a4a36a4 | ||
|
|
0d3267a728 | ||
|
|
8e33c08c84 | ||
|
|
197ea35ab2 | ||
|
|
366dfc521e | ||
|
|
667accab8e | ||
|
|
a2d4e44b48 | ||
|
|
3bcb80f1af | ||
|
|
a42aa81571 | ||
|
|
ca7c2b1b9f | ||
|
|
7d600c804d | ||
|
|
71fb7241c6 | ||
|
|
9f08349345 | ||
|
|
afdfa781e6 | ||
|
|
cd75cf10ca | ||
|
|
ea55ffb373 | ||
|
|
aa328addc0 | ||
|
|
e144966416 | ||
|
|
bb8a53ad91 | ||
|
|
e16fe40c87 | ||
|
|
7a387fffce | ||
|
|
8c0fdd856c | ||
|
|
873eb01234 | ||
|
|
6ae817752b | ||
|
|
814b9a4749 | ||
|
|
ec2309289d | ||
|
|
29bfb11725 | ||
|
|
08f396d720 | ||
|
|
38d0662a4c | ||
|
|
1be9e1dc56 | ||
|
|
ec2db7de7a | ||
|
|
417f38f066 | ||
|
|
2d37be61e3 | ||
|
|
483dcf538e | ||
|
|
b362e5e067 | ||
|
|
d08b2a28e6 | ||
|
|
597a0559fd | ||
|
|
188157fe87 | ||
|
|
58126404f5 | ||
|
|
569f5d668c | ||
|
|
750afe93fd | ||
|
|
00a67ba19a | ||
|
|
fafffaef4f | ||
|
|
a94a6abff4 | ||
|
|
c688a6eb18 | ||
|
|
27908725b9 | ||
|
|
dd016883fb | ||
|
|
d37aca6625 | ||
|
|
e6e5906b6e | ||
|
|
223b8a40d1 | ||
|
|
1f9519c92d | ||
|
|
b4511723bd | ||
|
|
d1beab8220 | ||
|
|
e3e97e7c90 | ||
|
|
47d02f6d5c | ||
|
|
93eac243d5 | ||
|
|
a7e6f8ba22 | ||
|
|
326199c270 | ||
|
|
8d7b0fbb3f | ||
|
|
5e966ce6f4 | ||
|
|
74ce674fa8 | ||
|
|
8988ae8945 | ||
|
|
69c3bcb48f | ||
|
|
42fc925ec0 | ||
|
|
6f15b608f2 | ||
|
|
17100159f1 | ||
|
|
79266dbd9e | ||
|
|
84631fd79c | ||
|
|
4f3baa4b36 | ||
|
|
f00fc47c15 | ||
|
|
ee0ea1d0dd | ||
|
|
02a1602e62 | ||
|
|
a5954d5c34 | ||
|
|
f537a28c97 | ||
|
|
ab1e34add6 | ||
|
|
3b21e03e04 | ||
|
|
ba86345802 | ||
|
|
d4afc623ae | ||
|
|
80b3ada7dd | ||
|
|
d2b5931756 | ||
|
|
e69954b9fc | ||
|
|
37dd208d38 | ||
|
|
05f83f0f95 | ||
|
|
df52b0009b | ||
|
|
8f40c388ef | ||
|
|
aef445bd7e | ||
|
|
6787f5fae0 | ||
|
|
b8174937ed | ||
|
|
519945dfbe | ||
|
|
707b3ee068 | ||
|
|
78600320a8 | ||
|
|
35db099ddb | ||
|
|
6bcb76c3b6 | ||
|
|
e4a89056df | ||
|
|
715748fa08 | ||
|
|
21206a104f | ||
|
|
094eed6ca5 | ||
|
|
9b94dc325b | ||
|
|
c6d46c200f | ||
|
|
e17a36ce41 | ||
|
|
03c1847584 | ||
|
|
67e999be93 | ||
|
|
91cc029598 | ||
|
|
c03b0f0fd8 | ||
|
|
6192bc374f | ||
|
|
a917d384ac | ||
|
|
508d92d057 | ||
|
|
64f5a135a7 | ||
|
|
a817d93656 | ||
|
|
fd44d81821 | ||
|
|
f45512feac | ||
|
|
6b21b973ab | ||
|
|
2192c33250 | ||
|
|
f542086dd4 | ||
|
|
ee0f47514c | ||
|
|
60659e3b44 | ||
|
|
f0e4217213 | ||
|
|
e6cda8e299 | ||
|
|
b56bdb328a | ||
|
|
a9f277ba8f | ||
|
|
19cb37389f | ||
|
|
66c6ef7678 | ||
|
|
ea185bbda7 | ||
|
|
83acc96b23 | ||
|
|
6e1b3e4da4 | ||
|
|
87b47350ed | ||
|
|
243a273ee0 | ||
|
|
c3d78997a3 | ||
|
|
e6cf6a8c7d | ||
|
|
1941d19c65 | ||
|
|
89b6b50892 | ||
|
|
d2269f6f64 | ||
|
|
dfd92d3a46 | ||
|
|
4c279bdf3a | ||
|
|
3dc1cb3428 | ||
|
|
35f1df84b6 | ||
|
|
69fba4a51e | ||
|
|
4d611c9a2f | ||
|
|
4ca9c76f36 | ||
|
|
2a98c1981f | ||
|
|
35b961cf8d | ||
|
|
8ccad811e6 | ||
|
|
e84a4fedf7 | ||
|
|
fb43f4dddc | ||
|
|
19d36792c0 | ||
|
|
90765429aa | ||
|
|
ce1a14dc0d | ||
|
|
51d6bae7a8 | ||
|
|
13a2e80f04 | ||
|
|
c88676f89c | ||
|
|
d15a771da1 | ||
|
|
a946592212 | ||
|
|
1aacf3489b | ||
|
|
51c1ebb1bc | ||
|
|
6eb5733a3c | ||
|
|
15e6690aca | ||
|
|
c47c33b098 | ||
|
|
e70332b376 | ||
|
|
faea38e786 | ||
|
|
42ca638823 | ||
|
|
9ab8a34a18 | ||
|
|
585f8587ad | ||
|
|
9e46cfa4c6 | ||
|
|
e2f909bef9 | ||
|
|
7f1a8398ab | ||
|
|
e7b81015e5 | ||
|
|
436e15b827 | ||
|
|
550be12730 | ||
|
|
979b67ad86 | ||
|
|
83f6409109 | ||
|
|
7954c73498 | ||
|
|
93b6b2a3cd | ||
|
|
d62ca2bb9b | ||
|
|
4615218210 | ||
|
|
f3a9676a60 |
No files matched your search
+12
-9
@@ -1,14 +1,16 @@
|
||||
arm-user
|
||||
arm-linux-user
|
||||
arm-softmmu
|
||||
armeb-user
|
||||
armeb-linux-user
|
||||
config-host.*
|
||||
dyngen
|
||||
i386
|
||||
i386-softmmu
|
||||
i386-user
|
||||
i386-darwin-user
|
||||
i386-linux-user
|
||||
ppc-softmmu
|
||||
ppc64-softmmu
|
||||
ppc-user
|
||||
ppc-darwin-user
|
||||
ppc-linux-user
|
||||
qemu-doc.html
|
||||
qemu-tech.html
|
||||
qemu-doc.info
|
||||
@@ -17,18 +19,19 @@ qemu.1
|
||||
qemu.pod
|
||||
qemu-img.1
|
||||
qemu-img.pod
|
||||
sparc-user
|
||||
sparc-linux-user
|
||||
qemu-img
|
||||
sparc-softmmu
|
||||
x86_64-softmmu
|
||||
sparc64-user
|
||||
sparc64-linux-user
|
||||
sparc64-softmmu
|
||||
mips-softmmu
|
||||
mipsel-softmmu
|
||||
mips-user
|
||||
mipsel-user
|
||||
mips-linux-user
|
||||
mipsel-linux-user
|
||||
m68k-linux-user
|
||||
.gdbinit
|
||||
sh4-user
|
||||
sh4-linux-user
|
||||
sh4-softmmu
|
||||
*.aux
|
||||
*.cp
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
version 0.9.0:
|
||||
|
||||
- Support for relative paths in backing files for disk images
|
||||
- Async file I/O API
|
||||
- New qcow2 disk image format
|
||||
- Support of multiple VM snapshots
|
||||
- Linux: specific host CDROM and floppy support
|
||||
- SMM support
|
||||
- Moved PCI init, MP table init and ACPI table init to Bochs BIOS
|
||||
- Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
|
||||
- MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
|
||||
- Darwin userspace emulation (Pierre d'Herbemont)
|
||||
- m68k user support (Paul Brook)
|
||||
- several x86 and x86_64 emulation fixes
|
||||
- Mouse relative offset VNC extension (Anthony Liguori)
|
||||
- PXE boot support (Anthony Liguori)
|
||||
- '-daemonize' option (Anthony Liguori)
|
||||
|
||||
version 0.8.2:
|
||||
|
||||
- ACPI support
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
The following points clarify the QEMU licenses:
|
||||
The following points clarify the QEMU license:
|
||||
|
||||
1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
|
||||
system emulator are released under the GNU Lesser General Public
|
||||
License.
|
||||
1) QEMU as a whole is released under the GNU General Public License
|
||||
|
||||
2) The Linux user mode QEMU emulator is released under the GNU General
|
||||
Public License.
|
||||
2) Parts of QEMU have specific licenses which are compatible with the
|
||||
GNU General Public License. Hence each source file contains its own
|
||||
licensing information.
|
||||
|
||||
In particular, the QEMU virtual CPU core library (libqemu.a) is
|
||||
released under the GNU Lesser General Public License. Many hardware
|
||||
device emulation sources are released under the BSD license.
|
||||
|
||||
3) QEMU is a trademark of Fabrice Bellard.
|
||||
|
||||
|
||||
@@ -5,19 +5,18 @@ include config-host.mak
|
||||
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
|
||||
speed test test2 html dvi info
|
||||
|
||||
CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I.
|
||||
ifdef CONFIG_DARWIN
|
||||
CFLAGS+= -mdynamic-no-pic
|
||||
endif
|
||||
BASE_CFLAGS=
|
||||
BASE_LDFLAGS=
|
||||
|
||||
BASE_CFLAGS += $(OS_CFLAGS)
|
||||
ifeq ($(ARCH),sparc)
|
||||
CFLAGS+=-mcpu=ultrasparc
|
||||
BASE_CFLAGS += -mcpu=ultrasparc
|
||||
endif
|
||||
LDFLAGS=-g
|
||||
CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
LIBS=
|
||||
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
TOOLS=qemu-img$(EXESUF)
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
BASE_LDFLAGS += -static
|
||||
endif
|
||||
ifdef BUILD_DOCS
|
||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
|
||||
@@ -25,18 +24,26 @@ else
|
||||
DOCS=
|
||||
endif
|
||||
|
||||
ifndef CONFIG_DARWIN
|
||||
ifndef CONFIG_WIN32
|
||||
ifndef CONFIG_SOLARIS
|
||||
LIBS+=-lrt
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(TOOLS) $(DOCS) recurse-all
|
||||
|
||||
subdir-%: dyngen$(EXESUF)
|
||||
$(MAKE) -C $(subst subdir-,,$@) all
|
||||
|
||||
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
|
||||
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c block-qcow2.c
|
||||
$(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
|
||||
|
||||
dyngen$(EXESUF): dyngen.c
|
||||
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
|
||||
$(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
|
||||
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
@@ -71,7 +78,8 @@ install: all $(if $(BUILD_DOCS),install-doc)
|
||||
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
mkdir -p "$(DESTDIR)$(datadir)"
|
||||
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
|
||||
video.x openbios-sparc32 linux_boot.bin; do \
|
||||
video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
|
||||
pxe-rtl8139.bin pxe-pcnet.bin; do \
|
||||
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
|
||||
done
|
||||
ifndef CONFIG_WIN32
|
||||
@@ -120,7 +128,8 @@ dvi: qemu-doc.dvi qemu-tech.dvi
|
||||
|
||||
html: qemu-doc.html qemu-tech.html
|
||||
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
VERSION ?= $(shell cat VERSION)
|
||||
FILE = qemu-$(VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
tar:
|
||||
@@ -154,6 +163,9 @@ tarbin:
|
||||
$(datadir)/video.x \
|
||||
$(datadir)/openbios-sparc32 \
|
||||
$(datadir)/linux_boot.bin \
|
||||
$(datadir)/pxe-ne2k_pci.bin \
|
||||
$(datadir)/pxe-rtl8139.bin \
|
||||
$(datadir)/pxe-pcnet.bin \
|
||||
$(docdir)/qemu-doc.html \
|
||||
$(docdir)/qemu-tech.html \
|
||||
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
|
||||
|
||||
+125
-79
@@ -12,14 +12,18 @@ TARGET_BASE_ARCH:=sparc
|
||||
endif
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
|
||||
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
|
||||
DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
|
||||
ifdef CONFIG_USER_ONLY
|
||||
VPATH+=:$(SRC_PATH)/linux-user
|
||||
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
|
||||
CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
|
||||
ifdef CONFIG_DARWIN_USER
|
||||
VPATH+=:$(SRC_PATH)/darwin-user
|
||||
CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
|
||||
endif
|
||||
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
|
||||
ifdef CONFIG_LINUX_USER
|
||||
VPATH+=:$(SRC_PATH)/linux-user
|
||||
CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
|
||||
endif
|
||||
BASE_CFLAGS=
|
||||
BASE_LDFLAGS=
|
||||
#CFLAGS+=-Werror
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen$(EXESUF)
|
||||
@@ -62,18 +66,20 @@ endif
|
||||
endif # !CONFIG_USER_ONLY
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
LDFLAGS+=-static
|
||||
BASE_LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
# We require -O2 to avoid the stack setup prologue in EXIT_TB
|
||||
OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
HELPER_CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
OP_CFLAGS+= -falign-functions=0 -fno-gcse
|
||||
else
|
||||
OP_CFLAGS+= -malign-functions=0
|
||||
endif
|
||||
|
||||
ifdef TARGET_GPROF
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
@@ -81,76 +87,80 @@ ifdef CONFIG_STATIC
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
ifdef USE_I386_LD
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
else
|
||||
ifdef CONFIG_LINUX_USER
|
||||
# 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
|
||||
BASE_LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
OP_CFLAGS=$(CFLAGS) -falign-functions=0
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
CFLAGS+= -D__powerpc__
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
|
||||
CPPFLAGS+= -D__powerpc__
|
||||
ifdef CONFIG_LINUX_USER
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc)
|
||||
ifeq ($(CONFIG_SOLARIS),yes)
|
||||
CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
|
||||
BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
|
||||
BASE_LDFLAGS+=-m32
|
||||
OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
|
||||
else
|
||||
CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
BASE_LDFLAGS+=-m32
|
||||
OP_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
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
|
||||
LDFLAGS+=-m64
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
|
||||
BASE_LDFLAGS+=-m64
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -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
|
||||
# -msmall-data is not used for OP_CFLAGS because we want two-instruction
|
||||
# relocations for the constant constructions
|
||||
# Ensure there's only a single GP
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
|
||||
BASE_CFLAGS+=-msmall-data
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
CFLAGS += -mno-sdata
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
|
||||
BASE_CFLAGS+=-mno-sdata
|
||||
OP_CFLAGS+=-mno-sdata
|
||||
BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
|
||||
OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),m68k)
|
||||
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,m68k.ld
|
||||
OP_CFLAGS+=-fomit-frame-pointer
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),mips)
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
@@ -159,13 +169,19 @@ OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DARWIN),yes)
|
||||
OP_CFLAGS+= -mdynamic-no-pic
|
||||
LIBS+=-lmx
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DARWIN_USER
|
||||
# Leave some space for the regular program loading zone
|
||||
BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
|
||||
endif
|
||||
|
||||
OP_CFLAGS+=$(OS_CFLAGS)
|
||||
|
||||
#########################################################
|
||||
|
||||
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
LIBS+=-lm
|
||||
ifndef CONFIG_USER_ONLY
|
||||
LIBS+=-lz
|
||||
@@ -179,10 +195,11 @@ endif
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
BASE_LDFLAGS+=-p
|
||||
main.o: BASE_CFLAGS+=-p
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
|
||||
elfload.o linuxload.o
|
||||
ifdef TARGET_HAS_BFLT
|
||||
@@ -197,6 +214,15 @@ OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
|
||||
nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
|
||||
nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), m68k)
|
||||
OBJS+= m68k-sim.o m68k-semi.o
|
||||
endif
|
||||
endif #CONFIG_LINUX_USER
|
||||
|
||||
ifdef CONFIG_DARWIN_USER
|
||||
OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o
|
||||
endif
|
||||
|
||||
SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
@@ -208,7 +234,7 @@ LIBOBJS+=fpu/softfloat.o
|
||||
else
|
||||
LIBOBJS+=fpu/softfloat-native.o
|
||||
endif
|
||||
DEFINES+=-I$(SRC_PATH)/fpu
|
||||
CPPFLAGS+=-I$(SRC_PATH)/fpu
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=helper.o helper2.o
|
||||
@@ -241,6 +267,10 @@ ifeq ($(TARGET_BASE_ARCH), sh4)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), m68k)
|
||||
LIBOBJS+= helper.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=disas.o
|
||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
||||
@@ -281,7 +311,7 @@ endif
|
||||
all: $(PROGS)
|
||||
|
||||
$(QEMU_USER): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(CC) $(LDFLAGS) $(BASE_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)
|
||||
@@ -289,8 +319,10 @@ ifeq ($(ARCH),alpha)
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o
|
||||
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
|
||||
VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o
|
||||
VL_OBJS+=cutils.o
|
||||
VL_OBJS+=block.o block-raw.o
|
||||
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o
|
||||
ifdef CONFIG_WIN32
|
||||
VL_OBJS+=tap-win32.o
|
||||
endif
|
||||
@@ -316,7 +348,7 @@ LIBS += -lole32 -ldxguid
|
||||
endif
|
||||
ifdef CONFIG_FMOD
|
||||
AUDIODRV += fmodaudio.o
|
||||
audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
|
||||
audio.o fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
|
||||
LIBS += $(CONFIG_FMOD_LIB)
|
||||
endif
|
||||
ifdef CONFIG_ADLIB
|
||||
@@ -338,19 +370,21 @@ ifeq ($(TARGET_BASE_ARCH), i386)
|
||||
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
|
||||
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
|
||||
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o
|
||||
VL_OBJS+= usb-uhci.o
|
||||
DEFINES += -DHAS_AUDIO
|
||||
VL_OBJS+= usb-uhci.o smbus_eeprom.o
|
||||
CPPFLAGS += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
|
||||
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
|
||||
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
|
||||
VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
|
||||
DEFINES += -DHAS_AUDIO
|
||||
CPPFLAGS += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
|
||||
#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
|
||||
VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
|
||||
VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o
|
||||
VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
|
||||
DEFINES += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sparc)
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
@@ -358,14 +392,17 @@ VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
|
||||
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
|
||||
VL_OBJS+= cirrus_vga.o parallel.o
|
||||
else
|
||||
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o
|
||||
VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
|
||||
VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
|
||||
VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
|
||||
VL_OBJS+= cs4231.o
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), arm)
|
||||
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
|
||||
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
|
||||
VL_OBJS+= versatile_pci.o
|
||||
VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
|
||||
VL_OBJS+= arm-semi.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sh4)
|
||||
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
|
||||
@@ -374,7 +411,7 @@ ifdef CONFIG_GDBSTUB
|
||||
VL_OBJS+=gdbstub.o
|
||||
endif
|
||||
ifdef CONFIG_SDL
|
||||
VL_OBJS+=sdl.o
|
||||
VL_OBJS+=sdl.o x_keymap.o
|
||||
endif
|
||||
VL_OBJS+=vnc.o
|
||||
ifdef CONFIG_COCOA
|
||||
@@ -385,7 +422,7 @@ COCOA_LIBS+=-framework CoreAudio
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_SLIRP
|
||||
DEFINES+=-I$(SRC_PATH)/slirp
|
||||
CPPFLAGS+=-I$(SRC_PATH)/slirp
|
||||
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
|
||||
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
|
||||
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
|
||||
@@ -408,7 +445,7 @@ endif
|
||||
endif
|
||||
endif
|
||||
ifdef TARGET_GPROF
|
||||
vl.o: CFLAGS+=-p
|
||||
vl.o: BASE_CFLAGS+=-p
|
||||
VL_LDFLAGS+=-p
|
||||
endif
|
||||
|
||||
@@ -429,22 +466,22 @@ $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
|
||||
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
|
||||
|
||||
cocoa.o: cocoa.m
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
sdl.o: sdl.c keymaps.c sdl_keysym.h
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
sdlaudio.o: sdlaudio.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
|
||||
|
||||
vldepend: $(VL_OBJS:.o=.c)
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
|
||||
@@ -468,10 +505,26 @@ gen-op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -g -o $@ $<
|
||||
|
||||
op.o: op.c
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
$(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
# HELPER_CFLAGS is used for all the code compiled with static register
|
||||
# variables
|
||||
ifeq ($(TARGET_BASE_ARCH), i386)
|
||||
# XXX: rename helper.c to op_helper.c
|
||||
helper.o: helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
else
|
||||
op_helper.o: op_helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
cpu-exec.o: cpu-exec.c
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
# Note: this is a workaround. The real fix is to avoid compiling
|
||||
# cpu_signal_handler() in cpu-exec.c.
|
||||
signal.o: signal.c
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), i386)
|
||||
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
|
||||
@@ -494,19 +547,12 @@ translate.o: translate.c translate_init.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
op.o: op.c op_template.c op_mem.c
|
||||
op.o: op.c op_template.c fop_template.c op_mem.c
|
||||
op_helper.o: op_helper_mem.c
|
||||
endif
|
||||
|
||||
loader.o: loader.c elf_ops.h
|
||||
|
||||
acpi.o: acpi.c acpi-dsdt.hex
|
||||
|
||||
ifdef BUILD_ACPI_TABLES
|
||||
$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
|
||||
iasl -tc -p $@ $<
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), sh4)
|
||||
op.o: op.c op_mem.c cpu.h
|
||||
op_helper.o: op_helper.c exec.h cpu.h
|
||||
@@ -520,10 +566,10 @@ endif
|
||||
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(DEFINES) -c -o $@ $<
|
||||
$(CC) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
Information about the various packages used to build the current qemu
|
||||
x86 binary distribution:
|
||||
|
||||
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
|
||||
was used to get most of the binary packages.
|
||||
|
||||
* wine-20020411 tarball
|
||||
|
||||
./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-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
|
||||
+458
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Arm "Angel" semihosting syscalls
|
||||
*
|
||||
* Copyright (c) 2005, 2007 CodeSourcery.
|
||||
* Written by Paul Brook.
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#include "qemu.h"
|
||||
|
||||
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
|
||||
#else
|
||||
#include "vl.h"
|
||||
#endif
|
||||
|
||||
#define SYS_OPEN 0x01
|
||||
#define SYS_CLOSE 0x02
|
||||
#define SYS_WRITEC 0x03
|
||||
#define SYS_WRITE0 0x04
|
||||
#define SYS_WRITE 0x05
|
||||
#define SYS_READ 0x06
|
||||
#define SYS_READC 0x07
|
||||
#define SYS_ISTTY 0x09
|
||||
#define SYS_SEEK 0x0a
|
||||
#define SYS_FLEN 0x0c
|
||||
#define SYS_TMPNAM 0x0d
|
||||
#define SYS_REMOVE 0x0e
|
||||
#define SYS_RENAME 0x0f
|
||||
#define SYS_CLOCK 0x10
|
||||
#define SYS_TIME 0x11
|
||||
#define SYS_SYSTEM 0x12
|
||||
#define SYS_ERRNO 0x13
|
||||
#define SYS_GET_CMDLINE 0x15
|
||||
#define SYS_HEAPINFO 0x16
|
||||
#define SYS_EXIT 0x18
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#define GDB_O_RDONLY 0x000
|
||||
#define GDB_O_WRONLY 0x001
|
||||
#define GDB_O_RDWR 0x002
|
||||
#define GDB_O_APPEND 0x008
|
||||
#define GDB_O_CREAT 0x200
|
||||
#define GDB_O_TRUNC 0x400
|
||||
#define GDB_O_BINARY 0
|
||||
|
||||
static int gdb_open_modeflags[12] = {
|
||||
GDB_O_RDONLY,
|
||||
GDB_O_RDONLY | GDB_O_BINARY,
|
||||
GDB_O_RDWR,
|
||||
GDB_O_RDWR | GDB_O_BINARY,
|
||||
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
|
||||
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
|
||||
GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
|
||||
GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
|
||||
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
|
||||
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
|
||||
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
|
||||
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
|
||||
};
|
||||
|
||||
static int open_modeflags[12] = {
|
||||
O_RDONLY,
|
||||
O_RDONLY | O_BINARY,
|
||||
O_RDWR,
|
||||
O_RDWR | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_TRUNC,
|
||||
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_APPEND,
|
||||
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_APPEND,
|
||||
O_RDWR | O_CREAT | O_APPEND | O_BINARY
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
|
||||
{
|
||||
if (code == (uint32_t)-1)
|
||||
ts->swi_errno = errno;
|
||||
return code;
|
||||
}
|
||||
#else
|
||||
static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
static uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
|
||||
return tswap32(val);
|
||||
}
|
||||
static uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
cpu_memory_rw_debug(env, addr, &val, 1, 0);
|
||||
return val;
|
||||
}
|
||||
#define tget32(p) softmmu_tget32(env, p)
|
||||
#define tget8(p) softmmu_tget8(env, p)
|
||||
|
||||
static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
|
||||
int copy)
|
||||
{
|
||||
char *p;
|
||||
/* TODO: Make this something that isn't fixed size. */
|
||||
p = malloc(len);
|
||||
if (copy)
|
||||
cpu_memory_rw_debug(env, addr, p, len, 0);
|
||||
return p;
|
||||
}
|
||||
#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
|
||||
static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
uint8_t c;
|
||||
/* TODO: Make this something that isn't fixed size. */
|
||||
s = p = malloc(1024);
|
||||
do {
|
||||
cpu_memory_rw_debug(env, addr, &c, 1, 0);
|
||||
addr++;
|
||||
*(p++) = c;
|
||||
} while (c);
|
||||
return s;
|
||||
}
|
||||
#define lock_user_string(p) softmmu_lock_user_string(env, p)
|
||||
static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
|
||||
target_ulong len)
|
||||
{
|
||||
if (len)
|
||||
cpu_memory_rw_debug(env, addr, p, len, 1);
|
||||
free(p);
|
||||
}
|
||||
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
|
||||
#endif
|
||||
|
||||
static target_ulong arm_semi_syscall_len;
|
||||
|
||||
static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
TaskState *ts = env->opaque;
|
||||
#endif
|
||||
if (ret == (target_ulong)-1) {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
ts->swi_errno = err;
|
||||
#endif
|
||||
env->regs[0] = ret;
|
||||
} else {
|
||||
/* Fixup syscalls that use nonstardard return conventions. */
|
||||
switch (env->regs[0]) {
|
||||
case SYS_WRITE:
|
||||
case SYS_READ:
|
||||
env->regs[0] = arm_semi_syscall_len - ret;
|
||||
break;
|
||||
case SYS_SEEK:
|
||||
env->regs[0] = 0;
|
||||
break;
|
||||
default:
|
||||
env->regs[0] = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ARG(n) tget32(args + (n) * 4)
|
||||
#define SET_ARG(n, val) tput32(args + (n) * 4,val)
|
||||
uint32_t do_arm_semihosting(CPUState *env)
|
||||
{
|
||||
target_ulong args;
|
||||
char * s;
|
||||
int nr;
|
||||
uint32_t ret;
|
||||
uint32_t len;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
TaskState *ts = env->opaque;
|
||||
#else
|
||||
CPUState *ts = env;
|
||||
#endif
|
||||
|
||||
nr = env->regs[0];
|
||||
args = env->regs[1];
|
||||
switch (nr) {
|
||||
case SYS_OPEN:
|
||||
s = lock_user_string(ARG(0));
|
||||
if (ARG(1) >= 12)
|
||||
return (uint32_t)-1;
|
||||
if (strcmp(s, ":tt") == 0) {
|
||||
if (ARG(1) < 4)
|
||||
return STDIN_FILENO;
|
||||
else
|
||||
return STDOUT_FILENO;
|
||||
}
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2),
|
||||
gdb_open_modeflags[ARG(1)]);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
|
||||
}
|
||||
unlock_user(s, ARG(0), 0);
|
||||
return ret;
|
||||
case SYS_CLOSE:
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
|
||||
return env->regs[0];
|
||||
} else {
|
||||
return set_swi_errno(ts, close(ARG(0)));
|
||||
}
|
||||
case SYS_WRITEC:
|
||||
{
|
||||
char c = tget8(args);
|
||||
/* Write to debug console. stderr is near enough. */
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
return write(STDERR_FILENO, &c, 1);
|
||||
}
|
||||
}
|
||||
case SYS_WRITE0:
|
||||
s = lock_user_string(args);
|
||||
len = strlen(s);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
|
||||
ret = env->regs[0];
|
||||
} else {
|
||||
ret = write(STDERR_FILENO, s, len);
|
||||
}
|
||||
unlock_user(s, args, 0);
|
||||
return ret;
|
||||
case SYS_WRITE:
|
||||
len = ARG(2);
|
||||
if (use_gdb_syscalls()) {
|
||||
arm_semi_syscall_len = len;
|
||||
gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
s = lock_user(ARG(1), len, 1);
|
||||
ret = set_swi_errno(ts, write(ARG(0), s, len));
|
||||
unlock_user(s, ARG(1), 0);
|
||||
if (ret == (uint32_t)-1)
|
||||
return -1;
|
||||
return len - ret;
|
||||
}
|
||||
case SYS_READ:
|
||||
len = ARG(2);
|
||||
if (use_gdb_syscalls()) {
|
||||
arm_semi_syscall_len = len;
|
||||
gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
s = lock_user(ARG(1), len, 0);
|
||||
do
|
||||
ret = set_swi_errno(ts, read(ARG(0), s, len));
|
||||
while (ret == -1 && errno == EINTR);
|
||||
unlock_user(s, ARG(1), len);
|
||||
if (ret == (uint32_t)-1)
|
||||
return -1;
|
||||
return len - ret;
|
||||
}
|
||||
case SYS_READC:
|
||||
/* XXX: Read from debug cosole. Not implemented. */
|
||||
return 0;
|
||||
case SYS_ISTTY:
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
|
||||
return env->regs[0];
|
||||
} else {
|
||||
return isatty(ARG(0));
|
||||
}
|
||||
case SYS_SEEK:
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1));
|
||||
return env->regs[0];
|
||||
} else {
|
||||
ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
|
||||
if (ret == (uint32_t)-1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
case SYS_FLEN:
|
||||
if (use_gdb_syscalls()) {
|
||||
/* TODO: Use stat syscall. */
|
||||
return -1;
|
||||
} else {
|
||||
struct stat buf;
|
||||
ret = set_swi_errno(ts, fstat(ARG(0), &buf));
|
||||
if (ret == (uint32_t)-1)
|
||||
return -1;
|
||||
return buf.st_size;
|
||||
}
|
||||
case SYS_TMPNAM:
|
||||
/* XXX: Not implemented. */
|
||||
return -1;
|
||||
case SYS_REMOVE:
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1));
|
||||
ret = env->regs[0];
|
||||
} else {
|
||||
s = lock_user_string(ARG(0));
|
||||
ret = set_swi_errno(ts, remove(s));
|
||||
unlock_user(s, ARG(0), 0);
|
||||
}
|
||||
return ret;
|
||||
case SYS_RENAME:
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
|
||||
ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
|
||||
return env->regs[0];
|
||||
} else {
|
||||
char *s2;
|
||||
s = lock_user_string(ARG(0));
|
||||
s2 = lock_user_string(ARG(2));
|
||||
ret = set_swi_errno(ts, rename(s, s2));
|
||||
unlock_user(s2, ARG(2), 0);
|
||||
unlock_user(s, ARG(0), 0);
|
||||
return ret;
|
||||
}
|
||||
case SYS_CLOCK:
|
||||
return clock() / (CLOCKS_PER_SEC / 100);
|
||||
case SYS_TIME:
|
||||
return set_swi_errno(ts, time(NULL));
|
||||
case SYS_SYSTEM:
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1));
|
||||
return env->regs[0];
|
||||
} else {
|
||||
s = lock_user_string(ARG(0));
|
||||
ret = set_swi_errno(ts, system(s));
|
||||
unlock_user(s, ARG(0), 0);
|
||||
}
|
||||
case SYS_ERRNO:
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return ts->swi_errno;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
case SYS_GET_CMDLINE:
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* Build a commandline from the original argv. */
|
||||
{
|
||||
char **arg = ts->info->host_argv;
|
||||
int len = ARG(1);
|
||||
/* lock the buffer on the ARM side */
|
||||
char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0);
|
||||
|
||||
s = cmdline_buffer;
|
||||
while (*arg && len > 2) {
|
||||
int n = strlen(*arg);
|
||||
|
||||
if (s != cmdline_buffer) {
|
||||
*(s++) = ' ';
|
||||
len--;
|
||||
}
|
||||
if (n >= len)
|
||||
n = len - 1;
|
||||
memcpy(s, *arg, n);
|
||||
s += n;
|
||||
len -= n;
|
||||
arg++;
|
||||
}
|
||||
/* Null terminate the string. */
|
||||
*s = 0;
|
||||
len = s - cmdline_buffer;
|
||||
|
||||
/* Unlock the buffer on the ARM side. */
|
||||
unlock_user(cmdline_buffer, ARG(0), len);
|
||||
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, len);
|
||||
|
||||
/* Return success if commandline fit into buffer. */
|
||||
return *arg ? -1 : 0;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
case SYS_HEAPINFO:
|
||||
{
|
||||
uint32_t *ptr;
|
||||
uint32_t limit;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* Some C libraries assume the heap immediately follows .bss, so
|
||||
allocate it using sbrk. */
|
||||
if (!ts->heap_limit) {
|
||||
long ret;
|
||||
|
||||
ts->heap_base = do_brk(0);
|
||||
limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
|
||||
/* Try a big heap, and reduce the size if that fails. */
|
||||
for (;;) {
|
||||
ret = do_brk(limit);
|
||||
if (ret != -1)
|
||||
break;
|
||||
limit = (ts->heap_base >> 1) + (limit >> 1);
|
||||
}
|
||||
ts->heap_limit = limit;
|
||||
}
|
||||
|
||||
ptr = lock_user(ARG(0), 16, 0);
|
||||
ptr[0] = tswap32(ts->heap_base);
|
||||
ptr[1] = tswap32(ts->heap_limit);
|
||||
ptr[2] = tswap32(ts->stack_base);
|
||||
ptr[3] = tswap32(0); /* Stack limit. */
|
||||
unlock_user(ptr, ARG(0), 16);
|
||||
#else
|
||||
limit = ram_size;
|
||||
ptr = lock_user(ARG(0), 16, 0);
|
||||
/* TODO: Make this use the limit of the loaded application. */
|
||||
ptr[0] = tswap32(limit / 2);
|
||||
ptr[1] = tswap32(limit);
|
||||
ptr[2] = tswap32(limit); /* Stack base */
|
||||
ptr[3] = tswap32(0); /* Stack limit. */
|
||||
unlock_user(ptr, ARG(0), 16);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
case SYS_EXIT:
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
|
||||
cpu_dump_state(env, stderr, fprintf, 0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,10 @@ SECTIONS
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
|
||||
__exidx_start = .;
|
||||
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
|
||||
__exidx_end = .;
|
||||
.reginfo : { *(.reginfo) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
@@ -63,7 +67,28 @@ SECTIONS
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.data1 : { *(.data1) }
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
}
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
.ctors :
|
||||
{
|
||||
*(.ctors)
|
||||
|
||||
+2
-2
@@ -605,11 +605,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
||||
}
|
||||
|
||||
if (info->sign) {
|
||||
memset (buf, len << info->shift, 0x00);
|
||||
memset (buf, 0x00, len << info->shift);
|
||||
}
|
||||
else {
|
||||
if (info->bits == 8) {
|
||||
memset (buf, len << info->shift, 0x80);
|
||||
memset (buf, 0x80, len << info->shift);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
|
||||
+2
-2
@@ -151,7 +151,7 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
|
||||
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
|
||||
|
||||
wav->f = fopen (conf.wav_path, "wb");
|
||||
wav->f = qemu_fopen (conf.wav_path, "wb");
|
||||
if (!wav->f) {
|
||||
dolog ("Failed to open wave file `%s'\nReason: %s\n",
|
||||
conf.wav_path, strerror (errno));
|
||||
@@ -185,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw)
|
||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||
qemu_put_buffer (wav->f, dlen, 4);
|
||||
|
||||
fclose (wav->f);
|
||||
qemu_fclose (wav->f);
|
||||
wav->f = NULL;
|
||||
|
||||
qemu_free (wav->pcm_buf);
|
||||
|
||||
+15
-16
@@ -34,22 +34,19 @@ static void wav_destroy (void *opaque)
|
||||
uint32_t datalen = wav->bytes;
|
||||
uint32_t rifflen = datalen + 36;
|
||||
|
||||
if (!wav->f) {
|
||||
return;
|
||||
}
|
||||
|
||||
le_store (rlen, rifflen, 4);
|
||||
le_store (dlen, datalen, 4);
|
||||
|
||||
qemu_fseek (wav->f, 4, SEEK_SET);
|
||||
qemu_put_buffer (wav->f, rlen, 4);
|
||||
|
||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||
qemu_put_buffer (wav->f, dlen, 4);
|
||||
fclose (wav->f);
|
||||
if (wav->path) {
|
||||
qemu_free (wav->path);
|
||||
if (wav->f) {
|
||||
le_store (rlen, rifflen, 4);
|
||||
le_store (dlen, datalen, 4);
|
||||
|
||||
qemu_fseek (wav->f, 4, SEEK_SET);
|
||||
qemu_put_buffer (wav->f, rlen, 4);
|
||||
|
||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||
qemu_put_buffer (wav->f, dlen, 4);
|
||||
qemu_fclose (wav->f);
|
||||
}
|
||||
|
||||
qemu_free (wav->path);
|
||||
}
|
||||
|
||||
static void wav_capture (void *opaque, void *buf, int size)
|
||||
@@ -135,7 +132,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
le_store (hdr + 28, freq << shift, 4);
|
||||
le_store (hdr + 32, 1 << shift, 2);
|
||||
|
||||
wav->f = fopen (path, "wb");
|
||||
wav->f = qemu_fopen (path, "wb");
|
||||
if (!wav->f) {
|
||||
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
|
||||
path, strerror (errno));
|
||||
@@ -153,6 +150,8 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
cap = AUD_add_capture (NULL, &as, &ops, wav);
|
||||
if (!cap) {
|
||||
term_printf ("Failed to add audio capture\n");
|
||||
qemu_free (wav->path);
|
||||
qemu_fclose (wav->f);
|
||||
qemu_free (wav);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+38
-8
@@ -28,7 +28,8 @@
|
||||
/**************************************************************/
|
||||
|
||||
#define HEADER_MAGIC "Bochs Virtual HD Image"
|
||||
#define HEADER_VERSION 0x00010000
|
||||
#define HEADER_VERSION 0x00020000
|
||||
#define HEADER_V1 0x00010000
|
||||
#define HEADER_SIZE 512
|
||||
|
||||
#define REDOLOG_TYPE "Redolog"
|
||||
@@ -36,6 +37,26 @@
|
||||
|
||||
// not allocated: 0xffffffff
|
||||
|
||||
// always little-endian
|
||||
struct bochs_header_v1 {
|
||||
char magic[32]; // "Bochs Virtual HD Image"
|
||||
char type[16]; // "Redolog"
|
||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
||||
uint32_t version;
|
||||
uint32_t header; // size of header
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t catalog; // num of entries
|
||||
uint32_t bitmap; // bitmap size
|
||||
uint32_t extent; // extent size
|
||||
uint64_t disk; // disk size
|
||||
char padding[HEADER_SIZE - 64 - 8 - 20];
|
||||
} redolog;
|
||||
char padding[HEADER_SIZE - 64 - 8];
|
||||
} extra;
|
||||
};
|
||||
|
||||
// always little-endian
|
||||
struct bochs_header {
|
||||
char magic[32]; // "Bochs Virtual HD Image"
|
||||
@@ -49,8 +70,9 @@ struct bochs_header {
|
||||
uint32_t catalog; // num of entries
|
||||
uint32_t bitmap; // bitmap size
|
||||
uint32_t extent; // extent size
|
||||
uint32_t reserved; // for ???
|
||||
uint64_t disk; // disk size
|
||||
char padding[HEADER_SIZE - 64 - 8 - 20];
|
||||
char padding[HEADER_SIZE - 64 - 8 - 24];
|
||||
} redolog;
|
||||
char padding[HEADER_SIZE - 64 - 8];
|
||||
} extra;
|
||||
@@ -79,21 +101,23 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
|
||||
!strcmp(bochs->type, REDOLOG_TYPE) &&
|
||||
!strcmp(bochs->subtype, GROWING_TYPE) &&
|
||||
(le32_to_cpu(bochs->version) == HEADER_VERSION))
|
||||
((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
|
||||
(le32_to_cpu(bochs->version) == HEADER_V1)))
|
||||
return 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bochs_open(BlockDriverState *bs, const char *filename)
|
||||
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int fd, i;
|
||||
struct bochs_header bochs;
|
||||
struct bochs_header_v1 header_v1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||
fd = open(filename, O_RDWR | O_BINARY);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
@@ -109,11 +133,17 @@ static int bochs_open(BlockDriverState *bs, const char *filename)
|
||||
if (strcmp(bochs.magic, HEADER_MAGIC) ||
|
||||
strcmp(bochs.type, REDOLOG_TYPE) ||
|
||||
strcmp(bochs.subtype, GROWING_TYPE) ||
|
||||
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
|
||||
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
|
||||
(le32_to_cpu(bochs.version) != HEADER_V1))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
||||
memcpy(&header_v1, &bochs, sizeof(bochs));
|
||||
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
|
||||
} else {
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
}
|
||||
|
||||
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
|
||||
|
||||
|
||||
+3
-3
@@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cloop_open(BlockDriverState *bs, const char *filename)
|
||||
static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
uint32_t offsets_size,max_compressed_block_size=1,i;
|
||||
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (s->fd < 0)
|
||||
return -1;
|
||||
return -errno;
|
||||
bs->read_only = 1;
|
||||
|
||||
/* read header */
|
||||
|
||||
+17
-21
@@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cow_open(BlockDriverState *bs, const char *filename)
|
||||
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
int fd;
|
||||
@@ -93,22 +93,6 @@ static int cow_open(BlockDriverState *bs, const char *filename)
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
||||
cow_header.backing_file);
|
||||
|
||||
#if 0
|
||||
if (cow_header.backing_file[0] != '\0') {
|
||||
if (stat(cow_header.backing_file, &st) != 0) {
|
||||
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
|
||||
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
bs->fd = fd;
|
||||
}
|
||||
#endif
|
||||
/* mmap the bitmap */
|
||||
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
|
||||
@@ -179,8 +163,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
} else {
|
||||
if (bs->backing_hd) {
|
||||
/* read from the base image */
|
||||
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
} else {
|
||||
memset(buf, 0, n * 512);
|
||||
}
|
||||
}
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
@@ -220,7 +211,7 @@ static int cow_create(const char *filename, int64_t image_sectors,
|
||||
if (flags)
|
||||
return -ENOTSUP;
|
||||
|
||||
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
0644);
|
||||
if (cow_fd < 0)
|
||||
return -1;
|
||||
@@ -228,18 +219,23 @@ static int cow_create(const char *filename, int64_t image_sectors,
|
||||
cow_header.magic = cpu_to_be32(COW_MAGIC);
|
||||
cow_header.version = cpu_to_be32(COW_VERSION);
|
||||
if (image_filename) {
|
||||
/* Note: if no file, we put a dummy mtime */
|
||||
cow_header.mtime = cpu_to_be32(0);
|
||||
|
||||
fd = open(image_filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
close(cow_fd);
|
||||
return -1;
|
||||
goto mtime_fail;
|
||||
}
|
||||
if (fstat(fd, &st) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
goto mtime_fail;
|
||||
}
|
||||
close(fd);
|
||||
cow_header.mtime = cpu_to_be32(st.st_mtime);
|
||||
realpath(image_filename, cow_header.backing_file);
|
||||
mtime_fail:
|
||||
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
|
||||
image_filename);
|
||||
}
|
||||
cow_header.sectorsize = cpu_to_be32(512);
|
||||
cow_header.size = cpu_to_be64(image_sectors * 512);
|
||||
|
||||
+4
-4
@@ -73,16 +73,16 @@ static off_t read_uint32(int fd)
|
||||
return be32_to_cpu(buffer);
|
||||
}
|
||||
|
||||
static int dmg_open(BlockDriverState *bs, const char *filename)
|
||||
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
off_t info_begin,info_end,last_in_offset,last_out_offset;
|
||||
uint32_t count;
|
||||
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
|
||||
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (s->fd < 0)
|
||||
return -1;
|
||||
return -errno;
|
||||
bs->read_only = 1;
|
||||
s->n_chunks = 0;
|
||||
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
|
||||
@@ -93,7 +93,7 @@ dmg_close:
|
||||
close(s->fd);
|
||||
/* open raw instead */
|
||||
bs->drv=&bdrv_raw;
|
||||
return bs->drv->bdrv_open(bs,filename);
|
||||
return bs->drv->bdrv_open(bs, filename, flags);
|
||||
}
|
||||
info_begin=read_off(s->fd);
|
||||
if(info_begin==0)
|
||||
|
||||
+282
-94
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Block driver for the QCOW format
|
||||
*
|
||||
* Copyright (c) 2004 Fabrice Bellard
|
||||
* Copyright (c) 2004-2006 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
|
||||
@@ -53,7 +53,7 @@ typedef struct QCowHeader {
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
typedef struct BDRVQcowState {
|
||||
int fd;
|
||||
BlockDriverState *hd;
|
||||
int cluster_bits;
|
||||
int cluster_size;
|
||||
int cluster_sectors;
|
||||
@@ -89,20 +89,16 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow_open(BlockDriverState *bs, const char *filename)
|
||||
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int fd, len, i, shift;
|
||||
int len, i, shift, ret;
|
||||
QCowHeader header;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
s->fd = fd;
|
||||
if (read(fd, &header, sizeof(header)) != sizeof(header))
|
||||
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
be32_to_cpus(&header.magic);
|
||||
be32_to_cpus(&header.version);
|
||||
@@ -138,8 +134,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
|
||||
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
|
||||
if (!s->l1_table)
|
||||
goto fail;
|
||||
lseek(fd, s->l1_table_offset, SEEK_SET);
|
||||
if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
s->l1_size * sizeof(uint64_t))
|
||||
goto fail;
|
||||
for(i = 0;i < s->l1_size; i++) {
|
||||
@@ -162,8 +157,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
lseek(fd, header.backing_file_offset, SEEK_SET);
|
||||
if (read(fd, bs->backing_file, len) != len)
|
||||
if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
|
||||
goto fail;
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
@@ -174,7 +168,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
close(fd);
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -276,14 +270,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
if (!allocate)
|
||||
return 0;
|
||||
/* allocate a new l2 entry */
|
||||
l2_offset = lseek(s->fd, 0, SEEK_END);
|
||||
l2_offset = bdrv_getlength(s->hd);
|
||||
/* round to cluster size */
|
||||
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
|
||||
/* update the L1 entry */
|
||||
s->l1_table[l1_index] = l2_offset;
|
||||
tmp = cpu_to_be64(l2_offset);
|
||||
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
|
||||
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
new_l2_table = 1;
|
||||
}
|
||||
@@ -309,14 +303,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||
lseek(s->fd, l2_offset, SEEK_SET);
|
||||
if (new_l2_table) {
|
||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return 0;
|
||||
} else {
|
||||
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return 0;
|
||||
}
|
||||
@@ -337,36 +330,35 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
overwritten */
|
||||
if (decompress_cluster(s, cluster_offset) < 0)
|
||||
return 0;
|
||||
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
/* write the cluster content */
|
||||
lseek(s->fd, cluster_offset, SEEK_SET);
|
||||
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
|
||||
s->cluster_size)
|
||||
return -1;
|
||||
} else {
|
||||
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
if (allocate == 1) {
|
||||
/* round to cluster size */
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
ftruncate(s->fd, cluster_offset + s->cluster_size);
|
||||
bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
|
||||
/* if encrypted, we must initialize the cluster
|
||||
content which won't be written */
|
||||
if (s->crypt_method &&
|
||||
(n_end - n_start) < s->cluster_sectors) {
|
||||
uint64_t start_sect;
|
||||
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
|
||||
memset(s->cluster_data + 512, 0xaa, 512);
|
||||
memset(s->cluster_data + 512, 0x00, 512);
|
||||
for(i = 0; i < s->cluster_sectors; i++) {
|
||||
if (i < n_start || i >= n_end) {
|
||||
encrypt_sectors(s, start_sect + i,
|
||||
s->cluster_data,
|
||||
s->cluster_data + 512, 1, 1,
|
||||
&s->aes_encrypt_key);
|
||||
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
|
||||
if (write(s->fd, s->cluster_data, 512) != 512)
|
||||
if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
|
||||
s->cluster_data, 512) != 512)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -379,8 +371,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
/* update L2 table */
|
||||
tmp = cpu_to_be64(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
|
||||
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
if (bdrv_pwrite(s->hd,
|
||||
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
}
|
||||
return cluster_offset;
|
||||
@@ -438,8 +430,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
||||
if (s->cluster_cache_offset != coffset) {
|
||||
csize = cluster_offset >> (63 - s->cluster_bits);
|
||||
csize &= (s->cluster_size - 1);
|
||||
lseek(s->fd, coffset, SEEK_SET);
|
||||
ret = read(s->fd, s->cluster_data, csize);
|
||||
ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
|
||||
if (ret != csize)
|
||||
return -1;
|
||||
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
||||
@@ -451,6 +442,8 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
@@ -465,14 +458,20 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
if (n > nb_sectors)
|
||||
n = nb_sectors;
|
||||
if (!cluster_offset) {
|
||||
memset(buf, 0, 512 * n);
|
||||
if (bs->backing_hd) {
|
||||
/* read from the base image */
|
||||
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
} else {
|
||||
memset(buf, 0, 512 * n);
|
||||
}
|
||||
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
if (decompress_cluster(s, cluster_offset) < 0)
|
||||
return -1;
|
||||
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
|
||||
} else {
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
ret = read(s->fd, buf, n * 512);
|
||||
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
if (s->crypt_method) {
|
||||
@@ -486,6 +485,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
@@ -504,13 +504,13 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
index_in_cluster + n);
|
||||
if (!cluster_offset)
|
||||
return -1;
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
if (s->crypt_method) {
|
||||
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
|
||||
&s->aes_encrypt_key);
|
||||
ret = write(s->fd, s->cluster_data, n * 512);
|
||||
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
|
||||
s->cluster_data, n * 512);
|
||||
} else {
|
||||
ret = write(s->fd, buf, n * 512);
|
||||
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
}
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
@@ -522,6 +522,209 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct QCowAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
int64_t sector_num;
|
||||
uint8_t *buf;
|
||||
int nb_sectors;
|
||||
int n;
|
||||
uint64_t cluster_offset;
|
||||
uint8_t *cluster_data;
|
||||
BlockDriverAIOCB *hd_aiocb;
|
||||
} QCowAIOCB;
|
||||
|
||||
static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
{
|
||||
QCowAIOCB *acb = opaque;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int index_in_cluster;
|
||||
|
||||
acb->hd_aiocb = NULL;
|
||||
if (ret < 0) {
|
||||
fail:
|
||||
acb->common.cb(acb->common.opaque, ret);
|
||||
qemu_aio_release(acb);
|
||||
return;
|
||||
}
|
||||
|
||||
redo:
|
||||
/* post process the read buffer */
|
||||
if (!acb->cluster_offset) {
|
||||
/* nothing to do */
|
||||
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
/* nothing to do */
|
||||
} else {
|
||||
if (s->crypt_method) {
|
||||
encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
|
||||
acb->n, 0,
|
||||
&s->aes_decrypt_key);
|
||||
}
|
||||
}
|
||||
|
||||
acb->nb_sectors -= acb->n;
|
||||
acb->sector_num += acb->n;
|
||||
acb->buf += acb->n * 512;
|
||||
|
||||
if (acb->nb_sectors == 0) {
|
||||
/* request completed */
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
qemu_aio_release(acb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* prepare next AIO request */
|
||||
acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
|
||||
0, 0, 0, 0);
|
||||
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
|
||||
acb->n = s->cluster_sectors - index_in_cluster;
|
||||
if (acb->n > acb->nb_sectors)
|
||||
acb->n = acb->nb_sectors;
|
||||
|
||||
if (!acb->cluster_offset) {
|
||||
if (bs->backing_hd) {
|
||||
/* read from the base image */
|
||||
acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
|
||||
acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
goto fail;
|
||||
} else {
|
||||
/* Note: in this case, no need to wait */
|
||||
memset(acb->buf, 0, 512 * acb->n);
|
||||
goto redo;
|
||||
}
|
||||
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
||||
/* add AIO support for compressed blocks ? */
|
||||
if (decompress_cluster(s, acb->cluster_offset) < 0)
|
||||
goto fail;
|
||||
memcpy(acb->buf,
|
||||
s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
|
||||
goto redo;
|
||||
} else {
|
||||
if ((acb->cluster_offset & 511) != 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
acb->hd_aiocb = bdrv_aio_read(s->hd,
|
||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||
acb->buf, acb->n, qcow_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
QCowAIOCB *acb;
|
||||
|
||||
acb = qemu_aio_get(bs, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
acb->hd_aiocb = NULL;
|
||||
acb->sector_num = sector_num;
|
||||
acb->buf = buf;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->n = 0;
|
||||
acb->cluster_offset = 0;
|
||||
|
||||
qcow_aio_read_cb(acb, 0);
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
{
|
||||
QCowAIOCB *acb = opaque;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int index_in_cluster;
|
||||
uint64_t cluster_offset;
|
||||
const uint8_t *src_buf;
|
||||
|
||||
acb->hd_aiocb = NULL;
|
||||
|
||||
if (ret < 0) {
|
||||
fail:
|
||||
acb->common.cb(acb->common.opaque, ret);
|
||||
qemu_aio_release(acb);
|
||||
return;
|
||||
}
|
||||
|
||||
acb->nb_sectors -= acb->n;
|
||||
acb->sector_num += acb->n;
|
||||
acb->buf += acb->n * 512;
|
||||
|
||||
if (acb->nb_sectors == 0) {
|
||||
/* request completed */
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
qemu_aio_release(acb);
|
||||
return;
|
||||
}
|
||||
|
||||
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
|
||||
acb->n = s->cluster_sectors - index_in_cluster;
|
||||
if (acb->n > acb->nb_sectors)
|
||||
acb->n = acb->nb_sectors;
|
||||
cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
|
||||
index_in_cluster,
|
||||
index_in_cluster + acb->n);
|
||||
if (!cluster_offset || (cluster_offset & 511) != 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
if (s->crypt_method) {
|
||||
if (!acb->cluster_data) {
|
||||
acb->cluster_data = qemu_mallocz(s->cluster_size);
|
||||
if (!acb->cluster_data) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
|
||||
acb->n, 1, &s->aes_encrypt_key);
|
||||
src_buf = acb->cluster_data;
|
||||
} else {
|
||||
src_buf = acb->buf;
|
||||
}
|
||||
acb->hd_aiocb = bdrv_aio_write(s->hd,
|
||||
(cluster_offset >> 9) + index_in_cluster,
|
||||
src_buf, acb->n,
|
||||
qcow_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
|
||||
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
QCowAIOCB *acb;
|
||||
|
||||
s->cluster_cache_offset = -1; /* disable compressed cache */
|
||||
|
||||
acb = qemu_aio_get(bs, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
acb->hd_aiocb = NULL;
|
||||
acb->sector_num = sector_num;
|
||||
acb->buf = (uint8_t *)buf;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->n = 0;
|
||||
|
||||
qcow_aio_write_cb(acb, 0);
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
QCowAIOCB *acb = (QCowAIOCB *)blockacb;
|
||||
if (acb->hd_aiocb)
|
||||
bdrv_aio_cancel(acb->hd_aiocb);
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static void qcow_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
@@ -529,7 +732,7 @@ static void qcow_close(BlockDriverState *bs)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
close(s->fd);
|
||||
bdrv_delete(s->hd);
|
||||
}
|
||||
|
||||
static int qcow_create(const char *filename, int64_t total_size,
|
||||
@@ -537,12 +740,9 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
{
|
||||
int fd, header_size, backing_filename_len, l1_size, i, shift;
|
||||
QCowHeader header;
|
||||
char backing_filename[1024];
|
||||
uint64_t tmp;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
memset(&header, 0, sizeof(header));
|
||||
@@ -552,28 +752,11 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
header_size = sizeof(header);
|
||||
backing_filename_len = 0;
|
||||
if (backing_file) {
|
||||
if (strcmp(backing_file, "fat:")) {
|
||||
const char *p;
|
||||
/* XXX: this is a hack: we do not attempt to check for URL
|
||||
like syntax */
|
||||
p = strchr(backing_file, ':');
|
||||
if (p && (p - backing_file) >= 2) {
|
||||
/* URL like but exclude "c:" like filenames */
|
||||
pstrcpy(backing_filename, sizeof(backing_filename),
|
||||
backing_file);
|
||||
} else {
|
||||
realpath(backing_file, backing_filename);
|
||||
if (stat(backing_filename, &st) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
header.backing_file_offset = cpu_to_be64(header_size);
|
||||
backing_filename_len = strlen(backing_filename);
|
||||
header.backing_file_size = cpu_to_be32(backing_filename_len);
|
||||
header_size += backing_filename_len;
|
||||
} else
|
||||
backing_file = NULL;
|
||||
header.mtime = cpu_to_be32(st.st_mtime);
|
||||
header.backing_file_offset = cpu_to_be64(header_size);
|
||||
backing_filename_len = strlen(backing_file);
|
||||
header.backing_file_size = cpu_to_be32(backing_filename_len);
|
||||
header_size += backing_filename_len;
|
||||
header.mtime = cpu_to_be32(0);
|
||||
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
||||
unmodifyed sectors */
|
||||
header.l2_bits = 12; /* 32 KB L2 tables */
|
||||
@@ -595,7 +778,7 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
/* write all the data */
|
||||
write(fd, &header, sizeof(header));
|
||||
if (backing_file) {
|
||||
write(fd, backing_filename, backing_filename_len);
|
||||
write(fd, backing_file, backing_filename_len);
|
||||
}
|
||||
lseek(fd, header_size, SEEK_SET);
|
||||
tmp = 0;
|
||||
@@ -606,16 +789,18 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcow_make_empty(BlockDriverState *bs)
|
||||
static int qcow_make_empty(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
|
||||
int ret;
|
||||
|
||||
memset(s->l1_table, 0, l1_length);
|
||||
lseek(s->fd, s->l1_table_offset, SEEK_SET);
|
||||
if (write(s->fd, s->l1_table, l1_length) < 0)
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
||||
return -1;
|
||||
ftruncate(s->fd, s->l1_table_offset + l1_length);
|
||||
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
|
||||
memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
|
||||
@@ -624,18 +809,10 @@ int qcow_make_empty(BlockDriverState *bs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcow_get_cluster_size(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
if (bs->drv != &bdrv_qcow)
|
||||
return -1;
|
||||
return s->cluster_size;
|
||||
}
|
||||
|
||||
/* XXX: put compressed sectors first, then all the cluster aligned
|
||||
tables to avoid losing bytes in alignment */
|
||||
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf)
|
||||
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
z_stream strm;
|
||||
@@ -643,8 +820,8 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *out_buf;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
if (bs->drv != &bdrv_qcow)
|
||||
return -1;
|
||||
if (nb_sectors != s->cluster_sectors)
|
||||
return -EINVAL;
|
||||
|
||||
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
|
||||
if (!out_buf)
|
||||
@@ -682,8 +859,7 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
||||
out_len, 0, 0);
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
lseek(s->fd, cluster_offset, SEEK_SET);
|
||||
if (write(s->fd, out_buf, out_len) != out_len) {
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
|
||||
qemu_free(out_buf);
|
||||
return -1;
|
||||
}
|
||||
@@ -696,7 +872,14 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||
static void qcow_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
bdrv_flush(s->hd);
|
||||
}
|
||||
|
||||
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
bdi->cluster_size = s->cluster_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BlockDriver bdrv_qcow = {
|
||||
@@ -704,14 +887,19 @@ BlockDriver bdrv_qcow = {
|
||||
sizeof(BDRVQcowState),
|
||||
qcow_probe,
|
||||
qcow_open,
|
||||
qcow_read,
|
||||
qcow_write,
|
||||
NULL,
|
||||
NULL,
|
||||
qcow_close,
|
||||
qcow_create,
|
||||
qcow_flush,
|
||||
qcow_is_allocated,
|
||||
qcow_set_key,
|
||||
qcow_make_empty
|
||||
qcow_make_empty,
|
||||
|
||||
.bdrv_aio_read = qcow_aio_read,
|
||||
.bdrv_aio_write = qcow_aio_write,
|
||||
.bdrv_aio_cancel = qcow_aio_cancel,
|
||||
.aiocb_size = sizeof(QCowAIOCB),
|
||||
.bdrv_write_compressed = qcow_write_compressed,
|
||||
.bdrv_get_info = qcow_get_info,
|
||||
};
|
||||
|
||||
|
||||
+2246
File diff suppressed because it is too large.
Load diff
+1352
File diff suppressed because it is too large.
Load diff
+354
-46
@@ -22,6 +22,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
|
||||
@@ -59,7 +60,7 @@ typedef struct {
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
typedef struct BDRVVmdkState {
|
||||
int fd;
|
||||
BlockDriverState *hd;
|
||||
int64_t l1_table_offset;
|
||||
int64_t l1_backup_table_offset;
|
||||
uint32_t *l1_table;
|
||||
@@ -73,6 +74,7 @@ typedef struct BDRVVmdkState {
|
||||
uint32_t l2_cache_counts[L2_CACHE_SIZE];
|
||||
|
||||
unsigned int cluster_sectors;
|
||||
uint32_t parent_cid;
|
||||
} BDRVVmdkState;
|
||||
|
||||
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
@@ -89,27 +91,278 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||
#define CHECK_CID 1
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each
|
||||
#define HEADER_SIZE 512 // first sector of 512 bytes
|
||||
|
||||
static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int fd, i;
|
||||
uint32_t magic;
|
||||
int l1_size;
|
||||
char desc[DESC_SIZE];
|
||||
uint32_t cid;
|
||||
char *p_name, *cid_str;
|
||||
size_t cid_str_size;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
bs->read_only = 1;
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return 0;
|
||||
|
||||
if (parent) {
|
||||
cid_str = "parentCID";
|
||||
cid_str_size = sizeof("parentCID");
|
||||
} else {
|
||||
cid_str = "CID";
|
||||
cid_str_size = sizeof("CID");
|
||||
}
|
||||
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
|
||||
|
||||
if ((p_name = strstr(desc,cid_str)) != 0) {
|
||||
p_name += cid_str_size;
|
||||
sscanf(p_name,"%x",&cid);
|
||||
}
|
||||
|
||||
return cid;
|
||||
}
|
||||
|
||||
static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
|
||||
char *p_name, *tmp_str;
|
||||
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return -1;
|
||||
|
||||
tmp_str = strstr(desc,"parentCID");
|
||||
strcpy(tmp_desc, tmp_str);
|
||||
if ((p_name = strstr(desc,"CID")) != 0) {
|
||||
p_name += sizeof("CID");
|
||||
sprintf(p_name,"%x\n",cid);
|
||||
strcat(desc,tmp_desc);
|
||||
}
|
||||
|
||||
if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_is_cid_valid(BlockDriverState *bs)
|
||||
{
|
||||
#ifdef CHECK_CID
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
BlockDriverState *p_bs = s->hd->backing_hd;
|
||||
uint32_t cur_pcid;
|
||||
|
||||
if (p_bs) {
|
||||
cur_pcid = vmdk_read_cid(p_bs,0);
|
||||
if (s->parent_cid != cur_pcid)
|
||||
// CID not valid
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// CID valid
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
{
|
||||
int snp_fd, p_fd;
|
||||
uint32_t p_cid;
|
||||
char *p_name, *gd_buf, *rgd_buf;
|
||||
const char *real_filename, *temp_str;
|
||||
VMDK4Header header;
|
||||
uint32_t gde_entries, gd_size;
|
||||
int64_t gd_offset, rgd_offset, capacity, gt_size;
|
||||
char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
|
||||
char *desc_template =
|
||||
"# Disk DescriptorFile\n"
|
||||
"version=1\n"
|
||||
"CID=%x\n"
|
||||
"parentCID=%x\n"
|
||||
"createType=\"monolithicSparse\"\n"
|
||||
"parentFileNameHint=\"%s\"\n"
|
||||
"\n"
|
||||
"# Extent description\n"
|
||||
"RW %lu SPARSE \"%s\"\n"
|
||||
"\n"
|
||||
"# The Disk Data Base \n"
|
||||
"#DDB\n"
|
||||
"\n";
|
||||
|
||||
snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
|
||||
if (snp_fd < 0)
|
||||
return -1;
|
||||
p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (p_fd < 0) {
|
||||
close(snp_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read the header */
|
||||
if (lseek(p_fd, 0x0, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
|
||||
goto fail;
|
||||
|
||||
/* write the header */
|
||||
if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (write(snp_fd, hdr, HEADER_SIZE) == -1)
|
||||
goto fail;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
|
||||
|
||||
ftruncate(snp_fd, header.grain_offset << 9);
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (lseek(p_fd, 0x200, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
|
||||
goto fail;
|
||||
|
||||
if ((p_name = strstr(p_desc,"CID")) != 0) {
|
||||
p_name += sizeof("CID");
|
||||
sscanf(p_name,"%x",&p_cid);
|
||||
}
|
||||
|
||||
real_filename = filename;
|
||||
if ((temp_str = strrchr(real_filename, '\\')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
if ((temp_str = strrchr(real_filename, '/')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
if ((temp_str = strrchr(real_filename, ':')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
|
||||
sprintf(s_desc, desc_template, p_cid, p_cid, backing_file
|
||||
, (uint32_t)header.capacity, real_filename);
|
||||
|
||||
/* write the descriptor */
|
||||
if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (write(snp_fd, s_desc, strlen(s_desc)) == -1)
|
||||
goto fail;
|
||||
|
||||
gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table
|
||||
rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table
|
||||
capacity = header.capacity * SECTOR_SIZE; // Extent size
|
||||
/*
|
||||
* Each GDE span 32M disk, means:
|
||||
* 512 GTE per GT, each GTE points to grain
|
||||
*/
|
||||
gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
|
||||
if (!gt_size)
|
||||
goto fail;
|
||||
gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde
|
||||
gd_size = gde_entries * sizeof(uint32_t);
|
||||
|
||||
/* write RGD */
|
||||
rgd_buf = qemu_malloc(gd_size);
|
||||
if (!rgd_buf)
|
||||
goto fail;
|
||||
if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
|
||||
goto fail_rgd;
|
||||
if (read(p_fd, rgd_buf, gd_size) != gd_size)
|
||||
goto fail_rgd;
|
||||
if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
|
||||
goto fail_rgd;
|
||||
if (write(snp_fd, rgd_buf, gd_size) == -1)
|
||||
goto fail_rgd;
|
||||
qemu_free(rgd_buf);
|
||||
|
||||
/* write GD */
|
||||
gd_buf = qemu_malloc(gd_size);
|
||||
if (!gd_buf)
|
||||
goto fail_rgd;
|
||||
if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
|
||||
goto fail_gd;
|
||||
if (read(p_fd, gd_buf, gd_size) != gd_size)
|
||||
goto fail_gd;
|
||||
if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
|
||||
goto fail_gd;
|
||||
if (write(snp_fd, gd_buf, gd_size) == -1)
|
||||
goto fail_gd;
|
||||
qemu_free(gd_buf);
|
||||
|
||||
close(p_fd);
|
||||
close(snp_fd);
|
||||
return 0;
|
||||
|
||||
fail_gd:
|
||||
qemu_free(gd_buf);
|
||||
fail_rgd:
|
||||
qemu_free(rgd_buf);
|
||||
fail:
|
||||
close(p_fd);
|
||||
close(snp_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void vmdk_parent_close(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->backing_hd)
|
||||
bdrv_close(bs->backing_hd);
|
||||
}
|
||||
|
||||
|
||||
static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
char *p_name;
|
||||
char desc[DESC_SIZE];
|
||||
char parent_img_name[1024];
|
||||
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
return -1;
|
||||
|
||||
if ((p_name = strstr(desc,"parentFileNameHint")) != 0) {
|
||||
char *end_name;
|
||||
struct stat file_buf;
|
||||
|
||||
p_name += sizeof("parentFileNameHint") + 1;
|
||||
if ((end_name = strchr(p_name,'\"')) == 0)
|
||||
return -1;
|
||||
|
||||
strncpy(s->hd->backing_file, p_name, end_name - p_name);
|
||||
if (stat(s->hd->backing_file, &file_buf) != 0) {
|
||||
path_combine(parent_img_name, sizeof(parent_img_name),
|
||||
filename, s->hd->backing_file);
|
||||
} else {
|
||||
strcpy(parent_img_name, s->hd->backing_file);
|
||||
}
|
||||
|
||||
s->hd->backing_hd = bdrv_new("");
|
||||
if (!s->hd->backing_hd) {
|
||||
failure:
|
||||
bdrv_close(s->hd);
|
||||
return -1;
|
||||
}
|
||||
if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0)
|
||||
goto failure;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint32_t magic;
|
||||
int l1_size, i, ret;
|
||||
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
|
||||
goto fail;
|
||||
|
||||
magic = be32_to_cpu(magic);
|
||||
if (magic == VMDK3_MAGIC) {
|
||||
VMDK3Header header;
|
||||
if (read(fd, &header, sizeof(header)) !=
|
||||
sizeof(header))
|
||||
|
||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
s->cluster_sectors = le32_to_cpu(header.granularity);
|
||||
s->l2_size = 1 << 9;
|
||||
@@ -120,8 +373,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
|
||||
} else if (magic == VMDK4_MAGIC) {
|
||||
VMDK4Header header;
|
||||
|
||||
if (read(fd, &header, sizeof(header)) != sizeof(header))
|
||||
|
||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
bs->total_sectors = le64_to_cpu(header.capacity);
|
||||
s->cluster_sectors = le64_to_cpu(header.granularity);
|
||||
@@ -133,17 +386,22 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||
/ s->l1_entry_sectors;
|
||||
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
|
||||
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
|
||||
|
||||
// try to open parent images, if exist
|
||||
if (vmdk_parent_open(bs, filename) != 0)
|
||||
goto fail;
|
||||
// write the CID once after the image creation
|
||||
s->parent_cid = vmdk_read_cid(bs,1);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* read the L1 table */
|
||||
l1_size = s->l1_size * sizeof(uint32_t);
|
||||
s->l1_table = qemu_malloc(l1_size);
|
||||
if (!s->l1_table)
|
||||
goto fail;
|
||||
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (read(fd, s->l1_table, l1_size) != l1_size)
|
||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
le32_to_cpus(&s->l1_table[i]);
|
||||
@@ -153,9 +411,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||
s->l1_backup_table = qemu_malloc(l1_size);
|
||||
if (!s->l1_backup_table)
|
||||
goto fail;
|
||||
if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (read(fd, s->l1_backup_table, l1_size) != l1_size)
|
||||
if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
le32_to_cpus(&s->l1_backup_table[i]);
|
||||
@@ -165,16 +421,43 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
|
||||
if (!s->l2_cache)
|
||||
goto fail;
|
||||
s->fd = fd;
|
||||
return 0;
|
||||
fail:
|
||||
qemu_free(s->l1_backup_table);
|
||||
qemu_free(s->l1_table);
|
||||
qemu_free(s->l2_cache);
|
||||
close(fd);
|
||||
bdrv_delete(s->hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate);
|
||||
|
||||
static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
uint64_t offset, int allocate)
|
||||
{
|
||||
uint64_t parent_cluster_offset;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB
|
||||
|
||||
// we will be here if it's first write on non-exist grain(cluster).
|
||||
// try to read from parent image, if exist
|
||||
if (s->hd->backing_hd) {
|
||||
BDRVVmdkState *ps = s->hd->backing_hd->opaque;
|
||||
|
||||
if (!vmdk_is_cid_valid(bs))
|
||||
return -1;
|
||||
parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate);
|
||||
if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) !=
|
||||
ps->cluster_sectors*512)
|
||||
return -1;
|
||||
|
||||
if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) !=
|
||||
sizeof(whole_grain))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset, int allocate)
|
||||
{
|
||||
@@ -212,34 +495,41 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
l2_table = s->l2_cache + (min_index * s->l2_size);
|
||||
lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
|
||||
if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
|
||||
s->l2_size * sizeof(uint32_t))
|
||||
if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
|
||||
s->l2_size * sizeof(uint32_t))
|
||||
return 0;
|
||||
|
||||
s->l2_cache_offsets[min_index] = l2_offset;
|
||||
s->l2_cache_counts[min_index] = 1;
|
||||
found:
|
||||
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
|
||||
cluster_offset = le32_to_cpu(l2_table[l2_index]);
|
||||
if (!cluster_offset) {
|
||||
struct stat file_buf;
|
||||
|
||||
if (!allocate)
|
||||
return 0;
|
||||
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||
ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
|
||||
stat(s->hd->filename, &file_buf);
|
||||
cluster_offset = file_buf.st_size;
|
||||
bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
|
||||
|
||||
cluster_offset >>= 9;
|
||||
/* update L2 table */
|
||||
tmp = cpu_to_le32(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
|
||||
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)),
|
||||
&tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
/* update backup L2 table */
|
||||
if (s->l1_backup_table_offset != 0) {
|
||||
l2_offset = s->l1_backup_table[l1_index];
|
||||
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
|
||||
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)),
|
||||
&tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
|
||||
return 0;
|
||||
}
|
||||
cluster_offset <<= 9;
|
||||
return cluster_offset;
|
||||
@@ -265,9 +555,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret, index_in_cluster, n;
|
||||
int index_in_cluster, n, ret;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
|
||||
index_in_cluster = sector_num % s->cluster_sectors;
|
||||
@@ -275,11 +565,18 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
if (n > nb_sectors)
|
||||
n = nb_sectors;
|
||||
if (!cluster_offset) {
|
||||
memset(buf, 0, 512 * n);
|
||||
// try to read from parent image, if exist
|
||||
if (s->hd->backing_hd) {
|
||||
if (!vmdk_is_cid_valid(bs))
|
||||
return -1;
|
||||
ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
} else {
|
||||
memset(buf, 0, 512 * n);
|
||||
}
|
||||
} else {
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
ret = read(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
return -1;
|
||||
}
|
||||
nb_sectors -= n;
|
||||
@@ -293,8 +590,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret, index_in_cluster, n;
|
||||
int index_in_cluster, n;
|
||||
uint64_t cluster_offset;
|
||||
static int cid_update = 0;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
@@ -304,13 +602,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
|
||||
if (!cluster_offset)
|
||||
return -1;
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
ret = write(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
return -1;
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
|
||||
// update CID on the first write every time the virtual disk is opened
|
||||
if (!cid_update) {
|
||||
vmdk_write_cid(bs, time(NULL));
|
||||
cid_update++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -334,7 +636,7 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
"# The Disk Data Base \n"
|
||||
"#DDB\n"
|
||||
"\n"
|
||||
"ddb.virtualHWVersion = \"3\"\n"
|
||||
"ddb.virtualHWVersion = \"4\"\n"
|
||||
"ddb.geometry.cylinders = \"%lu\"\n"
|
||||
"ddb.geometry.heads = \"16\"\n"
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
@@ -343,6 +645,9 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
const char *real_filename, *temp_str;
|
||||
|
||||
/* XXX: add support for backing file */
|
||||
if (backing_file) {
|
||||
return vmdk_snapshot_create(filename, backing_file);
|
||||
}
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
@@ -421,15 +726,18 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
static void vmdk_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
qemu_free(s->l1_table);
|
||||
qemu_free(s->l2_cache);
|
||||
close(s->fd);
|
||||
bdrv_delete(s->hd);
|
||||
// try to close parent image, if exist
|
||||
vmdk_parent_close(s->hd);
|
||||
}
|
||||
|
||||
static void vmdk_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
bdrv_flush(s->hd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_vmdk = {
|
||||
|
||||
+5
-8
@@ -86,19 +86,16 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_open(BlockDriverState *bs, const char *filename)
|
||||
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int fd, i;
|
||||
struct vpc_subheader header;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
bs->read_only = 1; // no write support yet
|
||||
|
||||
s->fd = fd;
|
||||
|
||||
+11
-15
@@ -61,7 +61,7 @@ void nonono(const char* file, int line, const char* msg) {
|
||||
exit(-5);
|
||||
}
|
||||
#undef assert
|
||||
#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
|
||||
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -351,13 +351,6 @@ typedef struct BDRVVVFATState {
|
||||
} BDRVVVFATState;
|
||||
|
||||
|
||||
static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
if (strstart(filename, "fat:", NULL))
|
||||
return 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_mbr(BDRVVVFATState* s)
|
||||
{
|
||||
/* TODO: if the files mbr.img and bootsect.img exist, use them */
|
||||
@@ -954,18 +947,22 @@ static int init_directories(BDRVVVFATState* s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static BDRVVVFATState *vvv = NULL;
|
||||
#endif
|
||||
|
||||
static int enable_write_target(BDRVVVFATState *s);
|
||||
static int is_consistent(BDRVVVFATState *s);
|
||||
|
||||
static int vvfat_open(BlockDriverState *bs, const char* dirname)
|
||||
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int floppy = 0;
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
vvv = s;
|
||||
#endif
|
||||
|
||||
DLOG(if (stderr == NULL) {
|
||||
stderr = fopen("vvfat.log", "a");
|
||||
@@ -1040,7 +1037,6 @@ DLOG(if (stderr == NULL) {
|
||||
bs->heads = bs->cyls = bs->secs = 0;
|
||||
|
||||
// assert(is_consistent(s));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2178,7 +2174,7 @@ static int commit_one_file(BDRVVVFATState* s,
|
||||
for (i = s->cluster_size; i < offset; i += s->cluster_size)
|
||||
c = modified_fat_get(s, c);
|
||||
|
||||
fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
|
||||
fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
|
||||
strerror(errno), errno);
|
||||
@@ -2732,8 +2728,7 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
array_init(&(s->commits), sizeof(commit_t));
|
||||
|
||||
s->qcow_filename = malloc(1024);
|
||||
strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
|
||||
get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
|
||||
get_tmp_filename(s->qcow_filename, 1024);
|
||||
if (bdrv_create(&bdrv_qcow,
|
||||
s->qcow_filename, s->sector_count, "fat:", 0) < 0)
|
||||
return -1;
|
||||
@@ -2767,14 +2762,15 @@ static void vvfat_close(BlockDriverState *bs)
|
||||
BlockDriver bdrv_vvfat = {
|
||||
"vvfat",
|
||||
sizeof(BDRVVVFATState),
|
||||
vvfat_probe,
|
||||
NULL, /* no probe for protocols */
|
||||
vvfat_open,
|
||||
vvfat_read,
|
||||
vvfat_write,
|
||||
vvfat_close,
|
||||
NULL, /* ??? Not sure if we can do any meaningful flushing. */
|
||||
NULL,
|
||||
vvfat_is_allocated
|
||||
vvfat_is_allocated,
|
||||
.protocol_name = "fat",
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
+56
-5
@@ -28,7 +28,7 @@ struct BlockDriver {
|
||||
const char *format_name;
|
||||
int instance_size;
|
||||
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
|
||||
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
|
||||
int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
|
||||
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -41,13 +41,49 @@ struct BlockDriver {
|
||||
int nb_sectors, int *pnum);
|
||||
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
|
||||
int (*bdrv_make_empty)(BlockDriverState *bs);
|
||||
/* aio */
|
||||
BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
|
||||
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
|
||||
int aiocb_size;
|
||||
|
||||
const char *protocol_name;
|
||||
int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
|
||||
uint8_t *buf, int count);
|
||||
int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
|
||||
const uint8_t *buf, int count);
|
||||
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
|
||||
int64_t (*bdrv_getlength)(BlockDriverState *bs);
|
||||
int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
|
||||
int (*bdrv_snapshot_create)(BlockDriverState *bs,
|
||||
QEMUSnapshotInfo *sn_info);
|
||||
int (*bdrv_snapshot_goto)(BlockDriverState *bs,
|
||||
const char *snapshot_id);
|
||||
int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
|
||||
int (*bdrv_snapshot_list)(BlockDriverState *bs,
|
||||
QEMUSnapshotInfo **psn_info);
|
||||
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||
|
||||
/* removable device specific */
|
||||
int (*bdrv_is_inserted)(BlockDriverState *bs);
|
||||
int (*bdrv_media_changed)(BlockDriverState *bs);
|
||||
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
|
||||
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
|
||||
|
||||
BlockDriverAIOCB *free_aiocb;
|
||||
struct BlockDriver *next;
|
||||
};
|
||||
|
||||
struct BlockDriverState {
|
||||
int64_t total_sectors;
|
||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
||||
size in sectors */
|
||||
int read_only; /* if true, the media is read only */
|
||||
int inserted; /* if true, the media is present */
|
||||
int removable; /* if true, the media can be removed */
|
||||
int locked; /* if true, the media cannot temporarily be ejected */
|
||||
int encrypted; /* if true, the media is encrypted */
|
||||
@@ -55,7 +91,7 @@ struct BlockDriverState {
|
||||
void (*change_cb)(void *opaque);
|
||||
void *change_opaque;
|
||||
|
||||
BlockDriver *drv;
|
||||
BlockDriver *drv; /* NULL means no media */
|
||||
void *opaque;
|
||||
|
||||
int boot_sector_enabled;
|
||||
@@ -65,8 +101,12 @@ struct BlockDriverState {
|
||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||
this file image */
|
||||
int is_temporary;
|
||||
|
||||
int media_changed;
|
||||
|
||||
BlockDriverState *backing_hd;
|
||||
/* async read/write emulation */
|
||||
|
||||
void *sync_aiocb;
|
||||
|
||||
/* NOTE: the following infos are only hints for real hardware
|
||||
drivers. They are not used by the block driver */
|
||||
@@ -76,6 +116,17 @@ struct BlockDriverState {
|
||||
BlockDriverState *next;
|
||||
};
|
||||
|
||||
struct BlockDriverAIOCB {
|
||||
BlockDriverState *bs;
|
||||
BlockDriverCompletionFunc *cb;
|
||||
void *opaque;
|
||||
BlockDriverAIOCB *next;
|
||||
};
|
||||
|
||||
void get_tmp_filename(char *filename, int size);
|
||||
|
||||
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
|
||||
void *opaque);
|
||||
void qemu_aio_release(void *p);
|
||||
|
||||
#endif /* BLOCK_INT_H */
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#! /bin/sh
|
||||
# Script to check for duplicate function prologues in op.o
|
||||
# Typically this indicates missing FORCE_RET();
|
||||
# This script does not detect other errors that may be present.
|
||||
|
||||
# Usage: check_ops.sh [-m machine] [op.o]
|
||||
# machine and op.o are guessed if not specified.
|
||||
|
||||
if [ "x$1" = "x-m" ]; then
|
||||
machine=$2
|
||||
shift 2
|
||||
else
|
||||
machine=`uname -m`
|
||||
fi
|
||||
if [ -z "$1" ]; then
|
||||
for f in `find . -name op.o`; do
|
||||
/bin/sh "$0" -m $machine $f
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case $machine in
|
||||
i?86)
|
||||
ret='\tret'
|
||||
;;
|
||||
x86_64)
|
||||
ret='\tretq'
|
||||
;;
|
||||
arm)
|
||||
ret='\tldm.*pc'
|
||||
;;
|
||||
ppc* | powerpc*)
|
||||
ret='\tblr'
|
||||
;;
|
||||
mips*)
|
||||
ret='\tjr.*ra'
|
||||
;;
|
||||
*)
|
||||
echo "Unknown machine `uname -m`"
|
||||
;;
|
||||
esac
|
||||
echo $1
|
||||
# op_exit_tb causes false positives on some hosts.
|
||||
${CROSS}objdump -dr $1 | \
|
||||
sed -e '/>:$\|'"$ret"'/!d' -e 's/.*<\(.*\)>:/~\1:/' -e 's/.*'"$ret"'.*/!/' | \
|
||||
sed -e ':1;N;s/\n//;t1' | sed -e 's/~/\n/g' | grep -v '^op_exit_tb' | \
|
||||
grep '^op_.*!!'
|
||||
@@ -22,6 +22,8 @@ interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
gcc3_search="yes"
|
||||
gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32"
|
||||
host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
@@ -88,14 +90,13 @@ bsd="no"
|
||||
linux="no"
|
||||
kqemu="no"
|
||||
profiler="no"
|
||||
kernel_path=""
|
||||
cocoa="no"
|
||||
check_gfx="yes"
|
||||
check_gcc="yes"
|
||||
softmmu="yes"
|
||||
user="no"
|
||||
linux_user="no"
|
||||
darwin_user="no"
|
||||
build_docs="no"
|
||||
build_acpi_tables="no"
|
||||
uname_release=""
|
||||
|
||||
# OS specific
|
||||
@@ -103,7 +104,7 @@ targetos=`uname -s`
|
||||
case $targetos in
|
||||
CYGWIN*)
|
||||
mingw32="yes"
|
||||
CFLAGS="-O2 -mno-cygwin"
|
||||
OS_CFLAGS="-mno-cygwin"
|
||||
;;
|
||||
MINGW32*)
|
||||
mingw32="yes"
|
||||
@@ -126,6 +127,10 @@ oss="yes"
|
||||
Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
darwin_user="yes"
|
||||
cocoa="yes"
|
||||
coreaudio="yes"
|
||||
OS_CFLAGS="-mdynamic-no-pic"
|
||||
;;
|
||||
SunOS)
|
||||
solaris="yes"
|
||||
@@ -133,7 +138,7 @@ solaris="yes"
|
||||
*)
|
||||
oss="yes"
|
||||
linux="yes"
|
||||
user="yes"
|
||||
linux_user="yes"
|
||||
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
|
||||
kqemu="yes"
|
||||
fi
|
||||
@@ -150,6 +155,11 @@ if [ "$solaris" = "yes" ] ; then
|
||||
make="gmake"
|
||||
install="ginstall"
|
||||
solarisrev=`uname -r | cut -f2 -d.`
|
||||
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
|
||||
if test "$solarisrev" -gt 10 ; then
|
||||
kqemu="yes"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# find source path
|
||||
@@ -180,6 +190,7 @@ for opt do
|
||||
--cross-prefix=*) cross_prefix="$optarg"
|
||||
;;
|
||||
--cc=*) cc="$optarg"
|
||||
gcc3_search="no"
|
||||
;;
|
||||
--host-cc=*) host_cc="$optarg"
|
||||
;;
|
||||
@@ -223,8 +234,6 @@ for opt do
|
||||
;;
|
||||
--enable-profiler) profiler="yes"
|
||||
;;
|
||||
--kernel-path=*) kernel_path="$optarg"
|
||||
;;
|
||||
--enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
|
||||
;;
|
||||
--disable-gfx-check) check_gfx="no"
|
||||
@@ -235,21 +244,22 @@ for opt do
|
||||
;;
|
||||
--enable-system) softmmu="yes"
|
||||
;;
|
||||
--disable-user) user="no"
|
||||
--disable-linux-user) linux_user="no"
|
||||
;;
|
||||
--enable-user) user="yes"
|
||||
--enable-linux-user) linux_user="yes"
|
||||
;;
|
||||
--disable-darwin-user) darwin_user="no"
|
||||
;;
|
||||
--enable-darwin-user) darwin_user="yes"
|
||||
;;
|
||||
--enable-uname-release=*) uname_release="$optarg"
|
||||
;;
|
||||
--enable-iasl) build_acpi_tables="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Checking for CFLAGS
|
||||
if test -z "$CFLAGS"; then
|
||||
CFLAGS="-O2"
|
||||
fi
|
||||
# default flags for all hosts
|
||||
CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
|
||||
LDFLAGS="$LDFLAGS -g"
|
||||
|
||||
if test x"$show_help" = x"yes" ; then
|
||||
cat << EOF
|
||||
@@ -267,7 +277,6 @@ echo " --target-list=LIST set target list [$target_list]"
|
||||
echo ""
|
||||
echo "kqemu kernel acceleration support:"
|
||||
echo " --disable-kqemu disable kqemu support"
|
||||
echo " --kernel-path=PATH set the kernel path (configure probes it)"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
@@ -286,14 +295,15 @@ echo " --enable-fmod enable FMOD audio driver"
|
||||
echo " --enabled-dsound enable DirectSound audio driver"
|
||||
echo " --enable-system enable all system emulation targets"
|
||||
echo " --disable-system disable all system emulation targets"
|
||||
echo " --enable-user enable all linux usermode emulation targets"
|
||||
echo " --disable-user disable all linux usermode emulation targets"
|
||||
echo " --enable-linux-user enable all linux usermode emulation targets"
|
||||
echo " --disable-linux-user disable all linux usermode emulation targets"
|
||||
echo " --enable-darwin-user enable all darwin usermode emulation targets"
|
||||
echo " --disable-darwin-user disable all darwin usermode emulation targets"
|
||||
echo " --fmod-lib path to FMOD library"
|
||||
echo " --fmod-inc path to FMOD includes"
|
||||
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
|
||||
echo " --enable-iasl compilation of ACPI tables with the IASL compiler"
|
||||
echo ""
|
||||
echo "NOTE: The object files are build at the place where configure is launched"
|
||||
echo "NOTE: The object files are built at the place where configure is launched"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -322,6 +332,45 @@ if test "$mingw32" = "yes" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for gcc4, error if pre-gcc4
|
||||
if test "$check_gcc" = "yes" ; then
|
||||
cat > $TMPC <<EOF
|
||||
#if __GNUC__ < 4
|
||||
#error gcc3
|
||||
#endif
|
||||
int main(){return 0;}
|
||||
EOF
|
||||
check_cc() {
|
||||
which "$1" >&/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
|
||||
echo "WARNING: \"$cc\" looks like gcc 4.x"
|
||||
found_compat_cc="no"
|
||||
if test "$gcc3_search" = "yes" ; then
|
||||
echo "Looking for gcc 3.x"
|
||||
for compat_cc in $gcc3_list ; do
|
||||
if check_cc "$compat_cc" ; then
|
||||
echo "Found \"$compat_cc\""
|
||||
cc="$compat_cc"
|
||||
found_compat_cc="yes"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "$found_compat_cc" = "no" ; then
|
||||
echo "gcc 3.x not found!"
|
||||
fi
|
||||
fi
|
||||
if test "$found_compat_cc" = "no" ; then
|
||||
echo "QEMU is known to have problems when compiled with gcc 4.x"
|
||||
echo "It is recommended that you use gcc 3.x to build QEMU"
|
||||
echo "To use this compiler anyway, configure with --disable-gcc-check"
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Solaris specific configure tool chain decisions
|
||||
#
|
||||
@@ -369,8 +418,12 @@ if test -z "$target_list" ; then
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
|
||||
fi
|
||||
# the following are Linux specific
|
||||
if [ "$user" = "yes" ] ; then
|
||||
target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
|
||||
if [ "$linux_user" = "yes" ] ; then
|
||||
target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user $target_list"
|
||||
fi
|
||||
# the following are Darwin specific
|
||||
if [ "$darwin_user" = "yes" ] ; then
|
||||
target_list="i386-darwin-user ppc-darwin-user $target_list"
|
||||
fi
|
||||
else
|
||||
target_list=`echo "$target_list" | sed -e 's/,/ /g'`
|
||||
@@ -424,23 +477,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
|
||||
have_gcc3_options="yes"
|
||||
fi
|
||||
|
||||
# Check for gcc4, error if pre-gcc4
|
||||
if test "$check_gcc" = "yes" ; then
|
||||
cat > $TMPC <<EOF
|
||||
#if __GNUC__ < 4
|
||||
#error gcc3
|
||||
#endif
|
||||
int main(){return 0;}
|
||||
EOF
|
||||
if $cc -o $TMPO $TMPC 2>/dev/null ; then
|
||||
echo "ERROR: \"$cc\" looks like gcc 4.x"
|
||||
echo "QEMU is known to have problems when compiled with gcc 4.x"
|
||||
echo "It is recommended that you use gcc 3.x to build QEMU"
|
||||
echo "To use this compiler anyway, configure with --disable-gcc-check"
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# SDL probe
|
||||
|
||||
@@ -469,7 +505,9 @@ _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
|
||||
if test "$_sdlversion" -lt 121 ; then
|
||||
sdl_too_old=yes
|
||||
else
|
||||
sdl=yes
|
||||
if test "$cocoa" = "no" ; then
|
||||
sdl=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
# static link with sdl ?
|
||||
@@ -490,8 +528,34 @@ fi # static link
|
||||
fi # sdl compile test
|
||||
|
||||
fi # cross compilation
|
||||
|
||||
else
|
||||
# Make sure to disable cocoa if sdl was set
|
||||
if test "$sdl" = "yes" ; then
|
||||
cocoa="no"
|
||||
coreaudio="no"
|
||||
fi
|
||||
fi # -z $sdl
|
||||
|
||||
##########################################
|
||||
# alsa sound support libraries
|
||||
|
||||
if test "$alsa" = "yes" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <alsa/asoundlib.h>
|
||||
int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
|
||||
EOF
|
||||
if $cc -o $TMPE $TMPC -lasound 2> /dev/null ; then
|
||||
:
|
||||
else
|
||||
echo
|
||||
echo "Error: Could not find alsa"
|
||||
echo "Make sure to have the alsa libs and headers installed."
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if tools are available to build documentation.
|
||||
if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
|
||||
build_docs="yes"
|
||||
@@ -593,6 +657,7 @@ fi
|
||||
echo "HOST_CC=$host_cc" >> $config_mak
|
||||
echo "AR=$ar" >> $config_mak
|
||||
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
|
||||
echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
|
||||
echo "CFLAGS=$CFLAGS" >> $config_mak
|
||||
echo "LDFLAGS=$LDFLAGS" >> $config_mak
|
||||
echo "EXESUF=$EXESUF" >> $config_mak
|
||||
@@ -712,9 +777,6 @@ echo "TARGET_DIRS=$target_list" >> $config_mak
|
||||
if [ "$build_docs" = "yes" ] ; then
|
||||
echo "BUILD_DOCS=yes" >> $config_mak
|
||||
fi
|
||||
if [ "$build_acpi_tables" = "yes" ] ; then
|
||||
echo "BUILD_ACPI_TABLES=yes" >> $config_mak
|
||||
fi
|
||||
|
||||
# XXX: suppress that
|
||||
if [ "$bsd" = "yes" ] ; then
|
||||
@@ -738,6 +800,7 @@ target_bigendian="no"
|
||||
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "mips" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "m68k" ] && target_bigendian=yes
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
@@ -747,6 +810,16 @@ if expr $target : '.*-user' > /dev/null ; then
|
||||
target_user_only="yes"
|
||||
fi
|
||||
|
||||
target_linux_user="no"
|
||||
if expr $target : '.*-linux-user' > /dev/null ; then
|
||||
target_linux_user="yes"
|
||||
fi
|
||||
|
||||
target_darwin_user="no"
|
||||
if expr $target : '.*-darwin-user' > /dev/null ; then
|
||||
target_darwin_user="yes"
|
||||
fi
|
||||
|
||||
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
|
||||
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
|
||||
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
|
||||
@@ -759,7 +832,7 @@ fi
|
||||
|
||||
mkdir -p $target_dir
|
||||
mkdir -p $target_dir/fpu
|
||||
if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
|
||||
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
|
||||
mkdir -p $target_dir/nwfpe
|
||||
fi
|
||||
if test "$target_user_only" = "no" ; then
|
||||
@@ -833,6 +906,11 @@ elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
|
||||
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
|
||||
echo "#define TARGET_SH4 1" >> $config_h
|
||||
bflt="yes"
|
||||
elif test "$target_cpu" = "m68k" ; then
|
||||
echo "TARGET_ARCH=m68k" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"m68k\"" >> $config_h
|
||||
echo "#define TARGET_M68K 1" >> $config_h
|
||||
bflt="yes"
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
@@ -849,8 +927,16 @@ 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 "$target_linux_user" = "yes" ; then
|
||||
echo "CONFIG_LINUX_USER=yes" >> $config_mak
|
||||
echo "#define CONFIG_LINUX_USER 1" >> $config_h
|
||||
fi
|
||||
if test "$target_darwin_user" = "yes" ; then
|
||||
echo "CONFIG_DARWIN_USER=yes" >> $config_mak
|
||||
echo "#define CONFIG_DARWIN_USER 1" >> $config_h
|
||||
fi
|
||||
|
||||
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then
|
||||
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
|
||||
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
|
||||
fi
|
||||
|
||||
@@ -121,6 +121,7 @@ struct TextConsole {
|
||||
int total_height;
|
||||
int backscroll_height;
|
||||
int x, y;
|
||||
int x_saved, y_saved;
|
||||
int y_displayed;
|
||||
int y_base;
|
||||
TextAttributes t_attrib_default; /* default text attributes */
|
||||
@@ -131,10 +132,7 @@ struct TextConsole {
|
||||
int esc_params[MAX_ESC_PARAMS];
|
||||
int nb_esc_params;
|
||||
|
||||
/* kbd read handler */
|
||||
IOCanRWHandler *fd_can_read;
|
||||
IOReadHandler *fd_read;
|
||||
void *fd_opaque;
|
||||
CharDriverState *chr;
|
||||
/* fifo for key pressed */
|
||||
QEMUFIFO out_fifo;
|
||||
uint8_t out_fifo_buf[16];
|
||||
@@ -147,7 +145,7 @@ static int nb_consoles = 0;
|
||||
|
||||
void vga_hw_update(void)
|
||||
{
|
||||
if (active_console->hw_update)
|
||||
if (active_console && active_console->hw_update)
|
||||
active_console->hw_update(active_console->hw);
|
||||
}
|
||||
|
||||
@@ -659,10 +657,6 @@ static void console_handle_escape(TextConsole *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
|
||||
s->t_attrib = s->t_attrib_default;
|
||||
return;
|
||||
}
|
||||
for (i=0; i<s->nb_esc_params; i++) {
|
||||
switch (s->esc_params[i]) {
|
||||
case 0: /* reset all console attributes to default */
|
||||
@@ -752,10 +746,21 @@ static void console_handle_escape(TextConsole *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void console_clear_xy(TextConsole *s, int x, int y)
|
||||
{
|
||||
int y1 = (s->y_base + y) % s->total_height;
|
||||
TextCell *c = &s->cells[y1 * s->width + x];
|
||||
c->ch = ' ';
|
||||
c->t_attrib = s->t_attrib_default;
|
||||
c++;
|
||||
update_xy(s, x, y);
|
||||
}
|
||||
|
||||
static void console_putchar(TextConsole *s, int ch)
|
||||
{
|
||||
TextCell *c;
|
||||
int y1, i, x;
|
||||
int y1, i;
|
||||
int x, y;
|
||||
|
||||
switch(s->state) {
|
||||
case TTY_STATE_NORM:
|
||||
@@ -781,20 +786,31 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
case '\a': /* alert aka. bell */
|
||||
/* TODO: has to be implemented */
|
||||
break;
|
||||
case 14:
|
||||
/* SI (shift in), character set 0 (ignored) */
|
||||
break;
|
||||
case 15:
|
||||
/* SO (shift out), character set 1 (ignored) */
|
||||
break;
|
||||
case 27: /* esc (introducing an escape sequence) */
|
||||
s->state = TTY_STATE_ESC;
|
||||
break;
|
||||
default:
|
||||
if (s->x >= s->width - 1) {
|
||||
break;
|
||||
}
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
c = &s->cells[y1 * s->width + s->x];
|
||||
c->ch = ch;
|
||||
c->t_attrib = s->t_attrib;
|
||||
update_xy(s, s->x, s->y);
|
||||
s->x++;
|
||||
#if 0 /* line wrap disabled */
|
||||
if (s->x >= s->width) {
|
||||
s->x = 0;
|
||||
console_put_lf(s);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -818,32 +834,150 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
s->nb_esc_params++;
|
||||
if (ch == ';')
|
||||
break;
|
||||
#ifdef DEBUG_CONSOLE
|
||||
fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
|
||||
s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
|
||||
#endif
|
||||
s->state = TTY_STATE_NORM;
|
||||
switch(ch) {
|
||||
case 'D':
|
||||
if (s->x > 0)
|
||||
s->x--;
|
||||
break;
|
||||
case 'C':
|
||||
if (s->x < (s->width - 1))
|
||||
s->x++;
|
||||
break;
|
||||
case 'K':
|
||||
/* clear to eol */
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
for(x = s->x; x < s->width; x++) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
c->ch = ' ';
|
||||
c->t_attrib = s->t_attrib_default;
|
||||
c++;
|
||||
update_xy(s, x, s->y);
|
||||
case 'A':
|
||||
/* move cursor up */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->y -= s->esc_params[0];
|
||||
if (s->y < 0) {
|
||||
s->y = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case 'B':
|
||||
/* move cursor down */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->y += s->esc_params[0];
|
||||
if (s->y >= s->height) {
|
||||
s->y = s->height - 1;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
/* move cursor right */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->x += s->esc_params[0];
|
||||
if (s->x >= s->width) {
|
||||
s->x = s->width - 1;
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
/* move cursor left */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->x -= s->esc_params[0];
|
||||
if (s->x < 0) {
|
||||
s->x = 0;
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
/* move cursor to column */
|
||||
s->x = s->esc_params[0] - 1;
|
||||
if (s->x < 0) {
|
||||
s->x = 0;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
case 'H':
|
||||
/* move cursor to row, column */
|
||||
s->x = s->esc_params[1] - 1;
|
||||
if (s->x < 0) {
|
||||
s->x = 0;
|
||||
}
|
||||
s->y = s->esc_params[0] - 1;
|
||||
if (s->y < 0) {
|
||||
s->y = 0;
|
||||
}
|
||||
break;
|
||||
case 'J':
|
||||
switch (s->esc_params[0]) {
|
||||
case 0:
|
||||
/* clear to end of screen */
|
||||
for (y = s->y; y < s->height; y++) {
|
||||
for (x = 0; x < s->width; x++) {
|
||||
if (y == s->y && x < s->x) {
|
||||
continue;
|
||||
}
|
||||
console_clear_xy(s, x, y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* clear from beginning of screen */
|
||||
for (y = 0; y <= s->y; y++) {
|
||||
for (x = 0; x < s->width; x++) {
|
||||
if (y == s->y && x > s->x) {
|
||||
break;
|
||||
}
|
||||
console_clear_xy(s, x, y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* clear entire screen */
|
||||
for (y = 0; y <= s->height; y++) {
|
||||
for (x = 0; x < s->width; x++) {
|
||||
console_clear_xy(s, x, y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'K':
|
||||
switch (s->esc_params[0]) {
|
||||
case 0:
|
||||
/* clear to eol */
|
||||
for(x = s->x; x < s->width; x++) {
|
||||
console_clear_xy(s, x, s->y);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* clear from beginning of line */
|
||||
for (x = 0; x <= s->x; x++) {
|
||||
console_clear_xy(s, x, s->y);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* clear entire line */
|
||||
for(x = 0; x < s->width; x++) {
|
||||
console_clear_xy(s, x, s->y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
console_handle_escape(s);
|
||||
break;
|
||||
case 'n':
|
||||
/* report cursor position */
|
||||
/* TODO: send ESC[row;colR */
|
||||
break;
|
||||
case 's':
|
||||
/* save cursor position */
|
||||
s->x_saved = s->x;
|
||||
s->y_saved = s->y;
|
||||
break;
|
||||
case 'u':
|
||||
/* restore cursor position */
|
||||
s->x = s->x_saved;
|
||||
s->y = s->y_saved;
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG_CONSOLE
|
||||
fprintf(stderr, "unhandled escape character '%c'\n", ch);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -884,16 +1018,6 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
static void console_chr_add_read_handler(CharDriverState *chr,
|
||||
IOCanRWHandler *fd_can_read,
|
||||
IOReadHandler *fd_read, void *opaque)
|
||||
{
|
||||
TextConsole *s = chr->opaque;
|
||||
s->fd_can_read = fd_can_read;
|
||||
s->fd_read = fd_read;
|
||||
s->fd_opaque = opaque;
|
||||
}
|
||||
|
||||
static void console_send_event(CharDriverState *chr, int event)
|
||||
{
|
||||
TextConsole *s = chr->opaque;
|
||||
@@ -915,14 +1039,14 @@ static void kbd_send_chars(void *opaque)
|
||||
int len;
|
||||
uint8_t buf[16];
|
||||
|
||||
len = s->fd_can_read(s->fd_opaque);
|
||||
len = qemu_chr_can_read(s->chr);
|
||||
if (len > s->out_fifo.count)
|
||||
len = s->out_fifo.count;
|
||||
if (len > 0) {
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
qemu_fifo_read(&s->out_fifo, buf, len);
|
||||
s->fd_read(s->fd_opaque, buf, len);
|
||||
qemu_chr_read(s->chr, buf, len);
|
||||
}
|
||||
/* characters are pending: we send them a bit later (XXX:
|
||||
horrible, should change char device API) */
|
||||
@@ -973,7 +1097,7 @@ void kbd_put_keysym(int keysym)
|
||||
} else {
|
||||
*q++ = keysym;
|
||||
}
|
||||
if (s->fd_read) {
|
||||
if (s->chr->chr_read) {
|
||||
qemu_fifo_write(&s->out_fifo, buf, q - buf);
|
||||
kbd_send_chars(s);
|
||||
}
|
||||
@@ -1049,9 +1173,9 @@ CharDriverState *text_console_init(DisplayState *ds)
|
||||
}
|
||||
chr->opaque = s;
|
||||
chr->chr_write = console_puts;
|
||||
chr->chr_add_read_handler = console_chr_add_read_handler;
|
||||
chr->chr_send_event = console_send_event;
|
||||
|
||||
s->chr = chr;
|
||||
s->out_fifo.buf = s->out_fifo_buf;
|
||||
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
|
||||
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
|
||||
@@ -1086,5 +1210,7 @@ CharDriverState *text_console_init(DisplayState *ds)
|
||||
s->t_attrib = s->t_attrib_default;
|
||||
text_console_resize(s);
|
||||
|
||||
qemu_chr_reset(chr);
|
||||
|
||||
return chr;
|
||||
}
|
||||
@@ -725,6 +725,13 @@ void page_unprotect_range(target_ulong data, target_ulong data_size);
|
||||
#define cpu_gen_code cpu_ppc_gen_code
|
||||
#define cpu_signal_handler cpu_ppc_signal_handler
|
||||
|
||||
#elif defined(TARGET_M68K)
|
||||
#define CPUState CPUM68KState
|
||||
#define cpu_init cpu_m68k_init
|
||||
#define cpu_exec cpu_m68k_exec
|
||||
#define cpu_gen_code cpu_m68k_gen_code
|
||||
#define cpu_signal_handler cpu_m68k_signal_handler
|
||||
|
||||
#elif defined(TARGET_MIPS)
|
||||
#define CPUState CPUMIPSState
|
||||
#define cpu_init cpu_mips_init
|
||||
@@ -762,6 +769,7 @@ extern int code_copy_enabled;
|
||||
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
|
||||
#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */
|
||||
#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */
|
||||
#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */
|
||||
|
||||
void cpu_interrupt(CPUState *s, int mask);
|
||||
void cpu_reset_interrupt(CPUState *env, int mask);
|
||||
@@ -839,6 +847,7 @@ typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
||||
void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
unsigned long size,
|
||||
unsigned long phys_offset);
|
||||
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
|
||||
int cpu_register_io_memory(int io_index,
|
||||
CPUReadMemoryFunc **mem_read,
|
||||
CPUWriteMemoryFunc **mem_write,
|
||||
@@ -992,6 +1001,15 @@ static inline int64_t cpu_get_real_ticks (void)
|
||||
return rval.i64;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
/* The host CPU doesn't have an easily accessible cycle counter.
|
||||
Just return a monotonically increasing vlue. This will be totally wrong,
|
||||
but hopefully better than nothing. */
|
||||
static inline int64_t cpu_get_real_ticks (void)
|
||||
{
|
||||
static int64_t ticks = 0;
|
||||
return ticks++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* profiling */
|
||||
|
||||
@@ -80,6 +80,14 @@ typedef unsigned long ram_addr_t;
|
||||
#define TB_JMP_CACHE_BITS 12
|
||||
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
|
||||
|
||||
/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
|
||||
addresses on the same page. The top bits are the same. This allows
|
||||
TLB invalidation to quickly clear a subset of the hash table. */
|
||||
#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
|
||||
#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
|
||||
#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
|
||||
#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
|
||||
|
||||
#define CPU_TLB_BITS 8
|
||||
#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
|
||||
|
||||
|
||||
+120
-116
@@ -40,14 +40,14 @@ int tb_invalidated_flag;
|
||||
//#define DEBUG_EXEC
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
|
||||
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
|
||||
/* XXX: unify with i386 target */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
#endif
|
||||
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4))
|
||||
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
|
||||
#define reg_T2
|
||||
#endif
|
||||
|
||||
@@ -194,6 +194,10 @@ static inline TranslationBlock *tb_find_fast(void)
|
||||
flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
|
||||
cs_base = 0;
|
||||
pc = env->PC;
|
||||
#elif defined(TARGET_M68K)
|
||||
flags = env->fpcr & M68K_FPCR_PREC;
|
||||
cs_base = 0;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_SH4)
|
||||
flags = env->sr & (SR_MD | SR_RB);
|
||||
cs_base = 0; /* XXXXX */
|
||||
@@ -222,43 +226,16 @@ static inline TranslationBlock *tb_find_fast(void)
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
int saved_T0, saved_T1;
|
||||
#if defined(reg_T2)
|
||||
int saved_T2;
|
||||
#endif
|
||||
CPUState *saved_env;
|
||||
#if defined(TARGET_I386)
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
int saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
int saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
int saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
int saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
int saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
int saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_SPARC)
|
||||
#define DECLARE_HOST_REGS 1
|
||||
#include "hostregs_helper.h"
|
||||
#if defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
uint32_t *saved_regwptr;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__sparc__) && !defined(HOST_SOLARIS)
|
||||
int saved_i7, tmp_T0;
|
||||
int saved_i7;
|
||||
target_ulong tmp_T0;
|
||||
#endif
|
||||
int ret, interrupt_request;
|
||||
void (*gen_func)(void);
|
||||
@@ -320,44 +297,15 @@ int cpu_exec(CPUState *env1)
|
||||
cpu_single_env = env1;
|
||||
|
||||
/* first we save global registers */
|
||||
saved_env = env;
|
||||
#define SAVE_HOST_REGS 1
|
||||
#include "hostregs_helper.h"
|
||||
env = env1;
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
#if defined(reg_T2)
|
||||
saved_T2 = T2;
|
||||
#endif
|
||||
#if defined(__sparc__) && !defined(HOST_SOLARIS)
|
||||
/* we also save i7 because longjmp may not restore it */
|
||||
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#ifdef reg_EAX
|
||||
saved_EAX = EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
saved_ECX = ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
saved_EDX = EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
saved_EBX = EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
saved_ESP = ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
saved_EBP = EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
saved_ESI = ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
saved_EDI = EDI;
|
||||
#endif
|
||||
|
||||
env_to_regs();
|
||||
/* put eflags in CPU temporary format */
|
||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
@@ -370,6 +318,10 @@ int cpu_exec(CPUState *env1)
|
||||
saved_regwptr = REGWPTR;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#elif defined(TARGET_M68K)
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
env->cc_dest = env->sr & 0xf;
|
||||
env->cc_x = (env->sr >> 4) & 1;
|
||||
#elif defined(TARGET_MIPS)
|
||||
#elif defined(TARGET_SH4)
|
||||
/* XXXXX */
|
||||
@@ -390,7 +342,7 @@ int cpu_exec(CPUState *env1)
|
||||
break;
|
||||
} else if (env->user_mode_only) {
|
||||
/* if user mode only, we simulate a fake exception
|
||||
which will be hanlded outside the cpu execution
|
||||
which will be handled outside the cpu execution
|
||||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
do_interrupt_user(env->exception_index,
|
||||
@@ -458,8 +410,16 @@ int cpu_exec(CPUState *env1)
|
||||
interrupt_request = env->interrupt_request;
|
||||
if (__builtin_expect(interrupt_request, 0)) {
|
||||
#if defined(TARGET_I386)
|
||||
/* if hardware interrupt pending, we execute it */
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
||||
!(env->hflags & HF_SMM_MASK)) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_SMI;
|
||||
do_smm_enter();
|
||||
#if defined(__sparc__) && !defined(HOST_SOLARIS)
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
T0 = 0;
|
||||
#endif
|
||||
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->eflags & IF_MASK) &&
|
||||
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
||||
int intno;
|
||||
@@ -519,7 +479,6 @@ int cpu_exec(CPUState *env1)
|
||||
env->exception_index = EXCP_EXT_INTERRUPT;
|
||||
env->error_code = 0;
|
||||
do_interrupt(env);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
#if defined(__sparc__) && !defined(HOST_SOLARIS)
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
@@ -548,8 +507,10 @@ int cpu_exec(CPUState *env1)
|
||||
//do_interrupt(0, 0, 0, 0, 0);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
|
||||
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
|
||||
env1->halted = 1;
|
||||
return EXCP_HALTED;
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
|
||||
env->halted = 1;
|
||||
env->exception_index = EXCP_HLT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
if (interrupt_request & CPU_INTERRUPT_FIQ
|
||||
@@ -622,6 +583,12 @@ int cpu_exec(CPUState *env1)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_M68K)
|
||||
cpu_m68k_flush_flags(env, env->cc_op);
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
env->sr = (env->sr & 0xffe0)
|
||||
| env->cc_dest | (env->cc_x << 4);
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_MIPS)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_SH4)
|
||||
@@ -803,32 +770,6 @@ int cpu_exec(CPUState *env1)
|
||||
#endif
|
||||
/* restore flags in standard format */
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
|
||||
/* restore global registers */
|
||||
#ifdef reg_EAX
|
||||
EAX = saved_EAX;
|
||||
#endif
|
||||
#ifdef reg_ECX
|
||||
ECX = saved_ECX;
|
||||
#endif
|
||||
#ifdef reg_EDX
|
||||
EDX = saved_EDX;
|
||||
#endif
|
||||
#ifdef reg_EBX
|
||||
EBX = saved_EBX;
|
||||
#endif
|
||||
#ifdef reg_ESP
|
||||
ESP = saved_ESP;
|
||||
#endif
|
||||
#ifdef reg_EBP
|
||||
EBP = saved_EBP;
|
||||
#endif
|
||||
#ifdef reg_ESI
|
||||
ESI = saved_ESI;
|
||||
#endif
|
||||
#ifdef reg_EDI
|
||||
EDI = saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
/* XXX: Save/restore host fpu exception state?. */
|
||||
#elif defined(TARGET_SPARC)
|
||||
@@ -836,21 +777,24 @@ int cpu_exec(CPUState *env1)
|
||||
REGWPTR = saved_regwptr;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#elif defined(TARGET_M68K)
|
||||
cpu_m68k_flush_flags(env, env->cc_op);
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
env->sr = (env->sr & 0xffe0)
|
||||
| env->cc_dest | (env->cc_x << 4);
|
||||
#elif defined(TARGET_MIPS)
|
||||
#elif defined(TARGET_SH4)
|
||||
/* XXXXX */
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
/* restore global registers */
|
||||
#if defined(__sparc__) && !defined(HOST_SOLARIS)
|
||||
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
|
||||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
#if defined(reg_T2)
|
||||
T2 = saved_T2;
|
||||
#endif
|
||||
env = saved_env;
|
||||
#include "hostregs_helper.h"
|
||||
|
||||
/* fail safe : never use cpu_single_env outside cpu_exec() */
|
||||
cpu_single_env = NULL;
|
||||
return ret;
|
||||
@@ -1093,6 +1037,45 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_M68K)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set,
|
||||
void *puc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address, pc, puc)) {
|
||||
return 1;
|
||||
}
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_m68k_handle_mmu_fault(env, address, is_write, 1, 0);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
return 1; /* the MMU fault was handled without causing real CPU fault */
|
||||
/* now we have a real cpu fault */
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, puc);
|
||||
}
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
cpu_loop_exit();
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined (TARGET_MIPS)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set,
|
||||
@@ -1193,6 +1176,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <sys/ucontext.h>
|
||||
|
||||
# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
|
||||
# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
|
||||
# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
|
||||
#else
|
||||
# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
|
||||
# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
|
||||
# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
|
||||
#endif
|
||||
|
||||
#if defined(USE_CODE_COPY)
|
||||
static void cpu_send_trap(unsigned long pc, int trap,
|
||||
struct ucontext *uc)
|
||||
@@ -1213,9 +1208,10 @@ static void cpu_send_trap(unsigned long pc, int trap,
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int trapno;
|
||||
@@ -1226,8 +1222,8 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
#define REG_ERR ERR
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#endif
|
||||
pc = uc->uc_mcontext.gregs[REG_EIP];
|
||||
trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
|
||||
pc = EIP_sig(uc);
|
||||
trapno = TRAP_sig(uc);
|
||||
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||
if (trapno == 0x00 || trapno == 0x05) {
|
||||
/* send division by zero or bound exception */
|
||||
@@ -1237,15 +1233,16 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
#endif
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
trapno == 0xe ?
|
||||
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
|
||||
(ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
|
||||
@@ -1307,9 +1304,10 @@ typedef struct ucontext SIGCONTEXT;
|
||||
# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
@@ -1330,9 +1328,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
|
||||
#elif defined(__alpha__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
uint32_t *pc = uc->uc_mcontext.sc_pc;
|
||||
uint32_t insn = *pc;
|
||||
@@ -1359,9 +1358,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
uint32_t *regs = (uint32_t *)(info + 1);
|
||||
void *sigmask = (regs + 20);
|
||||
unsigned long pc;
|
||||
@@ -1392,9 +1392,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
@@ -1404,14 +1405,15 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
&uc->uc_sigmask);
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#elif defined(__mc68000)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
@@ -1431,8 +1433,9 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
# define __ISR_VALID 1
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
|
||||
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long ip;
|
||||
int is_write = 0;
|
||||
@@ -1459,9 +1462,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Simple C functions to supplement the C library
|
||||
*
|
||||
* Copyright (c) 2006 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 "vl.h"
|
||||
|
||||
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 strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int stristart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (toupper(*p) != toupper(*q))
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Commpage syscalls
|
||||
*
|
||||
* Copyright (c) 2006 Pierre d'Herbemont
|
||||
*
|
||||
* 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 <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <mach/message.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG_COMMPAGE
|
||||
|
||||
#ifdef DEBUG_COMMPAGE
|
||||
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
|
||||
#else
|
||||
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
|
||||
#endif
|
||||
|
||||
/********************************************************************
|
||||
* Commpage definitions
|
||||
*/
|
||||
#ifdef TARGET_I386
|
||||
/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
|
||||
# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
|
||||
# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
|
||||
#elif defined(TARGET_PPC)
|
||||
/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
|
||||
# define COMMPAGE_START (-8*4096)
|
||||
# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
|
||||
#endif
|
||||
|
||||
void do_compare_and_swap32(void *cpu_env, int num);
|
||||
void do_compare_and_swap64(void *cpu_env, int num);
|
||||
void do_add_atomic_word32(void *cpu_env, int num);
|
||||
void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
|
||||
void do_nanotime(void *cpu_env, int num);
|
||||
|
||||
void unimpl_commpage(void *cpu_env, int num);
|
||||
|
||||
typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
|
||||
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
|
||||
uint32_t arg8);
|
||||
typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
|
||||
uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
|
||||
uint32_t arg6, uint32_t arg7, uint32_t arg8);
|
||||
|
||||
#define HAS_PTR 0x10
|
||||
#define NO_PTR 0x20
|
||||
#define CALL_DIRECT 0x1
|
||||
#define CALL_INDIRECT 0x2
|
||||
|
||||
#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
|
||||
{ #name, offset, nargs, options, (commpage_8args_function_t)func }
|
||||
|
||||
struct commpage_entry {
|
||||
char * name;
|
||||
int offset;
|
||||
int nargs;
|
||||
char options;
|
||||
commpage_8args_function_t function;
|
||||
};
|
||||
|
||||
static inline int commpage_code_num(struct commpage_entry *entry)
|
||||
{
|
||||
if((entry->options & HAS_PTR))
|
||||
return entry->offset + 4;
|
||||
else
|
||||
return entry->offset;
|
||||
}
|
||||
|
||||
static inline int commpage_is_indirect(struct commpage_entry *entry)
|
||||
{
|
||||
return !(entry->options & CALL_DIRECT);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Commpage entry
|
||||
*/
|
||||
static struct commpage_entry commpage_entries[] =
|
||||
{
|
||||
COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
|
||||
COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
|
||||
COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR),
|
||||
COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR),
|
||||
|
||||
COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT),
|
||||
COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT),
|
||||
COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(gettimeofday, 1, 0x2e0, do_cgettimeofday, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x4e0, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x520, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(pthread_self, 0, 0x580, unimpl_commpage, CALL_INDIRECT),
|
||||
|
||||
COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT),
|
||||
|
||||
#ifdef TARGET_I386
|
||||
COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT),
|
||||
#endif
|
||||
|
||||
COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT),
|
||||
COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT),
|
||||
COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT),
|
||||
|
||||
#ifdef TARGET_I386
|
||||
COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT),
|
||||
|
||||
COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT),
|
||||
|
||||
COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT),
|
||||
#elif TARGET_PPC
|
||||
COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT),
|
||||
COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Commpage backdoor
|
||||
*/
|
||||
static inline void print_commpage_entry(struct commpage_entry entry)
|
||||
{
|
||||
printf("@0x%x %s\n", entry.offset, entry.name);
|
||||
}
|
||||
|
||||
static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
char * commpage = (char*)(COMMPAGE_START+entry.offset);
|
||||
int c = 0;
|
||||
if(entry.options & HAS_PTR)
|
||||
{
|
||||
commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
|
||||
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
|
||||
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
|
||||
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
|
||||
}
|
||||
commpage[c++] = 0xcd;
|
||||
commpage[c++] = 0x79; /* int 0x79 */
|
||||
commpage[c++] = 0xc3; /* ret */
|
||||
#else
|
||||
qerror("can't install the commpage on this arch\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Commpage initialization
|
||||
*/
|
||||
void commpage_init(void)
|
||||
{
|
||||
#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC))
|
||||
int i;
|
||||
void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
|
||||
PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
if((int)commpage != COMMPAGE_START)
|
||||
qerror("can't allocate the commpage\n");
|
||||
|
||||
bzero(commpage, COMMPAGE_SIZE);
|
||||
|
||||
/* XXX: commpage data not handled */
|
||||
|
||||
for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++)
|
||||
install_commpage_backdoor_for_entry(commpage_entries[i]);
|
||||
#else
|
||||
/* simply map our pages so they can be executed
|
||||
XXX: we don't really want to do that since in the ppc on ppc situation we may
|
||||
not able to run commpages host optimized instructions (like G5's on a G5),
|
||||
hence this is sometimes a broken fix. */
|
||||
page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Commpage implementation
|
||||
*/
|
||||
void do_compare_and_swap32(void *cpu_env, int num)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
|
||||
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
|
||||
DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
|
||||
|
||||
if(value && old == tswap32(*value))
|
||||
{
|
||||
uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
|
||||
*value = tswap32(new);
|
||||
/* set zf flag */
|
||||
((CPUX86State*)cpu_env)->eflags |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
|
||||
/* unset zf flag */
|
||||
((CPUX86State*)cpu_env)->eflags &= ~0x40;
|
||||
}
|
||||
#else
|
||||
qerror("do_compare_and_swap32 unimplemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_compare_and_swap64(void *cpu_env, int num)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
/* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
|
||||
uint64_t old, new, swapped_val;
|
||||
uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
|
||||
old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
|
||||
|
||||
DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
|
||||
swapped_val = tswap64(*value);
|
||||
|
||||
if(old == swapped_val)
|
||||
{
|
||||
new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
|
||||
*value = tswap64(new);
|
||||
/* set zf flag */
|
||||
((CPUX86State*)cpu_env)->eflags |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
|
||||
((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
|
||||
/* unset zf flag */
|
||||
((CPUX86State*)cpu_env)->eflags &= ~0x40;
|
||||
}
|
||||
#else
|
||||
qerror("do_compare_and_swap64 unimplemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_add_atomic_word32(void *cpu_env, int num)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
|
||||
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
|
||||
uint32_t swapped_value = tswap32(*value);
|
||||
|
||||
DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
|
||||
|
||||
/* old value in EAX */
|
||||
((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
|
||||
*value = tswap32(swapped_value + amt);
|
||||
#else
|
||||
qerror("do_add_atomic_word32 unimplemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
extern int __commpage_gettimeofday(struct timeval *);
|
||||
DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
|
||||
struct timeval *time = (struct timeval *)arg1;
|
||||
int ret = __commpage_gettimeofday(time);
|
||||
tswap32s((uint32_t*)&time->tv_sec);
|
||||
tswap32s((uint32_t*)&time->tv_usec);
|
||||
((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
|
||||
#else
|
||||
qerror("do_gettimeofday unimplemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_nanotime(void *cpu_env, int num)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
uint64_t t = mach_absolute_time();
|
||||
((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
|
||||
((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
|
||||
#else
|
||||
qerror("do_nanotime unimplemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
void unimpl_commpage(void *cpu_env, int num)
|
||||
{
|
||||
qerror("qemu: commpage function 0x%x not implemented\n", num);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* do_commpage - called by the main cpu loop
|
||||
*/
|
||||
void
|
||||
do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
|
||||
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
|
||||
uint32_t arg8)
|
||||
{
|
||||
int i, found = 0;
|
||||
|
||||
arg1 = tswap32(arg1);
|
||||
arg2 = tswap32(arg2);
|
||||
arg3 = tswap32(arg3);
|
||||
arg4 = tswap32(arg4);
|
||||
arg5 = tswap32(arg5);
|
||||
arg6 = tswap32(arg6);
|
||||
arg7 = tswap32(arg7);
|
||||
arg8 = tswap32(arg8);
|
||||
|
||||
num = num-COMMPAGE_START-2;
|
||||
|
||||
for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) {
|
||||
if( num == commpage_code_num(&commpage_entries[i]) )
|
||||
{
|
||||
DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
|
||||
found = 1;
|
||||
if(commpage_is_indirect(&commpage_entries[i]))
|
||||
{
|
||||
commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
|
||||
function(cpu_env, num, arg1, arg2, arg3,
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
else
|
||||
{
|
||||
commpage_entries[i].function(arg1, arg2, arg3,
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
gemu_log("qemu: commpage function 0x%x not defined\n", num);
|
||||
gdb_handlesig (cpu_env, SIGTRAP);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* emulated ioctl list */
|
||||
|
||||
IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
@@ -0,0 +1 @@
|
||||
STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)
|
||||
@@ -0,0 +1,903 @@
|
||||
/*
|
||||
* Mach-O object file loading
|
||||
*
|
||||
* Copyright (c) 2006 Pierre d'Herbemont
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "disas.h"
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/reloc.h>
|
||||
#include <mach-o/ppc/reloc.h>
|
||||
|
||||
//#define DEBUG_MACHLOAD
|
||||
|
||||
#ifdef DEBUG_MACHLOAD
|
||||
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
|
||||
#else
|
||||
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
|
||||
#endif
|
||||
|
||||
# define check_mach_header(x) (x.magic == MH_CIGAM)
|
||||
|
||||
extern const char *interp_prefix;
|
||||
|
||||
/* we don't have a good implementation for this */
|
||||
#define DONT_USE_DYLD_SHARED_MAP
|
||||
|
||||
/* Pass extra arg to DYLD for debug */
|
||||
//#define ACTIVATE_DYLD_TRACE
|
||||
|
||||
//#define OVERRIDE_DYLINKER
|
||||
|
||||
#ifdef OVERRIDE_DYLINKER
|
||||
# ifdef TARGET_I386
|
||||
# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld"
|
||||
# else
|
||||
# define DYLINKER_NAME "/usr/lib/dyld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* XXX: in an include */
|
||||
struct nlist_extended
|
||||
{
|
||||
union {
|
||||
char *n_name;
|
||||
long n_strx;
|
||||
} n_un;
|
||||
unsigned char n_type;
|
||||
unsigned char n_sect;
|
||||
short st_desc;
|
||||
unsigned long st_value;
|
||||
unsigned long st_size;
|
||||
};
|
||||
|
||||
/* Print symbols in gdb */
|
||||
void *macho_text_sect = 0;
|
||||
int macho_offset = 0;
|
||||
|
||||
int load_object(const char *filename, struct target_pt_regs * regs, void ** mh);
|
||||
void qerror(const char *format, ...);
|
||||
#ifdef TARGET_I386
|
||||
typedef struct mach_i386_thread_state {
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
unsigned int edi;
|
||||
unsigned int esi;
|
||||
unsigned int ebp;
|
||||
unsigned int esp;
|
||||
unsigned int ss;
|
||||
unsigned int eflags;
|
||||
unsigned int eip;
|
||||
unsigned int cs;
|
||||
unsigned int ds;
|
||||
unsigned int es;
|
||||
unsigned int fs;
|
||||
unsigned int gs;
|
||||
} mach_i386_thread_state_t;
|
||||
|
||||
void bswap_i386_thread_state(struct mach_i386_thread_state *ts)
|
||||
{
|
||||
bswap32s((uint32_t*)&ts->eax);
|
||||
bswap32s((uint32_t*)&ts->ebx);
|
||||
bswap32s((uint32_t*)&ts->ecx);
|
||||
bswap32s((uint32_t*)&ts->edx);
|
||||
bswap32s((uint32_t*)&ts->edi);
|
||||
bswap32s((uint32_t*)&ts->esi);
|
||||
bswap32s((uint32_t*)&ts->ebp);
|
||||
bswap32s((uint32_t*)&ts->esp);
|
||||
bswap32s((uint32_t*)&ts->ss);
|
||||
bswap32s((uint32_t*)&ts->eflags);
|
||||
bswap32s((uint32_t*)&ts->eip);
|
||||
bswap32s((uint32_t*)&ts->cs);
|
||||
bswap32s((uint32_t*)&ts->ds);
|
||||
bswap32s((uint32_t*)&ts->es);
|
||||
bswap32s((uint32_t*)&ts->fs);
|
||||
bswap32s((uint32_t*)&ts->gs);
|
||||
}
|
||||
#define target_thread_state mach_i386_thread_state
|
||||
#define TARGET_CPU_TYPE CPU_TYPE_I386
|
||||
#define TARGET_CPU_NAME "i386"
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PPC
|
||||
struct mach_ppc_thread_state {
|
||||
unsigned int srr0; /* Instruction address register (PC) */
|
||||
unsigned int srr1; /* Machine state register (supervisor) */
|
||||
unsigned int r0;
|
||||
unsigned int r1;
|
||||
unsigned int r2;
|
||||
unsigned int r3;
|
||||
unsigned int r4;
|
||||
unsigned int r5;
|
||||
unsigned int r6;
|
||||
unsigned int r7;
|
||||
unsigned int r8;
|
||||
unsigned int r9;
|
||||
unsigned int r10;
|
||||
unsigned int r11;
|
||||
unsigned int r12;
|
||||
unsigned int r13;
|
||||
unsigned int r14;
|
||||
unsigned int r15;
|
||||
unsigned int r16;
|
||||
unsigned int r17;
|
||||
unsigned int r18;
|
||||
unsigned int r19;
|
||||
unsigned int r20;
|
||||
unsigned int r21;
|
||||
unsigned int r22;
|
||||
unsigned int r23;
|
||||
unsigned int r24;
|
||||
unsigned int r25;
|
||||
unsigned int r26;
|
||||
unsigned int r27;
|
||||
unsigned int r28;
|
||||
unsigned int r29;
|
||||
unsigned int r30;
|
||||
unsigned int r31;
|
||||
|
||||
unsigned int cr; /* Condition register */
|
||||
unsigned int xer; /* User's integer exception register */
|
||||
unsigned int lr; /* Link register */
|
||||
unsigned int ctr; /* Count register */
|
||||
unsigned int mq; /* MQ register (601 only) */
|
||||
|
||||
unsigned int vrsave; /* Vector Save Register */
|
||||
};
|
||||
|
||||
void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts)
|
||||
{
|
||||
bswap32s((uint32_t*)&ts->srr0);
|
||||
bswap32s((uint32_t*)&ts->srr1);
|
||||
bswap32s((uint32_t*)&ts->r0);
|
||||
bswap32s((uint32_t*)&ts->r1);
|
||||
bswap32s((uint32_t*)&ts->r2);
|
||||
bswap32s((uint32_t*)&ts->r3);
|
||||
bswap32s((uint32_t*)&ts->r4);
|
||||
bswap32s((uint32_t*)&ts->r5);
|
||||
bswap32s((uint32_t*)&ts->r6);
|
||||
bswap32s((uint32_t*)&ts->r7);
|
||||
bswap32s((uint32_t*)&ts->r8);
|
||||
bswap32s((uint32_t*)&ts->r9);
|
||||
bswap32s((uint32_t*)&ts->r10);
|
||||
bswap32s((uint32_t*)&ts->r11);
|
||||
bswap32s((uint32_t*)&ts->r12);
|
||||
bswap32s((uint32_t*)&ts->r13);
|
||||
bswap32s((uint32_t*)&ts->r14);
|
||||
bswap32s((uint32_t*)&ts->r15);
|
||||
bswap32s((uint32_t*)&ts->r16);
|
||||
bswap32s((uint32_t*)&ts->r17);
|
||||
bswap32s((uint32_t*)&ts->r18);
|
||||
bswap32s((uint32_t*)&ts->r19);
|
||||
bswap32s((uint32_t*)&ts->r20);
|
||||
bswap32s((uint32_t*)&ts->r21);
|
||||
bswap32s((uint32_t*)&ts->r22);
|
||||
bswap32s((uint32_t*)&ts->r23);
|
||||
bswap32s((uint32_t*)&ts->r24);
|
||||
bswap32s((uint32_t*)&ts->r25);
|
||||
bswap32s((uint32_t*)&ts->r26);
|
||||
bswap32s((uint32_t*)&ts->r27);
|
||||
bswap32s((uint32_t*)&ts->r28);
|
||||
bswap32s((uint32_t*)&ts->r29);
|
||||
bswap32s((uint32_t*)&ts->r30);
|
||||
bswap32s((uint32_t*)&ts->r31);
|
||||
|
||||
bswap32s((uint32_t*)&ts->cr);
|
||||
bswap32s((uint32_t*)&ts->xer);
|
||||
bswap32s((uint32_t*)&ts->lr);
|
||||
bswap32s((uint32_t*)&ts->ctr);
|
||||
bswap32s((uint32_t*)&ts->mq);
|
||||
|
||||
bswap32s((uint32_t*)&ts->vrsave);
|
||||
}
|
||||
|
||||
#define target_thread_state mach_ppc_thread_state
|
||||
#define TARGET_CPU_TYPE CPU_TYPE_POWERPC
|
||||
#define TARGET_CPU_NAME "PowerPC"
|
||||
#endif
|
||||
|
||||
struct target_thread_command {
|
||||
unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */
|
||||
unsigned long cmdsize; /* total size of this command */
|
||||
unsigned long flavor; /* flavor of thread state */
|
||||
unsigned long count; /* count of longs in thread state */
|
||||
struct target_thread_state state; /* thread state for this flavor */
|
||||
};
|
||||
|
||||
void bswap_tc(struct target_thread_command *tc)
|
||||
{
|
||||
bswap32s((uint32_t*)(&tc->flavor));
|
||||
bswap32s((uint32_t*)&tc->count);
|
||||
#if defined(TARGET_I386)
|
||||
bswap_i386_thread_state(&tc->state);
|
||||
#elif defined(TARGET_PPC)
|
||||
bswap_ppc_thread_state(&tc->state);
|
||||
#else
|
||||
# error unknown TARGET_CPU_TYPE
|
||||
#endif
|
||||
}
|
||||
|
||||
void bswap_mh(struct mach_header *mh)
|
||||
{
|
||||
bswap32s((uint32_t*)(&mh->magic));
|
||||
bswap32s((uint32_t*)&mh->cputype);
|
||||
bswap32s((uint32_t*)&mh->cpusubtype);
|
||||
bswap32s((uint32_t*)&mh->filetype);
|
||||
bswap32s((uint32_t*)&mh->ncmds);
|
||||
bswap32s((uint32_t*)&mh->sizeofcmds);
|
||||
bswap32s((uint32_t*)&mh->flags);
|
||||
}
|
||||
|
||||
void bswap_lc(struct load_command *lc)
|
||||
{
|
||||
bswap32s((uint32_t*)&lc->cmd);
|
||||
bswap32s((uint32_t*)&lc->cmdsize);
|
||||
}
|
||||
|
||||
|
||||
void bswap_fh(struct fat_header *fh)
|
||||
{
|
||||
bswap32s((uint32_t*)&fh->magic);
|
||||
bswap32s((uint32_t*)&fh->nfat_arch);
|
||||
}
|
||||
|
||||
void bswap_fa(struct fat_arch *fa)
|
||||
{
|
||||
bswap32s((uint32_t*)&fa->cputype);
|
||||
bswap32s((uint32_t*)&fa->cpusubtype);
|
||||
bswap32s((uint32_t*)&fa->offset);
|
||||
bswap32s((uint32_t*)&fa->size);
|
||||
bswap32s((uint32_t*)&fa->align);
|
||||
}
|
||||
|
||||
void bswap_segcmd(struct segment_command *sc)
|
||||
{
|
||||
bswap32s((uint32_t*)&sc->vmaddr);
|
||||
bswap32s((uint32_t*)&sc->vmsize);
|
||||
bswap32s((uint32_t*)&sc->fileoff);
|
||||
bswap32s((uint32_t*)&sc->filesize);
|
||||
bswap32s((uint32_t*)&sc->maxprot);
|
||||
bswap32s((uint32_t*)&sc->initprot);
|
||||
bswap32s((uint32_t*)&sc->nsects);
|
||||
bswap32s((uint32_t*)&sc->flags);
|
||||
}
|
||||
|
||||
void bswap_symtabcmd(struct symtab_command *stc)
|
||||
{
|
||||
bswap32s((uint32_t*)&stc->cmd);
|
||||
bswap32s((uint32_t*)&stc->cmdsize);
|
||||
bswap32s((uint32_t*)&stc->symoff);
|
||||
bswap32s((uint32_t*)&stc->nsyms);
|
||||
bswap32s((uint32_t*)&stc->stroff);
|
||||
bswap32s((uint32_t*)&stc->strsize);
|
||||
}
|
||||
|
||||
void bswap_sym(struct nlist *n)
|
||||
{
|
||||
bswap32s((uint32_t*)&n->n_un.n_strx);
|
||||
bswap16s((uint16_t*)&n->n_desc);
|
||||
bswap32s((uint32_t*)&n->n_value);
|
||||
}
|
||||
|
||||
int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap)
|
||||
{
|
||||
int entry;
|
||||
if(need_bswap)
|
||||
bswap_tc(tc);
|
||||
#if defined(TARGET_I386)
|
||||
entry = tc->state.eip;
|
||||
DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n",
|
||||
tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp,
|
||||
tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es,
|
||||
tc->state.fs, tc->state.gs );
|
||||
#define reg_copy(reg) regs->reg = tc->state.reg
|
||||
if(regs)
|
||||
{
|
||||
reg_copy(eax);
|
||||
reg_copy(ebx);
|
||||
reg_copy(ecx);
|
||||
reg_copy(edx);
|
||||
|
||||
reg_copy(edi);
|
||||
reg_copy(esi);
|
||||
|
||||
reg_copy(ebp);
|
||||
reg_copy(esp);
|
||||
|
||||
reg_copy(eflags);
|
||||
reg_copy(eip);
|
||||
/*
|
||||
reg_copy(ss);
|
||||
reg_copy(cs);
|
||||
reg_copy(ds);
|
||||
reg_copy(es);
|
||||
reg_copy(fs);
|
||||
reg_copy(gs);*/
|
||||
}
|
||||
#undef reg_copy
|
||||
#elif defined(TARGET_PPC)
|
||||
entry = tc->state.srr0;
|
||||
#endif
|
||||
DPRINTF("load_thread: entry 0x%x\n", entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap)
|
||||
{
|
||||
int size;
|
||||
char * dylinker_name;
|
||||
size = dc->cmdsize - sizeof(struct dylinker_command);
|
||||
|
||||
if(need_bswap)
|
||||
dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc);
|
||||
else
|
||||
dylinker_name = (char*)((dc->name.offset)+(int)dc);
|
||||
|
||||
#ifdef OVERRIDE_DYLINKER
|
||||
dylinker_name = DYLINKER_NAME;
|
||||
#else
|
||||
if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1)
|
||||
qerror("can't allocate the new dylinker name\n");
|
||||
#endif
|
||||
|
||||
DPRINTF("dylinker_name %s\n", dylinker_name);
|
||||
return load_object(dylinker_name, NULL, NULL);
|
||||
}
|
||||
|
||||
int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide)
|
||||
{
|
||||
unsigned long addr = sc->vmaddr;
|
||||
unsigned long size = sc->filesize;
|
||||
unsigned long error = 0;
|
||||
|
||||
if(need_bswap)
|
||||
bswap_segcmd(sc);
|
||||
|
||||
if(sc->vmaddr == 0)
|
||||
{
|
||||
DPRINTF("load_segment: sc->vmaddr == 0 returning\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(sc->segname, "__PAGEZERO") == 0)
|
||||
{
|
||||
DPRINTF("load_segment: __PAGEZERO returning\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Right now mmap memory */
|
||||
/* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */
|
||||
DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide);
|
||||
|
||||
if(sc->filesize > 0)
|
||||
{
|
||||
int opt = 0;
|
||||
|
||||
if(fixed)
|
||||
opt |= MAP_FIXED;
|
||||
|
||||
DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide);
|
||||
|
||||
addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff);
|
||||
|
||||
if(addr==-1)
|
||||
qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
|
||||
|
||||
error = addr-sc->vmaddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = sc->vmaddr+slide;
|
||||
error = slide;
|
||||
}
|
||||
|
||||
if(sc->vmsize > sc->filesize)
|
||||
{
|
||||
addr += sc->filesize;
|
||||
size = sc->vmsize-sc->filesize;
|
||||
addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
if(addr==-1)
|
||||
qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void *load_data(int fd, long offset, unsigned int size)
|
||||
{
|
||||
char *data;
|
||||
|
||||
data = malloc(size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
if (read(fd, data, size) != size) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/* load a mach-o object file */
|
||||
int load_object(const char *filename, struct target_pt_regs * regs, void ** mh)
|
||||
{
|
||||
int need_bswap = 0;
|
||||
int entry_point = 0;
|
||||
int dyld_entry_point = 0;
|
||||
int slide, mmapfixed;
|
||||
int fd;
|
||||
struct load_command *lcmds, *lc;
|
||||
int is_fat = 0;
|
||||
unsigned int i, magic;
|
||||
int mach_hdr_pos = 0;
|
||||
struct mach_header mach_hdr;
|
||||
|
||||
/* for symbol lookup whith -d flag. */
|
||||
struct symtab_command * symtabcmd = 0;
|
||||
struct nlist_extended *symtab, *sym;
|
||||
struct nlist *symtab_std, *syment;
|
||||
char *strtab;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
qerror("can't open file '%s'", filename);
|
||||
|
||||
/* Read magic header. */
|
||||
if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
|
||||
qerror("unable to read Magic of '%s'", filename);
|
||||
|
||||
/* Check Mach identification. */
|
||||
if(magic == MH_MAGIC)
|
||||
{
|
||||
is_fat = 0;
|
||||
need_bswap = 0;
|
||||
} else if (magic == MH_CIGAM)
|
||||
{
|
||||
is_fat = 0;
|
||||
need_bswap = 1;
|
||||
} else if (magic == FAT_MAGIC)
|
||||
{
|
||||
is_fat = 1;
|
||||
need_bswap = 0;
|
||||
} else if (magic == FAT_CIGAM)
|
||||
{
|
||||
is_fat = 1;
|
||||
need_bswap = 1;
|
||||
}
|
||||
else
|
||||
qerror("Not a Mach-O file.", filename);
|
||||
|
||||
DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]");
|
||||
if(is_fat)
|
||||
{
|
||||
int found = 0;
|
||||
struct fat_header fh;
|
||||
struct fat_arch *fa;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
/* Read Fat header. */
|
||||
if (read(fd, &fh, sizeof (fh)) != sizeof (fh))
|
||||
qerror("unable to read file header");
|
||||
|
||||
if(need_bswap)
|
||||
bswap_fh(&fh);
|
||||
|
||||
/* Read Fat Arch. */
|
||||
fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch);
|
||||
|
||||
if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch)
|
||||
qerror("unable to read file header");
|
||||
|
||||
for( i = 0; i < fh.nfat_arch; i++, fa++)
|
||||
{
|
||||
if(need_bswap)
|
||||
bswap_fa(fa);
|
||||
if(fa->cputype == TARGET_CPU_TYPE)
|
||||
{
|
||||
mach_hdr_pos = fa->offset;
|
||||
lseek(fd, mach_hdr_pos, SEEK_SET);
|
||||
|
||||
/* Read Mach header. */
|
||||
|
||||
if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header))
|
||||
qerror("unable to read file header");
|
||||
|
||||
if(mach_hdr.magic == MH_MAGIC)
|
||||
need_bswap = 0;
|
||||
else if (mach_hdr.magic == MH_CIGAM)
|
||||
need_bswap = 1;
|
||||
else
|
||||
qerror("Invalid mach header in Fat Mach-O File");
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
/* Read Mach header */
|
||||
if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
|
||||
qerror("%s: unable to read file header", filename);
|
||||
}
|
||||
|
||||
if(need_bswap)
|
||||
bswap_mh(&mach_hdr);
|
||||
|
||||
if ((mach_hdr.cputype) != TARGET_CPU_TYPE)
|
||||
qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME);
|
||||
|
||||
|
||||
switch(mach_hdr.filetype)
|
||||
{
|
||||
case MH_EXECUTE: break;
|
||||
case MH_FVMLIB:
|
||||
case MH_DYLIB:
|
||||
case MH_DYLINKER: break;
|
||||
default:
|
||||
qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype);
|
||||
}
|
||||
|
||||
/* read segment headers */
|
||||
lcmds = malloc(mach_hdr.sizeofcmds);
|
||||
|
||||
if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds)
|
||||
qerror("%s: unable to read load_command", filename);
|
||||
slide = 0;
|
||||
mmapfixed = 0;
|
||||
for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++)
|
||||
{
|
||||
|
||||
if(need_bswap)
|
||||
bswap_lc(lc);
|
||||
switch(lc->cmd)
|
||||
{
|
||||
case LC_SEGMENT:
|
||||
/* The main_exe can't be relocated */
|
||||
if(mach_hdr.filetype == MH_EXECUTE)
|
||||
mmapfixed = 1;
|
||||
|
||||
slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide);
|
||||
|
||||
/* other segment must be mapped according to slide exactly, if load_segment did something */
|
||||
if(slide != -1)
|
||||
mmapfixed = 1;
|
||||
else
|
||||
slide = 0; /* load_segment didn't map the segment */
|
||||
|
||||
if(mach_hdr.filetype == MH_EXECUTE && slide != 0)
|
||||
qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide);
|
||||
|
||||
if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0)
|
||||
{
|
||||
/* Text section */
|
||||
if(mach_hdr.filetype == MH_EXECUTE)
|
||||
{
|
||||
/* return the mach_header */
|
||||
*mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it is dyld save the section for gdb, we will be interested in dyld symbol
|
||||
while debuging */
|
||||
macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
|
||||
macho_offset = slide;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LC_LOAD_DYLINKER:
|
||||
dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap );
|
||||
break;
|
||||
case LC_LOAD_DYLIB:
|
||||
/* dyld will do that for us */
|
||||
break;
|
||||
case LC_THREAD:
|
||||
case LC_UNIXTHREAD:
|
||||
{
|
||||
struct target_pt_regs * _regs;
|
||||
if(mach_hdr.filetype == MH_DYLINKER)
|
||||
_regs = regs;
|
||||
else
|
||||
_regs = 0;
|
||||
entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap );
|
||||
}
|
||||
break;
|
||||
case LC_SYMTAB:
|
||||
/* Save the symtab and strtab */
|
||||
symtabcmd = (struct symtab_command *)lc;
|
||||
break;
|
||||
case LC_ID_DYLINKER:
|
||||
case LC_ID_DYLIB:
|
||||
case LC_UUID:
|
||||
case LC_DYSYMTAB:
|
||||
case LC_TWOLEVEL_HINTS:
|
||||
case LC_PREBIND_CKSUM:
|
||||
case LC_SUB_LIBRARY:
|
||||
break;
|
||||
default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename);
|
||||
}
|
||||
lc = (struct load_command*)((int)(lc)+(lc->cmdsize));
|
||||
}
|
||||
|
||||
if(symtabcmd)
|
||||
{
|
||||
if(need_bswap)
|
||||
bswap_symtabcmd(symtabcmd);
|
||||
|
||||
symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist));
|
||||
strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize);
|
||||
|
||||
symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms);
|
||||
|
||||
if(need_bswap)
|
||||
{
|
||||
for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++)
|
||||
bswap_sym(syment);
|
||||
}
|
||||
|
||||
for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++)
|
||||
{
|
||||
struct nlist *sym_follow, *sym_next = 0;
|
||||
unsigned int j;
|
||||
memset(sym, 0, sizeof(*sym));
|
||||
|
||||
sym->n_type = syment->n_type;
|
||||
if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
|
||||
continue;
|
||||
|
||||
memcpy(sym, syment, sizeof(*syment));
|
||||
|
||||
/* Find the following symbol in order to get the current symbol size */
|
||||
for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) {
|
||||
if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
|
||||
continue;
|
||||
if(!sym_next) {
|
||||
sym_next = sym_follow;
|
||||
continue;
|
||||
}
|
||||
if(!(sym_next->n_value > sym_follow->n_value))
|
||||
continue;
|
||||
sym_next = sym_follow;
|
||||
}
|
||||
if(sym_next)
|
||||
sym->st_size = sym_next->n_value - sym->st_value;
|
||||
else
|
||||
sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */
|
||||
|
||||
sym->st_value += slide;
|
||||
}
|
||||
|
||||
free((void*)symtab_std);
|
||||
|
||||
{
|
||||
DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms);
|
||||
struct syminfo *s;
|
||||
s = malloc(sizeof(*s));
|
||||
s->disas_symtab = symtab;
|
||||
s->disas_strtab = strtab;
|
||||
s->disas_num_syms = symtabcmd->nsyms;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point)
|
||||
return dyld_entry_point;
|
||||
else
|
||||
return entry_point+slide;
|
||||
}
|
||||
|
||||
extern unsigned long stack_size;
|
||||
|
||||
unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
|
||||
{
|
||||
unsigned long stack_base, error, size;
|
||||
int i;
|
||||
int * stack;
|
||||
int argc, envc;
|
||||
|
||||
/* Create enough stack to hold everything. If we don't use
|
||||
* it for args, we'll use it for something else...
|
||||
*/
|
||||
size = stack_size;
|
||||
|
||||
error = target_mmap(0,
|
||||
size + qemu_host_page_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (error == -1)
|
||||
qerror("stk mmap");
|
||||
|
||||
/* we reserve one extra page at the top of the stack as guard */
|
||||
target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
|
||||
|
||||
stack_base = error + size;
|
||||
stack = (void*)stack_base;
|
||||
/*
|
||||
* | STRING AREA |
|
||||
* +-------------+
|
||||
* | 0 |
|
||||
* +-------------+
|
||||
* | apple[n] |
|
||||
* +-------------+
|
||||
* :
|
||||
* +-------------+
|
||||
* | apple[0] |
|
||||
* +-------------+
|
||||
* | 0 |
|
||||
* +-------------+
|
||||
* | env[n] |
|
||||
* +-------------+
|
||||
* :
|
||||
* :
|
||||
* +-------------+
|
||||
* | env[0] |
|
||||
* +-------------+
|
||||
* | 0 |
|
||||
* +-------------+
|
||||
* | arg[argc-1] |
|
||||
* +-------------+
|
||||
* :
|
||||
* :
|
||||
* +-------------+
|
||||
* | arg[0] |
|
||||
* +-------------+
|
||||
* | argc |
|
||||
* +-------------+
|
||||
* sp-> | mh | address of where the a.out's file offset 0 is in memory
|
||||
* +-------------+
|
||||
*/
|
||||
/* Construct the stack Stack grows down */
|
||||
stack--;
|
||||
|
||||
/* XXX: string should go up there */
|
||||
|
||||
*stack = 0;
|
||||
stack--;
|
||||
|
||||
/* Push the absolute path of our executable */
|
||||
DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]);
|
||||
stl(stack, (int) argv[0]);
|
||||
|
||||
stack--;
|
||||
|
||||
stl(stack, 0);
|
||||
stack--;
|
||||
|
||||
/* Get envc */
|
||||
for(envc = 0; env[envc]; envc++);
|
||||
|
||||
for(i = envc-1; i >= 0; i--)
|
||||
{
|
||||
DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]);
|
||||
stl(stack, (int)env[i]);
|
||||
stack--;
|
||||
|
||||
/* XXX: remove that when string will be on top of the stack */
|
||||
page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID);
|
||||
}
|
||||
|
||||
/* Add on the stack the interp_prefix choosen if so */
|
||||
if(interp_prefix[0])
|
||||
{
|
||||
char *dyld_root;
|
||||
asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix);
|
||||
page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID);
|
||||
|
||||
stl(stack, (int)dyld_root);
|
||||
stack--;
|
||||
}
|
||||
|
||||
#ifdef DONT_USE_DYLD_SHARED_MAP
|
||||
{
|
||||
char *shared_map_mode;
|
||||
asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid");
|
||||
page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID);
|
||||
|
||||
stl(stack, (int)shared_map_mode);
|
||||
stack--;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ACTIVATE_DYLD_TRACE
|
||||
char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes",
|
||||
"DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes",
|
||||
"DYLD_PRINT_INITIALIZERS=yes",
|
||||
"DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" };
|
||||
|
||||
char ** extra_env = malloc(sizeof(extra_env_static));
|
||||
bcopy(extra_env_static, extra_env, sizeof(extra_env_static));
|
||||
page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID);
|
||||
|
||||
for(i = 0; i<9; i++)
|
||||
{
|
||||
DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]);
|
||||
stl(stack, (int) extra_env[i]);
|
||||
stack--;
|
||||
}
|
||||
#endif
|
||||
|
||||
stl(stack, 0);
|
||||
stack--;
|
||||
|
||||
/* Get argc */
|
||||
for(argc = 0; argv[argc]; argc++);
|
||||
|
||||
for(i = argc-1; i >= 0; i--)
|
||||
{
|
||||
DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]);
|
||||
stl(stack, (int) argv[i]);
|
||||
stack--;
|
||||
|
||||
/* XXX: remove that when string will be on top of the stack */
|
||||
page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
|
||||
}
|
||||
|
||||
DPRINTF("pushing argc %d \n", argc);
|
||||
stl(stack, argc);
|
||||
stack--;
|
||||
|
||||
DPRINTF("pushing mh 0x%x \n", (int)mh);
|
||||
stl(stack, (int) mh);
|
||||
|
||||
/* Stack points on the mh */
|
||||
return (unsigned long)stack;
|
||||
}
|
||||
|
||||
int mach_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs)
|
||||
{
|
||||
int entrypoint, stack;
|
||||
void * mh; /* the Mach Header that will be used by dyld */
|
||||
|
||||
DPRINTF("mach_exec at 0x%x\n", (int)mach_exec);
|
||||
|
||||
entrypoint = load_object(filename, regs, &mh);
|
||||
stack = setup_arg_pages(mh, argv, envp);
|
||||
#if defined(TARGET_I386)
|
||||
regs->eip = entrypoint;
|
||||
regs->esp = stack;
|
||||
#elif defined(TARGET_PPC)
|
||||
regs->nip = entrypoint;
|
||||
regs->gpr[1] = stack;
|
||||
#endif
|
||||
DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh);
|
||||
|
||||
if(!entrypoint)
|
||||
qerror("%s: no entry point!\n", filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,918 @@
|
||||
/*
|
||||
* qemu user main
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2006 Pierre d'Herbemont
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
#define DEBUG_LOGFILE "/tmp/qemu.log"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
#endif
|
||||
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/vm_map.h>
|
||||
|
||||
const char *interp_prefix = "";
|
||||
|
||||
asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000");
|
||||
|
||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||
we allocate a bigger stack. Need a better solution, for example
|
||||
by remapping the process stack directly at the right place */
|
||||
unsigned long stack_size = 512 * 1024;
|
||||
|
||||
void qerror(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void gemu_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void cpu_outb(CPUState *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
|
||||
}
|
||||
|
||||
void cpu_outw(CPUState *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
|
||||
}
|
||||
|
||||
void cpu_outl(CPUState *env, int addr, int val)
|
||||
{
|
||||
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
|
||||
}
|
||||
|
||||
int cpu_inb(CPUState *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inb: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_inw(CPUState *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inw: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_inl(CPUState *env, int addr)
|
||||
{
|
||||
fprintf(stderr, "inl: port=0x%04x\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_get_pic_interrupt(CPUState *env)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#ifdef TARGET_PPC
|
||||
|
||||
static inline uint64_t cpu_ppc_get_tb (CPUState *env)
|
||||
{
|
||||
/* TO FIX */
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc_load_tbl (CPUState *env)
|
||||
{
|
||||
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc_load_tbu (CPUState *env)
|
||||
{
|
||||
return cpu_ppc_get_tb(env) >> 32;
|
||||
}
|
||||
|
||||
static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
|
||||
{
|
||||
/* TO FIX */
|
||||
}
|
||||
|
||||
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
|
||||
}
|
||||
|
||||
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
|
||||
}
|
||||
|
||||
uint32_t cpu_ppc_load_decr (CPUState *env)
|
||||
{
|
||||
/* TO FIX */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
|
||||
{
|
||||
/* TO FIX */
|
||||
}
|
||||
|
||||
void cpu_loop(CPUPPCState *env)
|
||||
{
|
||||
int trapnr;
|
||||
uint32_t ret;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_ppc_exec(env);
|
||||
if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
|
||||
trapnr != EXCP_TRACE) {
|
||||
if (loglevel > 0) {
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
}
|
||||
}
|
||||
switch(trapnr) {
|
||||
case EXCP_NONE:
|
||||
break;
|
||||
case EXCP_SYSCALL_USER:
|
||||
/* system call */
|
||||
if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
|
||||
ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
|
||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||
env->gpr[8], env->gpr[9], env->gpr[10]*/);
|
||||
else if(((int)env->gpr[0])<0)
|
||||
ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||
env->gpr[8], env->gpr[9], env->gpr[10]);
|
||||
else
|
||||
ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||
env->gpr[8], env->gpr[9], env->gpr[10]);
|
||||
|
||||
/* Unix syscall error signaling */
|
||||
if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
|
||||
{
|
||||
if( (int)ret < 0 )
|
||||
env->nip += 0;
|
||||
else
|
||||
env->nip += 4;
|
||||
}
|
||||
|
||||
/* Return value */
|
||||
env->gpr[3] = ret;
|
||||
break;
|
||||
case EXCP_RESET:
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "RESET asked... Stop emulation\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "RESET asked... Stop emulation\n");
|
||||
abort();
|
||||
case EXCP_MACHINE_CHECK:
|
||||
fprintf(stderr, "Machine check exeption... Stop emulation\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "RESET asked... Stop emulation\n");
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = BUS_OBJERR;
|
||||
info.si_addr = (void*)(env->nip - 4);
|
||||
queue_signal(info.si_signo, &info);
|
||||
case EXCP_DSI:
|
||||
#ifndef DAR
|
||||
/* To deal with multiple qemu header version as host for the darwin-user code */
|
||||
# define DAR SPR_DAR
|
||||
#endif
|
||||
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
|
||||
env->spr[DAR]);
|
||||
}
|
||||
/* Handle this via the gdb */
|
||||
gdb_handlesig (env, SIGSEGV);
|
||||
|
||||
info.si_addr = (void*)env->nip;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_ISI:
|
||||
fprintf(stderr, "Invalid instruction fetch\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Invalid instruction fetch\n");
|
||||
/* Handle this via the gdb */
|
||||
gdb_handlesig (env, SIGSEGV);
|
||||
|
||||
info.si_addr = (void*)(env->nip - 4);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_EXTERNAL:
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "External interruption... Stop emulation\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "External interruption... Stop emulation\n");
|
||||
abort();
|
||||
case EXCP_ALIGN:
|
||||
fprintf(stderr, "Invalid unaligned memory access\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Invalid unaligned memory access\n");
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = BUS_ADRALN;
|
||||
info.si_addr = (void*)(env->nip - 4);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_PROGRAM:
|
||||
switch (env->error_code & ~0xF) {
|
||||
case EXCP_FP:
|
||||
fprintf(stderr, "Program exception\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Program exception\n");
|
||||
/* Set FX */
|
||||
env->fpscr[7] |= 0x8;
|
||||
/* Finally, update FEX */
|
||||
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
|
||||
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
|
||||
env->fpscr[7] |= 0x4;
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
case EXCP_FP_OX:
|
||||
info.si_code = FPE_FLTOVF;
|
||||
break;
|
||||
case EXCP_FP_UX:
|
||||
info.si_code = FPE_FLTUND;
|
||||
break;
|
||||
case EXCP_FP_ZX:
|
||||
case EXCP_FP_VXZDZ:
|
||||
info.si_code = FPE_FLTDIV;
|
||||
break;
|
||||
case EXCP_FP_XX:
|
||||
info.si_code = FPE_FLTRES;
|
||||
break;
|
||||
case EXCP_FP_VXSOFT:
|
||||
info.si_code = FPE_FLTINV;
|
||||
break;
|
||||
case EXCP_FP_VXNAN:
|
||||
case EXCP_FP_VXISI:
|
||||
case EXCP_FP_VXIDI:
|
||||
case EXCP_FP_VXIMZ:
|
||||
case EXCP_FP_VXVC:
|
||||
case EXCP_FP_VXSQRT:
|
||||
case EXCP_FP_VXCVI:
|
||||
info.si_code = FPE_FLTSUB;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown floating point exception "
|
||||
"(%02x)\n", env->error_code);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Unknown floating point exception "
|
||||
"(%02x)\n", env->error_code & 0xF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_INVAL:
|
||||
fprintf(stderr, "Invalid instruction\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Invalid instruction\n");
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
case EXCP_INVAL_INVAL:
|
||||
info.si_code = ILL_ILLOPC;
|
||||
break;
|
||||
case EXCP_INVAL_LSWX:
|
||||
info.si_code = ILL_ILLOPN;
|
||||
break;
|
||||
case EXCP_INVAL_SPR:
|
||||
info.si_code = ILL_PRVREG;
|
||||
break;
|
||||
case EXCP_INVAL_FP:
|
||||
info.si_code = ILL_COPROC;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown invalid operation (%02x)\n",
|
||||
env->error_code & 0xF);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Unknown invalid operation (%02x)\n",
|
||||
env->error_code & 0xF);
|
||||
}
|
||||
info.si_code = ILL_ILLADR;
|
||||
break;
|
||||
}
|
||||
/* Handle this via the gdb */
|
||||
gdb_handlesig (env, SIGSEGV);
|
||||
break;
|
||||
case EXCP_PRIV:
|
||||
fprintf(stderr, "Privilege violation\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Privilege violation\n");
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
case EXCP_PRIV_OPC:
|
||||
info.si_code = ILL_PRVOPC;
|
||||
break;
|
||||
case EXCP_PRIV_REG:
|
||||
info.si_code = ILL_PRVREG;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown privilege violation (%02x)\n",
|
||||
env->error_code & 0xF);
|
||||
info.si_code = ILL_PRVOPC;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EXCP_TRAP:
|
||||
fprintf(stderr, "Tried to call a TRAP\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Tried to call a TRAP\n");
|
||||
abort();
|
||||
default:
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "Unknown program exception (%02x)\n",
|
||||
env->error_code);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Unknwon program exception (%02x)\n",
|
||||
env->error_code);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
info.si_addr = (void*)(env->nip - 4);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_NO_FP:
|
||||
fprintf(stderr, "No floating point allowed\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "No floating point allowed\n");
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = ILL_COPROC;
|
||||
info.si_addr = (void*)(env->nip - 4);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_DECR:
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "Decrementer exception\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Decrementer exception\n");
|
||||
abort();
|
||||
case EXCP_TRACE:
|
||||
/* Pass to gdb: we use this to trace execution */
|
||||
gdb_handlesig (env, SIGTRAP);
|
||||
break;
|
||||
case EXCP_FP_ASSIST:
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "Floating point assist exception\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Floating point assist exception\n");
|
||||
abort();
|
||||
case EXCP_MTMSR:
|
||||
/* We reloaded the msr, just go on */
|
||||
if (msr_pr == 0) {
|
||||
fprintf(stderr, "Tried to go into supervisor mode !\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Tried to go into supervisor mode !\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case EXCP_BRANCH:
|
||||
/* We stopped because of a jump... */
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* Don't know why this should ever happen... */
|
||||
fprintf(stderr, "EXCP_INTERRUPT\n");
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
gdb_handlesig (env, SIGTRAP);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
|
||||
"0x%02x - aborting\n", trapnr, env->error_code);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
uint64_t cpu_get_tsc(CPUX86State *env)
|
||||
{
|
||||
return cpu_get_real_ticks();
|
||||
}
|
||||
|
||||
void
|
||||
write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
||||
int flags)
|
||||
{
|
||||
unsigned int e1, e2;
|
||||
e1 = (addr << 16) | (limit & 0xffff);
|
||||
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
|
||||
e2 |= flags;
|
||||
stl((uint8_t *)ptr, e1);
|
||||
stl((uint8_t *)ptr + 4, e2);
|
||||
}
|
||||
|
||||
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
|
||||
unsigned long addr, unsigned int sel)
|
||||
{
|
||||
unsigned int e1, e2;
|
||||
e1 = (addr & 0xffff) | (sel << 16);
|
||||
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
|
||||
stl((uint8_t *)ptr, e1);
|
||||
stl((uint8_t *)ptr + 4, e2);
|
||||
}
|
||||
|
||||
#define GDT_TABLE_SIZE 14
|
||||
#define LDT_TABLE_SIZE 15
|
||||
#define IDT_TABLE_SIZE 256
|
||||
#define TSS_SIZE 104
|
||||
uint64_t gdt_table[GDT_TABLE_SIZE];
|
||||
uint64_t ldt_table[LDT_TABLE_SIZE];
|
||||
uint64_t idt_table[IDT_TABLE_SIZE];
|
||||
uint32_t tss[TSS_SIZE];
|
||||
|
||||
/* only dpl matters as we do only user space emulation */
|
||||
static void set_idt(int n, unsigned int dpl)
|
||||
{
|
||||
set_gate(idt_table + n, 0, dpl, 0, 0);
|
||||
}
|
||||
|
||||
/* ABI convention: after a syscall if there was an error the CF flag is set */
|
||||
static inline void set_error(CPUX86State *env, int ret)
|
||||
{
|
||||
if(ret<0)
|
||||
env->eflags = env->eflags | 0x1;
|
||||
else
|
||||
env->eflags &= ~0x1;
|
||||
env->regs[R_EAX] = ret;
|
||||
}
|
||||
|
||||
void cpu_loop(CPUX86State *env)
|
||||
{
|
||||
int trapnr;
|
||||
int ret;
|
||||
uint8_t *pc;
|
||||
target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_x86_exec(env);
|
||||
uint32_t *params = (uint32_t *)env->regs[R_ESP];
|
||||
switch(trapnr) {
|
||||
case 0x79: /* Our commpage hack back door exit is here */
|
||||
do_commpage(env, env->eip, *(params + 1), *(params + 2),
|
||||
*(params + 3), *(params + 4),
|
||||
*(params + 5), *(params + 6),
|
||||
*(params + 7), *(params + 8));
|
||||
break;
|
||||
case 0x81: /* mach syscall */
|
||||
{
|
||||
ret = do_mach_syscall(env, env->regs[R_EAX],
|
||||
*(params + 1), *(params + 2),
|
||||
*(params + 3), *(params + 4),
|
||||
*(params + 5), *(params + 6),
|
||||
*(params + 7), *(params + 8));
|
||||
set_error(env, ret);
|
||||
break;
|
||||
}
|
||||
case 0x90: /* unix backdoor */
|
||||
{
|
||||
/* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/
|
||||
int saved_stack = env->regs[R_ESP];
|
||||
env->regs[R_ESP] = env->regs[R_ECX];
|
||||
|
||||
ret = do_unix_syscall(env, env->regs[R_EAX]);
|
||||
|
||||
env->regs[R_ECX] = env->regs[R_ESP];
|
||||
env->regs[R_ESP] = saved_stack;
|
||||
|
||||
set_error(env, ret);
|
||||
break;
|
||||
}
|
||||
case 0x80: /* unix syscall */
|
||||
{
|
||||
ret = do_unix_syscall(env, env->regs[R_EAX]/*,
|
||||
*(params + 1), *(params + 2),
|
||||
*(params + 3), *(params + 4),
|
||||
*(params + 5), *(params + 6),
|
||||
*(params + 7), *(params + 8)*/);
|
||||
set_error(env, ret);
|
||||
break;
|
||||
}
|
||||
case 0x82: /* thread syscall */
|
||||
{
|
||||
ret = do_thread_syscall(env, env->regs[R_EAX],
|
||||
*(params + 1), *(params + 2),
|
||||
*(params + 3), *(params + 4),
|
||||
*(params + 5), *(params + 6),
|
||||
*(params + 7), *(params + 8));
|
||||
set_error(env, ret);
|
||||
break;
|
||||
}
|
||||
case EXCP0B_NOSEG:
|
||||
case EXCP0C_STACK:
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = BUS_NOOP;
|
||||
info.si_addr = 0;
|
||||
gdb_handlesig (env, SIGBUS);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP0D_GPF:
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = SEGV_NOOP;
|
||||
info.si_addr = 0;
|
||||
gdb_handlesig (env, SIGSEGV);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP0E_PAGE:
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
if (!(env->error_code & 1))
|
||||
info.si_code = SEGV_MAPERR;
|
||||
else
|
||||
info.si_code = SEGV_ACCERR;
|
||||
info.si_addr = (void*)env->cr[2];
|
||||
gdb_handlesig (env, SIGSEGV);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP00_DIVZ:
|
||||
/* division by zero */
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_code = FPE_INTDIV;
|
||||
info.si_addr = (void*)env->eip;
|
||||
gdb_handlesig (env, SIGFPE);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP01_SSTP:
|
||||
case EXCP03_INT3:
|
||||
info.si_signo = SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TRAP_BRKPT;
|
||||
info.si_addr = (void*)env->eip;
|
||||
gdb_handlesig (env, SIGTRAP);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP04_INTO:
|
||||
case EXCP05_BOUND:
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = SEGV_NOOP;
|
||||
info.si_addr = 0;
|
||||
gdb_handlesig (env, SIGSEGV);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP06_ILLOP:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = ILL_ILLOPN;
|
||||
info.si_addr = (void*)env->eip;
|
||||
gdb_handlesig (env, SIGILL);
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
int sig;
|
||||
|
||||
sig = gdb_handlesig (env, SIGTRAP);
|
||||
if (sig)
|
||||
{
|
||||
info.si_signo = sig;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TRAP_BRKPT;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pc = (void*)(env->segs[R_CS].base + env->eip);
|
||||
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
||||
(long)pc, trapnr);
|
||||
abort();
|
||||
}
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
||||
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
||||
"Darwin CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
"-L path set the %s library path (default='%s')\n"
|
||||
"-s size set the stack size in bytes (default=%ld)\n"
|
||||
"\n"
|
||||
"debug options:\n"
|
||||
#ifdef USE_CODE_COPY
|
||||
"-no-code-copy disable code copy acceleration\n"
|
||||
#endif
|
||||
"-d options activate log (logfile='%s')\n"
|
||||
"-g wait for gdb on port 1234\n"
|
||||
"-p pagesize set the host page size to 'pagesize'\n",
|
||||
TARGET_ARCH,
|
||||
TARGET_ARCH,
|
||||
interp_prefix,
|
||||
stack_size,
|
||||
DEBUG_LOGFILE);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* XXX: currently only used for async signals (see signal.c) */
|
||||
CPUState *global_env;
|
||||
/* used only if single thread */
|
||||
CPUState *cpu_single_env = NULL;
|
||||
|
||||
/* used to free thread contexts */
|
||||
TaskState *first_task_state;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *filename;
|
||||
struct target_pt_regs regs1, *regs = ®s1;
|
||||
TaskState ts1, *ts = &ts1;
|
||||
CPUState *env;
|
||||
int optind;
|
||||
short use_gdbstub = 0;
|
||||
const char *r;
|
||||
|
||||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
/* init debug */
|
||||
cpu_set_log_filename(DEBUG_LOGFILE);
|
||||
|
||||
optind = 1;
|
||||
for(;;) {
|
||||
if (optind >= argc)
|
||||
break;
|
||||
r = argv[optind];
|
||||
if (r[0] != '-')
|
||||
break;
|
||||
optind++;
|
||||
r++;
|
||||
if (!strcmp(r, "-")) {
|
||||
break;
|
||||
} else if (!strcmp(r, "d")) {
|
||||
int mask;
|
||||
CPULogItem *item;
|
||||
|
||||
if (optind >= argc)
|
||||
break;
|
||||
|
||||
r = argv[optind++];
|
||||
mask = cpu_str_to_log_mask(r);
|
||||
if (!mask) {
|
||||
printf("Log items (comma separated):\n");
|
||||
for(item = cpu_log_items; item->mask != 0; item++) {
|
||||
printf("%-10s %s\n", item->name, item->help);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
cpu_set_log(mask);
|
||||
} else if (!strcmp(r, "s")) {
|
||||
r = argv[optind++];
|
||||
stack_size = strtol(r, (char **)&r, 0);
|
||||
if (stack_size <= 0)
|
||||
usage();
|
||||
if (*r == 'M')
|
||||
stack_size *= 1024 * 1024;
|
||||
else if (*r == 'k' || *r == 'K')
|
||||
stack_size *= 1024;
|
||||
} else if (!strcmp(r, "L")) {
|
||||
interp_prefix = argv[optind++];
|
||||
} else if (!strcmp(r, "p")) {
|
||||
qemu_host_page_size = atoi(argv[optind++]);
|
||||
if (qemu_host_page_size == 0 ||
|
||||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
|
||||
fprintf(stderr, "page size must be a power of two\n");
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
if (!strcmp(r, "g")) {
|
||||
use_gdbstub = 1;
|
||||
} else
|
||||
#ifdef USE_CODE_COPY
|
||||
if (!strcmp(r, "no-code-copy")) {
|
||||
code_copy_enabled = 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if (optind >= argc)
|
||||
usage();
|
||||
filename = argv[optind];
|
||||
|
||||
/* Zero out regs */
|
||||
memset(regs, 0, sizeof(struct target_pt_regs));
|
||||
|
||||
/* NOTE: we need to init the CPU at this stage to get
|
||||
qemu_host_page_size */
|
||||
env = cpu_init();
|
||||
|
||||
printf("Starting %s with qemu\n----------------\n", filename);
|
||||
|
||||
commpage_init();
|
||||
|
||||
if (mach_exec(filename, argv+optind, environ, regs) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
syscall_init();
|
||||
signal_init();
|
||||
global_env = env;
|
||||
|
||||
/* build Task State */
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
env->opaque = ts;
|
||||
ts->used = 1;
|
||||
env->user_mode_only = 1;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
cpu_x86_set_cpl(env, 3);
|
||||
|
||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||
env->hflags |= HF_PE_MASK;
|
||||
|
||||
if (env->cpuid_features & CPUID_SSE) {
|
||||
env->cr[4] |= CR4_OSFXSR_MASK;
|
||||
env->hflags |= HF_OSFXSR_MASK;
|
||||
}
|
||||
|
||||
/* flags setup : we activate the IRQs by default as in user mode */
|
||||
env->eflags |= IF_MASK;
|
||||
|
||||
/* darwin register setup */
|
||||
env->regs[R_EAX] = regs->eax;
|
||||
env->regs[R_EBX] = regs->ebx;
|
||||
env->regs[R_ECX] = regs->ecx;
|
||||
env->regs[R_EDX] = regs->edx;
|
||||
env->regs[R_ESI] = regs->esi;
|
||||
env->regs[R_EDI] = regs->edi;
|
||||
env->regs[R_EBP] = regs->ebp;
|
||||
env->regs[R_ESP] = regs->esp;
|
||||
env->eip = regs->eip;
|
||||
|
||||
/* Darwin LDT setup */
|
||||
/* 2 - User code segment
|
||||
3 - User data segment
|
||||
4 - User cthread */
|
||||
bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0]));
|
||||
env->ldt.base = (uint32_t) ldt_table;
|
||||
env->ldt.limit = sizeof(ldt_table) - 1;
|
||||
|
||||
write_dt(ldt_table + 2, 0, 0xfffff,
|
||||
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
||||
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
|
||||
write_dt(ldt_table + 3, 0, 0xfffff,
|
||||
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
||||
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
|
||||
write_dt(ldt_table + 4, 0, 0xfffff,
|
||||
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
||||
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
|
||||
|
||||
/* Darwin GDT setup.
|
||||
* has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86,
|
||||
now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */
|
||||
bzero(gdt_table, sizeof(gdt_table));
|
||||
env->gdt.base = (uint32_t)gdt_table;
|
||||
env->gdt.limit = sizeof(gdt_table) - 1;
|
||||
|
||||
/* Set up a back door to handle sysenter syscalls (unix) */
|
||||
char * syscallbackdoor = malloc(64);
|
||||
page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID);
|
||||
|
||||
int i = 0;
|
||||
syscallbackdoor[i++] = 0xcd;
|
||||
syscallbackdoor[i++] = 0x90; /* int 0x90 */
|
||||
syscallbackdoor[i++] = 0x0F;
|
||||
syscallbackdoor[i++] = 0x35; /* sysexit */
|
||||
|
||||
/* Darwin sysenter/sysexit setup */
|
||||
env->sysenter_cs = 0x1; //XXX
|
||||
env->sysenter_eip = (int)syscallbackdoor;
|
||||
env->sysenter_esp = (int)malloc(64);
|
||||
|
||||
/* Darwin TSS setup
|
||||
This must match up with GDT[4] */
|
||||
env->tr.base = (uint32_t) tss;
|
||||
env->tr.limit = sizeof(tss) - 1;
|
||||
env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT);
|
||||
stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment
|
||||
|
||||
/* Darwin interrupt setup */
|
||||
bzero(idt_table, sizeof(idt_table));
|
||||
env->idt.base = (uint32_t) idt_table;
|
||||
env->idt.limit = sizeof(idt_table) - 1;
|
||||
set_idt(0, 0);
|
||||
set_idt(1, 0);
|
||||
set_idt(2, 0);
|
||||
set_idt(3, 3);
|
||||
set_idt(4, 3);
|
||||
set_idt(5, 3);
|
||||
set_idt(6, 0);
|
||||
set_idt(7, 0);
|
||||
set_idt(8, 0);
|
||||
set_idt(9, 0);
|
||||
set_idt(10, 0);
|
||||
set_idt(11, 0);
|
||||
set_idt(12, 0);
|
||||
set_idt(13, 0);
|
||||
set_idt(14, 0);
|
||||
set_idt(15, 0);
|
||||
set_idt(16, 0);
|
||||
set_idt(17, 0);
|
||||
set_idt(18, 0);
|
||||
set_idt(19, 0);
|
||||
/* Syscalls are done via
|
||||
int 0x80 (unix) (rarely used)
|
||||
int 0x81 (mach)
|
||||
int 0x82 (thread)
|
||||
int 0x83 (diag) (not handled here)
|
||||
sysenter/sysexit (unix) -> we redirect that to int 0x90 */
|
||||
set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */
|
||||
set_idt(0x80, 3); /* Unix Syscall */
|
||||
set_idt(0x81, 3); /* Mach Syscalls */
|
||||
set_idt(0x82, 3); /* thread Syscalls */
|
||||
|
||||
set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */
|
||||
|
||||
|
||||
cpu_x86_load_seg(env, R_CS, __USER_CS);
|
||||
cpu_x86_load_seg(env, R_DS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_ES, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_SS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_FS, __USER_DS);
|
||||
cpu_x86_load_seg(env, R_GS, __USER_DS);
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
{
|
||||
int i;
|
||||
env->nip = regs->nip;
|
||||
for(i = 0; i < 32; i++) {
|
||||
env->gpr[i] = regs->gpr[i];
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
|
||||
if (use_gdbstub) {
|
||||
printf("Waiting for gdb Connection on port 1234...\n");
|
||||
gdbserver_start (1234);
|
||||
gdb_handlesig(env, 0);
|
||||
}
|
||||
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* mmap support for qemu
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
//#define DEBUG_MMAP
|
||||
|
||||
/* NOTE: all the constants are the HOST ones */
|
||||
int target_mprotect(unsigned long start, unsigned long len, int prot)
|
||||
{
|
||||
unsigned long end, host_start, host_end, addr;
|
||||
int prot1, ret;
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
|
||||
prot & PROT_READ ? 'r' : '-',
|
||||
prot & PROT_WRITE ? 'w' : '-',
|
||||
prot & PROT_EXEC ? 'x' : '-');
|
||||
#endif
|
||||
|
||||
if ((start & ~TARGET_PAGE_MASK) != 0)
|
||||
return -EINVAL;
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
end = start + len;
|
||||
if (end < start)
|
||||
return -EINVAL;
|
||||
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
return -EINVAL;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
host_start = start & qemu_host_page_mask;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
if (start > host_start) {
|
||||
/* handle host page containing start */
|
||||
prot1 = prot;
|
||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
if (host_end == host_start + qemu_host_page_size) {
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
end = host_end;
|
||||
}
|
||||
ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
host_start += qemu_host_page_size;
|
||||
}
|
||||
if (end < host_end) {
|
||||
prot1 = prot;
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
|
||||
prot1 & PAGE_BITS);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
host_end -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
/* handle the pages in the middle */
|
||||
if (host_start < host_end) {
|
||||
ret = mprotect((void *)host_start, host_end - host_start, prot);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* map an incomplete host page */
|
||||
int mmap_frag(unsigned long host_start,
|
||||
unsigned long start, unsigned long end,
|
||||
int prot, int flags, int fd, unsigned long offset)
|
||||
{
|
||||
unsigned long host_end, ret, addr;
|
||||
int prot1, prot_new;
|
||||
|
||||
host_end = host_start + qemu_host_page_size;
|
||||
|
||||
/* get the protection of the target pages outside the mapping */
|
||||
prot1 = 0;
|
||||
for(addr = host_start; addr < host_end; addr++) {
|
||||
if (addr < start || addr >= end)
|
||||
prot1 |= page_get_flags(addr);
|
||||
}
|
||||
|
||||
if (prot1 == 0) {
|
||||
/* no page was there, so we allocate one */
|
||||
ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
|
||||
flags | MAP_ANONYMOUS, -1, 0);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
}
|
||||
prot1 &= PAGE_BITS;
|
||||
|
||||
prot_new = prot | prot1;
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
/* msync() won't work here, so we return an error if write is
|
||||
possible while it is a shared mapping */
|
||||
#ifndef __APPLE__
|
||||
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
||||
#else
|
||||
if ((flags & MAP_SHARED) &&
|
||||
#endif
|
||||
(prot & PROT_WRITE))
|
||||
return -EINVAL;
|
||||
|
||||
/* adjust protection to be able to read */
|
||||
if (!(prot1 & PROT_WRITE))
|
||||
mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
|
||||
|
||||
/* read the corresponding file data */
|
||||
pread(fd, (void *)start, end - start, offset);
|
||||
|
||||
/* put final protection */
|
||||
if (prot_new != (prot1 | PROT_WRITE))
|
||||
mprotect((void *)host_start, qemu_host_page_size, prot_new);
|
||||
} else {
|
||||
/* just update the protection */
|
||||
if (prot_new != prot1) {
|
||||
mprotect((void *)host_start, qemu_host_page_size, prot_new);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NOTE: all the constants are the HOST ones */
|
||||
long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
int flags, int fd, unsigned long offset)
|
||||
{
|
||||
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
|
||||
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
|
||||
static unsigned long last_start = 0x40000000;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
{
|
||||
printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
|
||||
start, len,
|
||||
prot & PROT_READ ? 'r' : '-',
|
||||
prot & PROT_WRITE ? 'w' : '-',
|
||||
prot & PROT_EXEC ? 'x' : '-');
|
||||
if (flags & MAP_FIXED)
|
||||
printf("MAP_FIXED ");
|
||||
if (flags & MAP_ANONYMOUS)
|
||||
printf("MAP_ANON ");
|
||||
#ifndef MAP_TYPE
|
||||
# define MAP_TYPE 0x3
|
||||
#endif
|
||||
switch(flags & MAP_TYPE) {
|
||||
case MAP_PRIVATE:
|
||||
printf("MAP_PRIVATE ");
|
||||
break;
|
||||
case MAP_SHARED:
|
||||
printf("MAP_SHARED ");
|
||||
break;
|
||||
default:
|
||||
printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
|
||||
break;
|
||||
}
|
||||
printf("fd=%d offset=%lx\n", fd, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (offset & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
if (len == 0)
|
||||
return start;
|
||||
host_start = start & qemu_host_page_mask;
|
||||
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
|
||||
/* tell the kenel to search at the same place as i386 */
|
||||
if (host_start == 0) {
|
||||
host_start = last_start;
|
||||
last_start += HOST_PAGE_ALIGN(len);
|
||||
}
|
||||
#endif
|
||||
if (qemu_host_page_size != qemu_real_host_page_size) {
|
||||
/* NOTE: this code is only for debugging with '-p' option */
|
||||
/* reserve a memory area */
|
||||
host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
|
||||
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (host_start == -1)
|
||||
return host_start;
|
||||
host_end = host_start + host_len;
|
||||
start = HOST_PAGE_ALIGN(host_start);
|
||||
end = start + HOST_PAGE_ALIGN(len);
|
||||
if (start > host_start)
|
||||
munmap((void *)host_start, start - host_start);
|
||||
if (end < host_end)
|
||||
munmap((void *)end, host_end - end);
|
||||
/* use it as a fixed mapping */
|
||||
flags |= MAP_FIXED;
|
||||
} else {
|
||||
/* if not fixed, no need to do anything */
|
||||
host_offset = offset & qemu_host_page_mask;
|
||||
host_len = len + offset - host_offset;
|
||||
start = (long)mmap((void *)host_start, host_len,
|
||||
prot, flags, fd, host_offset);
|
||||
if (start == -1)
|
||||
return start;
|
||||
/* update start so that it points to the file position at 'offset' */
|
||||
if (!(flags & MAP_ANONYMOUS))
|
||||
start += offset - host_offset;
|
||||
goto the_end1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
end = start + len;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
|
||||
/* worst case: we cannot map the file because the offset is not
|
||||
aligned, so we read it */
|
||||
if (!(flags & MAP_ANONYMOUS) &&
|
||||
(offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
|
||||
/* msync() won't work here, so we return an error if write is
|
||||
possible while it is a shared mapping */
|
||||
#ifndef __APPLE__
|
||||
if ((flags & MAP_TYPE) == MAP_SHARED &&
|
||||
#else
|
||||
if ((flags & MAP_SHARED) &&
|
||||
#endif
|
||||
(prot & PROT_WRITE))
|
||||
return -EINVAL;
|
||||
retaddr = target_mmap(start, len, prot | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (retaddr == -1)
|
||||
return retaddr;
|
||||
pread(fd, (void *)start, len, offset);
|
||||
if (!(prot & PROT_WRITE)) {
|
||||
ret = target_mprotect(start, len, prot);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
/* handle the start of the mapping */
|
||||
if (start > host_start) {
|
||||
if (host_end == host_start + qemu_host_page_size) {
|
||||
/* one single host page */
|
||||
ret = mmap_frag(host_start, start, end,
|
||||
prot, flags, fd, offset);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
goto the_end1;
|
||||
}
|
||||
ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
|
||||
prot, flags, fd, offset);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
host_start += qemu_host_page_size;
|
||||
}
|
||||
/* handle the end of the mapping */
|
||||
if (end < host_end) {
|
||||
ret = mmap_frag(host_end - qemu_host_page_size,
|
||||
host_end - qemu_host_page_size, host_end,
|
||||
prot, flags, fd,
|
||||
offset + host_end - qemu_host_page_size - start);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
host_end -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
/* map the middle (easier) */
|
||||
if (host_start < host_end) {
|
||||
unsigned long offset1;
|
||||
if (flags & MAP_ANONYMOUS)
|
||||
offset1 = 0;
|
||||
else
|
||||
offset1 = offset + host_start - start;
|
||||
ret = (long)mmap((void *)host_start, host_end - host_start,
|
||||
prot, flags, fd, offset1);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
}
|
||||
the_end1:
|
||||
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||
the_end:
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("target_mmap: ret=0x%lx\n", (long)start);
|
||||
page_dump(stdout);
|
||||
printf("\n");
|
||||
#endif
|
||||
return start;
|
||||
}
|
||||
|
||||
int target_munmap(unsigned long start, unsigned long len)
|
||||
{
|
||||
unsigned long end, host_start, host_end, addr;
|
||||
int prot, ret;
|
||||
|
||||
#ifdef DEBUG_MMAP
|
||||
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
|
||||
#endif
|
||||
if (start & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
end = start + len;
|
||||
host_start = start & qemu_host_page_mask;
|
||||
host_end = HOST_PAGE_ALIGN(end);
|
||||
|
||||
if (start > host_start) {
|
||||
/* handle host page containing start */
|
||||
prot = 0;
|
||||
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (host_end == host_start + qemu_host_page_size) {
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
end = host_end;
|
||||
}
|
||||
if (prot != 0)
|
||||
host_start += qemu_host_page_size;
|
||||
}
|
||||
if (end < host_end) {
|
||||
prot = 0;
|
||||
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (prot != 0)
|
||||
host_end -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
/* unmap what we can */
|
||||
if (host_start < host_end) {
|
||||
ret = munmap((void *)host_start, host_end - host_start);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
page_set_flags(start, start + len, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
|
||||
blocks which have been allocated starting on a host page */
|
||||
long target_mremap(unsigned long old_addr, unsigned long old_size,
|
||||
unsigned long new_size, unsigned long flags,
|
||||
unsigned long new_addr)
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
/* XXX: use 5 args syscall */
|
||||
new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
|
||||
if (new_addr == -1)
|
||||
return new_addr;
|
||||
prot = page_get_flags(old_addr);
|
||||
page_set_flags(old_addr, old_addr + old_size, 0);
|
||||
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
|
||||
return new_addr;
|
||||
#else
|
||||
qerror("target_mremap: unsupported\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int target_msync(unsigned long start, unsigned long len, int flags)
|
||||
{
|
||||
unsigned long end;
|
||||
|
||||
if (start & ~TARGET_PAGE_MASK)
|
||||
return -EINVAL;
|
||||
len = TARGET_PAGE_ALIGN(len);
|
||||
end = start + len;
|
||||
if (end < start)
|
||||
return -EINVAL;
|
||||
if (end == start)
|
||||
return 0;
|
||||
|
||||
start &= qemu_host_page_mask;
|
||||
return msync((void *)start, end - start, flags);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
#ifndef GEMU_H
|
||||
#define GEMU_H
|
||||
|
||||
#include "thunk.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#include "gdbstub.h"
|
||||
|
||||
typedef siginfo_t target_siginfo_t;
|
||||
#define target_sigaction sigaction
|
||||
#ifdef TARGET_I386
|
||||
struct target_pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
struct target_sigcontext {
|
||||
int sc_onstack;
|
||||
int sc_mask;
|
||||
int sc_eax;
|
||||
int sc_ebx;
|
||||
int sc_ecx;
|
||||
int sc_edx;
|
||||
int sc_edi;
|
||||
int sc_esi;
|
||||
int sc_ebp;
|
||||
int sc_esp;
|
||||
int sc_ss;
|
||||
int sc_eflags;
|
||||
int sc_eip;
|
||||
int sc_cs;
|
||||
int sc_ds;
|
||||
int sc_es;
|
||||
int sc_fs;
|
||||
int sc_gs;
|
||||
};
|
||||
|
||||
#define __USER_CS (0x17)
|
||||
#define __USER_DS (0x1F)
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
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 */
|
||||
};
|
||||
|
||||
struct target_sigcontext {
|
||||
int sc_onstack; /* sigstack state to restore */
|
||||
int sc_mask; /* signal mask to restore */
|
||||
int sc_ir; /* pc */
|
||||
int sc_psw; /* processor status word */
|
||||
int sc_sp; /* stack pointer if sc_regs == NULL */
|
||||
void *sc_regs; /* (kernel private) saved state */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct TaskState {
|
||||
struct TaskState *next;
|
||||
int used; /* non zero if used */
|
||||
uint8_t stack[0];
|
||||
} __attribute__((aligned(16))) TaskState;
|
||||
|
||||
void syscall_init(void);
|
||||
long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
|
||||
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
|
||||
long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
|
||||
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
|
||||
long do_unix_syscall(void *cpu_env, int num);
|
||||
int do_sigaction(int sig, const struct sigaction *act,
|
||||
struct sigaction *oact);
|
||||
int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
|
||||
|
||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void qerror(const char *fmt, ...);
|
||||
|
||||
void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags);
|
||||
|
||||
extern CPUState *global_env;
|
||||
void cpu_loop(CPUState *env);
|
||||
void init_paths(const char *prefix);
|
||||
const char *path(const char *pathname);
|
||||
|
||||
extern int loglevel;
|
||||
extern FILE *logfile;
|
||||
|
||||
/* commpage.c */
|
||||
void commpage_init();
|
||||
void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
|
||||
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
|
||||
|
||||
/* signal.c */
|
||||
void process_pending_signals(void *cpu_env);
|
||||
void signal_init(void);
|
||||
int queue_signal(int sig, target_siginfo_t *info);
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUState *env, int num);
|
||||
|
||||
/* machload.c */
|
||||
int mach_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs);
|
||||
|
||||
/* mmap.c */
|
||||
int target_mprotect(unsigned long start, unsigned long len, int prot);
|
||||
long target_mmap(unsigned long start, unsigned long len, int prot,
|
||||
int flags, int fd, unsigned long offset);
|
||||
int target_munmap(unsigned long start, unsigned long len);
|
||||
long target_mremap(unsigned long old_addr, unsigned long old_size,
|
||||
unsigned long new_size, unsigned long flags,
|
||||
unsigned long new_addr);
|
||||
int target_msync(unsigned long start, unsigned long len, int flags);
|
||||
|
||||
/* user access */
|
||||
|
||||
/* XXX: todo protect every memory access */
|
||||
#define lock_user(x,y,z) (void*)(x)
|
||||
#define unlock_user(x,y,z)
|
||||
|
||||
/* Mac OS X ABI arguments processing */
|
||||
#ifdef TARGET_I386
|
||||
static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env)
|
||||
{
|
||||
uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i);
|
||||
*i+=4;
|
||||
return tswap32(*args);
|
||||
}
|
||||
static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env)
|
||||
{
|
||||
uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i);
|
||||
*i+=8;
|
||||
return tswap64(*args);
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env)
|
||||
{
|
||||
/* XXX: won't work when args goes on stack after gpr10 */
|
||||
uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]);
|
||||
*i+=4;
|
||||
return tswap32(args);
|
||||
}
|
||||
static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env)
|
||||
{
|
||||
/* XXX: won't work when args goes on stack after gpr10 */
|
||||
uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]);
|
||||
*i+=(8 << 8) + 8;
|
||||
return tswap64(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Emulation of Linux signals
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#ifdef __ia64__
|
||||
#undef uc_mcontext
|
||||
#undef uc_sigmask
|
||||
#undef uc_stack
|
||||
#undef uc_link
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
#define DEBUG_SIGNAL
|
||||
|
||||
#define MAX_SIGQUEUE_SIZE 1024
|
||||
|
||||
struct sigqueue {
|
||||
struct sigqueue *next;
|
||||
target_siginfo_t info;
|
||||
};
|
||||
|
||||
struct emulated_sigaction {
|
||||
struct target_sigaction sa;
|
||||
int pending; /* true if signal is pending */
|
||||
struct sigqueue *first;
|
||||
struct sigqueue info; /* in order to always have memory for the
|
||||
first signal, we put it here */
|
||||
};
|
||||
|
||||
struct sigaltstack target_sigaltstack_used = {
|
||||
0, 0, SA_DISABLE
|
||||
};
|
||||
|
||||
static struct emulated_sigaction sigact_table[NSIG];
|
||||
static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
|
||||
static struct sigqueue *first_free; /* first free siginfo queue entry */
|
||||
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);
|
||||
|
||||
|
||||
static inline int host_to_target_signal(int sig)
|
||||
{
|
||||
return sig;
|
||||
}
|
||||
|
||||
static inline int target_to_host_signal(int sig)
|
||||
{
|
||||
return sig;
|
||||
}
|
||||
|
||||
/* siginfo conversion */
|
||||
|
||||
|
||||
|
||||
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void signal_init(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
|
||||
/* set all host signal handlers. ALL signals are blocked during
|
||||
the handlers to serialize them. */
|
||||
sigfillset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = host_signal_handler;
|
||||
for(i = 1; i < NSIG; i++) {
|
||||
sigaction(i, &act, NULL);
|
||||
}
|
||||
|
||||
memset(sigact_table, 0, sizeof(sigact_table));
|
||||
|
||||
first_free = &sigqueue_table[0];
|
||||
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
|
||||
sigqueue_table[i].next = &sigqueue_table[i + 1];
|
||||
sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
|
||||
}
|
||||
|
||||
/* signal queue handling */
|
||||
|
||||
static inline struct sigqueue *alloc_sigqueue(void)
|
||||
{
|
||||
struct sigqueue *q = first_free;
|
||||
if (!q)
|
||||
return NULL;
|
||||
first_free = q->next;
|
||||
return q;
|
||||
}
|
||||
|
||||
static inline void free_sigqueue(struct sigqueue *q)
|
||||
{
|
||||
q->next = first_free;
|
||||
first_free = q;
|
||||
}
|
||||
|
||||
/* abort execution with signal */
|
||||
void __attribute((noreturn)) force_sig(int sig)
|
||||
{
|
||||
int host_sig;
|
||||
host_sig = target_to_host_signal(sig);
|
||||
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
|
||||
sig, strsignal(host_sig));
|
||||
_exit(-host_sig);
|
||||
}
|
||||
|
||||
/* queue a signal so that it will be send to the virtual CPU as soon
|
||||
as possible */
|
||||
int queue_signal(int sig, target_siginfo_t *info)
|
||||
{
|
||||
struct emulated_sigaction *k;
|
||||
struct sigqueue *q, **pq;
|
||||
target_ulong handler;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "queue_signal: sig=%d\n",
|
||||
sig);
|
||||
#endif
|
||||
k = &sigact_table[sig - 1];
|
||||
handler = (target_ulong)k->sa.sa_handler;
|
||||
if (handler == SIG_DFL) {
|
||||
/* default handler : ignore some signal. The other are fatal */
|
||||
if (sig != SIGCHLD &&
|
||||
sig != SIGURG &&
|
||||
sig != SIGWINCH) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
return 0; /* indicate ignored */
|
||||
}
|
||||
} else if (handler == host_to_target_signal(SIG_IGN)) {
|
||||
/* ignore signal */
|
||||
return 0;
|
||||
} else if (handler == host_to_target_signal(SIG_ERR)) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
pq = &k->first;
|
||||
if (!k->pending) {
|
||||
/* first signal */
|
||||
q = &k->info;
|
||||
} else {
|
||||
q = alloc_sigqueue();
|
||||
if (!q)
|
||||
return -EAGAIN;
|
||||
while (*pq != NULL)
|
||||
pq = &(*pq)->next;
|
||||
}
|
||||
*pq = q;
|
||||
q->info = *info;
|
||||
q->next = NULL;
|
||||
k->pending = 1;
|
||||
/* signal that a new signal is pending */
|
||||
signal_pending = 1;
|
||||
return 1; /* indicates that the signal was queued */
|
||||
}
|
||||
}
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
{
|
||||
int sig;
|
||||
target_siginfo_t tinfo;
|
||||
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we we forward to it some signals */
|
||||
if (host_signum == SIGSEGV || host_signum == SIGBUS
|
||||
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|
||||
|| host_signum == SIGFPE
|
||||
#endif
|
||||
) {
|
||||
if (cpu_signal_handler(host_signum, (void*)info, puc))
|
||||
return;
|
||||
}
|
||||
|
||||
/* get target signal number */
|
||||
sig = host_to_target_signal(host_signum);
|
||||
if (sig < 1 || sig > NSIG)
|
||||
return;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "qemu: got signal %d\n", sig);
|
||||
#endif
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
|
||||
{
|
||||
/* XXX: test errors */
|
||||
if(oss)
|
||||
{
|
||||
oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
|
||||
oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
|
||||
oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
|
||||
}
|
||||
if(ss)
|
||||
{
|
||||
target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
|
||||
target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
|
||||
target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_sigaction(int sig, const struct sigaction *act,
|
||||
struct sigaction *oact)
|
||||
{
|
||||
struct emulated_sigaction *k;
|
||||
struct sigaction act1;
|
||||
int host_sig;
|
||||
|
||||
if (sig < 1 || sig > NSIG)
|
||||
return -EINVAL;
|
||||
|
||||
k = &sigact_table[sig - 1];
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
|
||||
sig, (int)act, (int)oact);
|
||||
#endif
|
||||
if (oact) {
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
|
||||
sig, (int)act, (int)oact);
|
||||
#endif
|
||||
|
||||
oact->sa_handler = tswapl(k->sa.sa_handler);
|
||||
oact->sa_flags = tswapl(k->sa.sa_flags);
|
||||
oact->sa_mask = tswapl(k->sa.sa_mask);
|
||||
}
|
||||
if (act) {
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
|
||||
act->sa_handler, act->sa_flags, act->sa_mask);
|
||||
#endif
|
||||
|
||||
k->sa.sa_handler = tswapl(act->sa_handler);
|
||||
k->sa.sa_flags = tswapl(act->sa_flags);
|
||||
k->sa.sa_mask = tswapl(act->sa_mask);
|
||||
/* we update the host signal state */
|
||||
host_sig = target_to_host_signal(sig);
|
||||
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "sigaction handler going to call sigaction\n",
|
||||
act->sa_handler, act->sa_flags, act->sa_mask);
|
||||
#endif
|
||||
|
||||
sigfillset(&act1.sa_mask);
|
||||
act1.sa_flags = SA_SIGINFO;
|
||||
if (k->sa.sa_flags & SA_RESTART)
|
||||
act1.sa_flags |= SA_RESTART;
|
||||
/* NOTE: it is important to update the host kernel signal
|
||||
ignore state to avoid getting unexpected interrupted
|
||||
syscalls */
|
||||
if (k->sa.sa_handler == SIG_IGN) {
|
||||
act1.sa_sigaction = (void *)SIG_IGN;
|
||||
} else if (k->sa.sa_handler == SIG_DFL) {
|
||||
act1.sa_sigaction = (void *)SIG_DFL;
|
||||
} else {
|
||||
act1.sa_sigaction = host_signal_handler;
|
||||
}
|
||||
sigaction(host_sig, &act1, NULL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
static inline void *
|
||||
get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
|
||||
{
|
||||
/* XXX Fix that */
|
||||
if(target_sigaltstack_used.ss_flags & SA_DISABLE)
|
||||
{
|
||||
int esp;
|
||||
/* Default to using normal stack */
|
||||
esp = env->regs[R_ESP];
|
||||
|
||||
return (void *)((esp - frame_size) & -8ul);
|
||||
}
|
||||
else
|
||||
{
|
||||
return target_sigaltstack_used.ss_sp;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
void *set, CPUState *env)
|
||||
{
|
||||
void *frame;
|
||||
int i, err = 0;
|
||||
|
||||
fprintf(stderr, "setup_frame %d\n", sig);
|
||||
frame = get_sigframe(ka, env, sizeof(*frame));
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
env->regs[R_ESP] = (unsigned long) frame;
|
||||
env->eip = (unsigned long) ka->sa.sa_handler;
|
||||
|
||||
env->eflags &= ~TF_MASK;
|
||||
|
||||
return;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == SIGSEGV)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
force_sig(SIGSEGV /* , current */);
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUState *env, int num)
|
||||
{
|
||||
int i = 0;
|
||||
struct target_sigcontext *scp = get_int_arg(&i, env);
|
||||
/* XXX Get current signal number */
|
||||
/* XXX Adjust accordin to sc_onstack, sc_mask */
|
||||
if(tswapl(scp->sc_onstack) & 0x1)
|
||||
target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
|
||||
else
|
||||
target_sigaltstack_used.ss_flags &= SA_DISABLE;
|
||||
int set = tswapl(scp->sc_eax);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
|
||||
fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
|
||||
fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
|
||||
|
||||
env->regs[R_EAX] = tswapl(scp->sc_eax);
|
||||
env->regs[R_EBX] = tswapl(scp->sc_ebx);
|
||||
env->regs[R_ECX] = tswapl(scp->sc_ecx);
|
||||
env->regs[R_EDX] = tswapl(scp->sc_edx);
|
||||
env->regs[R_EDI] = tswapl(scp->sc_edi);
|
||||
env->regs[R_ESI] = tswapl(scp->sc_esi);
|
||||
env->regs[R_EBP] = tswapl(scp->sc_ebp);
|
||||
env->regs[R_ESP] = tswapl(scp->sc_esp);
|
||||
env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
|
||||
env->eflags = tswapl(scp->sc_eflags);
|
||||
env->eip = tswapl(scp->sc_eip);
|
||||
env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
|
||||
env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
|
||||
env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
|
||||
env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
|
||||
env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
|
||||
|
||||
/* Again, because our caller's caller will reset EAX */
|
||||
return env->regs[R_EAX];
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||
void *set, CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "setup_frame: not implemented\n");
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUState *env, int num)
|
||||
{
|
||||
int i = 0;
|
||||
struct target_sigcontext *scp = get_int_arg(&i, env);
|
||||
fprintf(stderr, "do_sigreturn: not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void process_pending_signals(void *cpu_env)
|
||||
{
|
||||
struct emulated_sigaction *k;
|
||||
struct sigqueue *q;
|
||||
target_ulong handler;
|
||||
int sig;
|
||||
|
||||
if (!signal_pending)
|
||||
return;
|
||||
|
||||
k = sigact_table;
|
||||
|
||||
for(sig = 1; sig <= NSIG; sig++) {
|
||||
if (k->pending)
|
||||
goto handle_signal;
|
||||
k++;
|
||||
}
|
||||
|
||||
/* if no signal is pending, just return */
|
||||
signal_pending = 0;
|
||||
return;
|
||||
handle_signal:
|
||||
#ifdef DEBUG_SIGNAL
|
||||
fprintf(stderr, "qemu: process signal %d\n", sig);
|
||||
#endif
|
||||
/* dequeue signal */
|
||||
q = k->first;
|
||||
k->first = q->next;
|
||||
if (!k->first)
|
||||
k->pending = 0;
|
||||
|
||||
sig = gdb_handlesig (cpu_env, sig);
|
||||
if (!sig) {
|
||||
fprintf (stderr, "Lost signal\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
handler = k->sa.sa_handler;
|
||||
if (handler == SIG_DFL) {
|
||||
/* default handler : ignore some signal. The other are fatal */
|
||||
if (sig != SIGCHLD &&
|
||||
sig != SIGURG &&
|
||||
sig != SIGWINCH) {
|
||||
force_sig(sig);
|
||||
}
|
||||
} else if (handler == SIG_IGN) {
|
||||
/* ignore sig */
|
||||
} else if (handler == SIG_ERR) {
|
||||
force_sig(sig);
|
||||
} else {
|
||||
|
||||
setup_frame(sig, k, 0, cpu_env);
|
||||
if (k->sa.sa_flags & SA_RESETHAND)
|
||||
k->sa.sa_handler = SIG_DFL;
|
||||
}
|
||||
if (q != &k->info)
|
||||
free_sigqueue(q);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,384 @@
|
||||
/* generated from xnu/bsd/kern/syscalls.master */
|
||||
|
||||
ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */
|
||||
ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */
|
||||
ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */
|
||||
ENTRY("read", SYS_read, do_read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */
|
||||
ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */
|
||||
ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */
|
||||
ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */
|
||||
ENTRY("wait4", SYS_wait4, wait4, 4, CALL_DIRECT, INT, PTR, INT, PTR) /* 7 */
|
||||
ENTRY("", 8, no_syscall, 0, CALL_INDIRECT, VOID) /* 8 old creat */
|
||||
ENTRY("link", SYS_link, link, 2, CALL_DIRECT, PTR, PTR) /* 9 */
|
||||
ENTRY("unlink", SYS_unlink, unlink, 1, CALL_DIRECT, PTR) /* 10 */
|
||||
ENTRY("", 11, no_syscall, 0, CALL_INDIRECT, VOID) /* 11 old execv */
|
||||
ENTRY("chdir", SYS_chdir, chdir, 1, CALL_DIRECT, PTR) /* 12 */
|
||||
ENTRY("fchdir", SYS_fchdir, fchdir, 1, CALL_DIRECT, INT) /* 13 */
|
||||
ENTRY("mknod", SYS_mknod, mknod, 3, CALL_DIRECT, PTR, INT, INT) /* 14 */
|
||||
ENTRY("chmod", SYS_chmod, chmod, 2, CALL_DIRECT, PTR, INT) /* 15 */
|
||||
ENTRY("chown", SYS_chown, chown, 3, CALL_DIRECT, PTR, INT, INT) /* 16 */
|
||||
ENTRY("obreak", SYS_obreak, no_syscall, 1, CALL_INDIRECT, VOID) /* 17 old break */
|
||||
ENTRY("ogetfsstat", 18, unimpl_unix_syscall, 3, CALL_INDIRECT, PTR, INT, INT) /* 18 */
|
||||
ENTRY("", 19, no_syscall, 0, CALL_INDIRECT, VOID) /* 19 old lseek */
|
||||
ENTRY("getpid", SYS_getpid, getpid, 0, CALL_NOERRNO, VOID) /* 20 */
|
||||
ENTRY("", 21, no_syscall, 0, CALL_INDIRECT, VOID) /* 21 old mount */
|
||||
ENTRY("", 22, no_syscall, 0, CALL_INDIRECT, VOID) /* 22 old umount */
|
||||
ENTRY("setuid", SYS_setuid, setuid, 1, CALL_DIRECT, INT) /* 23 */
|
||||
ENTRY("getuid", SYS_getuid, getuid, 0, CALL_NOERRNO, VOID) /* 24 */
|
||||
ENTRY("geteuid", SYS_geteuid, geteuid, 0, CALL_NOERRNO, VOID) /* 25 */
|
||||
ENTRY("ptrace", SYS_ptrace, ptrace, 4, CALL_DIRECT, INT, INT, PTR, INT) /* 26 */
|
||||
ENTRY("recvmsg", SYS_recvmsg, recvmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 27 */
|
||||
ENTRY("sendmsg", SYS_sendmsg, sendmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 28 */
|
||||
ENTRY("recvfrom", SYS_recvfrom, recvfrom, 6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR) /* 29 */
|
||||
ENTRY("accept", SYS_accept, accept, 3, CALL_DIRECT, INT, PTR, PTR) /* 30 */
|
||||
ENTRY("getpeername", SYS_getpeername, getpeername, 3, CALL_DIRECT, INT, PTR, PTR) /* 31 */
|
||||
ENTRY("getsockname", SYS_getsockname, getsockname, 3, CALL_DIRECT, INT, PTR, PTR) /* 32 */
|
||||
ENTRY("access", SYS_access, access, 2, CALL_DIRECT, PTR, INT) /* 33 */
|
||||
ENTRY("chflags", SYS_chflags, chflags, 2, CALL_DIRECT, PTR, INT) /* 34 */
|
||||
ENTRY("fchflags", SYS_fchflags, fchflags, 2, CALL_DIRECT, INT, INT) /* 35 */
|
||||
ENTRY("sync", SYS_sync, do_sync, 0, CALL_INDIRECT, VOID) /* 36 */
|
||||
ENTRY("kill", SYS_kill, kill, 2, CALL_DIRECT, INT, INT) /* 37 */
|
||||
ENTRY("", 38, no_syscall, 0, CALL_INDIRECT, VOID) /* 38 old stat */
|
||||
ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */
|
||||
ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */
|
||||
ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */
|
||||
ENTRY("pipe", SYS_pipe, unimpl_unix_syscall, 0, CALL_INDIRECT, PTR) /* 42 */
|
||||
ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */
|
||||
ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */
|
||||
ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */
|
||||
ENTRY("sigaction", SYS_sigaction, do_sigaction, 3, CALL_DIRECT, INT, PTR, PTR) /* 46 */
|
||||
ENTRY("getgid", SYS_getgid, getgid, 0, CALL_NOERRNO, VOID) /* 47 */
|
||||
ENTRY("sigprocmask", SYS_sigprocmask, do_sigprocmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 48 */
|
||||
ENTRY("getlogin", SYS_getlogin, do_getlogin, 2, CALL_DIRECT, PTR, UINT) /* 49 XXX */
|
||||
ENTRY("setlogin", SYS_setlogin, setlogin, 1, CALL_DIRECT, PTR) /* 50 */
|
||||
ENTRY("acct", SYS_acct, acct, 1, CALL_DIRECT, PTR) /* 51 */
|
||||
ENTRY("sigpending", SYS_sigpending, sigpending, 1, CALL_DIRECT, PTR) /* 52 */
|
||||
ENTRY("sigaltstack", SYS_sigaltstack, do_sigaltstack, 2, CALL_DIRECT, PTR, PTR) /* 53 */
|
||||
ENTRY("ioctl", SYS_ioctl, do_ioctl, 3, CALL_DIRECT, INT, INT, INT) /* 54 */
|
||||
ENTRY("reboot", SYS_reboot, unimpl_unix_syscall, 2, CALL_INDIRECT, INT, PTR) /* 55 */
|
||||
ENTRY("revoke", SYS_revoke, revoke, 1, CALL_DIRECT, PTR) /* 56 */
|
||||
ENTRY("symlink", SYS_symlink, symlink, 2, CALL_DIRECT, PTR, PTR) /* 57 */
|
||||
ENTRY("readlink", SYS_readlink, readlink, 3, CALL_DIRECT, PTR, PTR, INT) /* 58 */
|
||||
ENTRY("execve", SYS_execve, do_execve, 3, CALL_DIRECT, PTR, PTR, PTR) /* 59 */
|
||||
ENTRY("umask", SYS_umask, umask, 1, CALL_DIRECT, INT) /* 60 */
|
||||
ENTRY("chroot", SYS_chroot, chroot, 1, CALL_DIRECT, PTR) /* 61 */
|
||||
ENTRY("", 62, no_syscall, 0, CALL_INDIRECT, VOID) /* 62 old fstat */
|
||||
ENTRY("", 63, no_syscall, 0, CALL_INDIRECT, VOID) /* 63 used internally , reserved */
|
||||
ENTRY("", 64, no_syscall, 0, CALL_INDIRECT, VOID) /* 64 old getpagesize */
|
||||
ENTRY("msync", SYS_msync, target_msync, 3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT) /* 65 */
|
||||
ENTRY("vfork", SYS_vfork, vfork, 0, CALL_DIRECT, VOID) /* 66 */
|
||||
ENTRY("", 67, no_syscall, 0, CALL_INDIRECT, VOID) /* 67 old vread */
|
||||
ENTRY("", 68, no_syscall, 0, CALL_INDIRECT, VOID) /* 68 old vwrite */
|
||||
ENTRY("sbrk", SYS_sbrk, sbrk, 1, CALL_DIRECT, INT) /* 69 */
|
||||
ENTRY("sstk", SYS_sstk, no_syscall, 1, CALL_INDIRECT, VOID) /* 70 */
|
||||
ENTRY("", 71, no_syscall, 0, CALL_INDIRECT, VOID) /* 71 old mmap */
|
||||
ENTRY("ovadvise", SYS_ovadvise, no_syscall, 0, CALL_INDIRECT, VOID) /* 72 old vadvise */
|
||||
ENTRY("munmap", SYS_munmap, target_munmap, 2, CALL_DIRECT, UINT /* PTR */, SIZE) /* 73 */
|
||||
ENTRY("mprotect", SYS_mprotect, mprotect, 3, CALL_DIRECT, PTR, SIZE, INT) /* 74 */
|
||||
ENTRY("madvise", SYS_madvise, madvise, 3, CALL_DIRECT, PTR, SIZE, INT) /* 75 */
|
||||
ENTRY("", 76, no_syscall, 0, CALL_INDIRECT, VOID) /* 76 old vhangup */
|
||||
ENTRY("", 77, no_syscall, 0, CALL_INDIRECT, VOID) /* 77 old vlimit */
|
||||
ENTRY("mincore", SYS_mincore, mincore, 3, CALL_DIRECT, PTR, SIZE, PTR) /* 78 */
|
||||
ENTRY("getgroups", SYS_getgroups, do_getgroups, 2, CALL_DIRECT, UINT, PTR) /* 79 */
|
||||
ENTRY("setgroups", SYS_setgroups, setgroups, 2, CALL_DIRECT, UINT, PTR) /* 80 */
|
||||
ENTRY("getpgrp", SYS_getpgrp, getpgrp, 0, CALL_DIRECT, VOID) /* 81 */
|
||||
ENTRY("setpgid", SYS_setpgid, setpgid, 2, CALL_DIRECT, INT, INT) /* 82 */
|
||||
ENTRY("setitimer", SYS_setitimer, setitimer, 3, CALL_DIRECT, INT, PTR, PTR) /* 83 */
|
||||
ENTRY("", 84, no_syscall, 0, CALL_INDIRECT, VOID) /* 84 old wait */
|
||||
ENTRY("swapon", SYS_swapon, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 85 */
|
||||
ENTRY("getitimer", SYS_getitimer, getitimer, 2, CALL_DIRECT, INT, PTR) /* 86 */
|
||||
ENTRY("", 87, no_syscall, 0, CALL_INDIRECT, VOID) /* 87 old gethostname */
|
||||
ENTRY("", 88, no_syscall, 0, CALL_INDIRECT, VOID) /* 88 old sethostname */
|
||||
ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */
|
||||
ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */
|
||||
ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */
|
||||
ENTRY("fcntl", SYS_fcntl, do_fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */
|
||||
ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */
|
||||
ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */
|
||||
ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */
|
||||
ENTRY("setpriority", SYS_setpriority, setpriority, 3, CALL_DIRECT, INT, INT, INT) /* 96 */
|
||||
ENTRY("socket", SYS_socket, socket, 3, CALL_DIRECT, INT, INT, INT) /* 97 */
|
||||
ENTRY("connect", SYS_connect, connect, 3, CALL_DIRECT, INT, PTR, INT) /* 98 */
|
||||
ENTRY("", 99, no_syscall, 0, CALL_INDIRECT, VOID) /* 99 old accept */
|
||||
ENTRY("getpriority", SYS_getpriority, getpriority, 2, CALL_DIRECT, INT, INT) /* 100 */
|
||||
ENTRY("", 101, no_syscall, 0, CALL_INDIRECT, VOID) /* 101 old send */
|
||||
ENTRY("", 102, no_syscall, 0, CALL_INDIRECT, VOID) /* 102 old recv */
|
||||
ENTRY("", 103, no_syscall, 0, CALL_INDIRECT, VOID) /* 103 old sigreturn */
|
||||
ENTRY("bind", SYS_bind, bind, 3, CALL_DIRECT, INT, PTR, INT) /* 104 */
|
||||
ENTRY("setsockopt", SYS_setsockopt, setsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, INT) /* 105 */
|
||||
ENTRY("listen", SYS_listen, listen, 2, CALL_DIRECT, INT, INT) /* 106 */
|
||||
ENTRY("", 107, no_syscall, 0, CALL_INDIRECT, VOID) /* 107 old vtimes */
|
||||
ENTRY("", 108, no_syscall, 0, CALL_INDIRECT, VOID) /* 108 old sigvec */
|
||||
ENTRY("", 109, no_syscall, 0, CALL_INDIRECT, VOID) /* 109 old sigblock */
|
||||
ENTRY("", 110, no_syscall, 0, CALL_INDIRECT, VOID) /* 110 old sigsetmask */
|
||||
ENTRY("sigsuspend", SYS_sigsuspend, unimpl_unix_syscall, 1, CALL_INDIRECT, INT) /* 111 */
|
||||
ENTRY("", 112, no_syscall, 0, CALL_INDIRECT, VOID) /* 112 old sigstack */
|
||||
ENTRY("", 113, no_syscall, 0, CALL_INDIRECT, VOID) /* 113 old recvmsg */
|
||||
ENTRY("", 114, no_syscall, 0, CALL_INDIRECT, VOID) /* 114 old sendmsg */
|
||||
ENTRY("", 115, no_syscall, 0, CALL_INDIRECT, VOID) /* 115 old vtrace */
|
||||
ENTRY("gettimeofday", SYS_gettimeofday, do_gettimeofday, 2, CALL_DIRECT, PTR, PTR) /* 116 */
|
||||
ENTRY("getrusage", SYS_getrusage, getrusage, 2, CALL_DIRECT, INT, PTR) /* 117 */
|
||||
ENTRY("getsockopt", SYS_getsockopt, getsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, PTR) /* 118 */
|
||||
ENTRY("", 119, no_syscall, 0, CALL_INDIRECT, VOID) /* 119 old resuba */
|
||||
ENTRY("readv", SYS_readv, do_readv, 3, CALL_DIRECT, INT, PTR, UINT) /* 120 */
|
||||
ENTRY("writev", SYS_writev, do_writev, 3, CALL_DIRECT, INT, PTR, UINT) /* 121 */
|
||||
ENTRY("settimeofday", SYS_settimeofday, settimeofday, 2, CALL_DIRECT, PTR, PTR) /* 122 */
|
||||
ENTRY("fchown", SYS_fchown, fchown, 3, CALL_DIRECT, INT, INT, INT) /* 123 */
|
||||
ENTRY("fchmod", SYS_fchmod, fchmod, 2, CALL_DIRECT, INT, INT) /* 124 */
|
||||
ENTRY("", 125, no_syscall, 0, CALL_INDIRECT, VOID) /* 125 old recvfrom */
|
||||
ENTRY("", 126, no_syscall, 0, CALL_INDIRECT, VOID) /* 126 old setreuid */
|
||||
ENTRY("", 127, no_syscall, 0, CALL_INDIRECT, VOID) /* 127 old setregid */
|
||||
ENTRY("rename", SYS_rename, rename, 2, CALL_DIRECT, PTR, PTR) /* 128 */
|
||||
ENTRY("", 129, no_syscall, 0, CALL_INDIRECT, VOID) /* 129 old truncate */
|
||||
ENTRY("", 130, no_syscall, 0, CALL_INDIRECT, VOID) /* 130 old ftruncate */
|
||||
ENTRY("flock", SYS_flock, flock, 2, CALL_DIRECT, INT, INT) /* 131 */
|
||||
ENTRY("mkfifo", SYS_mkfifo, mkfifo, 2, CALL_DIRECT, PTR, INT) /* 132 */
|
||||
ENTRY("sendto", SYS_sendto, sendto, 6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT) /* 133 */
|
||||
ENTRY("shutdown", SYS_shutdown, shutdown, 2, CALL_DIRECT, INT, INT) /* 134 */
|
||||
ENTRY("socketpair", SYS_socketpair, socketpair, 4, CALL_DIRECT, INT, INT, INT, PTR) /* 135 */
|
||||
ENTRY("mkdir", SYS_mkdir, mkdir, 2, CALL_DIRECT, PTR, INT) /* 136 */
|
||||
ENTRY("rmdir", SYS_rmdir, rmdir, 1, CALL_DIRECT, PTR) /* 137 */
|
||||
ENTRY("utimes", SYS_utimes, do_utimes, 2, CALL_DIRECT, PTR, PTR) /* 138 */
|
||||
ENTRY("futimes", SYS_futimes, do_futimes, 2, CALL_DIRECT, INT, PTR) /* 139 */
|
||||
ENTRY("adjtime", SYS_adjtime, adjtime, 2, CALL_DIRECT, PTR, PTR) /* 140 */
|
||||
ENTRY("", 141, no_syscall, 0, CALL_INDIRECT, VOID) /* 141 old getpeername */
|
||||
ENTRY("", 142, no_syscall, 0, CALL_INDIRECT, VOID) /* 142 old gethostid */
|
||||
ENTRY("", 143, no_syscall, 0, CALL_INDIRECT, VOID) /* 143 old sethostid */
|
||||
ENTRY("", 144, no_syscall, 0, CALL_INDIRECT, VOID) /* 144 old getrlimit */
|
||||
ENTRY("", 145, no_syscall, 0, CALL_INDIRECT, VOID) /* 145 old setrlimit */
|
||||
ENTRY("", 146, no_syscall, 0, CALL_INDIRECT, VOID) /* 146 old killpg */
|
||||
ENTRY("setsid", SYS_setsid, setsid, 0, CALL_DIRECT, VOID) /* 147 */
|
||||
ENTRY("", 148, no_syscall, 0, CALL_INDIRECT, VOID) /* 148 old setquota */
|
||||
ENTRY("", 149, no_syscall, 0, CALL_INDIRECT, VOID) /* 149 old qquota */
|
||||
ENTRY("", 150, no_syscall, 0, CALL_INDIRECT, VOID) /* 150 old getsockname */
|
||||
ENTRY("getpgid", SYS_getpgid, getpgid, 1, CALL_DIRECT, INT) /* 151 */
|
||||
ENTRY("setprivexec", SYS_setprivexec, no_syscall, 1, CALL_INDIRECT, VOID) /* 152 */
|
||||
ENTRY("pread", SYS_pread, do_pread, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 153 */
|
||||
ENTRY("pwrite", SYS_pwrite, pwrite, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 154 */
|
||||
#ifdef SYS_nfssvc
|
||||
ENTRY("nfssvc", SYS_nfssvc, nfssvc, 2, CALL_DIRECT, INT, PTR) /* 155 */
|
||||
#else
|
||||
ENTRY("nfssvc", 155, no_syscall, 2, CALL_INDIRECT, VOID) /* 155 */
|
||||
#endif
|
||||
ENTRY("", 155, no_syscall, 0, CALL_INDIRECT, VOID) /* 155 */
|
||||
ENTRY("", 156, no_syscall, 0, CALL_INDIRECT, VOID) /* 156 old getdirentries */
|
||||
ENTRY("statfs", SYS_statfs, do_statfs, 2, CALL_DIRECT, PTR, PTR) /* 157 */
|
||||
ENTRY("fstatfs", SYS_fstatfs, do_fstatfs, 2, CALL_DIRECT, INT, PTR) /* 158 */
|
||||
ENTRY("unmount", SYS_unmount, unmount, 2, CALL_DIRECT, PTR, INT) /* 159 */
|
||||
ENTRY("", 160, no_syscall, 0, CALL_INDIRECT, VOID) /* 160 old async_daemon */
|
||||
ENTRY("", 161, no_syscall, 0, CALL_INDIRECT, VOID) /* 161 */
|
||||
ENTRY("", 162, no_syscall, 0, CALL_INDIRECT, VOID) /* 162 old getdomainname */
|
||||
ENTRY("", 163, no_syscall, 0, CALL_INDIRECT, VOID) /* 163 old setdomainname */
|
||||
ENTRY("", 164, no_syscall, 0, CALL_INDIRECT, VOID) /* 164 */
|
||||
ENTRY("quotactl", SYS_quotactl, no_syscall, 4, CALL_INDIRECT, VOID) /* 165 */
|
||||
ENTRY("", 166, no_syscall, 0, CALL_INDIRECT, VOID) /* 166 old exportfs */
|
||||
ENTRY("mount", SYS_mount, mount, 4, CALL_DIRECT, PTR, PTR, INT, PTR) /* 167 */
|
||||
ENTRY("", 168, no_syscall, 0, CALL_INDIRECT, VOID) /* 168 old ustat */
|
||||
ENTRY("", 169, no_syscall, 0, CALL_INDIRECT, VOID) /* 169 */
|
||||
ENTRY("table", SYS_table, no_syscall, 0, CALL_INDIRECT, VOID) /* 170 old table */
|
||||
ENTRY("", 171, no_syscall, 0, CALL_INDIRECT, VOID) /* 171 old wait3 */
|
||||
ENTRY("", 172, no_syscall, 0, CALL_INDIRECT, VOID) /* 172 old rpause */
|
||||
ENTRY("waitid", SYS_waitid, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 173 */
|
||||
ENTRY("", 174, no_syscall, 0, CALL_INDIRECT, VOID) /* 174 old getdents */
|
||||
ENTRY("", 175, no_syscall, 0, CALL_INDIRECT, VOID) /* 175 old gc_control */
|
||||
ENTRY("add_profil", SYS_add_profil, add_profil, 4, CALL_DIRECT, PTR, SIZE, UINT, UINT) /* 176 */
|
||||
ENTRY("", 177, no_syscall, 0, CALL_INDIRECT, VOID) /* 177 */
|
||||
ENTRY("", 178, no_syscall, 0, CALL_INDIRECT, VOID) /* 178 */
|
||||
ENTRY("", 179, no_syscall, 0, CALL_INDIRECT, VOID) /* 179 */
|
||||
ENTRY("kdebug_trace", SYS_kdebug_trace, no_syscall, 6, CALL_INDIRECT, VOID) /* 180 */
|
||||
ENTRY("setgid", SYS_setgid, setgid, 1, CALL_DIRECT, INT) /* 181 */
|
||||
ENTRY("setegid", SYS_setegid, setegid, 1, CALL_DIRECT, INT) /* 182 */
|
||||
ENTRY("seteuid", SYS_seteuid, seteuid, 1, CALL_DIRECT, INT) /* 183 */
|
||||
ENTRY("sigreturn", SYS_sigreturn, do_sigreturn, 2, CALL_INDIRECT, PTR, INT) /* 184 */
|
||||
ENTRY("chud", SYS_chud, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 185 */
|
||||
ENTRY("", 186, no_syscall, 0, CALL_INDIRECT, VOID) /* 186 */
|
||||
ENTRY("", 187, no_syscall, 0, CALL_INDIRECT, VOID) /* 187 */
|
||||
ENTRY("stat", SYS_stat, do_stat, 2, CALL_DIRECT, PTR, PTR) /* 188 */
|
||||
ENTRY("fstat", SYS_fstat, do_fstat, 2, CALL_DIRECT, INT, PTR) /* 189 */
|
||||
ENTRY("lstat", SYS_lstat, do_lstat, 2, CALL_DIRECT, PTR, PTR) /* 190 */
|
||||
ENTRY("pathconf", SYS_pathconf, pathconf, 2, CALL_DIRECT, PTR, INT) /* 191 */
|
||||
ENTRY("fpathconf", SYS_fpathconf, fpathconf, 2, CALL_DIRECT, INT, INT) /* 192 */
|
||||
ENTRY("getfsstat", SYS_getfsstat, do_getfsstat, 3, CALL_DIRECT, PTR, INT, INT) /* 193 */
|
||||
ENTRY("", 193, no_syscall, 0, CALL_INDIRECT, VOID) /* 193 */
|
||||
ENTRY("getrlimit", SYS_getrlimit, getrlimit, 2, CALL_DIRECT, UINT, PTR) /* 194 */
|
||||
ENTRY("setrlimit", SYS_setrlimit, setrlimit, 2, CALL_DIRECT, UINT, PTR) /* 195 */
|
||||
ENTRY("getdirentries", SYS_getdirentries, do_getdirentries, 4, CALL_DIRECT, INT, PTR, UINT, PTR) /* 196 */
|
||||
ENTRY("mmap", SYS_mmap, target_mmap, 6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET) /* 197 */
|
||||
ENTRY("", 198, no_syscall, 0, CALL_INDIRECT, VOID) /* 198 __syscall */
|
||||
ENTRY("lseek", SYS_lseek, do_lseek, 3, CALL_INDIRECT, INT, OFFSET, INT) /* 199 */
|
||||
ENTRY("truncate", SYS_truncate, truncate, 2, CALL_DIRECT, PTR, OFFSET) /* 200 */
|
||||
ENTRY("ftruncate", SYS_ftruncate, ftruncate, 2, CALL_DIRECT, INT, OFFSET) /* 201 */
|
||||
ENTRY("__sysctl", SYS___sysctl, do___sysctl, 6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE) /* 202 */
|
||||
ENTRY("mlock", SYS_mlock, mlock, 2, CALL_DIRECT, PTR, SIZE) /* 203 */
|
||||
ENTRY("munlock", SYS_munlock, munlock, 2, CALL_DIRECT, PTR, SIZE) /* 204 */
|
||||
ENTRY("undelete", SYS_undelete, undelete, 1, CALL_DIRECT, PTR) /* 205 */
|
||||
ENTRY("ATsocket", SYS_ATsocket, no_syscall, 1, CALL_INDIRECT, VOID) /* 206 */
|
||||
ENTRY("ATgetmsg", SYS_ATgetmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 207 */
|
||||
ENTRY("ATputmsg", SYS_ATputmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 208 */
|
||||
ENTRY("ATPsndreq", SYS_ATPsndreq, no_syscall, 4, CALL_INDIRECT, VOID) /* 209 */
|
||||
ENTRY("ATPsndrsp", SYS_ATPsndrsp, no_syscall, 4, CALL_INDIRECT, VOID) /* 210 */
|
||||
ENTRY("ATPgetreq", SYS_ATPgetreq, no_syscall, 3, CALL_INDIRECT, VOID) /* 211 */
|
||||
ENTRY("ATPgetrsp", SYS_ATPgetrsp, no_syscall, 2, CALL_INDIRECT, VOID) /* 212 */
|
||||
ENTRY("", 213, no_syscall, 0, CALL_INDIRECT, VOID) /* 213 Reserved for AppleTalk */
|
||||
ENTRY("kqueue_from_portset_np", SYS_kqueue_from_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 214 */
|
||||
ENTRY("kqueue_portset_np", SYS_kqueue_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 215 */
|
||||
ENTRY("mkcomplex", SYS_mkcomplex, no_syscall, 3, CALL_INDIRECT, VOID) /* 216 soon to be obsolete */
|
||||
ENTRY("statv", SYS_statv, no_syscall, 2, CALL_INDIRECT, VOID) /* 217 soon to be obsolete */
|
||||
ENTRY("lstatv", SYS_lstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 218 soon to be obsolete */
|
||||
ENTRY("fstatv", SYS_fstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 219 soon to be obsolete */
|
||||
ENTRY("getattrlist", SYS_getattrlist, do_getattrlist, 5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT) /* 220 */
|
||||
ENTRY("setattrlist", SYS_setattrlist, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 221 */
|
||||
ENTRY("getdirentriesattr", SYS_getdirentriesattr, do_getdirentriesattr, 8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT) /* 222 */
|
||||
ENTRY("exchangedata", SYS_exchangedata, exchangedata, 3, CALL_DIRECT, PTR, PTR, UINT) /* 223 */
|
||||
ENTRY("checkuseraccess", SYS_checkuseraccess, checkuseraccess, 6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT) /* 224 */
|
||||
ENTRY("", 224, no_syscall, 0, CALL_INDIRECT, VOID) /* 224 HFS checkuseraccess check access to a file */
|
||||
ENTRY("searchfs", SYS_searchfs, searchfs, 6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR) /* 225 */
|
||||
ENTRY("delete", SYS_delete, no_syscall, 1, CALL_INDIRECT, VOID) /* 226 private delete ( Carbon semantics ) */
|
||||
ENTRY("copyfile", SYS_copyfile, no_syscall, 4, CALL_INDIRECT, VOID) /* 227 */
|
||||
ENTRY("", 228, no_syscall, 0, CALL_INDIRECT, VOID) /* 228 */
|
||||
ENTRY("", 229, no_syscall, 0, CALL_INDIRECT, VOID) /* 229 */
|
||||
ENTRY("poll", SYS_poll, no_syscall, 3, CALL_INDIRECT, VOID) /* 230 */
|
||||
ENTRY("watchevent", SYS_watchevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 231 */
|
||||
ENTRY("waitevent", SYS_waitevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 232 */
|
||||
ENTRY("modwatch", SYS_modwatch, no_syscall, 2, CALL_INDIRECT, VOID) /* 233 */
|
||||
ENTRY("getxattr", SYS_getxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 234 */
|
||||
ENTRY("fgetxattr", SYS_fgetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 235 */
|
||||
ENTRY("setxattr", SYS_setxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 236 */
|
||||
ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */
|
||||
ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */
|
||||
ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */
|
||||
ENTRY("listxattr", SYS_listxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 240 */
|
||||
ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */
|
||||
ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */
|
||||
ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */
|
||||
ENTRY("", 244, no_syscall, 0, CALL_INDIRECT, VOID) /* 244 */
|
||||
ENTRY("", 245, no_syscall, 0, CALL_INDIRECT, VOID) /* 245 */
|
||||
ENTRY("", 246, no_syscall, 0, CALL_INDIRECT, VOID) /* 246 */
|
||||
#ifdef SYS_nfsclnt
|
||||
ENTRY("nfsclnt", SYS_nfsclnt, nfsclnt, 2, CALL_DIRECT, INT, PTR) /* 247 */
|
||||
#else
|
||||
ENTRY("nfsclnt", 247, no_syscall, 2, CALL_INDIRECT, VOID) /* 247 */
|
||||
#endif
|
||||
ENTRY("", 247, no_syscall, 0, CALL_INDIRECT, VOID) /* 247 */
|
||||
ENTRY("", 248, no_syscall, 0, CALL_INDIRECT, VOID) /* 248 */
|
||||
ENTRY("", 249, no_syscall, 0, CALL_INDIRECT, VOID) /* 249 */
|
||||
ENTRY("minherit", SYS_minherit, minherit, 3, CALL_DIRECT, PTR, INT, INT) /* 250 */
|
||||
ENTRY("semsys", SYS_semsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 251 */
|
||||
ENTRY("msgsys", SYS_msgsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 252 */
|
||||
ENTRY("shmsys", SYS_shmsys, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 253 */
|
||||
ENTRY("semctl", SYS_semctl, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 254 */
|
||||
ENTRY("semget", SYS_semget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 255 */
|
||||
ENTRY("semop", SYS_semop, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 256 */
|
||||
ENTRY("", 257, no_syscall, 0, CALL_INDIRECT, VOID) /* 257 */
|
||||
ENTRY("msgctl", SYS_msgctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 258 */
|
||||
ENTRY("msgget", SYS_msgget, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 259 */
|
||||
ENTRY("msgsnd", SYS_msgsnd, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 260 */
|
||||
ENTRY("msgrcv", SYS_msgrcv, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 261 */
|
||||
ENTRY("shmat", SYS_shmat, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 262 */
|
||||
ENTRY("shmctl", SYS_shmctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 263 */
|
||||
ENTRY("shmdt", SYS_shmdt, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 264 */
|
||||
ENTRY("shmget", SYS_shmget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 265 */
|
||||
ENTRY("shm_open", SYS_shm_open, shm_open, 3, CALL_DIRECT, PTR, INT, INT) /* 266 */
|
||||
ENTRY("shm_unlink", SYS_shm_unlink, shm_unlink, 1, CALL_DIRECT, PTR) /* 267 */
|
||||
ENTRY("sem_open", SYS_sem_open, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 268 */
|
||||
ENTRY("sem_close", SYS_sem_close, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 269 */
|
||||
ENTRY("sem_unlink", SYS_sem_unlink, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 270 */
|
||||
ENTRY("sem_wait", SYS_sem_wait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 271 */
|
||||
ENTRY("sem_trywait", SYS_sem_trywait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 272 */
|
||||
ENTRY("sem_post", SYS_sem_post, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 273 */
|
||||
ENTRY("sem_getvalue", SYS_sem_getvalue, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 274 */
|
||||
ENTRY("sem_init", SYS_sem_init, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 275 */
|
||||
ENTRY("sem_destroy", SYS_sem_destroy, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 276 */
|
||||
ENTRY("open_extended", SYS_open_extended, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 277 */
|
||||
ENTRY("umask_extended", SYS_umask_extended, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 278 */
|
||||
ENTRY("stat_extended", SYS_stat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 279 */
|
||||
ENTRY("lstat_extended", SYS_lstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 280 */
|
||||
ENTRY("fstat_extended", SYS_fstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 281 */
|
||||
ENTRY("chmod_extended", SYS_chmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 282 */
|
||||
ENTRY("fchmod_extended", SYS_fchmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 283 */
|
||||
ENTRY("access_extended", SYS_access_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 284 */
|
||||
ENTRY("settid", SYS_settid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 285 */
|
||||
ENTRY("gettid", SYS_gettid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 286 */
|
||||
ENTRY("setsgroups", SYS_setsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 287 */
|
||||
ENTRY("getsgroups", SYS_getsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 288 */
|
||||
ENTRY("setwgroups", SYS_setwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 289 */
|
||||
ENTRY("getwgroups", SYS_getwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 290 */
|
||||
ENTRY("mkfifo_extended", SYS_mkfifo_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 291 */
|
||||
ENTRY("mkdir_extended", SYS_mkdir_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 292 */
|
||||
ENTRY("identitysvc", SYS_identitysvc, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 293 */
|
||||
ENTRY("", 294, no_syscall, 0, CALL_INDIRECT, VOID) /* 294 */
|
||||
ENTRY("", 295, no_syscall, 0, CALL_INDIRECT, VOID) /* 295 */
|
||||
ENTRY("load_shared_file", SYS_load_shared_file, unimpl_unix_syscall, 7, CALL_INDIRECT, VOID) /* 296 */
|
||||
ENTRY("reset_shared_file", SYS_reset_shared_file, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 297 */
|
||||
ENTRY("new_system_shared_regions", SYS_new_system_shared_regions, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 298 */
|
||||
ENTRY("shared_region_map_file_np", SYS_shared_region_map_file_np, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 299 */
|
||||
ENTRY("shared_region_make_private_np", SYS_shared_region_make_private_np, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 300 */
|
||||
ENTRY("", 301, no_syscall, 0, CALL_INDIRECT, VOID) /* 301 */
|
||||
ENTRY("", 302, no_syscall, 0, CALL_INDIRECT, VOID) /* 302 */
|
||||
ENTRY("", 303, no_syscall, 0, CALL_INDIRECT, VOID) /* 303 */
|
||||
ENTRY("", 304, no_syscall, 0, CALL_INDIRECT, VOID) /* 304 */
|
||||
ENTRY("", 305, no_syscall, 0, CALL_INDIRECT, VOID) /* 305 */
|
||||
ENTRY("", 306, no_syscall, 0, CALL_INDIRECT, VOID) /* 306 */
|
||||
ENTRY("", 307, no_syscall, 0, CALL_INDIRECT, VOID) /* 307 */
|
||||
ENTRY("", 308, no_syscall, 0, CALL_INDIRECT, VOID) /* 308 */
|
||||
ENTRY("", 309, no_syscall, 0, CALL_INDIRECT, VOID) /* 309 */
|
||||
ENTRY("getsid", SYS_getsid, getsid, 1, CALL_DIRECT, INT) /* 310 */
|
||||
ENTRY("settid_with_pid", SYS_settid_with_pid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 311 */
|
||||
ENTRY("", 312, no_syscall, 0, CALL_INDIRECT, VOID) /* 312 */
|
||||
ENTRY("aio_fsync", SYS_aio_fsync, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 313 */
|
||||
ENTRY("aio_return", SYS_aio_return, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 314 */
|
||||
ENTRY("aio_suspend", SYS_aio_suspend, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 315 */
|
||||
ENTRY("aio_cancel", SYS_aio_cancel, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 316 */
|
||||
ENTRY("aio_error", SYS_aio_error, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 317 */
|
||||
ENTRY("aio_read", SYS_aio_read, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 318 */
|
||||
ENTRY("aio_write", SYS_aio_write, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 319 */
|
||||
ENTRY("lio_listio", SYS_lio_listio, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 320 */
|
||||
ENTRY("", 321, no_syscall, 0, CALL_INDIRECT, VOID) /* 321 */
|
||||
ENTRY("", 322, no_syscall, 0, CALL_INDIRECT, VOID) /* 322 */
|
||||
ENTRY("", 323, no_syscall, 0, CALL_INDIRECT, VOID) /* 323 */
|
||||
ENTRY("mlockall", SYS_mlockall, mlockall, 1, CALL_DIRECT, INT) /* 324 */
|
||||
ENTRY("munlockall", SYS_munlockall, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 325 */
|
||||
ENTRY("", 326, no_syscall, 0, CALL_INDIRECT, VOID) /* 326 */
|
||||
ENTRY("issetugid", SYS_issetugid, issetugid, 0, CALL_DIRECT, VOID) /* 327 */
|
||||
ENTRY("__pthread_kill", SYS___pthread_kill, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 328 */
|
||||
ENTRY("pthread_sigmask", SYS_pthread_sigmask, pthread_sigmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 329 */
|
||||
ENTRY("sigwait", SYS_sigwait, sigwait, 2, CALL_DIRECT, PTR, PTR) /* 330 */
|
||||
ENTRY("__disable_threadsignal", SYS___disable_threadsignal, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 331 */
|
||||
ENTRY("__pthread_markcancel", SYS___pthread_markcancel, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 332 */
|
||||
ENTRY("__pthread_canceled", SYS___pthread_canceled, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 333 */
|
||||
ENTRY("__semwait_signal", SYS___semwait_signal, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 334 */
|
||||
ENTRY("utrace", SYS_utrace, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 335 */
|
||||
ENTRY("proc_info", SYS_proc_info, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 336 */
|
||||
ENTRY("", 337, no_syscall, 0, CALL_INDIRECT, VOID) /* 337 */
|
||||
ENTRY("", 338, no_syscall, 0, CALL_INDIRECT, VOID) /* 338 */
|
||||
ENTRY("", 339, no_syscall, 0, CALL_INDIRECT, VOID) /* 339 */
|
||||
ENTRY("", 340, no_syscall, 0, CALL_INDIRECT, VOID) /* 340 */
|
||||
ENTRY("", 341, no_syscall, 0, CALL_INDIRECT, VOID) /* 341 */
|
||||
ENTRY("", 342, no_syscall, 0, CALL_INDIRECT, VOID) /* 342 */
|
||||
ENTRY("", 343, no_syscall, 0, CALL_INDIRECT, VOID) /* 343 */
|
||||
ENTRY("", 344, no_syscall, 0, CALL_INDIRECT, VOID) /* 344 */
|
||||
ENTRY("", 345, no_syscall, 0, CALL_INDIRECT, VOID) /* 345 */
|
||||
ENTRY("", 346, no_syscall, 0, CALL_INDIRECT, VOID) /* 346 */
|
||||
ENTRY("", 347, no_syscall, 0, CALL_INDIRECT, VOID) /* 347 */
|
||||
ENTRY("", 348, no_syscall, 0, CALL_INDIRECT, VOID) /* 348 */
|
||||
ENTRY("", 349, no_syscall, 0, CALL_INDIRECT, VOID) /* 349 */
|
||||
ENTRY("audit", SYS_audit, audit, 2, CALL_DIRECT, PTR, INT) /* 350 */
|
||||
ENTRY("auditon", SYS_auditon, auditon, 3, CALL_DIRECT, INT, PTR, INT) /* 351 */
|
||||
ENTRY("", 352, no_syscall, 0, CALL_INDIRECT, VOID) /* 352 */
|
||||
ENTRY("getauid", SYS_getauid, getauid, 1, CALL_DIRECT, PTR) /* 353 */
|
||||
ENTRY("setauid", SYS_setauid, setauid, 1, CALL_DIRECT, PTR) /* 354 */
|
||||
ENTRY("getaudit", SYS_getaudit, getaudit, 1, CALL_DIRECT, PTR) /* 355 */
|
||||
ENTRY("setaudit", SYS_setaudit, setaudit, 1, CALL_DIRECT, PTR) /* 356 */
|
||||
ENTRY("getaudit_addr", SYS_getaudit_addr, getaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 357 */
|
||||
ENTRY("setaudit_addr", SYS_setaudit_addr, setaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 358 */
|
||||
ENTRY("auditctl", SYS_auditctl, auditctl, 1, CALL_DIRECT, PTR) /* 359 */
|
||||
ENTRY("", 360, no_syscall, 0, CALL_INDIRECT, VOID) /* 360 */
|
||||
ENTRY("", 361, no_syscall, 0, CALL_INDIRECT, VOID) /* 361 */
|
||||
ENTRY("kqueue", SYS_kqueue, kqueue, 0, CALL_DIRECT, VOID) /* 362 */
|
||||
ENTRY("kevent", SYS_kevent, kevent, 6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR) /* 363 */
|
||||
ENTRY("lchown", SYS_lchown, lchown, 3, CALL_DIRECT, PTR, INT , INT) /* 364 */
|
||||
ENTRY("stack_snapshot", SYS_stack_snapshot, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 365 */
|
||||
ENTRY("", 366, no_syscall, 0, CALL_INDIRECT, VOID) /* 366 */
|
||||
ENTRY("", 367, no_syscall, 0, CALL_INDIRECT, VOID) /* 367 */
|
||||
ENTRY("", 368, no_syscall, 0, CALL_INDIRECT, VOID) /* 368 */
|
||||
ENTRY("", 369, no_syscall, 0, CALL_INDIRECT, VOID) /* 369 */
|
||||
@@ -186,14 +186,14 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(TARGET_M68K)
|
||||
print_insn = print_insn_m68k;
|
||||
#elif defined(TARGET_MIPS)
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
print_insn = print_insn_big_mips;
|
||||
#else
|
||||
print_insn = print_insn_little_mips;
|
||||
#endif
|
||||
#elif defined(TARGET_M68K)
|
||||
print_insn = print_insn_m68k;
|
||||
#elif defined(TARGET_SH4)
|
||||
disasm_info.mach = bfd_mach_sh4;
|
||||
print_insn = print_insn_sh;
|
||||
@@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
|
||||
fprintf(out, "0x%08lx: ", pc);
|
||||
#ifdef __arm__
|
||||
/* since data are included in the code, it is better to
|
||||
/* since data is included in the code, it is better to
|
||||
display code data too */
|
||||
if (is_host) {
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
}
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
#endif
|
||||
count = print_insn(pc, &disasm_info);
|
||||
fprintf(out, "\n");
|
||||
@@ -387,14 +385,14 @@ void monitor_disas(CPUState *env,
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(TARGET_M68K)
|
||||
print_insn = print_insn_m68k;
|
||||
#elif defined(TARGET_MIPS)
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
print_insn = print_insn_big_mips;
|
||||
#else
|
||||
print_insn = print_insn_little_mips;
|
||||
#endif
|
||||
#elif defined(TARGET_M68K)
|
||||
print_insn = print_insn_m68k;
|
||||
#else
|
||||
term_printf("0x" TARGET_FMT_lx
|
||||
": Asm output not supported on this arch\n", pc);
|
||||
|
||||
+4
-1
@@ -62,6 +62,9 @@ typedef signed long long int64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* XXX: This may be wrong for 64-bit ILP32 hosts. */
|
||||
typedef void * host_reg_t;
|
||||
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32767-1)
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
@@ -188,7 +191,7 @@ extern int printf(const char *, ...);
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
#define FORCE_RET() __asm__ __volatile__("" : : : "memory");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
|
||||
@@ -127,10 +127,12 @@
|
||||
typedef int32_t host_long;
|
||||
typedef uint32_t host_ulong;
|
||||
#define swabls(x) swab32s(x)
|
||||
#define swablss(x) swab32ss(x)
|
||||
#else
|
||||
typedef int64_t host_long;
|
||||
typedef uint64_t host_ulong;
|
||||
#define swabls(x) swab64s(x)
|
||||
#define swablss(x) swab64ss(x)
|
||||
#endif
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
@@ -284,11 +286,21 @@ void swab32s(uint32_t *p)
|
||||
*p = bswap32(*p);
|
||||
}
|
||||
|
||||
void swab32ss(int32_t *p)
|
||||
{
|
||||
*p = bswap32(*p);
|
||||
}
|
||||
|
||||
void swab64s(uint64_t *p)
|
||||
{
|
||||
*p = bswap64(*p);
|
||||
}
|
||||
|
||||
void swab64ss(int64_t *p)
|
||||
{
|
||||
*p = bswap64(*p);
|
||||
}
|
||||
|
||||
uint16_t get16(uint16_t *p)
|
||||
{
|
||||
uint16_t val;
|
||||
@@ -397,7 +409,7 @@ void elf_swap_rel(ELF_RELOC *rel)
|
||||
swabls(&rel->r_offset);
|
||||
swabls(&rel->r_info);
|
||||
#ifdef ELF_USES_RELOCA
|
||||
swabls(&rel->r_addend);
|
||||
swablss(&rel->r_addend);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -505,7 +517,7 @@ int load_object(const char *filename)
|
||||
}
|
||||
|
||||
sec = &shdr[ehdr.e_shstrndx];
|
||||
shstr = sdata[ehdr.e_shstrndx];
|
||||
shstr = (char *)sdata[ehdr.e_shstrndx];
|
||||
|
||||
/* swap relocations */
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
@@ -541,7 +553,7 @@ int load_object(const char *filename)
|
||||
strtab_sec = &shdr[symtab_sec->sh_link];
|
||||
|
||||
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
|
||||
strtab = sdata[symtab_sec->sh_link];
|
||||
strtab = (char *)sdata[symtab_sec->sh_link];
|
||||
|
||||
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
|
||||
if (do_swap) {
|
||||
@@ -1255,90 +1267,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
|
||||
{
|
||||
uint8_t *p;
|
||||
uint32_t insn;
|
||||
int offset, min_offset, pc_offset, data_size;
|
||||
int offset, min_offset, pc_offset, data_size, spare, max_pool;
|
||||
uint8_t data_allocated[1024];
|
||||
unsigned int data_index;
|
||||
int type;
|
||||
|
||||
memset(data_allocated, 0, sizeof(data_allocated));
|
||||
|
||||
p = p_start;
|
||||
min_offset = p_end - p_start;
|
||||
spare = 0x7fffffff;
|
||||
while (p < p_start + min_offset) {
|
||||
insn = get32((uint32_t *)p);
|
||||
/* TODO: Armv5e ldrd. */
|
||||
/* TODO: VFP load. */
|
||||
if ((insn & 0x0d5f0000) == 0x051f0000) {
|
||||
/* ldr reg, [pc, #im] */
|
||||
offset = insn & 0xfff;
|
||||
if (!(insn & 0x00800000))
|
||||
offset = -offset;
|
||||
offset = -offset;
|
||||
max_pool = 4096;
|
||||
type = 0;
|
||||
} else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
|
||||
/* FPA ldf. */
|
||||
offset = (insn & 0xff) << 2;
|
||||
if (!(insn & 0x00800000))
|
||||
offset = -offset;
|
||||
max_pool = 1024;
|
||||
type = 1;
|
||||
} else if ((insn & 0x0fff0000) == 0x028f0000) {
|
||||
/* Some gcc load a doubleword immediate with
|
||||
add regN, pc, #imm
|
||||
ldmia regN, {regN, regM}
|
||||
Hope and pray the compiler never generates somethin like
|
||||
add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
|
||||
int r;
|
||||
|
||||
r = (insn & 0xf00) >> 7;
|
||||
offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
|
||||
max_pool = 1024;
|
||||
type = 2;
|
||||
} else {
|
||||
max_pool = 0;
|
||||
type = -1;
|
||||
}
|
||||
if (type >= 0) {
|
||||
/* PC-relative load needs fixing up. */
|
||||
if (spare > max_pool - offset)
|
||||
spare = max_pool - offset;
|
||||
if ((offset & 3) !=0)
|
||||
error("%s:%04x: ldr pc offset must be 32 bit aligned",
|
||||
error("%s:%04x: pc offset must be 32 bit aligned",
|
||||
name, start_offset + p - p_start);
|
||||
if (offset < 0)
|
||||
error("%s:%04x: Embedded literal value",
|
||||
name, start_offset + p - p_start);
|
||||
pc_offset = p - p_start + offset + 8;
|
||||
if (pc_offset <= (p - p_start) ||
|
||||
pc_offset >= (p_end - p_start))
|
||||
error("%s:%04x: ldr pc offset must point inside the function code",
|
||||
error("%s:%04x: pc offset must point inside the function code",
|
||||
name, start_offset + p - p_start);
|
||||
if (pc_offset < min_offset)
|
||||
min_offset = pc_offset;
|
||||
if (outfile) {
|
||||
/* ldr position */
|
||||
/* The intruction position */
|
||||
fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
|
||||
p - p_start);
|
||||
/* ldr data index */
|
||||
data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
|
||||
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
|
||||
/* The position of the constant pool data. */
|
||||
data_index = ((p_end - p_start) - pc_offset) >> 2;
|
||||
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
|
||||
data_index);
|
||||
fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
|
||||
fprintf(outfile, " arm_ldr_ptr++;\n");
|
||||
if (data_index >= sizeof(data_allocated))
|
||||
error("%s: too many data", name);
|
||||
if (!data_allocated[data_index]) {
|
||||
ELF_RELOC *rel;
|
||||
int i, addend, type;
|
||||
const char *sym_name, *p;
|
||||
char relname[1024];
|
||||
|
||||
data_allocated[data_index] = 1;
|
||||
|
||||
/* data value */
|
||||
addend = get32((uint32_t *)(p_start + pc_offset));
|
||||
relname[0] = '\0';
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset == (pc_offset + start_offset)) {
|
||||
sym_name = get_rel_sym_name(rel);
|
||||
/* the compiler leave some unnecessary references to the code */
|
||||
get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
if (type != R_ARM_ABS32)
|
||||
error("%s: unsupported data relocation", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
|
||||
data_index, addend);
|
||||
if (relname[0] != '\0')
|
||||
fprintf(outfile, " + %s", relname);
|
||||
fprintf(outfile, ";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
p += 4;
|
||||
}
|
||||
|
||||
/* Copy and relocate the constant pool data. */
|
||||
data_size = (p_end - p_start) - min_offset;
|
||||
if (data_size > 0 && outfile) {
|
||||
fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2);
|
||||
spare += min_offset;
|
||||
fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2);
|
||||
fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size);
|
||||
fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n"
|
||||
" arm_pool_ptr = gen_code_ptr + %d;\n",
|
||||
spare, spare);
|
||||
|
||||
data_index = 0;
|
||||
for (pc_offset = min_offset;
|
||||
pc_offset < p_end - p_start;
|
||||
pc_offset += 4) {
|
||||
|
||||
ELF_RELOC *rel;
|
||||
int i, addend, type;
|
||||
const char *sym_name;
|
||||
char relname[1024];
|
||||
|
||||
/* data value */
|
||||
addend = get32((uint32_t *)(p_start + pc_offset));
|
||||
relname[0] = '\0';
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset == (pc_offset + start_offset)) {
|
||||
sym_name = get_rel_sym_name(rel);
|
||||
/* the compiler leave some unnecessary references to the code */
|
||||
get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
if (type != R_ARM_ABS32)
|
||||
error("%s: unsupported data relocation", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
|
||||
data_index, addend);
|
||||
if (relname[0] != '\0')
|
||||
fprintf(outfile, " + %s", relname);
|
||||
fprintf(outfile, ";\n");
|
||||
|
||||
data_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* the last instruction must be a mov pc, lr */
|
||||
if (p == p_start)
|
||||
goto arm_ret_error;
|
||||
p -= 4;
|
||||
insn = get32((uint32_t *)p);
|
||||
if ((insn & 0xffff0000) != 0xe91b0000) {
|
||||
/* The last instruction must be an ldm instruction. There are several
|
||||
forms generated by gcc:
|
||||
ldmib sp, {..., pc} (implies a sp adjustment of +4)
|
||||
ldmia sp, {..., pc}
|
||||
ldmea fp, {..., pc} */
|
||||
if ((insn & 0xffff8000) == 0xe99d8000) {
|
||||
if (outfile) {
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
|
||||
p - p_start);
|
||||
}
|
||||
p += 4;
|
||||
} else if ((insn & 0xffff8000) != 0xe89d8000
|
||||
&& (insn & 0xffff8000) != 0xe91b8000) {
|
||||
arm_ret_error:
|
||||
if (!outfile)
|
||||
printf("%s: invalid epilog\n", name);
|
||||
}
|
||||
return p - p_start;
|
||||
return p - p_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1537,6 +1608,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
#elif defined(HOST_ARM)
|
||||
{
|
||||
uint32_t insn;
|
||||
|
||||
if ((p_end - p_start) <= 16)
|
||||
error("%s: function too small", name);
|
||||
if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
|
||||
@@ -1545,6 +1618,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
error("%s: invalid prolog", name);
|
||||
p_start += 12;
|
||||
start_offset += 12;
|
||||
insn = get32((uint32_t *)p_start);
|
||||
if ((insn & 0xffffff00) == 0xe24dd000) {
|
||||
/* Stack adjustment. Assume op uses the frame pointer. */
|
||||
p_start -= 4;
|
||||
start_offset -= 4;
|
||||
}
|
||||
copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
|
||||
relocs, nb_relocs);
|
||||
}
|
||||
@@ -2282,7 +2361,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
int type;
|
||||
int addend;
|
||||
int reloc_offset;
|
||||
uint32_t insn;
|
||||
|
||||
insn = get32((uint32_t *)(p_start + 4));
|
||||
/* If prologue ends in sub sp, sp, #const then assume
|
||||
op has a stack frame and needs the frame pointer. */
|
||||
if ((insn & 0xffffff00) == 0xe24dd000) {
|
||||
int i;
|
||||
uint32_t opcode;
|
||||
opcode = 0xe28db000; /* add fp, sp, #0. */
|
||||
#if 0
|
||||
/* ??? Need to undo the extra stack adjustment at the end of the op.
|
||||
For now just leave the stack misaligned and hope it doesn't break anything
|
||||
too important. */
|
||||
if ((insn & 4) != 0) {
|
||||
/* Preserve doubleword stack alignment. */
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
|
||||
insn + 4);
|
||||
opcode -= 4;
|
||||
}
|
||||
#endif
|
||||
insn = get32((uint32_t *)(p_start - 4));
|
||||
/* Calculate the size of the saved registers,
|
||||
excluding pc. */
|
||||
for (i = 0; i < 15; i++) {
|
||||
if (insn & (1 << i))
|
||||
opcode += 4;
|
||||
}
|
||||
fprintf(outfile,
|
||||
" *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
|
||||
}
|
||||
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
|
||||
relocs, nb_relocs);
|
||||
|
||||
@@ -2303,6 +2412,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
reloc_offset, name, addend);
|
||||
break;
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_CALL:
|
||||
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
|
||||
reloc_offset, addend, name);
|
||||
break;
|
||||
@@ -2407,6 +2518,28 @@ int gen_file(FILE *outfile, int out_type)
|
||||
|
||||
} else {
|
||||
/* generate big code generation switch */
|
||||
|
||||
#ifdef HOST_ARM
|
||||
/* We need to know the size of all the ops so we can figure out when
|
||||
to emit constant pools. This must be consistent with opc.h. */
|
||||
fprintf(outfile,
|
||||
"static const uint32_t arm_opc_size[] = {\n"
|
||||
" 0,\n" /* end */
|
||||
" 0,\n" /* nop */
|
||||
" 0,\n" /* nop1 */
|
||||
" 0,\n" /* nop2 */
|
||||
" 0,\n"); /* nop3 */
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = get_sym_name(sym);
|
||||
if (strstart(name, OP_PREFIX, NULL)) {
|
||||
fprintf(outfile, " %d,\n", sym->st_size);
|
||||
}
|
||||
}
|
||||
fprintf(outfile,
|
||||
"};\n");
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
||||
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
|
||||
@@ -2417,10 +2550,36 @@ fprintf(outfile,
|
||||
" const uint32_t *opparam_ptr;\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
/* Arm is tricky because it uses constant pools for loading immediate values.
|
||||
We assume (and require) each function is code followed by a constant pool.
|
||||
All the ops are small so this should be ok. For each op we figure
|
||||
out how much "spare" range we have in the load instructions. This allows
|
||||
us to insert subsequent ops in between the op and the constant pool,
|
||||
eliminating the neeed to jump around the pool.
|
||||
|
||||
We currently generate:
|
||||
|
||||
[ For this example we assume merging would move op1_pool out of range.
|
||||
In practice we should be able to combine many ops before the offset
|
||||
limits are reached. ]
|
||||
op1_code;
|
||||
op2_code;
|
||||
goto op3;
|
||||
op2_pool;
|
||||
op1_pool;
|
||||
op3:
|
||||
op3_code;
|
||||
ret;
|
||||
op3_pool;
|
||||
|
||||
Ideally we'd put op1_pool before op2_pool, but that requires two passes.
|
||||
*/
|
||||
fprintf(outfile,
|
||||
" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
|
||||
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" uint32_t *arm_data_ptr = arm_data_table;\n");
|
||||
" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
|
||||
/* Initialise the parmissible pool offset to an arbitary large value. */
|
||||
" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
|
||||
#endif
|
||||
#ifdef HOST_IA64
|
||||
{
|
||||
@@ -2489,9 +2648,23 @@ fprintf(outfile,
|
||||
/* Generate prologue, if needed. */
|
||||
|
||||
fprintf(outfile,
|
||||
" for(;;) {\n"
|
||||
" switch(*opc_ptr++) {\n"
|
||||
);
|
||||
" for(;;) {\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
/* Generate constant pool if needed */
|
||||
fprintf(outfile,
|
||||
" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
|
||||
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
|
||||
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
|
||||
" last_gen_code_ptr = gen_code_ptr;\n"
|
||||
" arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
|
||||
" arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
|
||||
" }\n");
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
" switch(*opc_ptr++) {\n");
|
||||
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
@@ -2525,17 +2698,6 @@ fprintf(outfile,
|
||||
" goto the_end;\n"
|
||||
" }\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
/* generate constant table if needed */
|
||||
fprintf(outfile,
|
||||
" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
|
||||
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
|
||||
" last_gen_code_ptr = gen_code_ptr;\n"
|
||||
" arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" arm_data_ptr = arm_data_table;\n"
|
||||
" }\n");
|
||||
#endif
|
||||
|
||||
|
||||
fprintf(outfile,
|
||||
" }\n"
|
||||
@@ -2553,7 +2715,10 @@ fprintf(outfile,
|
||||
|
||||
/* 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");
|
||||
fprintf(outfile,
|
||||
"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
|
||||
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
|
||||
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 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;
|
||||
#ifdef __sparc__
|
||||
#if defined(__sparc__) || defined(__arm__)
|
||||
void __op_gen_label1(){}
|
||||
void __op_gen_label2(){}
|
||||
void __op_gen_label3(){}
|
||||
@@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) {
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define MAX_OP_SIZE (128 * 4) /* in bytes */
|
||||
/* max size of the code that can be generated without calling arm_flush_ldr */
|
||||
#define MAX_FRAG_SIZE (1024 * 4)
|
||||
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
|
||||
#define ARM_LDR_TABLE_SIZE 1024
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
unsigned type:2;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[1024];
|
||||
static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
@@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
uint32_t mask;
|
||||
|
||||
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
|
||||
data_size = (data_end - data_start) << 2;
|
||||
|
||||
if (gen_jmp) {
|
||||
/* generate branch to skip the data */
|
||||
@@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
insn = *ptr & ~(0xfff | 0x00800000);
|
||||
if (offset < 0) {
|
||||
offset = - offset;
|
||||
} else {
|
||||
insn |= 0x00800000;
|
||||
}
|
||||
if (offset > 0xfff) {
|
||||
fprintf(stderr, "Error ldr offset\n");
|
||||
fprintf(stderr, "Negative constant pool offset\n");
|
||||
abort();
|
||||
}
|
||||
insn |= offset;
|
||||
switch (le->type) {
|
||||
case 0: /* ldr */
|
||||
mask = ~0x00800fff;
|
||||
if (offset >= 4096) {
|
||||
fprintf(stderr, "Bad ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 1: /* ldc */
|
||||
mask = ~0x008000ff;
|
||||
if (offset >= 1024 ) {
|
||||
fprintf(stderr, "Bad ldc offset\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 2: /* add */
|
||||
mask = ~0xfff;
|
||||
if (offset >= 1024 ) {
|
||||
fprintf(stderr, "Bad add offset\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Bad pc relative fixup\n");
|
||||
abort();
|
||||
}
|
||||
insn = *ptr & mask;
|
||||
switch (le->type) {
|
||||
case 0: /* ldr */
|
||||
insn |= offset | 0x00800000;
|
||||
break;
|
||||
case 1: /* ldc */
|
||||
insn |= (offset >> 2) | 0x00800000;
|
||||
break;
|
||||
case 2: /* add */
|
||||
insn |= (offset >> 2) | 0xf00;
|
||||
break;
|
||||
}
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
|
||||
@@ -502,6 +502,8 @@ typedef struct {
|
||||
#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
|
||||
#define R_ARM_GOT32 26 /* 32 bit GOT entry */
|
||||
#define R_ARM_PLT32 27 /* 32 bit PLT address */
|
||||
#define R_ARM_CALL 28
|
||||
#define R_ARM_JUMP24 29
|
||||
#define R_ARM_GNU_VTENTRY 100
|
||||
#define R_ARM_GNU_VTINHERIT 101
|
||||
#define R_ARM_THM_PC11 102 /* thumb unconditional branch */
|
||||
|
||||
@@ -153,6 +153,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
|
||||
glue(bswap_ehdr, SZ)(&ehdr);
|
||||
}
|
||||
|
||||
if (ELF_MACHINE != ehdr.e_machine)
|
||||
goto fail;
|
||||
|
||||
if (pentry)
|
||||
*pentry = (uint64_t)ehdr.e_entry;
|
||||
|
||||
@@ -202,4 +205,3 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
|
||||
qemu_free(phdr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+11
-1
@@ -196,9 +196,19 @@ typedef struct TranslationBlock {
|
||||
struct TranslationBlock *jmp_first;
|
||||
} TranslationBlock;
|
||||
|
||||
static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
|
||||
{
|
||||
target_ulong tmp;
|
||||
tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
|
||||
return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
|
||||
{
|
||||
return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1);
|
||||
target_ulong tmp;
|
||||
tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
|
||||
return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) |
|
||||
(tmp & TB_JMP_ADDR_MASK));
|
||||
}
|
||||
|
||||
static inline unsigned int tb_phys_hash_func(unsigned long pc)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
//#define DEBUG_TB_INVALIDATE
|
||||
//#define DEBUG_FLUSH
|
||||
//#define DEBUG_TLB
|
||||
//#define DEBUG_UNASSIGNED
|
||||
|
||||
/* make various TB consistency checks */
|
||||
//#define DEBUG_TB_CHECK
|
||||
@@ -1288,14 +1289,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
|
||||
tlb_flush_entry(&env->tlb_table[0][i], addr);
|
||||
tlb_flush_entry(&env->tlb_table[1][i], addr);
|
||||
|
||||
for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
|
||||
tb = env->tb_jmp_cache[i];
|
||||
if (tb &&
|
||||
((tb->pc & TARGET_PAGE_MASK) == addr ||
|
||||
((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
|
||||
env->tb_jmp_cache[i] = NULL;
|
||||
}
|
||||
}
|
||||
/* Discard jump cache entries for any tb which might potentially
|
||||
overlap the flushed page. */
|
||||
i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
|
||||
memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
|
||||
|
||||
i = tb_jmp_cache_hash_page(addr);
|
||||
memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
if (addr < MMAP_AREA_END)
|
||||
@@ -1801,13 +1801,30 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: temporary until new memory mapping API */
|
||||
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
|
||||
{
|
||||
PhysPageDesc *p;
|
||||
|
||||
p = phys_page_find(addr >> TARGET_PAGE_BITS);
|
||||
if (!p)
|
||||
return IO_MEM_UNASSIGNED;
|
||||
return p->phys_offset;
|
||||
}
|
||||
|
||||
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
#ifdef DEBUG_UNASSIGNED
|
||||
printf("Unassigned mem read 0x%08x\n", (int)addr);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
#ifdef DEBUG_UNASSIGNED
|
||||
printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
|
||||
|
||||
+25
-9
@@ -149,7 +149,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM)
|
||||
{
|
||||
return sqrtf(a);
|
||||
}
|
||||
char float32_compare( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_compare( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
if (a < b) {
|
||||
return -1;
|
||||
@@ -161,7 +161,7 @@ char float32_compare( float32 a, float32 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
if (isless(a, b)) {
|
||||
return -1;
|
||||
@@ -173,7 +173,7 @@ char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
char float32_is_signaling_nan( float32 a1)
|
||||
int float32_is_signaling_nan( float32 a1)
|
||||
{
|
||||
float32u u;
|
||||
uint32_t a;
|
||||
@@ -221,6 +221,11 @@ float128 float64_to_float128( float64 a STATUS_PARAM)
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_trunc_to_int( float64 a STATUS_PARAM )
|
||||
{
|
||||
return trunc(a);
|
||||
}
|
||||
|
||||
float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
{
|
||||
#if defined(__arm__)
|
||||
@@ -253,7 +258,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM)
|
||||
{
|
||||
return sqrt(a);
|
||||
}
|
||||
char float64_compare( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_compare( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
if (a < b) {
|
||||
return -1;
|
||||
@@ -265,7 +270,7 @@ char float64_compare( float64 a, float64 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
if (isless(a, b)) {
|
||||
return -1;
|
||||
@@ -277,7 +282,7 @@ char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
char float64_is_signaling_nan( float64 a1)
|
||||
int float64_is_signaling_nan( float64 a1)
|
||||
{
|
||||
float64u u;
|
||||
uint64_t a;
|
||||
@@ -289,6 +294,17 @@ char float64_is_signaling_nan( float64 a1)
|
||||
|
||||
}
|
||||
|
||||
int float64_is_nan( float64 a1 )
|
||||
{
|
||||
float64u u;
|
||||
uint64_t a;
|
||||
u.f = a1;
|
||||
a = u.i;
|
||||
|
||||
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -334,7 +350,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
|
||||
{
|
||||
return sqrtl(a);
|
||||
}
|
||||
char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
if (a < b) {
|
||||
return -1;
|
||||
@@ -346,7 +362,7 @@ char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
if (isless(a, b)) {
|
||||
return -1;
|
||||
@@ -358,7 +374,7 @@ char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
char floatx80_is_signaling_nan( floatx80 a1)
|
||||
int floatx80_is_signaling_nan( floatx80 a1)
|
||||
{
|
||||
floatx80u u;
|
||||
u.f = a1;
|
||||
|
||||
+32
-30
@@ -152,38 +152,38 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
|
||||
}
|
||||
float32 float32_rem( float32, float32 STATUS_PARAM);
|
||||
float32 float32_sqrt( float32 STATUS_PARAM);
|
||||
INLINE char float32_eq( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
INLINE char float32_le( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_le( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
INLINE char float32_lt( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_lt( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b && a >= b;
|
||||
}
|
||||
INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return islessequal(a, b);
|
||||
}
|
||||
INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return isless(a, b);
|
||||
}
|
||||
INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return isunordered(a, b);
|
||||
|
||||
}
|
||||
char float32_compare( float32, float32 STATUS_PARAM );
|
||||
char float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
char float32_is_signaling_nan( float32 );
|
||||
int float32_compare( float32, float32 STATUS_PARAM );
|
||||
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_is_signaling_nan( float32 );
|
||||
|
||||
INLINE float32 float32_abs(float32 a)
|
||||
{
|
||||
@@ -214,6 +214,7 @@ float128 float64_to_float128( float64 STATUS_PARAM );
|
||||
| Software IEC/IEEE double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_round_to_int( float64 STATUS_PARAM );
|
||||
float64 float64_trunc_to_int( float64 STATUS_PARAM );
|
||||
INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a + b;
|
||||
@@ -232,39 +233,40 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
|
||||
}
|
||||
float64 float64_rem( float64, float64 STATUS_PARAM );
|
||||
float64 float64_sqrt( float64 STATUS_PARAM );
|
||||
INLINE char float64_eq( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
INLINE char float64_le( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_le( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
INLINE char float64_lt( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_lt( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b && a >= b;
|
||||
}
|
||||
INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return islessequal(a, b);
|
||||
}
|
||||
INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return isless(a, b);
|
||||
|
||||
}
|
||||
INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return isunordered(a, b);
|
||||
|
||||
}
|
||||
char float64_compare( float64, float64 STATUS_PARAM );
|
||||
char float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
char float64_is_signaling_nan( float64 );
|
||||
int float64_compare( float64, float64 STATUS_PARAM );
|
||||
int float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_is_signaling_nan( float64 );
|
||||
int float64_is_nan( float64 );
|
||||
|
||||
INLINE float64 float64_abs(float64 a)
|
||||
{
|
||||
@@ -313,39 +315,39 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
}
|
||||
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
|
||||
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
|
||||
INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b && a >= b;
|
||||
}
|
||||
INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return islessequal(a, b);
|
||||
}
|
||||
INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return isless(a, b);
|
||||
|
||||
}
|
||||
INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return isunordered(a, b);
|
||||
|
||||
}
|
||||
char floatx80_compare( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_is_signaling_nan( floatx80 );
|
||||
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_is_signaling_nan( floatx80 );
|
||||
|
||||
INLINE floatx80 floatx80_abs(floatx80 a)
|
||||
{
|
||||
|
||||
@@ -68,7 +68,7 @@ typedef struct {
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_is_nan( float32 a )
|
||||
int float32_is_nan( float32 a )
|
||||
{
|
||||
|
||||
return ( 0xFF000000 < (bits32) ( a<<1 ) );
|
||||
@@ -80,7 +80,7 @@ flag float32_is_nan( float32 a )
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_is_signaling_nan( float32 a )
|
||||
int float32_is_signaling_nan( float32 a )
|
||||
{
|
||||
|
||||
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
|
||||
@@ -161,7 +161,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_is_nan( float64 a )
|
||||
int float64_is_nan( float64 a )
|
||||
{
|
||||
|
||||
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
|
||||
@@ -173,7 +173,7 @@ flag float64_is_nan( float64 a )
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_is_signaling_nan( float64 a )
|
||||
int float64_is_signaling_nan( float64 a )
|
||||
{
|
||||
|
||||
return
|
||||
@@ -264,7 +264,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_is_nan( floatx80 a )
|
||||
int floatx80_is_nan( floatx80 a )
|
||||
{
|
||||
|
||||
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
|
||||
@@ -276,7 +276,7 @@ flag floatx80_is_nan( floatx80 a )
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_is_signaling_nan( floatx80 a )
|
||||
int floatx80_is_signaling_nan( floatx80 a )
|
||||
{
|
||||
bits64 aLow;
|
||||
|
||||
@@ -371,7 +371,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_is_nan( float128 a )
|
||||
int float128_is_nan( float128 a )
|
||||
{
|
||||
|
||||
return
|
||||
@@ -385,7 +385,7 @@ flag float128_is_nan( float128 a )
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_is_signaling_nan( float128 a )
|
||||
int float128_is_signaling_nan( float128 a )
|
||||
{
|
||||
|
||||
return
|
||||
|
||||
+38
-27
@@ -2023,7 +2023,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
@@ -2045,7 +2045,7 @@ flag float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -2068,7 +2068,7 @@ flag float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -2092,7 +2092,7 @@ flag float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
@@ -2112,7 +2112,7 @@ flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -2138,7 +2138,7 @@ flag float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
| Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -2483,6 +2483,17 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
|
||||
}
|
||||
|
||||
float64 float64_trunc_to_int( float64 a STATUS_PARAM)
|
||||
{
|
||||
int oldmode;
|
||||
float64 res;
|
||||
oldmode = STATUS(float_rounding_mode);
|
||||
STATUS(float_rounding_mode) = float_round_to_zero;
|
||||
res = float64_round_to_int(a STATUS_VAR);
|
||||
STATUS(float_rounding_mode) = oldmode;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of adding the absolute values of the double-precision
|
||||
| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
|
||||
@@ -2941,7 +2952,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
@@ -2963,7 +2974,7 @@ flag float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -2986,7 +2997,7 @@ flag float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -3010,7 +3021,7 @@ flag float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
@@ -3030,7 +3041,7 @@ flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -3056,7 +3067,7 @@ flag float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
| Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -3879,7 +3890,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
@@ -3909,7 +3920,7 @@ flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -3942,7 +3953,7 @@ flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -3975,7 +3986,7 @@ flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
@@ -4002,7 +4013,7 @@ flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -4038,7 +4049,7 @@ flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -4999,7 +5010,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_eq( float128 a, float128 b STATUS_PARAM )
|
||||
int float128_eq( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
|
||||
@@ -5029,7 +5040,7 @@ flag float128_eq( float128 a, float128 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_le( float128 a, float128 b STATUS_PARAM )
|
||||
int float128_le( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5061,7 +5072,7 @@ flag float128_le( float128 a, float128 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_lt( float128 a, float128 b STATUS_PARAM )
|
||||
int float128_lt( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5094,7 +5105,7 @@ flag float128_lt( float128 a, float128 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|
||||
int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
|
||||
@@ -5121,7 +5132,7 @@ flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_le_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5157,7 +5168,7 @@ flag float128_le_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
| Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5272,7 +5283,7 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
|
||||
}
|
||||
|
||||
#define COMPARE(s, nan_exp) \
|
||||
INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
int is_quiet STATUS_PARAM ) \
|
||||
{ \
|
||||
flag aSign, bSign; \
|
||||
@@ -5306,12 +5317,12 @@ INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
char float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
{ \
|
||||
return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
char float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
{ \
|
||||
return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \
|
||||
}
|
||||
|
||||
+35
-33
@@ -43,7 +43,7 @@ these four paragraphs for those parts of this code that are retained.
|
||||
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
|
||||
| to the same as `int'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef char flag;
|
||||
typedef uint8_t flag;
|
||||
typedef uint8_t uint8;
|
||||
typedef int8_t int8;
|
||||
typedef int uint16;
|
||||
@@ -228,15 +228,16 @@ float32 float32_mul( float32, float32 STATUS_PARAM );
|
||||
float32 float32_div( float32, float32 STATUS_PARAM );
|
||||
float32 float32_rem( float32, float32 STATUS_PARAM );
|
||||
float32 float32_sqrt( float32 STATUS_PARAM );
|
||||
char float32_eq( float32, float32 STATUS_PARAM );
|
||||
char float32_le( float32, float32 STATUS_PARAM );
|
||||
char float32_lt( float32, float32 STATUS_PARAM );
|
||||
char float32_eq_signaling( float32, float32 STATUS_PARAM );
|
||||
char float32_le_quiet( float32, float32 STATUS_PARAM );
|
||||
char float32_lt_quiet( float32, float32 STATUS_PARAM );
|
||||
char float32_compare( float32, float32 STATUS_PARAM );
|
||||
char float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
char float32_is_signaling_nan( float32 );
|
||||
int float32_eq( float32, float32 STATUS_PARAM );
|
||||
int float32_le( float32, float32 STATUS_PARAM );
|
||||
int float32_lt( float32, float32 STATUS_PARAM );
|
||||
int float32_eq_signaling( float32, float32 STATUS_PARAM );
|
||||
int float32_le_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_lt_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_compare( float32, float32 STATUS_PARAM );
|
||||
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_is_signaling_nan( float32 );
|
||||
int float64_is_nan( float64 a );
|
||||
|
||||
INLINE float32 float32_abs(float32 a)
|
||||
{
|
||||
@@ -269,21 +270,22 @@ float128 float64_to_float128( float64 STATUS_PARAM );
|
||||
| Software IEC/IEEE double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_round_to_int( float64 STATUS_PARAM );
|
||||
float64 float64_trunc_to_int( float64 STATUS_PARAM );
|
||||
float64 float64_add( float64, float64 STATUS_PARAM );
|
||||
float64 float64_sub( float64, float64 STATUS_PARAM );
|
||||
float64 float64_mul( float64, float64 STATUS_PARAM );
|
||||
float64 float64_div( float64, float64 STATUS_PARAM );
|
||||
float64 float64_rem( float64, float64 STATUS_PARAM );
|
||||
float64 float64_sqrt( float64 STATUS_PARAM );
|
||||
char float64_eq( float64, float64 STATUS_PARAM );
|
||||
char float64_le( float64, float64 STATUS_PARAM );
|
||||
char float64_lt( float64, float64 STATUS_PARAM );
|
||||
char float64_eq_signaling( float64, float64 STATUS_PARAM );
|
||||
char float64_le_quiet( float64, float64 STATUS_PARAM );
|
||||
char float64_lt_quiet( float64, float64 STATUS_PARAM );
|
||||
char float64_compare( float64, float64 STATUS_PARAM );
|
||||
char float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
char float64_is_signaling_nan( float64 );
|
||||
int float64_eq( float64, float64 STATUS_PARAM );
|
||||
int float64_le( float64, float64 STATUS_PARAM );
|
||||
int float64_lt( float64, float64 STATUS_PARAM );
|
||||
int float64_eq_signaling( float64, float64 STATUS_PARAM );
|
||||
int float64_le_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_lt_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_compare( float64, float64 STATUS_PARAM );
|
||||
int float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_is_signaling_nan( float64 );
|
||||
|
||||
INLINE float64 float64_abs(float64 a)
|
||||
{
|
||||
@@ -320,13 +322,13 @@ floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM );
|
||||
floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM );
|
||||
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
|
||||
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
|
||||
char floatx80_eq( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_le( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_lt( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_is_signaling_nan( floatx80 );
|
||||
int floatx80_eq( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_le( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_is_signaling_nan( floatx80 );
|
||||
|
||||
INLINE floatx80 floatx80_abs(floatx80 a)
|
||||
{
|
||||
@@ -367,13 +369,13 @@ float128 float128_mul( float128, float128 STATUS_PARAM );
|
||||
float128 float128_div( float128, float128 STATUS_PARAM );
|
||||
float128 float128_rem( float128, float128 STATUS_PARAM );
|
||||
float128 float128_sqrt( float128 STATUS_PARAM );
|
||||
char float128_eq( float128, float128 STATUS_PARAM );
|
||||
char float128_le( float128, float128 STATUS_PARAM );
|
||||
char float128_lt( float128, float128 STATUS_PARAM );
|
||||
char float128_eq_signaling( float128, float128 STATUS_PARAM );
|
||||
char float128_le_quiet( float128, float128 STATUS_PARAM );
|
||||
char float128_lt_quiet( float128, float128 STATUS_PARAM );
|
||||
char float128_is_signaling_nan( float128 );
|
||||
int float128_eq( float128, float128 STATUS_PARAM );
|
||||
int float128_le( float128, float128 STATUS_PARAM );
|
||||
int float128_lt( float128, float128 STATUS_PARAM );
|
||||
int float128_eq_signaling( float128, float128 STATUS_PARAM );
|
||||
int float128_le_quiet( float128, float128 STATUS_PARAM );
|
||||
int float128_lt_quiet( float128, float128 STATUS_PARAM );
|
||||
int float128_is_signaling_nan( float128 );
|
||||
|
||||
INLINE float128 float128_abs(float128 a)
|
||||
{
|
||||
|
||||
@@ -52,26 +52,30 @@ enum RSState {
|
||||
RS_GETLINE,
|
||||
RS_CHKSUM1,
|
||||
RS_CHKSUM2,
|
||||
RS_SYSCALL,
|
||||
};
|
||||
/* XXX: This is not thread safe. Do we care? */
|
||||
static int gdbserver_fd = -1;
|
||||
|
||||
typedef struct GDBState {
|
||||
CPUState *env; /* current CPU */
|
||||
enum RSState state; /* parsing state */
|
||||
int fd;
|
||||
char line_buf[4096];
|
||||
int line_buf_index;
|
||||
int line_csum;
|
||||
char last_packet[4100];
|
||||
int last_packet_len;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int fd;
|
||||
int running_state;
|
||||
#else
|
||||
CharDriverState *chr;
|
||||
#endif
|
||||
} GDBState;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* XXX: This is not thread safe. Do we care? */
|
||||
static int gdbserver_fd = -1;
|
||||
|
||||
/* XXX: remove this hack. */
|
||||
static GDBState gdbserver_state;
|
||||
#endif
|
||||
|
||||
static int get_char(GDBState *s)
|
||||
{
|
||||
@@ -91,9 +95,32 @@ static int get_char(GDBState *s)
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* GDB stub state for use by semihosting syscalls. */
|
||||
static GDBState *gdb_syscall_state;
|
||||
static gdb_syscall_complete_cb gdb_current_syscall_cb;
|
||||
|
||||
enum {
|
||||
GDB_SYS_UNKNOWN,
|
||||
GDB_SYS_ENABLED,
|
||||
GDB_SYS_DISABLED,
|
||||
} gdb_syscall_mode;
|
||||
|
||||
/* If gdb is connected when the first semihosting syscall occurs then use
|
||||
remote gdb syscalls. Otherwise use native file IO. */
|
||||
int use_gdb_syscalls(void)
|
||||
{
|
||||
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
|
||||
gdb_syscall_mode = (gdb_syscall_state ? GDB_SYS_ENABLED
|
||||
: GDB_SYS_DISABLED);
|
||||
}
|
||||
return gdb_syscall_mode == GDB_SYS_ENABLED;
|
||||
}
|
||||
|
||||
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
@@ -106,6 +133,9 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||
len -= ret;
|
||||
}
|
||||
}
|
||||
#else
|
||||
qemu_chr_write(s->chr, buf, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int fromhex(int v)
|
||||
@@ -154,33 +184,39 @@ static void hextomem(uint8_t *mem, const char *buf, int len)
|
||||
/* return -1 if error, 0 if OK */
|
||||
static int put_packet(GDBState *s, char *buf)
|
||||
{
|
||||
char buf1[3];
|
||||
int len, csum, ch, i;
|
||||
int len, csum, i;
|
||||
char *p;
|
||||
|
||||
#ifdef DEBUG_GDB
|
||||
printf("reply='%s'\n", buf);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
buf1[0] = '$';
|
||||
put_buffer(s, buf1, 1);
|
||||
p = s->last_packet;
|
||||
*(p++) = '$';
|
||||
len = strlen(buf);
|
||||
put_buffer(s, buf, len);
|
||||
memcpy(p, buf, len);
|
||||
p += len;
|
||||
csum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
csum += buf[i];
|
||||
}
|
||||
buf1[0] = '#';
|
||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||
buf1[2] = tohex((csum) & 0xf);
|
||||
*(p++) = '#';
|
||||
*(p++) = tohex((csum >> 4) & 0xf);
|
||||
*(p++) = tohex((csum) & 0xf);
|
||||
|
||||
put_buffer(s, buf1, 3);
|
||||
s->last_packet_len = p - s->last_packet;
|
||||
put_buffer(s, s->last_packet, s->last_packet_len);
|
||||
|
||||
ch = get_char(s);
|
||||
if (ch < 0)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
i = get_char(s);
|
||||
if (i < 0)
|
||||
return -1;
|
||||
if (ch == '+')
|
||||
if (i == '+')
|
||||
break;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -434,6 +470,73 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
ptr += 8 * 12 + 4;
|
||||
cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff);
|
||||
}
|
||||
#elif defined (TARGET_M68K)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
CPU_DoubleU u;
|
||||
|
||||
ptr = mem_buf;
|
||||
/* D0-D7 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
*(uint32_t *)ptr = tswapl(env->dregs[i]);
|
||||
ptr += 4;
|
||||
}
|
||||
/* A0-A7 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
*(uint32_t *)ptr = tswapl(env->aregs[i]);
|
||||
ptr += 4;
|
||||
}
|
||||
*(uint32_t *)ptr = tswapl(env->sr);
|
||||
ptr += 4;
|
||||
*(uint32_t *)ptr = tswapl(env->pc);
|
||||
ptr += 4;
|
||||
/* F0-F7. The 68881/68040 have 12-bit extended precision registers.
|
||||
ColdFire has 8-bit double precision registers. */
|
||||
for (i = 0; i < 8; i++) {
|
||||
u.d = env->fregs[i];
|
||||
*(uint32_t *)ptr = tswap32(u.l.upper);
|
||||
*(uint32_t *)ptr = tswap32(u.l.lower);
|
||||
}
|
||||
/* FP control regs (not implemented). */
|
||||
memset (ptr, 0, 3 * 4);
|
||||
ptr += 3 * 4;
|
||||
|
||||
return ptr - mem_buf;
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
CPU_DoubleU u;
|
||||
|
||||
ptr = mem_buf;
|
||||
/* D0-D7 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->dregs[i] = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
/* A0-A7 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->aregs[i] = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
env->sr = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
env->pc = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
/* F0-F7. The 68881/68040 have 12-bit extended precision registers.
|
||||
ColdFire has 8-bit double precision registers. */
|
||||
for (i = 0; i < 8; i++) {
|
||||
u.l.upper = tswap32(*(uint32_t *)ptr);
|
||||
u.l.lower = tswap32(*(uint32_t *)ptr);
|
||||
env->fregs[i] = u.d;
|
||||
}
|
||||
/* FP control regs (not implemented). */
|
||||
ptr += 3 * 4;
|
||||
}
|
||||
#elif defined (TARGET_MIPS)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
@@ -465,11 +568,37 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
*(uint32_t *)ptr = tswapl(env->PC);
|
||||
ptr += 4;
|
||||
|
||||
#ifdef MIPS_USES_FPU
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
*(uint32_t *)ptr = tswapl(FPR_W (env, i));
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
*(uint32_t *)ptr = tswapl(env->fcr31);
|
||||
ptr += 4;
|
||||
|
||||
*(uint32_t *)ptr = tswapl(env->fcr0);
|
||||
ptr += 4;
|
||||
#endif
|
||||
|
||||
/* 32 FP registers, fsr, fir, fp. Not yet implemented. */
|
||||
/* what's 'fp' mean here? */
|
||||
|
||||
return ptr - mem_buf;
|
||||
}
|
||||
|
||||
/* convert MIPS rounding mode in FCR31 to IEEE library */
|
||||
static unsigned int ieee_rm[] =
|
||||
{
|
||||
float_round_nearest_even,
|
||||
float_round_to_zero,
|
||||
float_round_up,
|
||||
float_round_down
|
||||
};
|
||||
#define RESTORE_ROUNDING_MODE \
|
||||
set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
int i;
|
||||
@@ -499,6 +628,28 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
|
||||
env->PC = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
|
||||
#ifdef MIPS_USES_FPU
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
FPR_W (env, i) = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF;
|
||||
ptr += 4;
|
||||
|
||||
env->fcr0 = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
|
||||
/* set rounding mode */
|
||||
RESTORE_ROUNDING_MODE;
|
||||
|
||||
#ifndef CONFIG_SOFTFLOAT
|
||||
/* no floating point exception for native float */
|
||||
SET_FP_ENABLE(env->fcr31, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#elif defined (TARGET_SH4)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
@@ -626,6 +777,34 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
|
||||
vm_start();
|
||||
#endif
|
||||
return RS_IDLE;
|
||||
case 'F':
|
||||
{
|
||||
target_ulong ret;
|
||||
target_ulong err;
|
||||
|
||||
ret = strtoull(p, (char **)&p, 16);
|
||||
if (*p == ',') {
|
||||
p++;
|
||||
err = strtoull(p, (char **)&p, 16);
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
if (*p == ',')
|
||||
p++;
|
||||
type = *p;
|
||||
if (gdb_current_syscall_cb)
|
||||
gdb_current_syscall_cb(s->env, ret, err);
|
||||
if (type == 'C') {
|
||||
put_packet(s, "T02");
|
||||
} else {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
s->running_state = 1;
|
||||
#else
|
||||
vm_start();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
reg_size = cpu_gdb_read_registers(env, mem_buf);
|
||||
memtohex(buf, mem_buf, reg_size);
|
||||
@@ -695,7 +874,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
|
||||
goto breakpoint_error;
|
||||
}
|
||||
break;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#ifdef CONFIG_LINUX_USER
|
||||
case 'q':
|
||||
if (strncmp(p, "Offsets", 7) == 0) {
|
||||
TaskState *ts = env->opaque;
|
||||
@@ -726,6 +905,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
if (s->state == RS_SYSCALL)
|
||||
return;
|
||||
|
||||
/* disable single step if it was enable */
|
||||
cpu_single_step(s->env, 0);
|
||||
|
||||
@@ -742,6 +924,60 @@ static void gdb_vm_stopped(void *opaque, int reason)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Send a gdb syscall request.
|
||||
This accepts limited printf-style format specifiers, specifically:
|
||||
%x - target_ulong argument printed in hex.
|
||||
%s - string pointer (target_ulong) and length (int) pair. */
|
||||
void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
char buf[256];
|
||||
char *p;
|
||||
target_ulong addr;
|
||||
GDBState *s;
|
||||
|
||||
s = gdb_syscall_state;
|
||||
if (!s)
|
||||
return;
|
||||
gdb_current_syscall_cb = cb;
|
||||
s->state = RS_SYSCALL;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
vm_stop(EXCP_DEBUG);
|
||||
#endif
|
||||
s->state = RS_IDLE;
|
||||
va_start(va, fmt);
|
||||
p = buf;
|
||||
*(p++) = 'F';
|
||||
while (*fmt) {
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
switch (*fmt++) {
|
||||
case 'x':
|
||||
addr = va_arg(va, target_ulong);
|
||||
p += sprintf(p, TARGET_FMT_lx, addr);
|
||||
break;
|
||||
case 's':
|
||||
addr = va_arg(va, target_ulong);
|
||||
p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
|
||||
fmt - 1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*(p++) = *(fmt++);
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
put_packet(s, buf);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
gdb_handlesig(s->env, 0);
|
||||
#else
|
||||
cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gdb_read_byte(GDBState *s, int ch)
|
||||
{
|
||||
CPUState *env = s->env;
|
||||
@@ -749,6 +985,26 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
char reply[1];
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (s->last_packet_len) {
|
||||
/* Waiting for a response to the last packet. If we see the start
|
||||
of a new command then abandon the previous response. */
|
||||
if (ch == '-') {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("Got NACK, retransmitting\n");
|
||||
#endif
|
||||
put_buffer(s, s->last_packet, s->last_packet_len);
|
||||
}
|
||||
#ifdef DEBUG_GDB
|
||||
else if (ch == '+')
|
||||
printf("Got ACK\n");
|
||||
else
|
||||
printf("Got '%c' when expecting ACK/NACK\n", ch);
|
||||
#endif
|
||||
if (ch == '+' || ch == '$')
|
||||
s->last_packet_len = 0;
|
||||
if (ch != '$')
|
||||
return;
|
||||
}
|
||||
if (vm_running) {
|
||||
/* when the CPU is running, we cannot do anything except stop
|
||||
it when receiving a char */
|
||||
@@ -793,6 +1049,8 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
s->state = gdb_handle_packet(s, env, s->line_buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -857,29 +1115,6 @@ void gdb_exit(CPUState *env, int code)
|
||||
put_packet(s, buf);
|
||||
}
|
||||
|
||||
#else
|
||||
static void gdb_read(void *opaque)
|
||||
{
|
||||
GDBState *s = opaque;
|
||||
int i, size;
|
||||
uint8_t buf[4096];
|
||||
|
||||
size = recv(s->fd, buf, sizeof(buf), 0);
|
||||
if (size < 0)
|
||||
return;
|
||||
if (size == 0) {
|
||||
/* end of connection */
|
||||
qemu_del_vm_stop_handler(gdb_vm_stopped, s);
|
||||
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
|
||||
qemu_free(s);
|
||||
vm_start();
|
||||
} else {
|
||||
for(i = 0; i < size; i++)
|
||||
gdb_read_byte(s, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void gdb_accept(void *opaque)
|
||||
{
|
||||
@@ -903,32 +1138,14 @@ static void gdb_accept(void *opaque)
|
||||
val = 1;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
s = &gdbserver_state;
|
||||
memset (s, 0, sizeof (GDBState));
|
||||
#else
|
||||
s = qemu_mallocz(sizeof(GDBState));
|
||||
if (!s) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
s->env = first_cpu; /* XXX: allow to change CPU */
|
||||
s->fd = fd;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
gdb_syscall_state = s;
|
||||
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
#else
|
||||
socket_set_nonblock(fd);
|
||||
|
||||
/* stop the VM */
|
||||
vm_stop(EXCP_INTERRUPT);
|
||||
|
||||
/* start handling I/O */
|
||||
qemu_set_fd_handler(s->fd, gdb_read, NULL, s);
|
||||
/* when the VM is stopped, the following callback is called */
|
||||
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int gdbserver_open(int port)
|
||||
@@ -959,9 +1176,6 @@ static int gdbserver_open(int port)
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
socket_set_nonblock(fd);
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -971,10 +1185,67 @@ int gdbserver_start(int port)
|
||||
if (gdbserver_fd < 0)
|
||||
return -1;
|
||||
/* accept connections */
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
gdb_accept (NULL);
|
||||
#else
|
||||
qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int gdb_chr_can_recieve(void *opaque)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
GDBState *s = opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
gdb_read_byte(s, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void gdb_chr_event(void *opaque, int event)
|
||||
{
|
||||
switch (event) {
|
||||
case CHR_EVENT_RESET:
|
||||
vm_stop(EXCP_INTERRUPT);
|
||||
gdb_syscall_state = opaque;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int gdbserver_start(CharDriverState *chr)
|
||||
{
|
||||
GDBState *s;
|
||||
|
||||
if (!chr)
|
||||
return -1;
|
||||
|
||||
s = qemu_mallocz(sizeof(GDBState));
|
||||
if (!s) {
|
||||
return -1;
|
||||
}
|
||||
s->env = first_cpu; /* XXX: allow to change CPU */
|
||||
s->chr = chr;
|
||||
qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve,
|
||||
gdb_chr_event, s);
|
||||
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gdbserver_start_port(int port)
|
||||
{
|
||||
CharDriverState *chr;
|
||||
char gdbstub_port_name[128];
|
||||
|
||||
snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
|
||||
"tcp::%d,nowait,nodelay,server", port);
|
||||
chr = qemu_chr_open(gdbstub_port_name);
|
||||
if (!chr)
|
||||
return -EIO;
|
||||
return gdbserver_start(chr);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,10 +3,18 @@
|
||||
|
||||
#define DEFAULT_GDBSTUB_PORT 1234
|
||||
|
||||
typedef void (*gdb_syscall_complete_cb)(CPUState *env,
|
||||
target_ulong ret, target_ulong err);
|
||||
|
||||
void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...);
|
||||
int use_gdb_syscalls(void);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int gdb_handlesig (CPUState *, int);
|
||||
void gdb_exit(CPUState *, int);
|
||||
#endif
|
||||
int gdbserver_start(int);
|
||||
#else
|
||||
int gdbserver_start(CharDriverState *chr);
|
||||
int gdbserver_start_port(int port);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Save/restore host registrs.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* The GCC global register vairable extension is used to reserve some
|
||||
host registers for use by dyngen. However only the core parts of the
|
||||
translation engine are compiled with these settings. We must manually
|
||||
save/restore these registers when called from regular code.
|
||||
It is not sufficient to save/restore T0 et. al. as these may be declared
|
||||
with a datatype smaller than the actual register. */
|
||||
|
||||
#if defined(DECLARE_HOST_REGS)
|
||||
|
||||
#define DO_REG(REG) \
|
||||
register host_reg_t reg_AREG##REG asm(AREG##REG); \
|
||||
volatile host_reg_t saved_AREG##REG;
|
||||
|
||||
#elif defined(SAVE_HOST_REGS)
|
||||
|
||||
#define DO_REG(REG) \
|
||||
__asm__ __volatile__ ("" : "=r" (reg_AREG##REG)); \
|
||||
saved_AREG##REG = reg_AREG##REG;
|
||||
|
||||
#else
|
||||
|
||||
#define DO_REG(REG) \
|
||||
reg_AREG##REG = saved_AREG##REG; \
|
||||
__asm__ __volatile__ ("" : : "r" (reg_AREG##REG));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef AREG0
|
||||
DO_REG(0)
|
||||
#endif
|
||||
|
||||
#ifdef AREG1
|
||||
DO_REG(1)
|
||||
#endif
|
||||
|
||||
#ifdef AREG2
|
||||
DO_REG(2)
|
||||
#endif
|
||||
|
||||
#ifdef AREG3
|
||||
DO_REG(3)
|
||||
#endif
|
||||
|
||||
#ifdef AREG4
|
||||
DO_REG(4)
|
||||
#endif
|
||||
|
||||
#ifdef AREG5
|
||||
DO_REG(5)
|
||||
#endif
|
||||
|
||||
#ifdef AREG6
|
||||
DO_REG(6)
|
||||
#endif
|
||||
|
||||
#ifdef AREG7
|
||||
DO_REG(7)
|
||||
#endif
|
||||
|
||||
#ifdef AREG8
|
||||
DO_REG(8)
|
||||
#endif
|
||||
|
||||
#ifdef AREG9
|
||||
DO_REG(9)
|
||||
#endif
|
||||
|
||||
#ifdef AREG10
|
||||
DO_REG(10)
|
||||
#endif
|
||||
|
||||
#ifdef AREG11
|
||||
DO_REG(11)
|
||||
#endif
|
||||
|
||||
#undef SAVE_HOST_REGS
|
||||
#undef DECLARE_HOST_REGS
|
||||
#undef DO_REG
|
||||
@@ -1,559 +0,0 @@
|
||||
/*
|
||||
* QEMU ACPI DSDT ASL definition
|
||||
*
|
||||
* Copyright (c) 2006 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 version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
DefinitionBlock (
|
||||
"acpi-dsdt.aml", // Output Filename
|
||||
"DSDT", // Signature
|
||||
0x01, // DSDT Compliance Revision
|
||||
"QEMU", // OEMID
|
||||
"QEMUDSDT", // TABLE ID
|
||||
0x1 // OEM Revision
|
||||
)
|
||||
{
|
||||
Scope (\)
|
||||
{
|
||||
/* CMOS memory access */
|
||||
OperationRegion (CMS, SystemIO, 0x70, 0x02)
|
||||
Field (CMS, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
CMSI, 8,
|
||||
CMSD, 8
|
||||
}
|
||||
Method (CMRD, 1, NotSerialized)
|
||||
{
|
||||
Store (Arg0, CMSI)
|
||||
Store (CMSD, Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
/* Debug Output */
|
||||
OperationRegion (DBG, SystemIO, 0xb044, 0x04)
|
||||
Field (DBG, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
DBGL, 32,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* PCI Bus definition */
|
||||
Scope(\_SB) {
|
||||
Device(PCI0) {
|
||||
Name (_HID, EisaId ("PNP0A03"))
|
||||
Name (_ADR, 0x00)
|
||||
Name (_UID, 1)
|
||||
Name(_PRT, Package() {
|
||||
/* PCI IRQ routing table, example from ACPI 2.0a specification,
|
||||
section 6.2.8.1 */
|
||||
/* Note: we provide the same info as the PCI routing
|
||||
table of the Bochs BIOS */
|
||||
|
||||
// PCI Slot 0
|
||||
Package() {0x0000ffff, 0, LNKD, 0},
|
||||
Package() {0x0000ffff, 1, LNKA, 0},
|
||||
Package() {0x0000ffff, 2, LNKB, 0},
|
||||
Package() {0x0000ffff, 3, LNKC, 0},
|
||||
|
||||
// PCI Slot 1
|
||||
Package() {0x0001ffff, 0, LNKA, 0},
|
||||
Package() {0x0001ffff, 1, LNKB, 0},
|
||||
Package() {0x0001ffff, 2, LNKC, 0},
|
||||
Package() {0x0001ffff, 3, LNKD, 0},
|
||||
|
||||
// PCI Slot 2
|
||||
Package() {0x0002ffff, 0, LNKB, 0},
|
||||
Package() {0x0002ffff, 1, LNKC, 0},
|
||||
Package() {0x0002ffff, 2, LNKD, 0},
|
||||
Package() {0x0002ffff, 3, LNKA, 0},
|
||||
|
||||
// PCI Slot 3
|
||||
Package() {0x0003ffff, 0, LNKC, 0},
|
||||
Package() {0x0003ffff, 1, LNKD, 0},
|
||||
Package() {0x0003ffff, 2, LNKA, 0},
|
||||
Package() {0x0003ffff, 3, LNKB, 0},
|
||||
|
||||
// PCI Slot 4
|
||||
Package() {0x0004ffff, 0, LNKD, 0},
|
||||
Package() {0x0004ffff, 1, LNKA, 0},
|
||||
Package() {0x0004ffff, 2, LNKB, 0},
|
||||
Package() {0x0004ffff, 3, LNKC, 0},
|
||||
|
||||
// PCI Slot 5
|
||||
Package() {0x0005ffff, 0, LNKA, 0},
|
||||
Package() {0x0005ffff, 1, LNKB, 0},
|
||||
Package() {0x0005ffff, 2, LNKC, 0},
|
||||
Package() {0x0005ffff, 3, LNKD, 0},
|
||||
})
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (MEMP, ResourceTemplate ()
|
||||
{
|
||||
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
|
||||
0x0000, // Address Space Granularity
|
||||
0x0000, // Address Range Minimum
|
||||
0x00FF, // Address Range Maximum
|
||||
0x0000, // Address Translation Offset
|
||||
0x0100, // Address Length
|
||||
,, )
|
||||
IO (Decode16,
|
||||
0x0CF8, // Address Range Minimum
|
||||
0x0CF8, // Address Range Maximum
|
||||
0x01, // Address Alignment
|
||||
0x08, // Address Length
|
||||
)
|
||||
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
||||
0x0000, // Address Space Granularity
|
||||
0x0000, // Address Range Minimum
|
||||
0x0CF7, // Address Range Maximum
|
||||
0x0000, // Address Translation Offset
|
||||
0x0CF8, // Address Length
|
||||
,, , TypeStatic)
|
||||
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
||||
0x0000, // Address Space Granularity
|
||||
0x0D00, // Address Range Minimum
|
||||
0xFFFF, // Address Range Maximum
|
||||
0x0000, // Address Translation Offset
|
||||
0xF300, // Address Length
|
||||
,, , TypeStatic)
|
||||
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
|
||||
0x00000000, // Address Space Granularity
|
||||
0x000A0000, // Address Range Minimum
|
||||
0x000BFFFF, // Address Range Maximum
|
||||
0x00000000, // Address Translation Offset
|
||||
0x00020000, // Address Length
|
||||
,, , AddressRangeMemory, TypeStatic)
|
||||
DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite,
|
||||
0x00000000, // Address Space Granularity
|
||||
0x00000000, // Address Range Minimum
|
||||
0xFEBFFFFF, // Address Range Maximum
|
||||
0x00000000, // Address Translation Offset
|
||||
0x00000000, // Address Length
|
||||
,, MEMF, AddressRangeMemory, TypeStatic)
|
||||
})
|
||||
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN)
|
||||
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX)
|
||||
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN)
|
||||
/* compute available RAM */
|
||||
Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0)
|
||||
ShiftLeft(Local0, 16, Local0)
|
||||
Add(Local0, 0x1000000, Local0)
|
||||
/* update field of last region */
|
||||
Store(Local0, PMIN)
|
||||
Subtract (PMAX, PMIN, PLEN)
|
||||
Increment (PLEN)
|
||||
Return (MEMP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scope(\_SB.PCI0) {
|
||||
|
||||
/* PIIX3 ISA bridge */
|
||||
Device (ISA) {
|
||||
Name (_ADR, 0x00010000)
|
||||
|
||||
/* PIIX PCI to ISA irq remapping */
|
||||
OperationRegion (P40C, PCI_Config, 0x60, 0x04)
|
||||
|
||||
|
||||
/* Keyboard seems to be important for WinXP install */
|
||||
Device (KBD)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0303"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (0x0f)
|
||||
}
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (TMP, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16,
|
||||
0x0060, // Address Range Minimum
|
||||
0x0060, // Address Range Maximum
|
||||
0x01, // Address Alignment
|
||||
0x01, // Address Length
|
||||
)
|
||||
IO (Decode16,
|
||||
0x0064, // Address Range Minimum
|
||||
0x0064, // Address Range Maximum
|
||||
0x01, // Address Alignment
|
||||
0x01, // Address Length
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{1}
|
||||
})
|
||||
Return (TMP)
|
||||
}
|
||||
}
|
||||
|
||||
/* PS/2 mouse */
|
||||
Device (MOU)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0F13"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (0x0f)
|
||||
}
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (TMP, ResourceTemplate ()
|
||||
{
|
||||
IRQNoFlags () {12}
|
||||
})
|
||||
Return (TMP)
|
||||
}
|
||||
}
|
||||
|
||||
/* PS/2 floppy controller */
|
||||
Device (FDC0)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0700"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
|
||||
IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
|
||||
IRQNoFlags () {6}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8) {2}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
|
||||
/* Parallel port */
|
||||
Device (LPT)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0400"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (\_SB.PCI0.PX13.DRSA, Local0)
|
||||
And (Local0, 0x80000000, Local0)
|
||||
If (LEqual (Local0, 0))
|
||||
{
|
||||
Return (0x00)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
|
||||
IRQNoFlags () {7}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
|
||||
/* Serial Ports */
|
||||
Device (COM1)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0501"))
|
||||
Name (_UID, 0x01)
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (\_SB.PCI0.PX13.DRSC, Local0)
|
||||
And (Local0, 0x08000000, Local0)
|
||||
If (LEqual (Local0, 0))
|
||||
{
|
||||
Return (0x00)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
|
||||
IRQNoFlags () {4}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
|
||||
Device (COM2)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0501"))
|
||||
Name (_UID, 0x02)
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (\_SB.PCI0.PX13.DRSC, Local0)
|
||||
And (Local0, 0x80000000, Local0)
|
||||
If (LEqual (Local0, 0))
|
||||
{
|
||||
Return (0x00)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
|
||||
IRQNoFlags () {3}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PIIX4 PM */
|
||||
Device (PX13) {
|
||||
Name (_ADR, 0x00010003)
|
||||
|
||||
OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
|
||||
Field (P13C, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
DRSA, 32,
|
||||
DRSB, 32,
|
||||
DRSC, 32,
|
||||
DRSE, 32,
|
||||
DRSF, 32,
|
||||
DRSG, 32,
|
||||
DRSH, 32,
|
||||
DRSI, 32,
|
||||
DRSJ, 32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PCI IRQs */
|
||||
Scope(\_SB) {
|
||||
Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
PRQ0, 8,
|
||||
PRQ1, 8,
|
||||
PRQ2, 8,
|
||||
PRQ3, 8
|
||||
}
|
||||
|
||||
Device(LNKA){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 1)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ0, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ0, 0x80, PRQ0)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ0, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ0)
|
||||
}
|
||||
}
|
||||
Device(LNKB){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 2)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ1, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ1, 0x80, PRQ1)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ1, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ1)
|
||||
}
|
||||
}
|
||||
Device(LNKC){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 3)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ2, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ2, 0x80, PRQ2)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ2, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ2)
|
||||
}
|
||||
}
|
||||
Device(LNKD){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 4)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ3, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ3, 0x80, PRQ3)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ3, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* S5 = power off state */
|
||||
Name (_S5, Package (4) {
|
||||
0x00, // PM1a_CNT.SLP_TYP
|
||||
0x00, // PM2a_CNT.SLP_TYP
|
||||
0x00, // reserved
|
||||
0x00, // reserved
|
||||
})
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Intel ACPI Component Architecture
|
||||
* ASL Optimizing Compiler version 20060421 [Apr 29 2006]
|
||||
* Copyright (C) 2000 - 2006 Intel Corporation
|
||||
* Supports ACPI Specification Revision 3.0a
|
||||
*
|
||||
* Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006
|
||||
*
|
||||
* C source code output
|
||||
*
|
||||
*/
|
||||
unsigned char AmlCode[] =
|
||||
{
|
||||
0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */
|
||||
0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */
|
||||
0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */
|
||||
0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
||||
0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */
|
||||
0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */
|
||||
0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */
|
||||
0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */
|
||||
0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */
|
||||
0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */
|
||||
0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */
|
||||
0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */
|
||||
0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */
|
||||
0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */
|
||||
0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */
|
||||
0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */
|
||||
0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */
|
||||
0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */
|
||||
0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */
|
||||
0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */
|
||||
0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */
|
||||
0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */
|
||||
0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */
|
||||
0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */
|
||||
0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */
|
||||
0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */
|
||||
0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */
|
||||
0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */
|
||||
0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */
|
||||
0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */
|
||||
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */
|
||||
0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */
|
||||
0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */
|
||||
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */
|
||||
0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */
|
||||
0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */
|
||||
0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */
|
||||
0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */
|
||||
0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */
|
||||
0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */
|
||||
0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */
|
||||
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */
|
||||
0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */
|
||||
0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */
|
||||
0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */
|
||||
0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */
|
||||
0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */
|
||||
0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */
|
||||
0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */
|
||||
0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */
|
||||
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */
|
||||
0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */
|
||||
0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */
|
||||
0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */
|
||||
0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */
|
||||
0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */
|
||||
0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */
|
||||
0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */
|
||||
0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */
|
||||
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */
|
||||
0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */
|
||||
0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */
|
||||
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */
|
||||
0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */
|
||||
0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */
|
||||
0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */
|
||||
0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */
|
||||
0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */
|
||||
0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */
|
||||
0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */
|
||||
0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */
|
||||
0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */
|
||||
0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */
|
||||
0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */
|
||||
0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */
|
||||
0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */
|
||||
0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */
|
||||
0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */
|
||||
0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */
|
||||
0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */
|
||||
0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */
|
||||
0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */
|
||||
0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */
|
||||
0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */
|
||||
0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */
|
||||
0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */
|
||||
0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */
|
||||
0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */
|
||||
0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */
|
||||
0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */
|
||||
0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */
|
||||
0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */
|
||||
0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */
|
||||
0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */
|
||||
0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */
|
||||
0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */
|
||||
0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */
|
||||
0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */
|
||||
0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */
|
||||
0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */
|
||||
0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */
|
||||
0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */
|
||||
0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */
|
||||
0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */
|
||||
0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */
|
||||
0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */
|
||||
0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */
|
||||
0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */
|
||||
0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */
|
||||
0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */
|
||||
0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */
|
||||
0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */
|
||||
0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */
|
||||
0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */
|
||||
0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */
|
||||
0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */
|
||||
0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */
|
||||
0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */
|
||||
0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */
|
||||
0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */
|
||||
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */
|
||||
0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */
|
||||
0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */
|
||||
0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */
|
||||
0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */
|
||||
0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */
|
||||
0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */
|
||||
0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */
|
||||
0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */
|
||||
0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */
|
||||
0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */
|
||||
0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */
|
||||
0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */
|
||||
0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */
|
||||
0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */
|
||||
0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */
|
||||
0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */
|
||||
0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */
|
||||
0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */
|
||||
0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */
|
||||
0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */
|
||||
0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */
|
||||
0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */
|
||||
0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */
|
||||
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */
|
||||
0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */
|
||||
0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */
|
||||
0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */
|
||||
0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */
|
||||
0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */
|
||||
0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */
|
||||
0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */
|
||||
0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */
|
||||
0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */
|
||||
0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */
|
||||
0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */
|
||||
0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */
|
||||
0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */
|
||||
0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */
|
||||
0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */
|
||||
0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */
|
||||
0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */
|
||||
0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */
|
||||
0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */
|
||||
0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */
|
||||
0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */
|
||||
0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */
|
||||
0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */
|
||||
0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */
|
||||
0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */
|
||||
0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */
|
||||
0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */
|
||||
0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */
|
||||
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */
|
||||
0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */
|
||||
0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */
|
||||
0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */
|
||||
0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */
|
||||
0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */
|
||||
0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */
|
||||
0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */
|
||||
0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */
|
||||
0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */
|
||||
0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */
|
||||
0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */
|
||||
0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */
|
||||
0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */
|
||||
0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */
|
||||
0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */
|
||||
0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */
|
||||
0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */
|
||||
0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */
|
||||
0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */
|
||||
0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */
|
||||
0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */
|
||||
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */
|
||||
0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */
|
||||
0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */
|
||||
0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */
|
||||
0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */
|
||||
0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */
|
||||
0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */
|
||||
0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */
|
||||
0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */
|
||||
0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */
|
||||
0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */
|
||||
0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */
|
||||
0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */
|
||||
0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */
|
||||
0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */
|
||||
0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */
|
||||
0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */
|
||||
0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */
|
||||
0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */
|
||||
0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */
|
||||
0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */
|
||||
0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */
|
||||
0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */
|
||||
0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */
|
||||
0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */
|
||||
0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */
|
||||
0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */
|
||||
0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */
|
||||
0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */
|
||||
0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */
|
||||
0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */
|
||||
0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */
|
||||
0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */
|
||||
0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */
|
||||
0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */
|
||||
0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */
|
||||
0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */
|
||||
0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */
|
||||
0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */
|
||||
0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */
|
||||
0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */
|
||||
0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */
|
||||
0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */
|
||||
0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */
|
||||
0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */
|
||||
0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */
|
||||
0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */
|
||||
0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */
|
||||
0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */
|
||||
0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */
|
||||
0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */
|
||||
0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */
|
||||
0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */
|
||||
0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */
|
||||
0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */
|
||||
0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */
|
||||
0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */
|
||||
0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */
|
||||
0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */
|
||||
0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */
|
||||
0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */
|
||||
0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */
|
||||
0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */
|
||||
0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */
|
||||
0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */
|
||||
0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */
|
||||
0x00,0x00,
|
||||
};
|
||||
@@ -23,18 +23,27 @@
|
||||
/* i82731AB (PIIX4) compatible power management function */
|
||||
#define PM_FREQ 3579545
|
||||
|
||||
/* XXX: make them variable */
|
||||
#define PM_IO_BASE 0xb000
|
||||
#define SMI_CMD_IO_ADDR 0xb040
|
||||
#define ACPI_DBG_IO_ADDR 0xb044
|
||||
#define SMB_IO_BASE 0xb100
|
||||
|
||||
typedef struct PIIX4PMState {
|
||||
PCIDevice dev;
|
||||
uint16_t pmsts;
|
||||
uint16_t pmen;
|
||||
uint16_t pmcntrl;
|
||||
uint8_t apmc;
|
||||
uint8_t apms;
|
||||
QEMUTimer *tmr_timer;
|
||||
int64_t tmr_overflow_time;
|
||||
SMBusDevice *smb_dev[128];
|
||||
uint8_t smb_stat;
|
||||
uint8_t smb_ctl;
|
||||
uint8_t smb_cmd;
|
||||
uint8_t smb_addr;
|
||||
uint8_t smb_data0;
|
||||
uint8_t smb_data1;
|
||||
uint8_t smb_data[32];
|
||||
uint8_t smb_index;
|
||||
} PIIX4PMState;
|
||||
|
||||
#define RTC_EN (1 << 10)
|
||||
@@ -46,8 +55,15 @@ typedef struct PIIX4PMState {
|
||||
|
||||
#define SUS_EN (1 << 13)
|
||||
|
||||
/* Note: only used for ACPI bios init. Could be deleted when ACPI init
|
||||
is integrated in Bochs BIOS */
|
||||
#define SMBHSTSTS 0x00
|
||||
#define SMBHSTCNT 0x02
|
||||
#define SMBHSTCMD 0x03
|
||||
#define SMBHSTADD 0x04
|
||||
#define SMBHSTDAT0 0x05
|
||||
#define SMBHSTDAT1 0x06
|
||||
#define SMBBLKDAT 0x07
|
||||
|
||||
/* Note: only used for piix4_smbus_register_device */
|
||||
static PIIX4PMState *piix4_pm_state;
|
||||
|
||||
static uint32_t get_pmtmr(PIIX4PMState *s)
|
||||
@@ -195,22 +211,40 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
addr &= 1;
|
||||
#ifdef DEBUG
|
||||
printf("SMI cmd val=0x%02x\n", val);
|
||||
printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
switch(val) {
|
||||
case 0xf0: /* ACPI disable */
|
||||
s->pmcntrl &= ~SCI_EN;
|
||||
break;
|
||||
case 0xf1: /* ACPI enable */
|
||||
s->pmcntrl |= SCI_EN;
|
||||
break;
|
||||
if (addr == 0) {
|
||||
s->apmc = val;
|
||||
if (s->dev.config[0x5b] & (1 << 1)) {
|
||||
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
|
||||
}
|
||||
} else {
|
||||
s->apms = val;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pm_smi_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 1;
|
||||
if (addr == 0) {
|
||||
val = s->apmc;
|
||||
} else {
|
||||
val = s->apms;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("pm_smi_readb addr=0x%x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
@@ -218,17 +252,232 @@ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* XXX: we still add it to the PIIX3 and we count on the fact that
|
||||
OSes are smart enough to accept this strange configuration */
|
||||
static void smb_transaction(PIIX4PMState *s)
|
||||
{
|
||||
uint8_t prot = (s->smb_ctl >> 2) & 0x07;
|
||||
uint8_t read = s->smb_addr & 0x01;
|
||||
uint8_t cmd = s->smb_cmd;
|
||||
uint8_t addr = s->smb_addr >> 1;
|
||||
SMBusDevice *dev = s->smb_dev[addr];
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
|
||||
#endif
|
||||
if (!dev) goto error;
|
||||
|
||||
switch(prot) {
|
||||
case 0x0:
|
||||
if (!dev->quick_cmd) goto error;
|
||||
(*dev->quick_cmd)(dev, read);
|
||||
break;
|
||||
case 0x1:
|
||||
if (read) {
|
||||
if (!dev->receive_byte) goto error;
|
||||
s->smb_data0 = (*dev->receive_byte)(dev);
|
||||
}
|
||||
else {
|
||||
if (!dev->send_byte) goto error;
|
||||
(*dev->send_byte)(dev, cmd);
|
||||
}
|
||||
break;
|
||||
case 0x2:
|
||||
if (read) {
|
||||
if (!dev->read_byte) goto error;
|
||||
s->smb_data0 = (*dev->read_byte)(dev, cmd);
|
||||
}
|
||||
else {
|
||||
if (!dev->write_byte) goto error;
|
||||
(*dev->write_byte)(dev, cmd, s->smb_data0);
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
if (read) {
|
||||
uint16_t val;
|
||||
if (!dev->read_word) goto error;
|
||||
val = (*dev->read_word)(dev, cmd);
|
||||
s->smb_data0 = val;
|
||||
s->smb_data1 = val >> 8;
|
||||
}
|
||||
else {
|
||||
if (!dev->write_word) goto error;
|
||||
(*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0);
|
||||
}
|
||||
break;
|
||||
case 0x5:
|
||||
if (read) {
|
||||
if (!dev->read_block) goto error;
|
||||
s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data);
|
||||
}
|
||||
else {
|
||||
if (!dev->write_block) goto error;
|
||||
(*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
s->smb_stat |= 0x04;
|
||||
}
|
||||
|
||||
static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
addr &= 0x3f;
|
||||
#ifdef DEBUG
|
||||
printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
switch(addr) {
|
||||
case SMBHSTSTS:
|
||||
s->smb_stat = 0;
|
||||
s->smb_index = 0;
|
||||
break;
|
||||
case SMBHSTCNT:
|
||||
s->smb_ctl = val;
|
||||
if (val & 0x40)
|
||||
smb_transaction(s);
|
||||
break;
|
||||
case SMBHSTCMD:
|
||||
s->smb_cmd = val;
|
||||
break;
|
||||
case SMBHSTADD:
|
||||
s->smb_addr = val;
|
||||
break;
|
||||
case SMBHSTDAT0:
|
||||
s->smb_data0 = val;
|
||||
break;
|
||||
case SMBHSTDAT1:
|
||||
s->smb_data1 = val;
|
||||
break;
|
||||
case SMBBLKDAT:
|
||||
s->smb_data[s->smb_index++] = val;
|
||||
if (s->smb_index > 31)
|
||||
s->smb_index = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case SMBHSTSTS:
|
||||
val = s->smb_stat;
|
||||
break;
|
||||
case SMBHSTCNT:
|
||||
s->smb_index = 0;
|
||||
val = s->smb_ctl & 0x1f;
|
||||
break;
|
||||
case SMBHSTCMD:
|
||||
val = s->smb_cmd;
|
||||
break;
|
||||
case SMBHSTADD:
|
||||
val = s->smb_addr;
|
||||
break;
|
||||
case SMBHSTDAT0:
|
||||
val = s->smb_data0;
|
||||
break;
|
||||
case SMBHSTDAT1:
|
||||
val = s->smb_data1;
|
||||
break;
|
||||
case SMBBLKDAT:
|
||||
val = s->smb_data[s->smb_index++];
|
||||
if (s->smb_index > 31)
|
||||
s->smb_index = 0;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_io_space_update(PIIX4PMState *s)
|
||||
{
|
||||
uint32_t pm_io_base;
|
||||
|
||||
if (s->dev.config[0x80] & 1) {
|
||||
pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
|
||||
pm_io_base &= 0xfffe;
|
||||
|
||||
/* XXX: need to improve memory and ioport allocation */
|
||||
#if defined(DEBUG)
|
||||
printf("PM: mapping to 0x%x\n", pm_io_base);
|
||||
#endif
|
||||
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
|
||||
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
|
||||
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
|
||||
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
pci_default_write_config(d, address, val, len);
|
||||
if (address == 0x80)
|
||||
pm_io_space_update((PIIX4PMState *)d);
|
||||
}
|
||||
|
||||
static void pm_save(QEMUFile* f,void *opaque)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
|
||||
pci_device_save(&s->dev, f);
|
||||
|
||||
qemu_put_be16s(f, &s->pmsts);
|
||||
qemu_put_be16s(f, &s->pmen);
|
||||
qemu_put_be16s(f, &s->pmcntrl);
|
||||
qemu_put_8s(f, &s->apmc);
|
||||
qemu_put_8s(f, &s->apms);
|
||||
qemu_put_timer(f, s->tmr_timer);
|
||||
qemu_put_be64s(f, &s->tmr_overflow_time);
|
||||
}
|
||||
|
||||
static int pm_load(QEMUFile* f,void* opaque,int version_id)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id > 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pci_device_load(&s->dev, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
qemu_get_be16s(f, &s->pmsts);
|
||||
qemu_get_be16s(f, &s->pmen);
|
||||
qemu_get_be16s(f, &s->pmcntrl);
|
||||
qemu_get_8s(f, &s->apmc);
|
||||
qemu_get_8s(f, &s->apms);
|
||||
qemu_get_timer(f, s->tmr_timer);
|
||||
qemu_get_be64s(f, &s->tmr_overflow_time);
|
||||
|
||||
pm_io_space_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void piix4_pm_init(PCIBus *bus, int devfn)
|
||||
{
|
||||
PIIX4PMState *s;
|
||||
uint8_t *pci_conf;
|
||||
uint32_t pm_io_base;
|
||||
uint32_t pm_io_base, smb_io_base;
|
||||
|
||||
s = (PIIX4PMState *)pci_register_device(bus,
|
||||
"PM", sizeof(PIIX4PMState),
|
||||
devfn, NULL, NULL);
|
||||
devfn, NULL, pm_write_config);
|
||||
pci_conf = s->dev.config;
|
||||
pci_conf[0x00] = 0x86;
|
||||
pci_conf[0x01] = 0x80;
|
||||
@@ -241,15 +490,11 @@ void piix4_pm_init(PCIBus *bus, int devfn)
|
||||
pci_conf[0x0e] = 0x00; // header_type
|
||||
pci_conf[0x3d] = 0x01; // interrupt pin 1
|
||||
|
||||
pm_io_base = PM_IO_BASE;
|
||||
pci_conf[0x40] = pm_io_base | 1;
|
||||
pci_conf[0x41] = pm_io_base >> 8;
|
||||
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
|
||||
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
|
||||
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
|
||||
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
|
||||
pci_conf[0x40] = 0x01; /* PM io base read only bit */
|
||||
|
||||
register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s);
|
||||
register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
|
||||
register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
|
||||
|
||||
register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
|
||||
|
||||
/* XXX: which specification is used ? The i82731AB has different
|
||||
@@ -259,357 +504,20 @@ void piix4_pm_init(PCIBus *bus, int devfn)
|
||||
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
|
||||
(serial_hds[1] != NULL ? 0x90 : 0);
|
||||
|
||||
smb_io_base = SMB_IO_BASE;
|
||||
pci_conf[0x90] = smb_io_base | 1;
|
||||
pci_conf[0x91] = smb_io_base >> 8;
|
||||
pci_conf[0xd2] = 0x09;
|
||||
register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s);
|
||||
register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
|
||||
|
||||
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
|
||||
|
||||
register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
|
||||
piix4_pm_state = s;
|
||||
}
|
||||
|
||||
/* ACPI tables */
|
||||
/* XXX: move them in the Bochs BIOS ? */
|
||||
|
||||
/*************************************************/
|
||||
|
||||
/* Table structure from Linux kernel (the ACPI tables are under the
|
||||
BSD license) */
|
||||
|
||||
#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
|
||||
uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
|
||||
uint32_t length; /* Length of table, in bytes, including header */\
|
||||
uint8_t revision; /* ACPI Specification minor version # */\
|
||||
uint8_t checksum; /* To make sum of entire table == 0 */\
|
||||
uint8_t oem_id [6]; /* OEM identification */\
|
||||
uint8_t oem_table_id [8]; /* OEM table identification */\
|
||||
uint32_t oem_revision; /* OEM revision number */\
|
||||
uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
|
||||
uint32_t asl_compiler_revision; /* ASL compiler revision number */
|
||||
|
||||
|
||||
struct acpi_table_header /* ACPI common table header */
|
||||
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr)
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF
|
||||
};
|
||||
|
||||
struct rsdp_descriptor /* Root System Descriptor Pointer */
|
||||
{
|
||||
uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
|
||||
uint8_t checksum; /* To make sum of struct == 0 */
|
||||
uint8_t oem_id [6]; /* OEM identification */
|
||||
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
|
||||
uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
|
||||
uint32_t length; /* XSDT Length in bytes including hdr */
|
||||
uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
|
||||
uint8_t extended_checksum; /* Checksum of entire table */
|
||||
uint8_t reserved [3]; /* Reserved field must be 0 */
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI 1.0 Root System Description Table (RSDT)
|
||||
*/
|
||||
struct rsdt_descriptor_rev1
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||
uint32_t table_offset_entry [2]; /* Array of pointers to other */
|
||||
/* ACPI tables */
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI 1.0 Firmware ACPI Control Structure (FACS)
|
||||
*/
|
||||
struct facs_descriptor_rev1
|
||||
{
|
||||
uint8_t signature[4]; /* ACPI Signature */
|
||||
uint32_t length; /* Length of structure, in bytes */
|
||||
uint32_t hardware_signature; /* Hardware configuration signature */
|
||||
uint32_t firmware_waking_vector; /* ACPI OS waking vector */
|
||||
uint32_t global_lock; /* Global Lock */
|
||||
uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
|
||||
uint32_t reserved1 : 31; /* Must be 0 */
|
||||
uint8_t resverved3 [40]; /* Reserved - must be zero */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ACPI 1.0 Fixed ACPI Description Table (FADT)
|
||||
*/
|
||||
struct fadt_descriptor_rev1
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||
uint32_t firmware_ctrl; /* Physical address of FACS */
|
||||
uint32_t dsdt; /* Physical address of DSDT */
|
||||
uint8_t model; /* System Interrupt Model */
|
||||
uint8_t reserved1; /* Reserved */
|
||||
uint16_t sci_int; /* System vector of SCI interrupt */
|
||||
uint32_t smi_cmd; /* Port address of SMI command port */
|
||||
uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
|
||||
uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
|
||||
uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
|
||||
uint8_t reserved2; /* Reserved - must be zero */
|
||||
uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
|
||||
uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
|
||||
uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
|
||||
uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
|
||||
uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
|
||||
uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
|
||||
uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
|
||||
uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
|
||||
uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
|
||||
uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
|
||||
uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
|
||||
uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
|
||||
uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
|
||||
uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
|
||||
uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
|
||||
uint8_t reserved3; /* Reserved */
|
||||
uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
|
||||
uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
|
||||
uint16_t flush_size; /* Size of area read to flush caches */
|
||||
uint16_t flush_stride; /* Stride used in flushing caches */
|
||||
uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
|
||||
uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
|
||||
uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
|
||||
uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
|
||||
uint8_t century; /* Index to century in RTC CMOS RAM */
|
||||
uint8_t reserved4; /* Reserved */
|
||||
uint8_t reserved4a; /* Reserved */
|
||||
uint8_t reserved4b; /* Reserved */
|
||||
#if 0
|
||||
uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
|
||||
uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
|
||||
uint32_t proc_c1 : 1; /* All processors support C1 state */
|
||||
uint32_t plvl2_up : 1; /* C2 state works on MP system */
|
||||
uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
|
||||
uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
|
||||
uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
|
||||
uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
|
||||
uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
|
||||
uint32_t reserved5 : 23; /* Reserved - must be zero */
|
||||
#else
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* MADT values and structures
|
||||
*/
|
||||
|
||||
/* Values for MADT PCATCompat */
|
||||
|
||||
#define DUAL_PIC 0
|
||||
#define MULTIPLE_APIC 1
|
||||
|
||||
|
||||
/* Master MADT */
|
||||
|
||||
struct multiple_apic_table
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||
uint32_t local_apic_address; /* Physical address of local APIC */
|
||||
#if 0
|
||||
uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
|
||||
uint32_t reserved1 : 31;
|
||||
#else
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* Values for Type in APIC_HEADER_DEF */
|
||||
|
||||
#define APIC_PROCESSOR 0
|
||||
#define APIC_IO 1
|
||||
#define APIC_XRUPT_OVERRIDE 2
|
||||
#define APIC_NMI 3
|
||||
#define APIC_LOCAL_NMI 4
|
||||
#define APIC_ADDRESS_OVERRIDE 5
|
||||
#define APIC_IO_SAPIC 6
|
||||
#define APIC_LOCAL_SAPIC 7
|
||||
#define APIC_XRUPT_SOURCE 8
|
||||
#define APIC_RESERVED 9 /* 9 and greater are reserved */
|
||||
|
||||
/*
|
||||
* MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
|
||||
*/
|
||||
#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
|
||||
uint8_t type; \
|
||||
uint8_t length;
|
||||
|
||||
/* Sub-structures for MADT */
|
||||
|
||||
struct madt_processor_apic
|
||||
{
|
||||
APIC_HEADER_DEF
|
||||
uint8_t processor_id; /* ACPI processor id */
|
||||
uint8_t local_apic_id; /* Processor's local APIC id */
|
||||
#if 0
|
||||
uint32_t processor_enabled: 1; /* Processor is usable if set */
|
||||
uint32_t reserved2 : 31; /* Reserved, must be zero */
|
||||
#else
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct madt_io_apic
|
||||
{
|
||||
APIC_HEADER_DEF
|
||||
uint8_t io_apic_id; /* I/O APIC ID */
|
||||
uint8_t reserved; /* Reserved - must be zero */
|
||||
uint32_t address; /* APIC physical address */
|
||||
uint32_t interrupt; /* Global system interrupt where INTI
|
||||
* lines start */
|
||||
};
|
||||
|
||||
#include "acpi-dsdt.hex"
|
||||
|
||||
static int acpi_checksum(const uint8_t *data, int len)
|
||||
{
|
||||
int sum, i;
|
||||
sum = 0;
|
||||
for(i = 0; i < len; i++)
|
||||
sum += data[i];
|
||||
return (-sum) & 0xff;
|
||||
}
|
||||
|
||||
static void acpi_build_table_header(struct acpi_table_header *h,
|
||||
char *sig, int len)
|
||||
{
|
||||
memcpy(h->signature, sig, 4);
|
||||
h->length = cpu_to_le32(len);
|
||||
h->revision = 0;
|
||||
memcpy(h->oem_id, "QEMU ", 6);
|
||||
memcpy(h->oem_table_id, "QEMU", 4);
|
||||
memcpy(h->oem_table_id + 4, sig, 4);
|
||||
h->oem_revision = cpu_to_le32(1);
|
||||
memcpy(h->asl_compiler_id, "QEMU", 4);
|
||||
h->asl_compiler_revision = cpu_to_le32(1);
|
||||
h->checksum = acpi_checksum((void *)h, len);
|
||||
}
|
||||
|
||||
#define ACPI_TABLES_BASE 0x000e8000
|
||||
|
||||
/* base_addr must be a multiple of 4KB */
|
||||
void acpi_bios_init(void)
|
||||
{
|
||||
struct rsdp_descriptor *rsdp;
|
||||
struct rsdt_descriptor_rev1 *rsdt;
|
||||
struct fadt_descriptor_rev1 *fadt;
|
||||
struct facs_descriptor_rev1 *facs;
|
||||
struct multiple_apic_table *madt;
|
||||
uint8_t *dsdt;
|
||||
uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr;
|
||||
uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size;
|
||||
int i;
|
||||
|
||||
/* compute PCI I/O addresses */
|
||||
pm_io_base = (piix4_pm_state->dev.config[0x40] |
|
||||
(piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f;
|
||||
|
||||
base_addr = ACPI_TABLES_BASE;
|
||||
|
||||
/* reserve memory space for tables */
|
||||
addr = base_addr;
|
||||
rsdp = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*rsdp);
|
||||
|
||||
rsdt_addr = addr;
|
||||
rsdt = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*rsdt);
|
||||
|
||||
fadt_addr = addr;
|
||||
fadt = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*fadt);
|
||||
|
||||
/* XXX: FACS should be in RAM */
|
||||
addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
|
||||
facs_addr = addr;
|
||||
facs = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*facs);
|
||||
|
||||
dsdt_addr = addr;
|
||||
dsdt = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(AmlCode);
|
||||
|
||||
addr = (addr + 7) & ~7;
|
||||
madt_addr = addr;
|
||||
madt_size = sizeof(*madt) +
|
||||
sizeof(struct madt_processor_apic) * smp_cpus +
|
||||
sizeof(struct madt_io_apic);
|
||||
madt = (void *)(phys_ram_base + addr);
|
||||
addr += madt_size;
|
||||
|
||||
acpi_tables_size = addr - base_addr;
|
||||
|
||||
cpu_register_physical_memory(base_addr, acpi_tables_size,
|
||||
base_addr | IO_MEM_ROM);
|
||||
|
||||
/* RSDP */
|
||||
memset(rsdp, 0, sizeof(*rsdp));
|
||||
memcpy(rsdp->signature, "RSD PTR ", 8);
|
||||
memcpy(rsdp->oem_id, "QEMU ", 6);
|
||||
rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
|
||||
rsdp->checksum = acpi_checksum((void *)rsdp, 20);
|
||||
|
||||
/* RSDT */
|
||||
rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
|
||||
rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
|
||||
acpi_build_table_header((struct acpi_table_header *)rsdt,
|
||||
"RSDT", sizeof(*rsdt));
|
||||
|
||||
/* FADT */
|
||||
memset(fadt, 0, sizeof(*fadt));
|
||||
fadt->firmware_ctrl = cpu_to_le32(facs_addr);
|
||||
fadt->dsdt = cpu_to_le32(dsdt_addr);
|
||||
fadt->model = 1;
|
||||
fadt->reserved1 = 0;
|
||||
fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]);
|
||||
fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
|
||||
fadt->acpi_enable = 0xf1;
|
||||
fadt->acpi_disable = 0xf0;
|
||||
fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
|
||||
fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
|
||||
fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
|
||||
fadt->pm1_evt_len = 4;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
fadt->pm_tmr_len = 4;
|
||||
fadt->plvl2_lat = cpu_to_le16(50);
|
||||
fadt->plvl3_lat = cpu_to_le16(50);
|
||||
fadt->plvl3_lat = cpu_to_le16(50);
|
||||
/* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
|
||||
fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
|
||||
acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
|
||||
sizeof(*fadt));
|
||||
|
||||
/* FACS */
|
||||
memset(facs, 0, sizeof(*facs));
|
||||
memcpy(facs->signature, "FACS", 4);
|
||||
facs->length = cpu_to_le32(sizeof(*facs));
|
||||
|
||||
/* DSDT */
|
||||
memcpy(dsdt, AmlCode, sizeof(AmlCode));
|
||||
|
||||
/* MADT */
|
||||
{
|
||||
struct madt_processor_apic *apic;
|
||||
struct madt_io_apic *io_apic;
|
||||
|
||||
memset(madt, 0, madt_size);
|
||||
madt->local_apic_address = cpu_to_le32(0xfee00000);
|
||||
madt->flags = cpu_to_le32(1);
|
||||
apic = (void *)(madt + 1);
|
||||
for(i=0;i<smp_cpus;i++) {
|
||||
apic->type = APIC_PROCESSOR;
|
||||
apic->length = sizeof(*apic);
|
||||
apic->processor_id = i;
|
||||
apic->local_apic_id = i;
|
||||
apic->flags = cpu_to_le32(1);
|
||||
apic++;
|
||||
}
|
||||
io_apic = (void *)apic;
|
||||
io_apic->type = APIC_IO;
|
||||
io_apic->length = sizeof(*io_apic);
|
||||
io_apic->io_apic_id = smp_cpus;
|
||||
io_apic->address = cpu_to_le32(0xfec00000);
|
||||
io_apic->interrupt = cpu_to_le32(0);
|
||||
|
||||
acpi_build_table_header((struct acpi_table_header *)madt,
|
||||
"APIC", madt_size);
|
||||
}
|
||||
piix4_pm_state->smb_dev[addr] = dev;
|
||||
}
|
||||
@@ -406,5 +406,5 @@ void adb_mouse_init(ADBBusState *bus)
|
||||
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
|
||||
adb_mouse_reset, s);
|
||||
adb_mouse_reset(d);
|
||||
qemu_add_mouse_event_handler(adb_mouse_event, d, 0);
|
||||
qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
|
||||
}
|
||||
+34
-7
@@ -21,6 +21,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* XXX This file and most of its contests are somewhat misnamed. The
|
||||
Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
|
||||
the secondary PCI bridge. */
|
||||
|
||||
#include "vl.h"
|
||||
typedef target_phys_addr_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
@@ -179,10 +184,26 @@ static CPUReadMemoryFunc *pci_apb_ioread[] = {
|
||||
&pci_apb_ioreadl,
|
||||
};
|
||||
|
||||
/* ??? This is probably wrong. */
|
||||
static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
/* The APB host has an IRQ line for each IRQ line of each slot. */
|
||||
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level);
|
||||
return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
|
||||
}
|
||||
|
||||
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
int bus_offset;
|
||||
if (pci_dev->devfn & 1)
|
||||
bus_offset = 16;
|
||||
else
|
||||
bus_offset = 0;
|
||||
return bus_offset + irq_num;
|
||||
}
|
||||
|
||||
static void pci_apb_set_irq(void *pic, int irq_num, int level)
|
||||
{
|
||||
/* PCI IRQ map onto the first 32 INO. */
|
||||
pic_set_irq_new(pic, irq_num, level);
|
||||
}
|
||||
|
||||
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
|
||||
@@ -191,10 +212,12 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
|
||||
APBState *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
|
||||
PCIDevice *apb;
|
||||
PCIBus *secondary;
|
||||
|
||||
s = qemu_mallocz(sizeof(APBState));
|
||||
/* Ultrasparc APB main bus */
|
||||
s->bus = pci_register_bus(pci_apb_set_irq, pic, 0);
|
||||
/* Ultrasparc PBM main bus */
|
||||
s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
|
||||
pci_apb_config_write, s);
|
||||
@@ -211,7 +234,7 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
|
||||
cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
|
||||
|
||||
d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
|
||||
-1, NULL, NULL);
|
||||
0, NULL, NULL);
|
||||
d->config[0x00] = 0x8e; // vendor_id : Sun
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x00; // device_id
|
||||
@@ -226,7 +249,11 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
|
||||
d->config[0x0B] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0D] = 0x10; // latency_timer
|
||||
d->config[0x0E] = 0x00; // header_type
|
||||
return s->bus;
|
||||
|
||||
/* APB secondary busses */
|
||||
secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 1");
|
||||
pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 2");
|
||||
return secondary;
|
||||
}
|
||||
|
||||
|
||||
@@ -382,8 +382,6 @@ static void apic_init_ipi(APICState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < APIC_LVT_NB; i++)
|
||||
s->lvt[i] = 1 << 16; /* mask LVT */
|
||||
s->tpr = 0;
|
||||
s->spurious_vec = 0xff;
|
||||
s->log_dest = 0;
|
||||
@@ -391,7 +389,8 @@ static void apic_init_ipi(APICState *s)
|
||||
memset(s->isr, 0, sizeof(s->isr));
|
||||
memset(s->tmr, 0, sizeof(s->tmr));
|
||||
memset(s->irr, 0, sizeof(s->irr));
|
||||
memset(s->lvt, 0, sizeof(s->lvt));
|
||||
for(i = 0; i < APIC_LVT_NB; i++)
|
||||
s->lvt[i] = 1 << 16; /* mask LVT */
|
||||
s->esr = 0;
|
||||
memset(s->icr, 0, sizeof(s->icr));
|
||||
s->divide_conf = 0;
|
||||
@@ -477,9 +476,9 @@ int apic_get_interrupt(CPUState *env)
|
||||
intno = get_highest_priority_int(s->irr);
|
||||
if (intno < 0)
|
||||
return -1;
|
||||
reset_bit(s->irr, intno);
|
||||
if (s->tpr && intno <= s->tpr)
|
||||
return s->spurious_vec & 0xff;
|
||||
reset_bit(s->irr, intno);
|
||||
set_bit(s->isr, intno);
|
||||
apic_update_irq(s);
|
||||
return intno;
|
||||
@@ -745,6 +744,8 @@ static void apic_save(QEMUFile *f, void *opaque)
|
||||
qemu_put_be32s(f, &s->initial_count);
|
||||
qemu_put_be64s(f, &s->initial_count_load_time);
|
||||
qemu_put_be64s(f, &s->next_time);
|
||||
|
||||
qemu_put_timer(f, s->timer);
|
||||
}
|
||||
|
||||
static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
@@ -752,7 +753,7 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
APICState *s = opaque;
|
||||
int i;
|
||||
|
||||
if (version_id != 1)
|
||||
if (version_id > 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* XXX: what if the base changes? (registered memory regions) */
|
||||
@@ -779,6 +780,9 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
qemu_get_be32s(f, &s->initial_count);
|
||||
qemu_get_be64s(f, &s->initial_count_load_time);
|
||||
qemu_get_be64s(f, &s->next_time);
|
||||
|
||||
if (version_id >= 2)
|
||||
qemu_get_timer(f, s->timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -827,7 +831,7 @@ int apic_init(CPUState *env)
|
||||
}
|
||||
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
|
||||
|
||||
register_savevm("apic", 0, 1, apic_save, apic_load, s);
|
||||
register_savevm("apic", 0, 2, apic_save, apic_load, s);
|
||||
qemu_register_reset(apic_reset, s);
|
||||
|
||||
local_apics[s->id] = s;
|
||||
|
||||
+32
-22
@@ -64,42 +64,52 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size,
|
||||
stl_raw(p++, 0);
|
||||
}
|
||||
|
||||
void arm_load_kernel(int ram_size, const char *kernel_filename,
|
||||
void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
int board_id)
|
||||
{
|
||||
int kernel_size;
|
||||
int initrd_size;
|
||||
int n;
|
||||
uint64_t entry;
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!kernel_filename) {
|
||||
fprintf(stderr, "Kernel image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
if (initrd_filename) {
|
||||
initrd_size = load_image(initrd_filename,
|
||||
phys_ram_base + INITRD_LOAD_ADDR);
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initrd '%s'\n",
|
||||
initrd_filename);
|
||||
|
||||
kernel_size = load_elf(kernel_filename, 0, &entry);
|
||||
if (kernel_size >= 0) {
|
||||
/* An ELF image. Jump to the entry point. */
|
||||
env->regs[15] = entry & 0xfffffffe;
|
||||
env->thumb = entry & 1;
|
||||
} else {
|
||||
/* Raw binary image. Assume it is a Linux zImage. */
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
initrd_size = 0;
|
||||
if (initrd_filename) {
|
||||
initrd_size = load_image(initrd_filename,
|
||||
phys_ram_base + INITRD_LOAD_ADDR);
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initrd '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
initrd_size = 0;
|
||||
}
|
||||
bootloader[1] |= board_id & 0xff;
|
||||
bootloader[2] |= (board_id >> 8) & 0xff;
|
||||
bootloader[5] = KERNEL_ARGS_ADDR;
|
||||
bootloader[6] = KERNEL_LOAD_ADDR;
|
||||
for (n = 0; n < sizeof(bootloader) / 4; n++)
|
||||
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
|
||||
set_kernel_args(ram_size, initrd_size, kernel_cmdline);
|
||||
}
|
||||
bootloader[1] |= board_id & 0xff;
|
||||
bootloader[2] |= (board_id >> 8) & 0xff;
|
||||
bootloader[5] = KERNEL_ARGS_ADDR;
|
||||
bootloader[6] = KERNEL_LOAD_ADDR;
|
||||
for (n = 0; n < sizeof(bootloader) / 4; n++)
|
||||
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
|
||||
set_kernel_args(ram_size, initrd_size, kernel_cmdline);
|
||||
}
|
||||
|
||||
+547
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* ARM AMBA Generic/Distributed Interrupt Controller
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the GPL.
|
||||
*/
|
||||
|
||||
/* TODO: Some variants of this controller can handle multiple CPUs.
|
||||
Currently only single CPU operation is implemented. */
|
||||
|
||||
#include "vl.h"
|
||||
#include "arm_pic.h"
|
||||
|
||||
//#define DEBUG_GIC
|
||||
|
||||
#ifdef DEBUG_GIC
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("arm_gic: " fmt , ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while(0)
|
||||
#endif
|
||||
|
||||
/* Distributed interrupt controller. */
|
||||
|
||||
static const uint8_t gic_id[] =
|
||||
{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
|
||||
|
||||
#define GIC_NIRQ 96
|
||||
|
||||
typedef struct gic_irq_state
|
||||
{
|
||||
unsigned enabled:1;
|
||||
unsigned pending:1;
|
||||
unsigned active:1;
|
||||
unsigned level:1;
|
||||
unsigned model:1; /* 0 = 1:N, 1 = N:N */
|
||||
unsigned trigger:1; /* nonzero = edge triggered. */
|
||||
} gic_irq_state;
|
||||
|
||||
#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
|
||||
#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
|
||||
#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
|
||||
#define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1
|
||||
#define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0
|
||||
#define GIC_TEST_PENDING(irq) s->irq_state[irq].pending
|
||||
#define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1
|
||||
#define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0
|
||||
#define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active
|
||||
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
|
||||
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
|
||||
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
|
||||
#define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1
|
||||
#define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0
|
||||
#define GIC_TEST_LEVEL(irq) s->irq_state[irq].level
|
||||
#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
|
||||
#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
|
||||
#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
|
||||
|
||||
typedef struct gic_state
|
||||
{
|
||||
arm_pic_handler handler;
|
||||
uint32_t base;
|
||||
void *parent;
|
||||
int parent_irq;
|
||||
int enabled;
|
||||
int cpu_enabled;
|
||||
|
||||
gic_irq_state irq_state[GIC_NIRQ];
|
||||
int irq_target[GIC_NIRQ];
|
||||
int priority[GIC_NIRQ];
|
||||
int last_active[GIC_NIRQ];
|
||||
|
||||
int priority_mask;
|
||||
int running_irq;
|
||||
int running_priority;
|
||||
int current_pending;
|
||||
} gic_state;
|
||||
|
||||
/* TODO: Many places that call this routine could be optimized. */
|
||||
/* Update interrupt status after enabled or pending bits have been changed. */
|
||||
static void gic_update(gic_state *s)
|
||||
{
|
||||
int best_irq;
|
||||
int best_prio;
|
||||
int irq;
|
||||
|
||||
s->current_pending = 1023;
|
||||
if (!s->enabled || !s->cpu_enabled) {
|
||||
pic_set_irq_new(s->parent, s->parent_irq, 0);
|
||||
return;
|
||||
}
|
||||
best_prio = 0x100;
|
||||
best_irq = 1023;
|
||||
for (irq = 0; irq < 96; irq++) {
|
||||
if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) {
|
||||
if (s->priority[irq] < best_prio) {
|
||||
best_prio = s->priority[irq];
|
||||
best_irq = irq;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best_prio > s->priority_mask) {
|
||||
pic_set_irq_new(s->parent, s->parent_irq, 0);
|
||||
} else {
|
||||
s->current_pending = best_irq;
|
||||
if (best_prio < s->running_priority) {
|
||||
DPRINTF("Raised pending IRQ %d\n", best_irq);
|
||||
pic_set_irq_new(s->parent, s->parent_irq, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
/* The first external input line is internal interrupt 32. */
|
||||
irq += 32;
|
||||
if (level == GIC_TEST_LEVEL(irq))
|
||||
return;
|
||||
|
||||
if (level) {
|
||||
GIC_SET_LEVEL(irq);
|
||||
if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
|
||||
DPRINTF("Set %d pending\n", irq);
|
||||
GIC_SET_PENDING(irq);
|
||||
}
|
||||
} else {
|
||||
GIC_CLEAR_LEVEL(irq);
|
||||
}
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
static void gic_set_running_irq(gic_state *s, int irq)
|
||||
{
|
||||
s->running_irq = irq;
|
||||
if (irq == 1023)
|
||||
s->running_priority = 0x100;
|
||||
else
|
||||
s->running_priority = s->priority[irq];
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
static uint32_t gic_acknowledge_irq(gic_state *s)
|
||||
{
|
||||
int new_irq;
|
||||
new_irq = s->current_pending;
|
||||
if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) {
|
||||
DPRINTF("ACK no pending IRQ\n");
|
||||
return 1023;
|
||||
}
|
||||
pic_set_irq_new(s->parent, s->parent_irq, 0);
|
||||
s->last_active[new_irq] = s->running_irq;
|
||||
/* For level triggered interrupts we clear the pending bit while
|
||||
the interrupt is active. */
|
||||
GIC_CLEAR_PENDING(new_irq);
|
||||
gic_set_running_irq(s, new_irq);
|
||||
DPRINTF("ACK %d\n", new_irq);
|
||||
return new_irq;
|
||||
}
|
||||
|
||||
static void gic_complete_irq(gic_state * s, int irq)
|
||||
{
|
||||
int update = 0;
|
||||
DPRINTF("EOI %d\n", irq);
|
||||
if (s->running_irq == 1023)
|
||||
return; /* No active IRQ. */
|
||||
if (irq != 1023) {
|
||||
/* Mark level triggered interrupts as pending if they are still
|
||||
raised. */
|
||||
if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
|
||||
&& GIC_TEST_LEVEL(irq)) {
|
||||
GIC_SET_PENDING(irq);
|
||||
update = 1;
|
||||
}
|
||||
}
|
||||
if (irq != s->running_irq) {
|
||||
/* Complete an IRQ that is not currently running. */
|
||||
int tmp = s->running_irq;
|
||||
while (s->last_active[tmp] != 1023) {
|
||||
if (s->last_active[tmp] == irq) {
|
||||
s->last_active[tmp] = s->last_active[irq];
|
||||
break;
|
||||
}
|
||||
tmp = s->last_active[tmp];
|
||||
}
|
||||
if (update) {
|
||||
gic_update(s);
|
||||
}
|
||||
} else {
|
||||
/* Complete the current running IRQ. */
|
||||
gic_set_running_irq(s, s->last_active[s->running_irq]);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
uint32_t res;
|
||||
int irq;
|
||||
int i;
|
||||
|
||||
offset -= s->base + 0x1000;
|
||||
if (offset < 0x100) {
|
||||
if (offset == 0)
|
||||
return s->enabled;
|
||||
if (offset == 4)
|
||||
return (GIC_NIRQ / 32) - 1;
|
||||
if (offset < 0x08)
|
||||
return 0;
|
||||
goto bad_reg;
|
||||
} else if (offset < 0x200) {
|
||||
/* Interrupt Set/Clear Enable. */
|
||||
if (offset < 0x180)
|
||||
irq = (offset - 0x100) * 8;
|
||||
else
|
||||
irq = (offset - 0x180) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
res = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (GIC_TEST_ENABLED(irq + i)) {
|
||||
res |= (1 << i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x300) {
|
||||
/* Interrupt Set/Clear Pending. */
|
||||
if (offset < 0x280)
|
||||
irq = (offset - 0x200) * 8;
|
||||
else
|
||||
irq = (offset - 0x280) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
res = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (GIC_TEST_PENDING(irq + i)) {
|
||||
res |= (1 << i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x400) {
|
||||
/* Interrupt Active. */
|
||||
irq = (offset - 0x300) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
res = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (GIC_TEST_ACTIVE(irq + i)) {
|
||||
res |= (1 << i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x800) {
|
||||
/* Interrupt Priority. */
|
||||
irq = offset - 0x400;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
res = s->priority[irq];
|
||||
} else if (offset < 0xc00) {
|
||||
/* Interrupt CPU Target. */
|
||||
irq = offset - 0x800;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
res = s->irq_target[irq];
|
||||
} else if (offset < 0xf00) {
|
||||
/* Interrupt Configuration. */
|
||||
irq = (offset - 0xc00) * 2;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
res = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (GIC_TEST_MODEL(irq + i))
|
||||
res |= (1 << (i * 2));
|
||||
if (GIC_TEST_TRIGGER(irq + i))
|
||||
res |= (2 << (i * 2));
|
||||
}
|
||||
} else if (offset < 0xfe0) {
|
||||
goto bad_reg;
|
||||
} else /* offset >= 0xfe0 */ {
|
||||
if (offset & 3) {
|
||||
res = 0;
|
||||
} else {
|
||||
res = gic_id[(offset - 0xfe0) >> 2];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
bad_reg:
|
||||
cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
uint32_t val;
|
||||
val = gic_dist_readb(opaque, offset);
|
||||
val |= gic_dist_readb(opaque, offset + 1) << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
uint32_t val;
|
||||
val = gic_dist_readw(opaque, offset);
|
||||
val |= gic_dist_readw(opaque, offset + 2) << 16;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
int irq;
|
||||
int i;
|
||||
|
||||
offset -= s->base + 0x1000;
|
||||
if (offset < 0x100) {
|
||||
if (offset == 0) {
|
||||
s->enabled = (value & 1);
|
||||
DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
|
||||
} else if (offset < 4) {
|
||||
/* ignored. */
|
||||
} else {
|
||||
goto bad_reg;
|
||||
}
|
||||
} else if (offset < 0x180) {
|
||||
/* Interrupt Set Enable. */
|
||||
irq = (offset - 0x100) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
if (!GIC_TEST_ENABLED(irq + i))
|
||||
DPRINTF("Enabled IRQ %d\n", irq + i);
|
||||
GIC_SET_ENABLED(irq + i);
|
||||
/* If a raised level triggered IRQ enabled then mark
|
||||
is as pending. */
|
||||
if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i))
|
||||
GIC_SET_PENDING(irq + i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x200) {
|
||||
/* Interrupt Clear Enable. */
|
||||
irq = (offset - 0x180) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
if (GIC_TEST_ENABLED(irq + i))
|
||||
DPRINTF("Disabled IRQ %d\n", irq + i);
|
||||
GIC_CLEAR_ENABLED(irq + i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x280) {
|
||||
/* Interrupt Set Pending. */
|
||||
irq = (offset - 0x200) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
GIC_SET_PENDING(irq + i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x300) {
|
||||
/* Interrupt Clear Pending. */
|
||||
irq = (offset - 0x280) * 8;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
GIC_CLEAR_PENDING(irq + i);
|
||||
}
|
||||
}
|
||||
} else if (offset < 0x400) {
|
||||
/* Interrupt Active. */
|
||||
goto bad_reg;
|
||||
} else if (offset < 0x800) {
|
||||
/* Interrupt Priority. */
|
||||
irq = offset - 0x400;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
s->priority[irq] = value;
|
||||
} else if (offset < 0xc00) {
|
||||
/* Interrupt CPU Target. */
|
||||
irq = offset - 0x800;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
s->irq_target[irq] = value;
|
||||
} else if (offset < 0xf00) {
|
||||
/* Interrupt Configuration. */
|
||||
irq = (offset - 0xc00) * 4;
|
||||
if (irq >= GIC_NIRQ)
|
||||
goto bad_reg;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (value & (1 << (i * 2))) {
|
||||
GIC_SET_MODEL(irq + i);
|
||||
} else {
|
||||
GIC_CLEAR_MODEL(irq + i);
|
||||
}
|
||||
if (value & (2 << (i * 2))) {
|
||||
GIC_SET_TRIGGER(irq + i);
|
||||
} else {
|
||||
GIC_CLEAR_TRIGGER(irq + i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* 0xf00 is only handled for word writes. */
|
||||
goto bad_reg;
|
||||
}
|
||||
gic_update(s);
|
||||
return;
|
||||
bad_reg:
|
||||
cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset);
|
||||
}
|
||||
|
||||
static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
if (offset - s->base == 0xf00) {
|
||||
GIC_SET_PENDING(value & 0x3ff);
|
||||
gic_update(s);
|
||||
return;
|
||||
}
|
||||
gic_dist_writeb(opaque, offset, value & 0xff);
|
||||
gic_dist_writeb(opaque, offset + 1, value >> 8);
|
||||
}
|
||||
|
||||
static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
gic_dist_writew(opaque, offset, value & 0xffff);
|
||||
gic_dist_writew(opaque, offset + 2, value >> 16);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *gic_dist_readfn[] = {
|
||||
gic_dist_readb,
|
||||
gic_dist_readw,
|
||||
gic_dist_readl
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *gic_dist_writefn[] = {
|
||||
gic_dist_writeb,
|
||||
gic_dist_writew,
|
||||
gic_dist_writel
|
||||
};
|
||||
|
||||
static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
offset -= s->base;
|
||||
switch (offset) {
|
||||
case 0x00: /* Control */
|
||||
return s->cpu_enabled;
|
||||
case 0x04: /* Priority mask */
|
||||
return s->priority_mask;
|
||||
case 0x08: /* Binary Point */
|
||||
/* ??? Not implemented. */
|
||||
return 0;
|
||||
case 0x0c: /* Acknowledge */
|
||||
return gic_acknowledge_irq(s);
|
||||
case 0x14: /* Runing Priority */
|
||||
return s->running_priority;
|
||||
case 0x18: /* Highest Pending Interrupt */
|
||||
return s->current_pending;
|
||||
default:
|
||||
cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void gic_cpu_write(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
offset -= s->base;
|
||||
switch (offset) {
|
||||
case 0x00: /* Control */
|
||||
s->cpu_enabled = (value & 1);
|
||||
DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
|
||||
break;
|
||||
case 0x04: /* Priority mask */
|
||||
s->priority_mask = (value & 0x3ff);
|
||||
break;
|
||||
case 0x08: /* Binary Point */
|
||||
/* ??? Not implemented. */
|
||||
break;
|
||||
case 0x10: /* End Of Interrupt */
|
||||
return gic_complete_irq(s, value & 0x3ff);
|
||||
default:
|
||||
cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
|
||||
return;
|
||||
}
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *gic_cpu_readfn[] = {
|
||||
gic_cpu_read,
|
||||
gic_cpu_read,
|
||||
gic_cpu_read
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *gic_cpu_writefn[] = {
|
||||
gic_cpu_write,
|
||||
gic_cpu_write,
|
||||
gic_cpu_write
|
||||
};
|
||||
|
||||
static void gic_reset(gic_state *s)
|
||||
{
|
||||
int i;
|
||||
memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
|
||||
s->priority_mask = 0xf0;
|
||||
s->current_pending = 1023;
|
||||
s->running_irq = 1023;
|
||||
s->running_priority = 0x100;
|
||||
for (i = 0; i < 15; i++) {
|
||||
GIC_SET_ENABLED(i);
|
||||
GIC_SET_TRIGGER(i);
|
||||
}
|
||||
s->enabled = 0;
|
||||
s->cpu_enabled = 0;
|
||||
}
|
||||
|
||||
void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
|
||||
{
|
||||
gic_state *s;
|
||||
int iomemtype;
|
||||
|
||||
s = (gic_state *)qemu_mallocz(sizeof(gic_state));
|
||||
if (!s)
|
||||
return NULL;
|
||||
s->handler = gic_set_irq;
|
||||
s->parent = parent;
|
||||
s->parent_irq = parent_irq;
|
||||
if (base != 0xffffffff) {
|
||||
iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
|
||||
gic_cpu_writefn, s);
|
||||
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
|
||||
iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
|
||||
gic_dist_writefn, s);
|
||||
cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype);
|
||||
s->base = base;
|
||||
} else {
|
||||
s->base = 0;
|
||||
}
|
||||
gic_reset(s);
|
||||
return s;
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Status and system control registers for ARM RealView/Versatile boards.
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
#include "arm_pic.h"
|
||||
|
||||
#define LOCK_VALUE 0xa05f
|
||||
|
||||
typedef struct {
|
||||
uint32_t base;
|
||||
uint32_t sys_id;
|
||||
uint32_t leds;
|
||||
uint16_t lockval;
|
||||
uint32_t cfgdata1;
|
||||
uint32_t cfgdata2;
|
||||
uint32_t flags;
|
||||
uint32_t nvflags;
|
||||
uint32_t resetlevel;
|
||||
} arm_sysctl_state;
|
||||
|
||||
static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
|
||||
{
|
||||
arm_sysctl_state *s = (arm_sysctl_state *)opaque;
|
||||
|
||||
offset -= s->base;
|
||||
switch (offset) {
|
||||
case 0x00: /* ID */
|
||||
return s->sys_id;
|
||||
case 0x04: /* SW */
|
||||
/* General purpose hardware switches.
|
||||
We don't have a useful way of exposing these to the user. */
|
||||
return 0;
|
||||
case 0x08: /* LED */
|
||||
return s->leds;
|
||||
case 0x20: /* LOCK */
|
||||
return s->lockval;
|
||||
case 0x0c: /* OSC0 */
|
||||
case 0x10: /* OSC1 */
|
||||
case 0x14: /* OSC2 */
|
||||
case 0x18: /* OSC3 */
|
||||
case 0x1c: /* OSC4 */
|
||||
case 0x24: /* 100HZ */
|
||||
/* ??? Implement these. */
|
||||
return 0;
|
||||
case 0x28: /* CFGDATA1 */
|
||||
return s->cfgdata1;
|
||||
case 0x2c: /* CFGDATA2 */
|
||||
return s->cfgdata2;
|
||||
case 0x30: /* FLAGS */
|
||||
return s->flags;
|
||||
case 0x38: /* NVFLAGS */
|
||||
return s->nvflags;
|
||||
case 0x40: /* RESETCTL */
|
||||
return s->resetlevel;
|
||||
case 0x44: /* PCICTL */
|
||||
return 1;
|
||||
case 0x48: /* MCI */
|
||||
return 0;
|
||||
case 0x4c: /* FLASH */
|
||||
return 0;
|
||||
case 0x50: /* CLCD */
|
||||
return 0x1000;
|
||||
case 0x54: /* CLCDSER */
|
||||
return 0;
|
||||
case 0x58: /* BOOTCS */
|
||||
return 0;
|
||||
case 0x5c: /* 24MHz */
|
||||
/* ??? not implemented. */
|
||||
return 0;
|
||||
case 0x60: /* MISC */
|
||||
return 0;
|
||||
case 0x84: /* PROCID0 */
|
||||
/* ??? Don't know what the proper value for the core tile ID is. */
|
||||
return 0x02000000;
|
||||
case 0x88: /* PROCID1 */
|
||||
return 0xff000000;
|
||||
case 0x64: /* DMAPSR0 */
|
||||
case 0x68: /* DMAPSR1 */
|
||||
case 0x6c: /* DMAPSR2 */
|
||||
case 0x70: /* IOSEL */
|
||||
case 0x74: /* PLDCTL */
|
||||
case 0x80: /* BUSID */
|
||||
case 0x8c: /* OSCRESET0 */
|
||||
case 0x90: /* OSCRESET1 */
|
||||
case 0x94: /* OSCRESET2 */
|
||||
case 0x98: /* OSCRESET3 */
|
||||
case 0x9c: /* OSCRESET4 */
|
||||
case 0xc0: /* SYS_TEST_OSC0 */
|
||||
case 0xc4: /* SYS_TEST_OSC1 */
|
||||
case 0xc8: /* SYS_TEST_OSC2 */
|
||||
case 0xcc: /* SYS_TEST_OSC3 */
|
||||
case 0xd0: /* SYS_TEST_OSC4 */
|
||||
return 0;
|
||||
default:
|
||||
printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
|
||||
uint32_t val)
|
||||
{
|
||||
arm_sysctl_state *s = (arm_sysctl_state *)opaque;
|
||||
offset -= s->base;
|
||||
|
||||
switch (offset) {
|
||||
case 0x08: /* LED */
|
||||
s->leds = val;
|
||||
case 0x0c: /* OSC0 */
|
||||
case 0x10: /* OSC1 */
|
||||
case 0x14: /* OSC2 */
|
||||
case 0x18: /* OSC3 */
|
||||
case 0x1c: /* OSC4 */
|
||||
/* ??? */
|
||||
break;
|
||||
case 0x20: /* LOCK */
|
||||
if (val == LOCK_VALUE)
|
||||
s->lockval = val;
|
||||
else
|
||||
s->lockval = val & 0x7fff;
|
||||
break;
|
||||
case 0x28: /* CFGDATA1 */
|
||||
/* ??? Need to implement this. */
|
||||
s->cfgdata1 = val;
|
||||
break;
|
||||
case 0x2c: /* CFGDATA2 */
|
||||
/* ??? Need to implement this. */
|
||||
s->cfgdata2 = val;
|
||||
break;
|
||||
case 0x30: /* FLAGSSET */
|
||||
s->flags |= val;
|
||||
break;
|
||||
case 0x34: /* FLAGSCLR */
|
||||
s->flags &= ~val;
|
||||
break;
|
||||
case 0x38: /* NVFLAGSSET */
|
||||
s->nvflags |= val;
|
||||
break;
|
||||
case 0x3c: /* NVFLAGSCLR */
|
||||
s->nvflags &= ~val;
|
||||
break;
|
||||
case 0x40: /* RESETCTL */
|
||||
if (s->lockval == LOCK_VALUE) {
|
||||
s->resetlevel = val;
|
||||
if (val & 0x100)
|
||||
cpu_abort(cpu_single_env, "Board reset\n");
|
||||
}
|
||||
break;
|
||||
case 0x44: /* PCICTL */
|
||||
/* nothing to do. */
|
||||
break;
|
||||
case 0x4c: /* FLASH */
|
||||
case 0x50: /* CLCD */
|
||||
case 0x54: /* CLCDSER */
|
||||
case 0x64: /* DMAPSR0 */
|
||||
case 0x68: /* DMAPSR1 */
|
||||
case 0x6c: /* DMAPSR2 */
|
||||
case 0x70: /* IOSEL */
|
||||
case 0x74: /* PLDCTL */
|
||||
case 0x80: /* BUSID */
|
||||
case 0x84: /* PROCID0 */
|
||||
case 0x88: /* PROCID1 */
|
||||
case 0x8c: /* OSCRESET0 */
|
||||
case 0x90: /* OSCRESET1 */
|
||||
case 0x94: /* OSCRESET2 */
|
||||
case 0x98: /* OSCRESET3 */
|
||||
case 0x9c: /* OSCRESET4 */
|
||||
break;
|
||||
default:
|
||||
printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *arm_sysctl_readfn[] = {
|
||||
arm_sysctl_read,
|
||||
arm_sysctl_read,
|
||||
arm_sysctl_read
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *arm_sysctl_writefn[] = {
|
||||
arm_sysctl_write,
|
||||
arm_sysctl_write,
|
||||
arm_sysctl_write
|
||||
};
|
||||
|
||||
void arm_sysctl_init(uint32_t base, uint32_t sys_id)
|
||||
{
|
||||
arm_sysctl_state *s;
|
||||
int iomemtype;
|
||||
|
||||
s = (arm_sysctl_state *)qemu_mallocz(sizeof(arm_sysctl_state));
|
||||
if (!s)
|
||||
return;
|
||||
s->base = base;
|
||||
s->sys_id = sys_id;
|
||||
iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn,
|
||||
arm_sysctl_writefn, s);
|
||||
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
|
||||
/* ??? Save/restore. */
|
||||
}
|
||||
|
||||
+5
-5
@@ -107,29 +107,29 @@ static void arm_timer_update(arm_timer_state *s, int64_t now)
|
||||
/* Return the current value of the timer. */
|
||||
static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
|
||||
{
|
||||
int64_t elapsed;
|
||||
int64_t left;
|
||||
int64_t period;
|
||||
|
||||
if (s->count == 0)
|
||||
return 0;
|
||||
if ((s->control & TIMER_CTRL_ENABLE) == 0)
|
||||
return s->count;
|
||||
elapsed = now - s->loaded;
|
||||
left = s->expires - now;
|
||||
period = s->expires - s->loaded;
|
||||
/* If the timer should have expired then return 0. This can happen
|
||||
when the host timer signal doesnt occur immediately. It's better to
|
||||
have a timer appear to sit at zero for a while than have it wrap
|
||||
around before the guest interrupt is raised. */
|
||||
/* ??? Could we trigger the interrupt here? */
|
||||
if (elapsed > period)
|
||||
if (left < 0)
|
||||
return 0;
|
||||
/* We need to calculate count * elapsed / period without overfowing.
|
||||
Scale both elapsed and period so they fit in a 32-bit int. */
|
||||
while (period != (int32_t)period) {
|
||||
period >>= 1;
|
||||
elapsed >>= 1;
|
||||
left >>= 1;
|
||||
}
|
||||
return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed)
|
||||
return ((uint64_t)s->count * (uint64_t)(int32_t)left)
|
||||
/ (int32_t)period;
|
||||
}
|
||||
|
||||
|
||||
+22
-6
@@ -1000,12 +1000,12 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
|
||||
***************************************/
|
||||
|
||||
static void cirrus_get_offsets(VGAState *s1,
|
||||
uint32_t *pline_offset,
|
||||
uint32_t *pstart_addr)
|
||||
uint32_t *pline_offset,
|
||||
uint32_t *pstart_addr,
|
||||
uint32_t *pline_compare)
|
||||
{
|
||||
CirrusVGAState * s = (CirrusVGAState *)s1;
|
||||
uint32_t start_addr;
|
||||
uint32_t line_offset;
|
||||
uint32_t start_addr, line_offset, line_compare;
|
||||
|
||||
line_offset = s->cr[0x13]
|
||||
| ((s->cr[0x1b] & 0x10) << 4);
|
||||
@@ -1018,6 +1018,11 @@ static void cirrus_get_offsets(VGAState *s1,
|
||||
| ((s->cr[0x1b] & 0x0c) << 15)
|
||||
| ((s->cr[0x1d] & 0x80) << 12);
|
||||
*pstart_addr = start_addr;
|
||||
|
||||
line_compare = s->cr[0x18] |
|
||||
((s->cr[0x07] & 0x10) << 4) |
|
||||
((s->cr[0x09] & 0x40) << 3);
|
||||
*pline_compare = line_compare;
|
||||
}
|
||||
|
||||
static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
|
||||
@@ -2905,6 +2910,9 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
CirrusVGAState *s = opaque;
|
||||
|
||||
if (s->pci_dev)
|
||||
pci_device_save(s->pci_dev, f);
|
||||
|
||||
qemu_put_be32s(f, &s->latch);
|
||||
qemu_put_8s(f, &s->sr_index);
|
||||
qemu_put_buffer(f, s->sr, 256);
|
||||
@@ -2943,10 +2951,17 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque)
|
||||
static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
CirrusVGAState *s = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id != 1)
|
||||
if (version_id > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (s->pci_dev && version_id >= 2) {
|
||||
ret = pci_device_load(s->pci_dev, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_get_be32s(f, &s->latch);
|
||||
qemu_get_8s(f, &s->sr_index);
|
||||
qemu_get_buffer(f, s->sr, 256);
|
||||
@@ -3100,7 +3115,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
|
||||
s->cursor_invalidate = cirrus_cursor_invalidate;
|
||||
s->cursor_draw_line = cirrus_cursor_draw_line;
|
||||
|
||||
register_savevm("cirrus_vga", 0, 1, cirrus_vga_save, cirrus_vga_load, s);
|
||||
register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
@@ -3178,6 +3193,7 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
vga_common_init((VGAState *)s,
|
||||
ds, vga_ram_base, vga_ram_offset, vga_ram_size);
|
||||
cirrus_init_common(s, device_id, 1);
|
||||
s->pci_dev = (PCIDevice *)d;
|
||||
|
||||
/* setup memory space */
|
||||
/* memory #0 LFB */
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* QEMU Crystal CS4231 audio chip emulation
|
||||
*
|
||||
* Copyright (c) 2006 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 "vl.h"
|
||||
|
||||
/* debug CS4231 */
|
||||
//#define DEBUG_CS
|
||||
|
||||
/*
|
||||
* In addition to Crystal CS4231 there is a DMA controller on Sparc.
|
||||
*/
|
||||
#define CS_MAXADDR 0x3f
|
||||
#define CS_REGS 16
|
||||
#define CS_DREGS 32
|
||||
#define CS_MAXDREG (CS_DREGS - 1)
|
||||
|
||||
typedef struct CSState {
|
||||
uint32_t regs[CS_REGS];
|
||||
uint8_t dregs[CS_DREGS];
|
||||
void *intctl;
|
||||
} CSState;
|
||||
|
||||
#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG)
|
||||
#define CS_VER 0xa0
|
||||
#define CS_CDC_VER 0x8a
|
||||
|
||||
#ifdef DEBUG_CS
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("CS: " fmt , ##args); } while (0)
|
||||
#define pic_set_irq_new(intctl, irq, level) \
|
||||
do { printf("CS: set_irq(%d): %d\n", (irq), (level)); \
|
||||
pic_set_irq_new((intctl), (irq),(level));} while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...)
|
||||
#endif
|
||||
|
||||
static void cs_reset(void *opaque)
|
||||
{
|
||||
CSState *s = opaque;
|
||||
|
||||
memset(s->regs, 0, CS_REGS * 4);
|
||||
memset(s->dregs, 0, CS_DREGS);
|
||||
s->dregs[12] = CS_CDC_VER;
|
||||
s->dregs[25] = CS_VER;
|
||||
}
|
||||
|
||||
static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
CSState *s = opaque;
|
||||
uint32_t saddr, ret;
|
||||
|
||||
saddr = (addr & CS_MAXADDR) >> 2;
|
||||
switch (saddr) {
|
||||
case 1:
|
||||
switch (CS_RAP(s)) {
|
||||
case 3: // Write only
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = s->dregs[CS_RAP(s)];
|
||||
break;
|
||||
}
|
||||
DPRINTF("read dreg[%d]: 0x%8.8x\n", CS_RAP(s), ret);
|
||||
break;
|
||||
default:
|
||||
ret = s->regs[saddr];
|
||||
DPRINTF("read reg[%d]: 0x%8.8x\n", saddr, ret);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
CSState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & CS_MAXADDR) >> 2;
|
||||
DPRINTF("write reg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->regs[saddr], val);
|
||||
switch (saddr) {
|
||||
case 1:
|
||||
DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s), s->dregs[CS_RAP(s)], val);
|
||||
switch(CS_RAP(s)) {
|
||||
case 11:
|
||||
case 25: // Read only
|
||||
break;
|
||||
case 12:
|
||||
val &= 0x40;
|
||||
val |= CS_CDC_VER; // Codec version
|
||||
s->dregs[CS_RAP(s)] = val;
|
||||
break;
|
||||
default:
|
||||
s->dregs[CS_RAP(s)] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2: // Read only
|
||||
break;
|
||||
case 4:
|
||||
if (val & 1)
|
||||
cs_reset(s);
|
||||
val &= 0x7f;
|
||||
s->regs[saddr] = val;
|
||||
break;
|
||||
default:
|
||||
s->regs[saddr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *cs_mem_read[3] = {
|
||||
cs_mem_readl,
|
||||
cs_mem_readl,
|
||||
cs_mem_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *cs_mem_write[3] = {
|
||||
cs_mem_writel,
|
||||
cs_mem_writel,
|
||||
cs_mem_writel,
|
||||
};
|
||||
|
||||
static void cs_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
CSState *s = opaque;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < CS_REGS; i++)
|
||||
qemu_put_be32s(f, &s->regs[i]);
|
||||
|
||||
qemu_put_buffer(f, s->dregs, CS_DREGS);
|
||||
}
|
||||
|
||||
static int cs_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
CSState *s = opaque;
|
||||
unsigned int i;
|
||||
|
||||
if (version_id > 1)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < CS_REGS; i++)
|
||||
qemu_get_be32s(f, &s->regs[i]);
|
||||
|
||||
qemu_get_buffer(f, s->dregs, CS_DREGS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cs_init(target_phys_addr_t base, int irq, void *intctl)
|
||||
{
|
||||
int cs_io_memory;
|
||||
CSState *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(CSState));
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
cs_io_memory = cpu_register_io_memory(0, cs_mem_read, cs_mem_write, s);
|
||||
cpu_register_physical_memory(base, CS_MAXADDR, cs_io_memory);
|
||||
register_savevm("cs4231", base, 1, cs_save, cs_load, s);
|
||||
qemu_register_reset(cs_reset, s);
|
||||
cs_reset(s);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* QEMU ESP emulation
|
||||
* QEMU ESP/NCR53C9x emulation
|
||||
*
|
||||
* Copyright (c) 2005-2006 Fabrice Bellard
|
||||
*
|
||||
@@ -26,33 +26,33 @@
|
||||
/* debug ESP card */
|
||||
//#define DEBUG_ESP
|
||||
|
||||
/*
|
||||
* On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also
|
||||
* produced as NCR89C100. See
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
|
||||
* and
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_ESP
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("ESP: " fmt , ##args); } while (0)
|
||||
#define pic_set_irq(irq, level) \
|
||||
do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...)
|
||||
#endif
|
||||
|
||||
#define ESPDMA_REGS 4
|
||||
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
|
||||
#define ESP_MAXREG 0x3f
|
||||
#define TI_BUFSZ 32
|
||||
#define DMA_VER 0xa0000000
|
||||
#define DMA_INTR 1
|
||||
#define DMA_INTREN 0x10
|
||||
#define DMA_WRITE_MEM 0x100
|
||||
#define DMA_LOADED 0x04000000
|
||||
/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
|
||||
#define ESP_MAX_DEVS 7
|
||||
|
||||
typedef struct ESPState ESPState;
|
||||
|
||||
struct ESPState {
|
||||
BlockDriverState **bd;
|
||||
uint8_t rregs[ESP_MAXREG];
|
||||
uint8_t wregs[ESP_MAXREG];
|
||||
int irq;
|
||||
uint32_t espdmaregs[ESPDMA_REGS];
|
||||
uint32_t ti_size;
|
||||
int32_t ti_size;
|
||||
uint32_t ti_rptr, ti_wptr;
|
||||
uint8_t ti_buf[TI_BUFSZ];
|
||||
int sense;
|
||||
@@ -62,6 +62,15 @@ struct ESPState {
|
||||
uint8_t cmdbuf[TI_BUFSZ];
|
||||
int cmdlen;
|
||||
int do_cmd;
|
||||
|
||||
/* The amount of data left in the current DMA transfer. */
|
||||
uint32_t dma_left;
|
||||
/* The size of the current DMA transfer. Zero if no transfer is in
|
||||
progress. */
|
||||
uint32_t dma_counter;
|
||||
uint8_t *async_buf;
|
||||
uint32_t async_len;
|
||||
void *dma_opaque;
|
||||
};
|
||||
|
||||
#define STAT_DO 0x00
|
||||
@@ -72,6 +81,8 @@ struct ESPState {
|
||||
#define STAT_MO 0x07
|
||||
|
||||
#define STAT_TC 0x10
|
||||
#define STAT_PE 0x20
|
||||
#define STAT_GE 0x40
|
||||
#define STAT_IN 0x80
|
||||
|
||||
#define INTR_FC 0x08
|
||||
@@ -84,17 +95,14 @@ struct ESPState {
|
||||
|
||||
static int get_cmd(ESPState *s, uint8_t *buf)
|
||||
{
|
||||
uint32_t dmaptr, dmalen;
|
||||
uint32_t dmalen;
|
||||
int target;
|
||||
|
||||
dmalen = s->wregs[0] | (s->wregs[1] << 8);
|
||||
dmalen = s->rregs[0] | (s->rregs[1] << 8);
|
||||
target = s->wregs[4] & 7;
|
||||
DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
|
||||
if (s->dma) {
|
||||
dmaptr = iommu_translate(s->espdmaregs[1]);
|
||||
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
|
||||
s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
|
||||
cpu_physical_memory_read(dmaptr, buf, dmalen);
|
||||
espdma_memory_read(s->dma_opaque, buf, dmalen);
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
memcpy(&buf[1], s->ti_buf, dmalen);
|
||||
@@ -105,13 +113,18 @@ static int get_cmd(ESPState *s, uint8_t *buf)
|
||||
s->ti_rptr = 0;
|
||||
s->ti_wptr = 0;
|
||||
|
||||
if (target >= 4 || !s->scsi_dev[target]) {
|
||||
if (s->current_dev) {
|
||||
/* Started a new command before the old one finished. Cancel it. */
|
||||
scsi_cancel_io(s->current_dev, 0);
|
||||
s->async_len = 0;
|
||||
}
|
||||
|
||||
if (target >= MAX_DISKS || !s->scsi_dev[target]) {
|
||||
// No such drive
|
||||
s->rregs[4] = STAT_IN;
|
||||
s->rregs[5] = INTR_DC;
|
||||
s->rregs[6] = SEQ_0;
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
pic_set_irq(s->irq, 1);
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
return 0;
|
||||
}
|
||||
s->current_dev = s->scsi_dev[target];
|
||||
@@ -126,22 +139,22 @@ static void do_cmd(ESPState *s, uint8_t *buf)
|
||||
DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
|
||||
lun = buf[0] & 7;
|
||||
datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
|
||||
if (datalen == 0) {
|
||||
s->ti_size = 0;
|
||||
} else {
|
||||
s->ti_size = datalen;
|
||||
if (datalen != 0) {
|
||||
s->rregs[4] = STAT_IN | STAT_TC;
|
||||
s->dma_left = 0;
|
||||
s->dma_counter = 0;
|
||||
if (datalen > 0) {
|
||||
s->rregs[4] |= STAT_DI;
|
||||
s->ti_size = datalen;
|
||||
scsi_read_data(s->current_dev, 0);
|
||||
} else {
|
||||
s->rregs[4] |= STAT_DO;
|
||||
s->ti_size = -datalen;
|
||||
scsi_write_data(s->current_dev, 0);
|
||||
}
|
||||
}
|
||||
s->rregs[5] = INTR_BS | INTR_FC;
|
||||
s->rregs[6] = SEQ_CD;
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
pic_set_irq(s->irq, 1);
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
}
|
||||
|
||||
static void handle_satn(ESPState *s)
|
||||
@@ -160,27 +173,20 @@ static void handle_satn_stop(ESPState *s)
|
||||
if (s->cmdlen) {
|
||||
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
|
||||
s->do_cmd = 1;
|
||||
s->espdmaregs[1] += s->cmdlen;
|
||||
s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
|
||||
s->rregs[5] = INTR_BS | INTR_FC;
|
||||
s->rregs[6] = SEQ_CD;
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
pic_set_irq(s->irq, 1);
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_response(ESPState *s)
|
||||
{
|
||||
uint32_t dmaptr;
|
||||
|
||||
DPRINTF("Transfer status (sense=%d)\n", s->sense);
|
||||
s->ti_buf[0] = s->sense;
|
||||
s->ti_buf[1] = 0;
|
||||
if (s->dma) {
|
||||
dmaptr = iommu_translate(s->espdmaregs[1]);
|
||||
DPRINTF("DMA Direction: %c\n",
|
||||
s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
|
||||
cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
|
||||
espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
|
||||
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
|
||||
s->rregs[5] = INTR_BS | INTR_FC;
|
||||
s->rregs[6] = SEQ_CD;
|
||||
@@ -190,84 +196,127 @@ static void write_response(ESPState *s)
|
||||
s->ti_wptr = 0;
|
||||
s->rregs[7] = 2;
|
||||
}
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
pic_set_irq(s->irq, 1);
|
||||
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
}
|
||||
|
||||
static void esp_command_complete(void *opaque, uint32_t tag, int sense)
|
||||
static void esp_dma_done(ESPState *s)
|
||||
{
|
||||
s->rregs[4] |= STAT_IN | STAT_TC;
|
||||
s->rregs[5] = INTR_BS;
|
||||
s->rregs[6] = 0;
|
||||
s->rregs[7] = 0;
|
||||
s->rregs[0] = 0;
|
||||
s->rregs[1] = 0;
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
}
|
||||
|
||||
static void esp_do_dma(ESPState *s)
|
||||
{
|
||||
uint32_t len;
|
||||
int to_device;
|
||||
|
||||
to_device = (s->ti_size < 0);
|
||||
len = s->dma_left;
|
||||
if (s->do_cmd) {
|
||||
DPRINTF("command len %d + %d\n", s->cmdlen, len);
|
||||
espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
|
||||
s->ti_size = 0;
|
||||
s->cmdlen = 0;
|
||||
s->do_cmd = 0;
|
||||
do_cmd(s, s->cmdbuf);
|
||||
return;
|
||||
}
|
||||
if (s->async_len == 0) {
|
||||
/* Defer until data is available. */
|
||||
return;
|
||||
}
|
||||
if (len > s->async_len) {
|
||||
len = s->async_len;
|
||||
}
|
||||
if (to_device) {
|
||||
espdma_memory_read(s->dma_opaque, s->async_buf, len);
|
||||
} else {
|
||||
espdma_memory_write(s->dma_opaque, s->async_buf, len);
|
||||
}
|
||||
s->dma_left -= len;
|
||||
s->async_buf += len;
|
||||
s->async_len -= len;
|
||||
if (to_device)
|
||||
s->ti_size += len;
|
||||
else
|
||||
s->ti_size -= len;
|
||||
if (s->async_len == 0) {
|
||||
if (to_device) {
|
||||
// ti_size is negative
|
||||
scsi_write_data(s->current_dev, 0);
|
||||
} else {
|
||||
scsi_read_data(s->current_dev, 0);
|
||||
/* If there is still data to be read from the device then
|
||||
complete the DMA operation immeriately. Otherwise defer
|
||||
until the scsi layer has completed. */
|
||||
if (s->dma_left == 0 && s->ti_size > 0) {
|
||||
esp_dma_done(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Partially filled a scsi buffer. Complete immediately. */
|
||||
esp_dma_done(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_command_complete(void *opaque, int reason, uint32_t tag,
|
||||
uint32_t arg)
|
||||
{
|
||||
ESPState *s = (ESPState *)opaque;
|
||||
|
||||
DPRINTF("SCSI Command complete\n");
|
||||
if (s->ti_size != 0)
|
||||
DPRINTF("SCSI command completed unexpectedly\n");
|
||||
s->ti_size = 0;
|
||||
if (sense)
|
||||
DPRINTF("Command failed\n");
|
||||
s->sense = sense;
|
||||
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
|
||||
if (reason == SCSI_REASON_DONE) {
|
||||
DPRINTF("SCSI Command complete\n");
|
||||
if (s->ti_size != 0)
|
||||
DPRINTF("SCSI command completed unexpectedly\n");
|
||||
s->ti_size = 0;
|
||||
s->dma_left = 0;
|
||||
s->async_len = 0;
|
||||
if (arg)
|
||||
DPRINTF("Command failed\n");
|
||||
s->sense = arg;
|
||||
s->rregs[4] = STAT_ST;
|
||||
esp_dma_done(s);
|
||||
s->current_dev = NULL;
|
||||
} else {
|
||||
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
|
||||
s->async_len = arg;
|
||||
s->async_buf = scsi_get_buf(s->current_dev, 0);
|
||||
if (s->dma_left) {
|
||||
esp_do_dma(s);
|
||||
} else if (s->dma_counter != 0 && s->ti_size <= 0) {
|
||||
/* If this was the last part of a DMA transfer then the
|
||||
completion interrupt is deferred to here. */
|
||||
esp_dma_done(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ti(ESPState *s)
|
||||
{
|
||||
uint32_t dmaptr, dmalen, minlen, len, from, to;
|
||||
unsigned int i;
|
||||
int to_device;
|
||||
uint8_t buf[TARGET_PAGE_SIZE];
|
||||
uint32_t dmalen, minlen;
|
||||
|
||||
dmalen = s->wregs[0] | (s->wregs[1] << 8);
|
||||
dmalen = s->rregs[0] | (s->rregs[1] << 8);
|
||||
if (dmalen==0) {
|
||||
dmalen=0x10000;
|
||||
}
|
||||
s->dma_counter = dmalen;
|
||||
|
||||
if (s->do_cmd)
|
||||
minlen = (dmalen < 32) ? dmalen : 32;
|
||||
else if (s->ti_size < 0)
|
||||
minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
|
||||
else
|
||||
minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
|
||||
DPRINTF("Transfer Information len %d\n", minlen);
|
||||
if (s->dma) {
|
||||
dmaptr = iommu_translate(s->espdmaregs[1]);
|
||||
/* Check if the transfer writes to to reads from the device. */
|
||||
to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
|
||||
DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
|
||||
to_device ? 'r': 'w', dmaptr, s->ti_size);
|
||||
from = s->espdmaregs[1];
|
||||
to = from + minlen;
|
||||
for (i = 0; i < minlen; i += len, from += len) {
|
||||
dmaptr = iommu_translate(s->espdmaregs[1] + i);
|
||||
if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
|
||||
len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
|
||||
} else {
|
||||
len = to - from;
|
||||
}
|
||||
DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
|
||||
s->ti_size -= len;
|
||||
if (s->do_cmd) {
|
||||
DPRINTF("command len %d + %d\n", s->cmdlen, len);
|
||||
cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
|
||||
s->ti_size = 0;
|
||||
s->cmdlen = 0;
|
||||
s->do_cmd = 0;
|
||||
do_cmd(s, s->cmdbuf);
|
||||
return;
|
||||
} else {
|
||||
if (to_device) {
|
||||
cpu_physical_memory_read(dmaptr, buf, len);
|
||||
scsi_write_data(s->current_dev, buf, len);
|
||||
} else {
|
||||
scsi_read_data(s->current_dev, buf, len);
|
||||
cpu_physical_memory_write(dmaptr, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s->ti_size) {
|
||||
s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
|
||||
}
|
||||
s->rregs[5] = INTR_BS;
|
||||
s->rregs[6] = 0;
|
||||
s->rregs[7] = 0;
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
s->dma_left = minlen;
|
||||
s->rregs[4] &= ~STAT_TC;
|
||||
esp_do_dma(s);
|
||||
} else if (s->do_cmd) {
|
||||
DPRINTF("command len %d\n", s->cmdlen);
|
||||
s->ti_size = 0;
|
||||
@@ -276,16 +325,15 @@ static void handle_ti(ESPState *s)
|
||||
do_cmd(s, s->cmdbuf);
|
||||
return;
|
||||
}
|
||||
pic_set_irq(s->irq, 1);
|
||||
}
|
||||
|
||||
static void esp_reset(void *opaque)
|
||||
void esp_reset(void *opaque)
|
||||
{
|
||||
ESPState *s = opaque;
|
||||
|
||||
memset(s->rregs, 0, ESP_MAXREG);
|
||||
memset(s->wregs, 0, ESP_MAXREG);
|
||||
s->rregs[0x0e] = 0x4; // Indicate fas100a
|
||||
memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
|
||||
s->ti_size = 0;
|
||||
s->ti_rptr = 0;
|
||||
s->ti_wptr = 0;
|
||||
@@ -307,11 +355,12 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
s->ti_size--;
|
||||
if ((s->rregs[4] & 6) == 0) {
|
||||
/* Data in/out. */
|
||||
scsi_read_data(s->current_dev, &s->rregs[2], 0);
|
||||
fprintf(stderr, "esp: PIO data read not implemented\n");
|
||||
s->rregs[2] = 0;
|
||||
} else {
|
||||
s->rregs[2] = s->ti_buf[s->ti_rptr++];
|
||||
}
|
||||
pic_set_irq(s->irq, 1);
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
}
|
||||
if (s->ti_size == 0) {
|
||||
s->ti_rptr = 0;
|
||||
@@ -320,10 +369,9 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
break;
|
||||
case 5:
|
||||
// interrupt
|
||||
// Clear status bits except TC
|
||||
s->rregs[4] &= STAT_TC;
|
||||
pic_set_irq(s->irq, 0);
|
||||
s->espdmaregs[0] &= ~DMA_INTR;
|
||||
// Clear interrupt/error status bits
|
||||
s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
|
||||
espdma_clear_irq(s->dma_opaque);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -341,7 +389,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
switch (saddr) {
|
||||
case 0:
|
||||
case 1:
|
||||
s->rregs[saddr] = val;
|
||||
s->rregs[4] &= ~STAT_TC;
|
||||
break;
|
||||
case 2:
|
||||
// FIFO
|
||||
@@ -351,7 +399,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
uint8_t buf;
|
||||
buf = val & 0xff;
|
||||
s->ti_size--;
|
||||
scsi_write_data(s->current_dev, &buf, 0);
|
||||
fprintf(stderr, "esp: PIO data write not implemented\n");
|
||||
} else {
|
||||
s->ti_size++;
|
||||
s->ti_buf[s->ti_wptr++] = val & 0xff;
|
||||
@@ -362,6 +410,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
// Command
|
||||
if (val & 0x80) {
|
||||
s->dma = 1;
|
||||
/* Reload DMA counter. */
|
||||
s->rregs[0] = s->wregs[0];
|
||||
s->rregs[1] = s->wregs[1];
|
||||
} else {
|
||||
s->dma = 0;
|
||||
}
|
||||
@@ -383,8 +434,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
DPRINTF("Bus reset (%2.2x)\n", val);
|
||||
s->rregs[5] = INTR_RST;
|
||||
if (!(s->wregs[8] & 0x40)) {
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
pic_set_irq(s->irq, 1);
|
||||
espdma_raise_irq(s->dma_opaque);
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
@@ -447,68 +497,12 @@ static CPUWriteMemoryFunc *esp_mem_write[3] = {
|
||||
esp_mem_writeb,
|
||||
};
|
||||
|
||||
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ESPState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & ESPDMA_MAXADDR) >> 2;
|
||||
DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
|
||||
|
||||
return s->espdmaregs[saddr];
|
||||
}
|
||||
|
||||
static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
ESPState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & ESPDMA_MAXADDR) >> 2;
|
||||
DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
|
||||
switch (saddr) {
|
||||
case 0:
|
||||
if (!(val & DMA_INTREN))
|
||||
pic_set_irq(s->irq, 0);
|
||||
if (val & 0x80) {
|
||||
esp_reset(s);
|
||||
} else if (val & 0x40) {
|
||||
val &= ~0x40;
|
||||
} else if (val == 0)
|
||||
val = 0x40;
|
||||
val &= 0x0fffffff;
|
||||
val |= DMA_VER;
|
||||
break;
|
||||
case 1:
|
||||
s->espdmaregs[0] |= DMA_LOADED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s->espdmaregs[saddr] = val;
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *espdma_mem_read[3] = {
|
||||
espdma_mem_readl,
|
||||
espdma_mem_readl,
|
||||
espdma_mem_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *espdma_mem_write[3] = {
|
||||
espdma_mem_writel,
|
||||
espdma_mem_writel,
|
||||
espdma_mem_writel,
|
||||
};
|
||||
|
||||
static void esp_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
ESPState *s = opaque;
|
||||
unsigned int i;
|
||||
|
||||
qemu_put_buffer(f, s->rregs, ESP_MAXREG);
|
||||
qemu_put_buffer(f, s->wregs, ESP_MAXREG);
|
||||
qemu_put_be32s(f, &s->irq);
|
||||
for (i = 0; i < ESPDMA_REGS; i++)
|
||||
qemu_put_be32s(f, &s->espdmaregs[i]);
|
||||
qemu_put_be32s(f, &s->ti_size);
|
||||
qemu_put_be32s(f, &s->ti_rptr);
|
||||
qemu_put_be32s(f, &s->ti_wptr);
|
||||
@@ -519,16 +513,12 @@ static void esp_save(QEMUFile *f, void *opaque)
|
||||
static int esp_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
ESPState *s = opaque;
|
||||
unsigned int i;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
if (version_id != 2)
|
||||
return -EINVAL; // Cannot emulate 1
|
||||
|
||||
qemu_get_buffer(f, s->rregs, ESP_MAXREG);
|
||||
qemu_get_buffer(f, s->wregs, ESP_MAXREG);
|
||||
qemu_get_be32s(f, &s->irq);
|
||||
for (i = 0; i < ESPDMA_REGS; i++)
|
||||
qemu_get_be32s(f, &s->espdmaregs[i]);
|
||||
qemu_get_be32s(f, &s->ti_size);
|
||||
qemu_get_be32s(f, &s->ti_rptr);
|
||||
qemu_get_be32s(f, &s->ti_wptr);
|
||||
@@ -538,34 +528,48 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
|
||||
void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
|
||||
{
|
||||
ESPState *s = (ESPState *)opaque;
|
||||
|
||||
if (id < 0) {
|
||||
for (id = 0; id < ESP_MAX_DEVS; id++) {
|
||||
if (s->scsi_dev[id] == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id >= ESP_MAX_DEVS) {
|
||||
DPRINTF("Bad Device ID %d\n", id);
|
||||
return;
|
||||
}
|
||||
if (s->scsi_dev[id]) {
|
||||
DPRINTF("Destroying device %d\n", id);
|
||||
scsi_disk_destroy(s->scsi_dev[id]);
|
||||
}
|
||||
DPRINTF("Attaching block device %d\n", id);
|
||||
/* Command queueing is not implemented. */
|
||||
s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
|
||||
}
|
||||
|
||||
void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque)
|
||||
{
|
||||
ESPState *s;
|
||||
int esp_io_memory, espdma_io_memory;
|
||||
int i;
|
||||
int esp_io_memory;
|
||||
|
||||
s = qemu_mallocz(sizeof(ESPState));
|
||||
if (!s)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
s->bd = bd;
|
||||
s->irq = irq;
|
||||
s->dma_opaque = dma_opaque;
|
||||
|
||||
esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
|
||||
cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
|
||||
|
||||
espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
|
||||
cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
|
||||
|
||||
esp_reset(s);
|
||||
|
||||
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
|
||||
register_savevm("esp", espaddr, 2, esp_save, esp_load, s);
|
||||
qemu_register_reset(esp_reset, s);
|
||||
for (i = 0; i < MAX_DISKS; i++) {
|
||||
if (bs_table[i]) {
|
||||
s->scsi_dev[i] =
|
||||
scsi_disk_init(bs_table[i], esp_command_complete, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -66,7 +66,6 @@ typedef enum fdrive_type_t {
|
||||
|
||||
typedef enum fdrive_flags_t {
|
||||
FDRIVE_MOTOR_ON = 0x01, /* motor on/off */
|
||||
FDRIVE_REVALIDATE = 0x02, /* Revalidated */
|
||||
} fdrive_flags_t;
|
||||
|
||||
typedef enum fdisk_flags_t {
|
||||
@@ -236,7 +235,6 @@ static void fd_revalidate (fdrive_t *drv)
|
||||
int nb_heads, max_track, last_sect, ro;
|
||||
|
||||
FLOPPY_DPRINTF("revalidate\n");
|
||||
drv->drflags &= ~FDRIVE_REVALIDATE;
|
||||
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
|
||||
ro = bdrv_is_read_only(drv->bs);
|
||||
bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
|
||||
@@ -291,7 +289,6 @@ static void fd_revalidate (fdrive_t *drv)
|
||||
drv->max_track = 0;
|
||||
drv->flags &= ~FDISK_DBL_SIDES;
|
||||
}
|
||||
drv->drflags |= FDRIVE_REVALIDATE;
|
||||
}
|
||||
|
||||
/* Motor control */
|
||||
@@ -488,19 +485,6 @@ static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
|
||||
fdctrl_write_mem,
|
||||
};
|
||||
|
||||
static void fd_change_cb (void *opaque)
|
||||
{
|
||||
fdrive_t *drv = opaque;
|
||||
|
||||
FLOPPY_DPRINTF("disk change\n");
|
||||
fd_revalidate(drv);
|
||||
#if 0
|
||||
fd_recalibrate(drv);
|
||||
fdctrl_reset_fifo(drv->fdctrl);
|
||||
fdctrl_raise_irq(drv->fdctrl, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
||||
fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
|
||||
uint32_t io_base,
|
||||
BlockDriverState **fds)
|
||||
@@ -529,10 +513,6 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
fd_init(&fdctrl->drives[i], fds[i]);
|
||||
if (fds[i]) {
|
||||
bdrv_set_change_cb(fds[i],
|
||||
&fd_change_cb, &fdctrl->drives[i]);
|
||||
}
|
||||
}
|
||||
fdctrl_reset(fdctrl, 0);
|
||||
fdctrl->state = FD_CTRL_ACTIVE;
|
||||
@@ -760,18 +740,28 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
|
||||
// fdctrl.precomp = (value >> 2) & 0x07;
|
||||
}
|
||||
|
||||
static int fdctrl_media_changed(fdrive_t *drv)
|
||||
{
|
||||
int ret;
|
||||
if (!drv->bs)
|
||||
return 0;
|
||||
ret = bdrv_media_changed(drv->bs);
|
||||
if (ret) {
|
||||
fd_revalidate(drv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Digital input register : 0x07 (read-only) */
|
||||
static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
|
||||
{
|
||||
uint32_t retval = 0;
|
||||
|
||||
if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE ||
|
||||
drv1(fdctrl)->drflags & FDRIVE_REVALIDATE)
|
||||
if (fdctrl_media_changed(drv0(fdctrl)) ||
|
||||
fdctrl_media_changed(drv1(fdctrl)))
|
||||
retval |= 0x80;
|
||||
if (retval != 0)
|
||||
FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
|
||||
drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
|
||||
drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -898,7 +888,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
|
||||
fdctrl->data_len = fdctrl->fifo[8];
|
||||
} else {
|
||||
int tmp;
|
||||
fdctrl->data_len = 128 << fdctrl->fifo[5];
|
||||
fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
|
||||
tmp = (cur_drv->last_sect - ks + 1);
|
||||
if (fdctrl->fifo[0] & 0x80)
|
||||
tmp += cur_drv->last_sect;
|
||||
@@ -1683,8 +1673,9 @@ enqueue:
|
||||
#else
|
||||
cur_drv->last_sect = fdctrl->fifo[3];
|
||||
#endif
|
||||
/* Bochs BIOS is buggy and don't send format informations
|
||||
* for each sector. So, pretend all's done right now...
|
||||
/* TODO: implement format using DMA expected by the Bochs BIOS
|
||||
* and Linux fdformat (read 3 bytes per sector via DMA and fill
|
||||
* the sector with the specified fill byte
|
||||
*/
|
||||
fdctrl->data_state &= ~FD_STATE_FORMAT;
|
||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||
|
||||
+10
-5
@@ -74,11 +74,15 @@ static CPUReadMemoryFunc *pci_grackle_read[] = {
|
||||
&pci_host_data_readl,
|
||||
};
|
||||
|
||||
/* XXX: we do not simulate the hardware - we rely on the BIOS to
|
||||
set correctly for irq line field */
|
||||
static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
/* Don't know if this matches real hardware, but it agrees with OHW. */
|
||||
static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
|
||||
return (irq_num + (pci_dev->devfn >> 3)) & 3;
|
||||
}
|
||||
|
||||
static void pci_grackle_set_irq(void *pic, int irq_num, int level)
|
||||
{
|
||||
heathrow_pic_set_irq(pic, irq_num + 8, level);
|
||||
}
|
||||
|
||||
PCIBus *pci_grackle_init(uint32_t base, void *pic)
|
||||
@@ -88,7 +92,8 @@ PCIBus *pci_grackle_init(uint32_t base, void *pic)
|
||||
int pci_mem_config, pci_mem_data;
|
||||
|
||||
s = qemu_mallocz(sizeof(GrackleState));
|
||||
s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0);
|
||||
s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq,
|
||||
pic, 0, 0);
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
|
||||
pci_grackle_config_write, s);
|
||||
|
||||
+648
@@ -0,0 +1,648 @@
|
||||
/*
|
||||
* QEMU GT64120 PCI host
|
||||
*
|
||||
* Copyright (c) 2006,2007 Aurelien Jarno
|
||||
*
|
||||
* 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 "vl.h"
|
||||
typedef target_phys_addr_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
#define GT_REGS (0x1000 >> 2)
|
||||
|
||||
/* CPU Configuration */
|
||||
#define GT_CPU (0x000 >> 2)
|
||||
#define GT_MULTI (0x120 >> 2)
|
||||
|
||||
/* CPU Address Decode */
|
||||
#define GT_SCS10LD (0x008 >> 2)
|
||||
#define GT_SCS10HD (0x010 >> 2)
|
||||
#define GT_SCS32LD (0x018 >> 2)
|
||||
#define GT_SCS32HD (0x020 >> 2)
|
||||
#define GT_CS20LD (0x028 >> 2)
|
||||
#define GT_CS20HD (0x030 >> 2)
|
||||
#define GT_CS3BOOTLD (0x038 >> 2)
|
||||
#define GT_CS3BOOTHD (0x040 >> 2)
|
||||
#define GT_PCI0IOLD (0x048 >> 2)
|
||||
#define GT_PCI0IOHD (0x050 >> 2)
|
||||
#define GT_PCI0M0LD (0x058 >> 2)
|
||||
#define GT_PCI0M0HD (0x060 >> 2)
|
||||
#define GT_ISD (0x068 >> 2)
|
||||
|
||||
#define GT_PCI0M1LD (0x080 >> 2)
|
||||
#define GT_PCI0M1HD (0x088 >> 2)
|
||||
#define GT_PCI1IOLD (0x090 >> 2)
|
||||
#define GT_PCI1IOHD (0x098 >> 2)
|
||||
#define GT_PCI1M0LD (0x0a0 >> 2)
|
||||
#define GT_PCI1M0HD (0x0a8 >> 2)
|
||||
#define GT_PCI1M1LD (0x0b0 >> 2)
|
||||
#define GT_PCI1M1HD (0x0b8 >> 2)
|
||||
#define GT_PCI1M1LD (0x0b0 >> 2)
|
||||
#define GT_PCI1M1HD (0x0b8 >> 2)
|
||||
|
||||
#define GT_SCS10AR (0x0d0 >> 2)
|
||||
#define GT_SCS32AR (0x0d8 >> 2)
|
||||
#define GT_CS20R (0x0e0 >> 2)
|
||||
#define GT_CS3BOOTR (0x0e8 >> 2)
|
||||
|
||||
#define GT_PCI0IOREMAP (0x0f0 >> 2)
|
||||
#define GT_PCI0M0REMAP (0x0f8 >> 2)
|
||||
#define GT_PCI0M1REMAP (0x100 >> 2)
|
||||
#define GT_PCI1IOREMAP (0x108 >> 2)
|
||||
#define GT_PCI1M0REMAP (0x110 >> 2)
|
||||
#define GT_PCI1M1REMAP (0x118 >> 2)
|
||||
|
||||
/* CPU Error Report */
|
||||
#define GT_CPUERR_ADDRLO (0x070 >> 2)
|
||||
#define GT_CPUERR_ADDRHI (0x078 >> 2)
|
||||
#define GT_CPUERR_DATALO (0x128 >> 2) /* GT-64120A only */
|
||||
#define GT_CPUERR_DATAHI (0x130 >> 2) /* GT-64120A only */
|
||||
#define GT_CPUERR_PARITY (0x138 >> 2) /* GT-64120A only */
|
||||
|
||||
/* CPU Sync Barrier */
|
||||
#define GT_PCI0SYNC (0x0c0 >> 2)
|
||||
#define GT_PCI1SYNC (0x0c8 >> 2)
|
||||
|
||||
/* SDRAM and Device Address Decode */
|
||||
#define GT_SCS0LD (0x400 >> 2)
|
||||
#define GT_SCS0HD (0x404 >> 2)
|
||||
#define GT_SCS1LD (0x408 >> 2)
|
||||
#define GT_SCS1HD (0x40c >> 2)
|
||||
#define GT_SCS2LD (0x410 >> 2)
|
||||
#define GT_SCS2HD (0x414 >> 2)
|
||||
#define GT_SCS3LD (0x418 >> 2)
|
||||
#define GT_SCS3HD (0x41c >> 2)
|
||||
#define GT_CS0LD (0x420 >> 2)
|
||||
#define GT_CS0HD (0x424 >> 2)
|
||||
#define GT_CS1LD (0x428 >> 2)
|
||||
#define GT_CS1HD (0x42c >> 2)
|
||||
#define GT_CS2LD (0x430 >> 2)
|
||||
#define GT_CS2HD (0x434 >> 2)
|
||||
#define GT_CS3LD (0x438 >> 2)
|
||||
#define GT_CS3HD (0x43c >> 2)
|
||||
#define GT_BOOTLD (0x440 >> 2)
|
||||
#define GT_BOOTHD (0x444 >> 2)
|
||||
#define GT_ADERR (0x470 >> 2)
|
||||
|
||||
/* SDRAM Configuration */
|
||||
#define GT_SDRAM_CFG (0x448 >> 2)
|
||||
#define GT_SDRAM_OPMODE (0x474 >> 2)
|
||||
#define GT_SDRAM_BM (0x478 >> 2)
|
||||
#define GT_SDRAM_ADDRDECODE (0x47c >> 2)
|
||||
|
||||
/* SDRAM Parameters */
|
||||
#define GT_SDRAM_B0 (0x44c >> 2)
|
||||
#define GT_SDRAM_B1 (0x450 >> 2)
|
||||
#define GT_SDRAM_B2 (0x454 >> 2)
|
||||
#define GT_SDRAM_B3 (0x458 >> 2)
|
||||
|
||||
/* Device Parameters */
|
||||
#define GT_DEV_B0 (0x45c >> 2)
|
||||
#define GT_DEV_B1 (0x460 >> 2)
|
||||
#define GT_DEV_B2 (0x464 >> 2)
|
||||
#define GT_DEV_B3 (0x468 >> 2)
|
||||
#define GT_DEV_BOOT (0x46c >> 2)
|
||||
|
||||
/* ECC */
|
||||
#define GT_ECC_ERRDATALO (0x480 >> 2) /* GT-64120A only */
|
||||
#define GT_ECC_ERRDATAHI (0x484 >> 2) /* GT-64120A only */
|
||||
#define GT_ECC_MEM (0x488 >> 2) /* GT-64120A only */
|
||||
#define GT_ECC_CALC (0x48c >> 2) /* GT-64120A only */
|
||||
#define GT_ECC_ERRADDR (0x490 >> 2) /* GT-64120A only */
|
||||
|
||||
/* DMA Record */
|
||||
#define GT_DMA0_CNT (0x800 >> 2)
|
||||
#define GT_DMA1_CNT (0x804 >> 2)
|
||||
#define GT_DMA2_CNT (0x808 >> 2)
|
||||
#define GT_DMA3_CNT (0x80c >> 2)
|
||||
#define GT_DMA0_SA (0x810 >> 2)
|
||||
#define GT_DMA1_SA (0x814 >> 2)
|
||||
#define GT_DMA2_SA (0x818 >> 2)
|
||||
#define GT_DMA3_SA (0x81c >> 2)
|
||||
#define GT_DMA0_DA (0x820 >> 2)
|
||||
#define GT_DMA1_DA (0x824 >> 2)
|
||||
#define GT_DMA2_DA (0x828 >> 2)
|
||||
#define GT_DMA3_DA (0x82c >> 2)
|
||||
#define GT_DMA0_NEXT (0x830 >> 2)
|
||||
#define GT_DMA1_NEXT (0x834 >> 2)
|
||||
#define GT_DMA2_NEXT (0x838 >> 2)
|
||||
#define GT_DMA3_NEXT (0x83c >> 2)
|
||||
#define GT_DMA0_CUR (0x870 >> 2)
|
||||
#define GT_DMA1_CUR (0x874 >> 2)
|
||||
#define GT_DMA2_CUR (0x878 >> 2)
|
||||
#define GT_DMA3_CUR (0x87c >> 2)
|
||||
|
||||
/* DMA Channel Control */
|
||||
#define GT_DMA0_CTRL (0x840 >> 2)
|
||||
#define GT_DMA1_CTRL (0x844 >> 2)
|
||||
#define GT_DMA2_CTRL (0x848 >> 2)
|
||||
#define GT_DMA3_CTRL (0x84c >> 2)
|
||||
|
||||
/* DMA Arbiter */
|
||||
#define GT_DMA_ARB (0x860 >> 2)
|
||||
|
||||
/* Timer/Counter */
|
||||
#define GT_TC0 (0x850 >> 2)
|
||||
#define GT_TC1 (0x854 >> 2)
|
||||
#define GT_TC2 (0x858 >> 2)
|
||||
#define GT_TC3 (0x85c >> 2)
|
||||
#define GT_TC_CONTROL (0x864 >> 2)
|
||||
|
||||
/* PCI Internal */
|
||||
#define GT_PCI0_CMD (0xc00 >> 2)
|
||||
#define GT_PCI0_TOR (0xc04 >> 2)
|
||||
#define GT_PCI0_BS_SCS10 (0xc08 >> 2)
|
||||
#define GT_PCI0_BS_SCS32 (0xc0c >> 2)
|
||||
#define GT_PCI0_BS_CS20 (0xc10 >> 2)
|
||||
#define GT_PCI0_BS_CS3BT (0xc14 >> 2)
|
||||
#define GT_PCI1_IACK (0xc30 >> 2)
|
||||
#define GT_PCI0_IACK (0xc34 >> 2)
|
||||
#define GT_PCI0_BARE (0xc3c >> 2)
|
||||
#define GT_PCI0_PREFMBR (0xc40 >> 2)
|
||||
#define GT_PCI0_SCS10_BAR (0xc48 >> 2)
|
||||
#define GT_PCI0_SCS32_BAR (0xc4c >> 2)
|
||||
#define GT_PCI0_CS20_BAR (0xc50 >> 2)
|
||||
#define GT_PCI0_CS3BT_BAR (0xc54 >> 2)
|
||||
#define GT_PCI0_SSCS10_BAR (0xc58 >> 2)
|
||||
#define GT_PCI0_SSCS32_BAR (0xc5c >> 2)
|
||||
#define GT_PCI0_SCS3BT_BAR (0xc64 >> 2)
|
||||
#define GT_PCI1_CMD (0xc80 >> 2)
|
||||
#define GT_PCI1_TOR (0xc84 >> 2)
|
||||
#define GT_PCI1_BS_SCS10 (0xc88 >> 2)
|
||||
#define GT_PCI1_BS_SCS32 (0xc8c >> 2)
|
||||
#define GT_PCI1_BS_CS20 (0xc90 >> 2)
|
||||
#define GT_PCI1_BS_CS3BT (0xc94 >> 2)
|
||||
#define GT_PCI1_BARE (0xcbc >> 2)
|
||||
#define GT_PCI1_PREFMBR (0xcc0 >> 2)
|
||||
#define GT_PCI1_SCS10_BAR (0xcc8 >> 2)
|
||||
#define GT_PCI1_SCS32_BAR (0xccc >> 2)
|
||||
#define GT_PCI1_CS20_BAR (0xcd0 >> 2)
|
||||
#define GT_PCI1_CS3BT_BAR (0xcd4 >> 2)
|
||||
#define GT_PCI1_SSCS10_BAR (0xcd8 >> 2)
|
||||
#define GT_PCI1_SSCS32_BAR (0xcdc >> 2)
|
||||
#define GT_PCI1_SCS3BT_BAR (0xce4 >> 2)
|
||||
#define GT_PCI1_CFGADDR (0xcf0 >> 2)
|
||||
#define GT_PCI1_CFGDATA (0xcf4 >> 2)
|
||||
#define GT_PCI0_CFGADDR (0xcf8 >> 2)
|
||||
#define GT_PCI0_CFGDATA (0xcfc >> 2)
|
||||
|
||||
/* Interrupts */
|
||||
#define GT_INTRCAUSE (0xc18 >> 2)
|
||||
#define GT_INTRMASK (0xc1c >> 2)
|
||||
#define GT_PCI0_ICMASK (0xc24 >> 2)
|
||||
#define GT_PCI0_SERR0MASK (0xc28 >> 2)
|
||||
#define GT_CPU_INTSEL (0xc70 >> 2)
|
||||
#define GT_PCI0_INTSEL (0xc74 >> 2)
|
||||
#define GT_HINTRCAUSE (0xc98 >> 2)
|
||||
#define GT_HINTRMASK (0xc9c >> 2)
|
||||
#define GT_PCI0_HICMASK (0xca4 >> 2)
|
||||
#define GT_PCI1_SERR1MASK (0xca8 >> 2)
|
||||
|
||||
|
||||
typedef PCIHostState GT64120PCIState;
|
||||
|
||||
typedef struct GT64120State {
|
||||
GT64120PCIState *pci;
|
||||
uint32_t regs[GT_REGS];
|
||||
} GT64120State;
|
||||
|
||||
static void gt64120_pci_mapping(GT64120State *s)
|
||||
{
|
||||
target_phys_addr_t start, length;
|
||||
|
||||
/* Update IO mapping */
|
||||
if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
|
||||
{
|
||||
start = s->regs[GT_PCI0IOLD] << 21;
|
||||
length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
|
||||
isa_mmio_init(start, length);
|
||||
}
|
||||
}
|
||||
|
||||
static void gt64120_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
|
||||
saddr = (addr & 0xfff) >> 2;
|
||||
switch (saddr) {
|
||||
|
||||
/* CPU Configuration */
|
||||
case GT_CPU:
|
||||
s->regs[GT_CPU] = val;
|
||||
break;
|
||||
case GT_MULTI:
|
||||
/* Read-only register as only one GT64xxx is present on the CPU bus */
|
||||
break;
|
||||
|
||||
/* CPU Address Decode */
|
||||
case GT_PCI0IOLD:
|
||||
s->regs[GT_PCI0IOLD] = val & 0x00007fff;
|
||||
s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI0M0LD:
|
||||
s->regs[GT_PCI0M0LD] = val & 0x00007fff;
|
||||
s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI0M1LD:
|
||||
s->regs[GT_PCI0M1LD] = val & 0x00007fff;
|
||||
s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI1IOLD:
|
||||
s->regs[GT_PCI1IOLD] = val & 0x00007fff;
|
||||
s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI1M0LD:
|
||||
s->regs[GT_PCI1M0LD] = val & 0x00007fff;
|
||||
s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI1M1LD:
|
||||
s->regs[GT_PCI1M1LD] = val & 0x00007fff;
|
||||
s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI0IOHD:
|
||||
case GT_PCI0M0HD:
|
||||
case GT_PCI0M1HD:
|
||||
case GT_PCI1IOHD:
|
||||
case GT_PCI1M0HD:
|
||||
case GT_PCI1M1HD:
|
||||
s->regs[saddr] = val & 0x0000007f;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
case GT_PCI0IOREMAP:
|
||||
case GT_PCI0M0REMAP:
|
||||
case GT_PCI0M1REMAP:
|
||||
case GT_PCI1IOREMAP:
|
||||
case GT_PCI1M0REMAP:
|
||||
case GT_PCI1M1REMAP:
|
||||
s->regs[saddr] = val & 0x000007ff;
|
||||
gt64120_pci_mapping(s);
|
||||
break;
|
||||
|
||||
/* CPU Error Report */
|
||||
case GT_CPUERR_ADDRLO:
|
||||
case GT_CPUERR_ADDRHI:
|
||||
case GT_CPUERR_DATALO:
|
||||
case GT_CPUERR_DATAHI:
|
||||
case GT_CPUERR_PARITY:
|
||||
/* Read-only registers, do nothing */
|
||||
break;
|
||||
|
||||
/* CPU Sync Barrier */
|
||||
case GT_PCI0SYNC:
|
||||
case GT_PCI1SYNC:
|
||||
/* Read-only registers, do nothing */
|
||||
break;
|
||||
|
||||
/* ECC */
|
||||
case GT_ECC_ERRDATALO:
|
||||
case GT_ECC_ERRDATAHI:
|
||||
case GT_ECC_MEM:
|
||||
case GT_ECC_CALC:
|
||||
case GT_ECC_ERRADDR:
|
||||
/* Read-only registers, do nothing */
|
||||
break;
|
||||
|
||||
/* PCI Internal */
|
||||
case GT_PCI0_CMD:
|
||||
case GT_PCI1_CMD:
|
||||
s->regs[saddr] = val & 0x0401fc0f;
|
||||
break;
|
||||
case GT_PCI0_CFGADDR:
|
||||
s->pci->config_reg = val & 0x80fffffc;
|
||||
break;
|
||||
case GT_PCI0_CFGDATA:
|
||||
pci_host_data_writel(s->pci, 0, val);
|
||||
break;
|
||||
|
||||
/* SDRAM Parameters */
|
||||
case GT_SDRAM_B0:
|
||||
case GT_SDRAM_B1:
|
||||
case GT_SDRAM_B2:
|
||||
case GT_SDRAM_B3:
|
||||
/* We don't simulate electrical parameters of the SDRAM.
|
||||
Accept, but ignore the values. */
|
||||
s->regs[saddr] = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
#if 0
|
||||
printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t gt64120_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
uint32_t val;
|
||||
uint32_t saddr;
|
||||
|
||||
val = 0;
|
||||
saddr = (addr & 0xfff) >> 2;
|
||||
|
||||
switch (saddr) {
|
||||
|
||||
/* CPU Configuration */
|
||||
case GT_MULTI:
|
||||
/* Only one GT64xxx is present on the CPU bus, return
|
||||
the initial value */
|
||||
val = s->regs[saddr];
|
||||
break;
|
||||
|
||||
/* CPU Error Report */
|
||||
case GT_CPUERR_ADDRLO:
|
||||
case GT_CPUERR_ADDRHI:
|
||||
case GT_CPUERR_DATALO:
|
||||
case GT_CPUERR_DATAHI:
|
||||
case GT_CPUERR_PARITY:
|
||||
/* Emulated memory has no error, always return the initial
|
||||
values */
|
||||
val = s->regs[saddr];
|
||||
break;
|
||||
|
||||
/* CPU Sync Barrier */
|
||||
case GT_PCI0SYNC:
|
||||
case GT_PCI1SYNC:
|
||||
/* Reading those register should empty all FIFO on the PCI
|
||||
bus, which are not emulated. The return value should be
|
||||
a random value that should be ignored. */
|
||||
val = 0xc000ffee;
|
||||
break;
|
||||
|
||||
/* ECC */
|
||||
case GT_ECC_ERRDATALO:
|
||||
case GT_ECC_ERRDATAHI:
|
||||
case GT_ECC_MEM:
|
||||
case GT_ECC_CALC:
|
||||
case GT_ECC_ERRADDR:
|
||||
/* Emulated memory has no error, always return the initial
|
||||
values */
|
||||
val = s->regs[saddr];
|
||||
break;
|
||||
|
||||
case GT_CPU:
|
||||
case GT_PCI0IOLD:
|
||||
case GT_PCI0M0LD:
|
||||
case GT_PCI0M1LD:
|
||||
case GT_PCI1IOLD:
|
||||
case GT_PCI1M0LD:
|
||||
case GT_PCI1M1LD:
|
||||
case GT_PCI0IOHD:
|
||||
case GT_PCI0M0HD:
|
||||
case GT_PCI0M1HD:
|
||||
case GT_PCI1IOHD:
|
||||
case GT_PCI1M0HD:
|
||||
case GT_PCI1M1HD:
|
||||
case GT_PCI0_CMD:
|
||||
case GT_PCI1_CMD:
|
||||
case GT_PCI0IOREMAP:
|
||||
case GT_PCI0M0REMAP:
|
||||
case GT_PCI0M1REMAP:
|
||||
case GT_PCI1IOREMAP:
|
||||
case GT_PCI1M0REMAP:
|
||||
case GT_PCI1M1REMAP:
|
||||
val = s->regs[saddr];
|
||||
break;
|
||||
case GT_PCI0_IACK:
|
||||
/* Read the IRQ number */
|
||||
val = pic_read_irq(isa_pic);
|
||||
break;
|
||||
|
||||
/* SDRAM Parameters */
|
||||
case GT_SDRAM_B0:
|
||||
case GT_SDRAM_B1:
|
||||
case GT_SDRAM_B2:
|
||||
case GT_SDRAM_B3:
|
||||
/* We don't simulate electrical parameters of the SDRAM.
|
||||
Just return the last written value. */
|
||||
val = s->regs[saddr];
|
||||
break;
|
||||
|
||||
/* PCI Internal */
|
||||
case GT_PCI0_CFGADDR:
|
||||
val = s->pci->config_reg;
|
||||
break;
|
||||
case GT_PCI0_CFGDATA:
|
||||
val = pci_host_data_readl(s->pci, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
val = s->regs[saddr];
|
||||
#if 0
|
||||
printf ("gt64120_readl: Bad register offset 0x%x\n", (int)addr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
return bswap32(val);
|
||||
#else
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *gt64120_write[] = {
|
||||
>64120_writel,
|
||||
>64120_writel,
|
||||
>64120_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *gt64120_read[] = {
|
||||
>64120_readl,
|
||||
>64120_readl,
|
||||
>64120_readl,
|
||||
};
|
||||
|
||||
static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
int slot;
|
||||
|
||||
slot = (pci_dev->devfn >> 3);
|
||||
|
||||
switch (slot) {
|
||||
/* PIIX4 USB */
|
||||
case 10:
|
||||
return 3;
|
||||
/* AMD 79C973 Ethernet */
|
||||
case 11:
|
||||
return 0;
|
||||
/* Crystal 4281 Sound */
|
||||
case 12:
|
||||
return 0;
|
||||
/* PCI slot 1 to 4 */
|
||||
case 18 ... 21:
|
||||
return ((slot - 18) + irq_num) & 0x03;
|
||||
/* Unknown device, don't do any translation */
|
||||
default:
|
||||
return irq_num;
|
||||
}
|
||||
}
|
||||
|
||||
extern PCIDevice *piix4_dev;
|
||||
static int pci_irq_levels[4];
|
||||
|
||||
static void pci_gt64120_set_irq(void *pic, int irq_num, int level)
|
||||
{
|
||||
int i, pic_irq, pic_level;
|
||||
|
||||
pci_irq_levels[irq_num] = level;
|
||||
|
||||
/* now we change the pic irq level according to the piix irq mappings */
|
||||
/* XXX: optimize */
|
||||
pic_irq = piix4_dev->config[0x60 + irq_num];
|
||||
if (pic_irq < 16) {
|
||||
/* The pic level is the logical OR of all the PCI irqs mapped
|
||||
to it */
|
||||
pic_level = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (pic_irq == piix4_dev->config[0x60 + i])
|
||||
pic_level |= pci_irq_levels[i];
|
||||
}
|
||||
pic_set_irq(pic_irq, pic_level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gt64120_reset(void *opaque)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
|
||||
/* CPU Configuration */
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
s->regs[GT_CPU] = 0x00000000;
|
||||
#else
|
||||
s->regs[GT_CPU] = 0x00000800;
|
||||
#endif
|
||||
s->regs[GT_MULTI] = 0x00000000;
|
||||
|
||||
/* CPU Address decode FIXME: not complete*/
|
||||
s->regs[GT_PCI0IOLD] = 0x00000080;
|
||||
s->regs[GT_PCI0IOHD] = 0x0000000f;
|
||||
s->regs[GT_PCI0M0LD] = 0x00000090;
|
||||
s->regs[GT_PCI0M0HD] = 0x0000001f;
|
||||
s->regs[GT_PCI0M1LD] = 0x00000790;
|
||||
s->regs[GT_PCI0M1HD] = 0x0000001f;
|
||||
s->regs[GT_PCI1IOLD] = 0x00000100;
|
||||
s->regs[GT_PCI1IOHD] = 0x0000000f;
|
||||
s->regs[GT_PCI1M0LD] = 0x00000110;
|
||||
s->regs[GT_PCI1M0HD] = 0x0000001f;
|
||||
s->regs[GT_PCI1M1LD] = 0x00000120;
|
||||
s->regs[GT_PCI1M1HD] = 0x0000002f;
|
||||
s->regs[GT_PCI0IOREMAP] = 0x00000080;
|
||||
s->regs[GT_PCI0M0REMAP] = 0x00000090;
|
||||
s->regs[GT_PCI0M1REMAP] = 0x00000790;
|
||||
s->regs[GT_PCI1IOREMAP] = 0x00000100;
|
||||
s->regs[GT_PCI1M0REMAP] = 0x00000110;
|
||||
s->regs[GT_PCI1M1REMAP] = 0x00000120;
|
||||
|
||||
/* CPU Error Report */
|
||||
s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
|
||||
s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
|
||||
s->regs[GT_CPUERR_DATALO] = 0xffffffff;
|
||||
s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
|
||||
s->regs[GT_CPUERR_PARITY] = 0x000000ff;
|
||||
|
||||
/* ECC */
|
||||
s->regs[GT_ECC_ERRDATALO] = 0x00000000;
|
||||
s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
|
||||
s->regs[GT_ECC_MEM] = 0x00000000;
|
||||
s->regs[GT_ECC_CALC] = 0x00000000;
|
||||
s->regs[GT_ECC_ERRADDR] = 0x00000000;
|
||||
|
||||
/* SDRAM Parameters */
|
||||
s->regs[GT_SDRAM_B0] = 0x00000005;
|
||||
s->regs[GT_SDRAM_B1] = 0x00000005;
|
||||
s->regs[GT_SDRAM_B2] = 0x00000005;
|
||||
s->regs[GT_SDRAM_B3] = 0x00000005;
|
||||
|
||||
/* PCI Internal FIXME: not complete*/
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
s->regs[GT_PCI0_CMD] = 0x00000000;
|
||||
s->regs[GT_PCI1_CMD] = 0x00000000;
|
||||
#else
|
||||
s->regs[GT_PCI0_CMD] = 0x00010001;
|
||||
s->regs[GT_PCI1_CMD] = 0x00010001;
|
||||
#endif
|
||||
s->regs[GT_PCI0_IACK] = 0x00000000;
|
||||
s->regs[GT_PCI1_IACK] = 0x00000000;
|
||||
|
||||
gt64120_pci_mapping(s);
|
||||
}
|
||||
|
||||
PCIBus *pci_gt64120_init(void *pic)
|
||||
{
|
||||
GT64120State *s;
|
||||
PCIDevice *d;
|
||||
int gt64120;
|
||||
|
||||
s = qemu_mallocz(sizeof(GT64120State));
|
||||
s->pci = qemu_mallocz(sizeof(GT64120PCIState));
|
||||
gt64120_reset(s);
|
||||
|
||||
s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq,
|
||||
pic, 144, 4);
|
||||
|
||||
gt64120 = cpu_register_io_memory(0, gt64120_read,
|
||||
gt64120_write, s);
|
||||
cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120);
|
||||
|
||||
d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
|
||||
0, NULL, NULL);
|
||||
|
||||
d->config[0x00] = 0xab; // vendor_id
|
||||
d->config[0x01] = 0x11;
|
||||
d->config[0x02] = 0x46; // device_id
|
||||
d->config[0x03] = 0x20;
|
||||
d->config[0x04] = 0x06;
|
||||
d->config[0x05] = 0x00;
|
||||
d->config[0x06] = 0x80;
|
||||
d->config[0x07] = 0xa2;
|
||||
d->config[0x08] = 0x10;
|
||||
d->config[0x09] = 0x00;
|
||||
d->config[0x0A] = 0x80;
|
||||
d->config[0x0B] = 0x05;
|
||||
d->config[0x0C] = 0x08;
|
||||
d->config[0x0D] = 0x40;
|
||||
d->config[0x0E] = 0x00;
|
||||
d->config[0x0F] = 0x00;
|
||||
d->config[0x17] = 0x08;
|
||||
d->config[0x1B] = 0x1c;
|
||||
d->config[0x1F] = 0x1f;
|
||||
d->config[0x23] = 0x14;
|
||||
d->config[0x27] = 0x14;
|
||||
d->config[0x3D] = 0x01;
|
||||
|
||||
return s->pci->bus;
|
||||
}
|
||||
@@ -161,6 +161,13 @@ void pic_update_irq(PicState2 *s)
|
||||
#endif
|
||||
s->irq_request(s->irq_request_opaque, 1);
|
||||
}
|
||||
|
||||
/* all targets should do this rather than acking the IRQ in the cpu */
|
||||
#if defined(TARGET_MIPS)
|
||||
else {
|
||||
s->irq_request(s->irq_request_opaque, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
|
||||
+3
-3
@@ -325,7 +325,7 @@ static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset)
|
||||
case 5: /* INT_SOFTCLR */
|
||||
case 11: /* FRQ_ENABLECLR */
|
||||
default:
|
||||
printf ("icp_pic_read: Bad register offset 0x%x\n", offset);
|
||||
printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -362,7 +362,7 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset,
|
||||
case 8: /* FRQ_STATUS */
|
||||
case 9: /* FRQ_RAWSTAT */
|
||||
default:
|
||||
printf ("icp_pic_write: Bad register offset 0x%x\n", offset);
|
||||
printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
|
||||
return;
|
||||
}
|
||||
icp_pic_update(s);
|
||||
@@ -509,7 +509,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
pl110_init(ds, 0xc0000000, pic, 22, 0);
|
||||
|
||||
arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
|
||||
arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, 0x113);
|
||||
}
|
||||
|
||||
|
||||
+38
-5
@@ -186,21 +186,54 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = {
|
||||
iommu_mem_writew,
|
||||
};
|
||||
|
||||
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
|
||||
static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr)
|
||||
{
|
||||
IOMMUState *s = opaque;
|
||||
uint32_t iopte, pa, tmppte;
|
||||
uint32_t iopte;
|
||||
|
||||
iopte = s->regs[1] << 4;
|
||||
addr &= ~s->iostart;
|
||||
iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
|
||||
pa = ldl_phys(iopte);
|
||||
return ldl_phys(iopte);
|
||||
}
|
||||
|
||||
static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa)
|
||||
{
|
||||
uint32_t tmppte;
|
||||
|
||||
tmppte = pa;
|
||||
pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
|
||||
DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
|
||||
DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte);
|
||||
return pa;
|
||||
}
|
||||
|
||||
void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int is_write)
|
||||
{
|
||||
int l, flags;
|
||||
target_ulong page, phys_addr;
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
l = (page + TARGET_PAGE_SIZE) - addr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
flags = iommu_page_get_flags(opaque, page);
|
||||
if (!(flags & IOPTE_VALID))
|
||||
return;
|
||||
phys_addr = iommu_translate_pa(opaque, addr, flags);
|
||||
if (is_write) {
|
||||
if (!(flags & IOPTE_WRITE))
|
||||
return;
|
||||
cpu_physical_memory_write(phys_addr, buf, len);
|
||||
} else {
|
||||
cpu_physical_memory_read(phys_addr, buf, len);
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
}
|
||||
}
|
||||
|
||||
static void iommu_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
IOMMUState *s = opaque;
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Memory mapped access to ISA IO space.
|
||||
*
|
||||
* Copyright (c) 2006 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 "vl.h"
|
||||
|
||||
static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outb(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void isa_mmio_writew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
cpu_outw(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void isa_mmio_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
cpu_outl(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static uint32_t isa_mmio_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inb(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t isa_mmio_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inw(NULL, addr & 0xffff);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t isa_mmio_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inl(NULL, addr & 0xffff);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *isa_mmio_write[] = {
|
||||
&isa_mmio_writeb,
|
||||
&isa_mmio_writew,
|
||||
&isa_mmio_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *isa_mmio_read[] = {
|
||||
&isa_mmio_readb,
|
||||
&isa_mmio_readw,
|
||||
&isa_mmio_readl,
|
||||
};
|
||||
|
||||
static int isa_mmio_iomemtype = 0;
|
||||
|
||||
void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size)
|
||||
{
|
||||
if (!isa_mmio_iomemtype) {
|
||||
isa_mmio_iomemtype = cpu_register_io_memory(0, isa_mmio_read,
|
||||
isa_mmio_write, NULL);
|
||||
}
|
||||
cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
|
||||
}
|
||||
-462
@@ -1,462 +0,0 @@
|
||||
/*
|
||||
* QEMU Lance emulation
|
||||
*
|
||||
* Copyright (c) 2003-2005 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 "vl.h"
|
||||
|
||||
/* debug LANCE card */
|
||||
//#define DEBUG_LANCE
|
||||
|
||||
#ifdef DEBUG_LANCE
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("LANCE: " fmt , ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...)
|
||||
#endif
|
||||
|
||||
#ifndef LANCE_LOG_TX_BUFFERS
|
||||
#define LANCE_LOG_TX_BUFFERS 4
|
||||
#define LANCE_LOG_RX_BUFFERS 4
|
||||
#endif
|
||||
|
||||
#define LE_CSR0 0
|
||||
#define LE_CSR1 1
|
||||
#define LE_CSR2 2
|
||||
#define LE_CSR3 3
|
||||
#define LE_NREGS (LE_CSR3 + 1)
|
||||
#define LE_MAXREG LE_CSR3
|
||||
|
||||
#define LE_RDP 0
|
||||
#define LE_RAP 1
|
||||
|
||||
#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
|
||||
|
||||
#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
|
||||
#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
|
||||
#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
|
||||
#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
|
||||
#define LE_C0_MERR 0x0800 /* ME: Memory error */
|
||||
#define LE_C0_RINT 0x0400 /* Received interrupt */
|
||||
#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
|
||||
#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
|
||||
#define LE_C0_INTR 0x0080 /* Interrupt or error */
|
||||
#define LE_C0_INEA 0x0040 /* Interrupt enable */
|
||||
#define LE_C0_RXON 0x0020 /* Receiver on */
|
||||
#define LE_C0_TXON 0x0010 /* Transmitter on */
|
||||
#define LE_C0_TDMD 0x0008 /* Transmitter demand */
|
||||
#define LE_C0_STOP 0x0004 /* Stop the card */
|
||||
#define LE_C0_STRT 0x0002 /* Start the card */
|
||||
#define LE_C0_INIT 0x0001 /* Init the card */
|
||||
|
||||
#define LE_C3_BSWP 0x4 /* SWAP */
|
||||
#define LE_C3_ACON 0x2 /* ALE Control */
|
||||
#define LE_C3_BCON 0x1 /* Byte control */
|
||||
|
||||
/* Receive message descriptor 1 */
|
||||
#define LE_R1_OWN 0x80 /* Who owns the entry */
|
||||
#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
|
||||
#define LE_R1_FRA 0x20 /* FRA: Frame error */
|
||||
#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
|
||||
#define LE_R1_CRC 0x08 /* CRC error */
|
||||
#define LE_R1_BUF 0x04 /* BUF: Buffer error */
|
||||
#define LE_R1_SOP 0x02 /* Start of packet */
|
||||
#define LE_R1_EOP 0x01 /* End of packet */
|
||||
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
|
||||
|
||||
#define LE_T1_OWN 0x80 /* Lance owns the packet */
|
||||
#define LE_T1_ERR 0x40 /* Error summary */
|
||||
#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
|
||||
#define LE_T1_EONE 0x08 /* Error: one retry needed */
|
||||
#define LE_T1_EDEF 0x04 /* Error: deferred */
|
||||
#define LE_T1_SOP 0x02 /* Start of packet */
|
||||
#define LE_T1_EOP 0x01 /* End of packet */
|
||||
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
|
||||
|
||||
#define LE_T3_BUF 0x8000 /* Buffer error */
|
||||
#define LE_T3_UFL 0x4000 /* Error underflow */
|
||||
#define LE_T3_LCOL 0x1000 /* Error late collision */
|
||||
#define LE_T3_CLOS 0x0800 /* Error carrier loss */
|
||||
#define LE_T3_RTY 0x0400 /* Error retry */
|
||||
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
|
||||
|
||||
#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
|
||||
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
|
||||
#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
|
||||
|
||||
#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
|
||||
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
|
||||
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
|
||||
|
||||
#define PKT_BUF_SZ 1544
|
||||
#define RX_BUFF_SIZE PKT_BUF_SZ
|
||||
#define TX_BUFF_SIZE PKT_BUF_SZ
|
||||
|
||||
struct lance_rx_desc {
|
||||
unsigned short rmd0; /* low address of packet */
|
||||
unsigned char rmd1_bits; /* descriptor bits */
|
||||
unsigned char rmd1_hadr; /* high address of packet */
|
||||
short length; /* This length is 2s complement (negative)!
|
||||
* Buffer length
|
||||
*/
|
||||
unsigned short mblength; /* This is the actual number of bytes received */
|
||||
};
|
||||
|
||||
struct lance_tx_desc {
|
||||
unsigned short tmd0; /* low address of packet */
|
||||
unsigned char tmd1_bits; /* descriptor bits */
|
||||
unsigned char tmd1_hadr; /* high address of packet */
|
||||
short length; /* Length is 2s complement (negative)! */
|
||||
unsigned short misc;
|
||||
};
|
||||
|
||||
/* The LANCE initialization block, described in databook. */
|
||||
/* On the Sparc, this block should be on a DMA region */
|
||||
struct lance_init_block {
|
||||
unsigned short mode; /* Pre-set mode (reg. 15) */
|
||||
unsigned char phys_addr[6]; /* Physical ethernet address */
|
||||
unsigned filter[2]; /* Multicast filter. */
|
||||
|
||||
/* Receive and transmit ring base, along with extra bits. */
|
||||
unsigned short rx_ptr; /* receive descriptor addr */
|
||||
unsigned short rx_len; /* receive len and high addr */
|
||||
unsigned short tx_ptr; /* transmit descriptor addr */
|
||||
unsigned short tx_len; /* transmit len and high addr */
|
||||
|
||||
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
|
||||
struct lance_rx_desc brx_ring[RX_RING_SIZE];
|
||||
struct lance_tx_desc btx_ring[TX_RING_SIZE];
|
||||
|
||||
char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
|
||||
char pad[2]; /* align rx_buf for copy_and_sum(). */
|
||||
char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
|
||||
};
|
||||
|
||||
#define LEDMA_REGS 4
|
||||
#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
|
||||
|
||||
typedef struct LANCEState {
|
||||
VLANClientState *vc;
|
||||
uint8_t macaddr[6]; /* init mac address */
|
||||
uint32_t leptr;
|
||||
uint16_t addr;
|
||||
uint16_t regs[LE_NREGS];
|
||||
uint8_t phys[6]; /* mac address */
|
||||
int irq;
|
||||
unsigned int rxptr, txptr;
|
||||
uint32_t ledmaregs[LEDMA_REGS];
|
||||
} LANCEState;
|
||||
|
||||
static void lance_send(void *opaque);
|
||||
|
||||
static void lance_reset(void *opaque)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
memcpy(s->phys, s->macaddr, 6);
|
||||
s->rxptr = 0;
|
||||
s->txptr = 0;
|
||||
memset(s->regs, 0, LE_NREGS * 2);
|
||||
s->regs[LE_CSR0] = LE_C0_STOP;
|
||||
memset(s->ledmaregs, 0, LEDMA_REGS * 4);
|
||||
}
|
||||
|
||||
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = addr & LE_MAXREG;
|
||||
switch (saddr >> 1) {
|
||||
case LE_RDP:
|
||||
DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
|
||||
return s->regs[s->addr];
|
||||
case LE_RAP:
|
||||
DPRINTF("read areg = %4.4x\n", s->addr);
|
||||
return s->addr;
|
||||
default:
|
||||
DPRINTF("read unknown(%d)\n", saddr>>1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
uint32_t saddr;
|
||||
uint16_t reg;
|
||||
|
||||
saddr = addr & LE_MAXREG;
|
||||
switch (saddr >> 1) {
|
||||
case LE_RDP:
|
||||
DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
|
||||
switch(s->addr) {
|
||||
case LE_CSR0:
|
||||
if (val & LE_C0_STOP) {
|
||||
s->regs[LE_CSR0] = LE_C0_STOP;
|
||||
break;
|
||||
}
|
||||
|
||||
reg = s->regs[LE_CSR0];
|
||||
|
||||
// 1 = clear for some bits
|
||||
reg &= ~(val & 0x7f00);
|
||||
|
||||
// generated bits
|
||||
reg &= ~(LE_C0_ERR | LE_C0_INTR);
|
||||
if (reg & 0x7100)
|
||||
reg |= LE_C0_ERR;
|
||||
if (reg & 0x7f00)
|
||||
reg |= LE_C0_INTR;
|
||||
|
||||
// direct bit
|
||||
reg &= ~LE_C0_INEA;
|
||||
reg |= val & LE_C0_INEA;
|
||||
|
||||
// exclusive bits
|
||||
if (val & LE_C0_INIT) {
|
||||
reg |= LE_C0_IDON | LE_C0_INIT;
|
||||
reg &= ~LE_C0_STOP;
|
||||
}
|
||||
else if (val & LE_C0_STRT) {
|
||||
reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
|
||||
reg &= ~LE_C0_STOP;
|
||||
}
|
||||
|
||||
s->regs[LE_CSR0] = reg;
|
||||
break;
|
||||
case LE_CSR1:
|
||||
s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
|
||||
s->regs[s->addr] = val;
|
||||
break;
|
||||
case LE_CSR2:
|
||||
s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
|
||||
s->regs[s->addr] = val;
|
||||
break;
|
||||
case LE_CSR3:
|
||||
s->regs[s->addr] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LE_RAP:
|
||||
DPRINTF("write areg = %4.4x\n", val);
|
||||
if (val < LE_NREGS)
|
||||
s->addr = val;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val);
|
||||
break;
|
||||
}
|
||||
lance_send(s);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *lance_mem_read[3] = {
|
||||
lance_mem_readw,
|
||||
lance_mem_readw,
|
||||
lance_mem_readw,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *lance_mem_write[3] = {
|
||||
lance_mem_writew,
|
||||
lance_mem_writew,
|
||||
lance_mem_writew,
|
||||
};
|
||||
|
||||
|
||||
#define MIN_BUF_SIZE 60
|
||||
|
||||
static int lance_can_receive(void *opaque)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void lance_receive(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
||||
struct lance_init_block *ib;
|
||||
unsigned int i, old_rxptr;
|
||||
uint16_t temp16;
|
||||
uint8_t temp8;
|
||||
|
||||
DPRINTF("receive size %d\n", size);
|
||||
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
||||
return;
|
||||
|
||||
ib = (void *) iommu_translate(dmaptr);
|
||||
|
||||
old_rxptr = s->rxptr;
|
||||
for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
|
||||
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
|
||||
if (temp8 == (LE_R1_OWN)) {
|
||||
s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
|
||||
temp16 = size + 4;
|
||||
bswap16s(&temp16);
|
||||
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2);
|
||||
cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
|
||||
temp8 = LE_R1_POK;
|
||||
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
|
||||
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
|
||||
if (s->regs[LE_CSR0] & LE_C0_INEA)
|
||||
pic_set_irq(s->irq, 1);
|
||||
DPRINTF("got packet, len %d\n", size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lance_send(void *opaque)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
||||
struct lance_init_block *ib;
|
||||
unsigned int i, old_txptr;
|
||||
uint16_t temp16;
|
||||
uint8_t temp8;
|
||||
char pkt_buf[PKT_BUF_SZ];
|
||||
|
||||
DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
|
||||
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
|
||||
return;
|
||||
|
||||
ib = (void *) iommu_translate(dmaptr);
|
||||
|
||||
DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
|
||||
old_txptr = s->txptr;
|
||||
for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
|
||||
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
|
||||
if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
|
||||
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2);
|
||||
bswap16s(&temp16);
|
||||
temp16 = (~temp16) + 1;
|
||||
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
|
||||
DPRINTF("sending packet, len %d\n", temp16);
|
||||
qemu_send_packet(s->vc, pkt_buf, temp16);
|
||||
temp8 = LE_T1_POK;
|
||||
cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
|
||||
s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
|
||||
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
|
||||
}
|
||||
}
|
||||
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
|
||||
pic_set_irq(s->irq, 1);
|
||||
}
|
||||
|
||||
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & LEDMA_MAXADDR) >> 2;
|
||||
return s->ledmaregs[saddr];
|
||||
}
|
||||
|
||||
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & LEDMA_MAXADDR) >> 2;
|
||||
s->ledmaregs[saddr] = val;
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *ledma_mem_read[3] = {
|
||||
ledma_mem_readl,
|
||||
ledma_mem_readl,
|
||||
ledma_mem_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *ledma_mem_write[3] = {
|
||||
ledma_mem_writel,
|
||||
ledma_mem_writel,
|
||||
ledma_mem_writel,
|
||||
};
|
||||
|
||||
static void lance_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
int i;
|
||||
|
||||
qemu_put_be32s(f, &s->leptr);
|
||||
qemu_put_be16s(f, &s->addr);
|
||||
for (i = 0; i < LE_NREGS; i ++)
|
||||
qemu_put_be16s(f, &s->regs[i]);
|
||||
qemu_put_buffer(f, s->phys, 6);
|
||||
qemu_put_be32s(f, &s->irq);
|
||||
for (i = 0; i < LEDMA_REGS; i ++)
|
||||
qemu_put_be32s(f, &s->ledmaregs[i]);
|
||||
}
|
||||
|
||||
static int lance_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
LANCEState *s = opaque;
|
||||
int i;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
qemu_get_be32s(f, &s->leptr);
|
||||
qemu_get_be16s(f, &s->addr);
|
||||
for (i = 0; i < LE_NREGS; i ++)
|
||||
qemu_get_be16s(f, &s->regs[i]);
|
||||
qemu_get_buffer(f, s->phys, 6);
|
||||
qemu_get_be32s(f, &s->irq);
|
||||
for (i = 0; i < LEDMA_REGS; i ++)
|
||||
qemu_get_be32s(f, &s->ledmaregs[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
|
||||
{
|
||||
LANCEState *s;
|
||||
int lance_io_memory, ledma_io_memory;
|
||||
|
||||
s = qemu_mallocz(sizeof(LANCEState));
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
s->irq = irq;
|
||||
|
||||
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
|
||||
cpu_register_physical_memory(leaddr, 4, lance_io_memory);
|
||||
|
||||
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
|
||||
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
|
||||
|
||||
memcpy(s->macaddr, nd->macaddr, 6);
|
||||
|
||||
lance_reset(s);
|
||||
|
||||
s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s);
|
||||
|
||||
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
|
||||
"lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
s->macaddr[0],
|
||||
s->macaddr[1],
|
||||
s->macaddr[2],
|
||||
s->macaddr[3],
|
||||
s->macaddr[4],
|
||||
s->macaddr[5]);
|
||||
|
||||
register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
|
||||
qemu_register_reset(lance_reset, s);
|
||||
}
|
||||
|
||||
+393
-100
@@ -19,11 +19,11 @@
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("lsi_scsi: " fmt , ##args); } while (0)
|
||||
#define BADF(fmt, args...) \
|
||||
do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0)
|
||||
do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args); exit(1);} while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while(0)
|
||||
#define BADF(fmt, args...) \
|
||||
do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0)
|
||||
do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args);} while (0)
|
||||
#endif
|
||||
|
||||
#define LSI_SCNTL0_TRG 0x01
|
||||
@@ -152,21 +152,46 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0)
|
||||
/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
|
||||
#define LSI_MAX_DEVS 7
|
||||
|
||||
/* Maximum length of MSG IN data. */
|
||||
#define LSI_MAX_MSGIN_LEN 8
|
||||
|
||||
/* Flag set if this is a tagged command. */
|
||||
#define LSI_TAG_VALID (1 << 16)
|
||||
|
||||
typedef struct {
|
||||
uint32_t tag;
|
||||
uint32_t pending;
|
||||
int out;
|
||||
} lsi_queue;
|
||||
|
||||
typedef struct {
|
||||
PCIDevice pci_dev;
|
||||
int mmio_io_addr;
|
||||
int ram_io_addr;
|
||||
uint32_t script_ram_base;
|
||||
uint32_t data_len;
|
||||
|
||||
int carry; /* ??? Should this be an a visible register somewhere? */
|
||||
int sense;
|
||||
uint8_t msg;
|
||||
/* Nonzero if a Wait Reselect instruction has been issued. */
|
||||
/* Action to take at the end of a MSG IN phase.
|
||||
0 = COMMAND, 1 = disconect, 2 = DATA OUT, 3 = DATA IN. */
|
||||
int msg_action;
|
||||
int msg_len;
|
||||
uint8_t msg[LSI_MAX_MSGIN_LEN];
|
||||
/* 0 if SCRIPTS are running or stopped.
|
||||
* 1 if a Wait Reselect instruction has been issued.
|
||||
* 2 if processing DMA from lsi_execute_script.
|
||||
* 3 if a DMA operation is in progress. */
|
||||
int waiting;
|
||||
SCSIDevice *scsi_dev[LSI_MAX_DEVS];
|
||||
SCSIDevice *current_dev;
|
||||
int current_lun;
|
||||
/* The tag is a combination of the device ID and the SCSI tag. */
|
||||
uint32_t current_tag;
|
||||
uint32_t current_dma_len;
|
||||
uint8_t *dma_buf;
|
||||
lsi_queue *queue;
|
||||
int queue_len;
|
||||
int active_commands;
|
||||
|
||||
uint32_t dsa;
|
||||
uint32_t temp;
|
||||
@@ -203,10 +228,12 @@ typedef struct {
|
||||
uint8_t sxfer;
|
||||
uint8_t socl;
|
||||
uint8_t sdid;
|
||||
uint8_t ssid;
|
||||
uint8_t sfbr;
|
||||
uint8_t stest1;
|
||||
uint8_t stest2;
|
||||
uint8_t stest3;
|
||||
uint8_t sidl;
|
||||
uint8_t stime0;
|
||||
uint8_t respid0;
|
||||
uint8_t respid1;
|
||||
@@ -274,6 +301,7 @@ static void lsi_soft_reset(LSIState *s)
|
||||
s->stest1 = 0;
|
||||
s->stest2 = 0;
|
||||
s->stest3 = 0;
|
||||
s->sidl = 0;
|
||||
s->stime0 = 0;
|
||||
s->respid0 = 0x80;
|
||||
s->respid1 = 0;
|
||||
@@ -295,6 +323,7 @@ static void lsi_soft_reset(LSIState *s)
|
||||
|
||||
static uint8_t lsi_reg_readb(LSIState *s, int offset);
|
||||
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
|
||||
static void lsi_execute_script(LSIState *s);
|
||||
|
||||
static inline uint32_t read_dword(LSIState *s, uint32_t addr)
|
||||
{
|
||||
@@ -402,44 +431,196 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase)
|
||||
lsi_set_phase(s, new_phase);
|
||||
}
|
||||
|
||||
static void lsi_do_dma(LSIState *s, int out)
|
||||
|
||||
/* Resume SCRIPTS execution after a DMA operation. */
|
||||
static void lsi_resume_script(LSIState *s)
|
||||
{
|
||||
uint8_t buf[TARGET_PAGE_SIZE];
|
||||
uint32_t addr;
|
||||
uint32_t count;
|
||||
int n;
|
||||
|
||||
count = s->dbc;
|
||||
addr = s->dnad;
|
||||
DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in",
|
||||
addr, count, s->data_len);
|
||||
/* ??? Too long transfers are truncated. Don't know if this is the
|
||||
correct behavior. */
|
||||
if (count > s->data_len) {
|
||||
/* If the DMA length is greater then the device data length then
|
||||
a phase mismatch will occur. */
|
||||
count = s->data_len;
|
||||
s->dbc = count;
|
||||
lsi_bad_phase(s, out, PHASE_ST);
|
||||
}
|
||||
|
||||
s->csbc += count;
|
||||
|
||||
/* ??? Set SFBR to first data byte. */
|
||||
while (count) {
|
||||
n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;
|
||||
if (out) {
|
||||
cpu_physical_memory_read(addr, buf, n);
|
||||
scsi_write_data(s->current_dev, buf, n);
|
||||
} else {
|
||||
scsi_read_data(s->current_dev, buf, n);
|
||||
cpu_physical_memory_write(addr, buf, n);
|
||||
}
|
||||
addr += n;
|
||||
count -= n;
|
||||
if (s->waiting != 2) {
|
||||
s->waiting = 0;
|
||||
lsi_execute_script(s);
|
||||
} else {
|
||||
s->waiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initiate a SCSI layer data transfer. */
|
||||
static void lsi_do_dma(LSIState *s, int out)
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t addr;
|
||||
|
||||
if (!s->current_dma_len) {
|
||||
/* Wait until data is available. */
|
||||
DPRINTF("DMA no data available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
count = s->dbc;
|
||||
if (count > s->current_dma_len)
|
||||
count = s->current_dma_len;
|
||||
DPRINTF("DMA addr=0x%08x len=%d\n", s->dnad, count);
|
||||
|
||||
addr = s->dnad;
|
||||
s->csbc += count;
|
||||
s->dnad += count;
|
||||
s->dbc -= count;
|
||||
|
||||
if (s->dma_buf == NULL) {
|
||||
s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag);
|
||||
}
|
||||
|
||||
/* ??? Set SFBR to first data byte. */
|
||||
if (out) {
|
||||
cpu_physical_memory_read(addr, s->dma_buf, count);
|
||||
} else {
|
||||
cpu_physical_memory_write(addr, s->dma_buf, count);
|
||||
}
|
||||
s->current_dma_len -= count;
|
||||
if (s->current_dma_len == 0) {
|
||||
s->dma_buf = NULL;
|
||||
if (out) {
|
||||
/* Write the data. */
|
||||
scsi_write_data(s->current_dev, s->current_tag);
|
||||
} else {
|
||||
/* Request any remaining data. */
|
||||
scsi_read_data(s->current_dev, s->current_tag);
|
||||
}
|
||||
} else {
|
||||
s->dma_buf += count;
|
||||
lsi_resume_script(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add a command to the queue. */
|
||||
static void lsi_queue_command(LSIState *s)
|
||||
{
|
||||
lsi_queue *p;
|
||||
|
||||
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
|
||||
if (s->queue_len == s->active_commands) {
|
||||
s->queue_len++;
|
||||
s->queue = realloc(s->queue, s->queue_len * sizeof(lsi_queue));
|
||||
}
|
||||
p = &s->queue[s->active_commands++];
|
||||
p->tag = s->current_tag;
|
||||
p->pending = 0;
|
||||
p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||
}
|
||||
|
||||
/* Queue a byte for a MSG IN phase. */
|
||||
static void lsi_add_msg_byte(LSIState *s, uint8_t data)
|
||||
{
|
||||
if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
|
||||
BADF("MSG IN data too long\n");
|
||||
} else {
|
||||
DPRINTF("MSG IN 0x%02x\n", data);
|
||||
s->msg[s->msg_len++] = data;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform reselection to continue a command. */
|
||||
static void lsi_reselect(LSIState *s, uint32_t tag)
|
||||
{
|
||||
lsi_queue *p;
|
||||
int n;
|
||||
int id;
|
||||
|
||||
p = NULL;
|
||||
for (n = 0; n < s->active_commands; n++) {
|
||||
p = &s->queue[n];
|
||||
if (p->tag == tag)
|
||||
break;
|
||||
}
|
||||
if (n == s->active_commands) {
|
||||
BADF("Reselected non-existant command tag=0x%x\n", tag);
|
||||
return;
|
||||
}
|
||||
id = (tag >> 8) & 0xf;
|
||||
s->ssid = id | 0x80;
|
||||
DPRINTF("Reselected target %d\n", id);
|
||||
s->current_dev = s->scsi_dev[id];
|
||||
s->current_tag = tag;
|
||||
s->scntl1 |= LSI_SCNTL1_CON;
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
s->msg_action = p->out ? 2 : 3;
|
||||
s->current_dma_len = p->pending;
|
||||
s->dma_buf = NULL;
|
||||
lsi_add_msg_byte(s, 0x80);
|
||||
if (s->current_tag & LSI_TAG_VALID) {
|
||||
lsi_add_msg_byte(s, 0x20);
|
||||
lsi_add_msg_byte(s, tag & 0xff);
|
||||
}
|
||||
|
||||
s->active_commands--;
|
||||
if (n != s->active_commands) {
|
||||
s->queue[n] = s->queue[s->active_commands];
|
||||
}
|
||||
}
|
||||
|
||||
/* Record that data is available for a queued command. Returns zero if
|
||||
the device was reselected, nonzero if the IO is deferred. */
|
||||
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
|
||||
{
|
||||
lsi_queue *p;
|
||||
int i;
|
||||
for (i = 0; i < s->active_commands; i++) {
|
||||
p = &s->queue[i];
|
||||
if (p->tag == tag) {
|
||||
if (p->pending) {
|
||||
BADF("Multiple IO pending for tag %d\n", tag);
|
||||
}
|
||||
p->pending = arg;
|
||||
if (s->waiting == 1) {
|
||||
/* Reselect device. */
|
||||
lsi_reselect(s, tag);
|
||||
return 0;
|
||||
} else {
|
||||
DPRINTF("Queueing IO tag=0x%x\n", tag);
|
||||
p->pending = arg;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
BADF("IO with unknown tag %d\n", tag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Callback to indicate that the SCSI layer has completed a transfer. */
|
||||
static void lsi_command_complete(void *opaque, int reason, uint32_t tag,
|
||||
uint32_t arg)
|
||||
{
|
||||
LSIState *s = (LSIState *)opaque;
|
||||
int out;
|
||||
|
||||
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||
if (reason == SCSI_REASON_DONE) {
|
||||
DPRINTF("Command complete sense=%d\n", (int)arg);
|
||||
s->sense = arg;
|
||||
if (s->waiting && s->dbc != 0) {
|
||||
/* Raise phase mismatch for short transfers. */
|
||||
lsi_bad_phase(s, out, PHASE_ST);
|
||||
} else {
|
||||
lsi_set_phase(s, PHASE_ST);
|
||||
}
|
||||
lsi_resume_script(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->waiting == 1 || tag != s->current_tag) {
|
||||
if (lsi_queue_tag(s, tag, arg))
|
||||
return;
|
||||
}
|
||||
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
|
||||
s->current_dma_len = arg;
|
||||
if (!s->waiting)
|
||||
return;
|
||||
if (s->waiting == 1 || s->dbc == 0) {
|
||||
lsi_resume_script(s);
|
||||
} else {
|
||||
lsi_do_dma(s, out);
|
||||
}
|
||||
}
|
||||
|
||||
static void lsi_do_command(LSIState *s)
|
||||
{
|
||||
@@ -451,36 +632,37 @@ static void lsi_do_command(LSIState *s)
|
||||
s->dbc = 16;
|
||||
cpu_physical_memory_read(s->dnad, buf, s->dbc);
|
||||
s->sfbr = buf[0];
|
||||
n = scsi_send_command(s->current_dev, 0, buf, s->current_lun);
|
||||
n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun);
|
||||
if (n > 0) {
|
||||
s->data_len = n;
|
||||
lsi_set_phase(s, PHASE_DI);
|
||||
scsi_read_data(s->current_dev, s->current_tag);
|
||||
} else if (n < 0) {
|
||||
s->data_len = -n;
|
||||
lsi_set_phase(s, PHASE_DO);
|
||||
scsi_write_data(s->current_dev, s->current_tag);
|
||||
}
|
||||
if (n && s->current_dma_len == 0) {
|
||||
/* Command did not complete immediately so disconnect. */
|
||||
lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
|
||||
lsi_add_msg_byte(s, 4); /* DISCONNECT */
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
s->msg_action = 1;
|
||||
lsi_queue_command(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void lsi_command_complete(void *opaque, uint32_t tag, int sense)
|
||||
{
|
||||
LSIState *s = (LSIState *)opaque;
|
||||
|
||||
DPRINTF("Command complete sense=%d\n", sense);
|
||||
s->sense = sense;
|
||||
lsi_set_phase(s, PHASE_ST);
|
||||
}
|
||||
|
||||
static void lsi_do_status(LSIState *s)
|
||||
{
|
||||
uint8_t sense;
|
||||
DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense);
|
||||
if (s->dbc != 1)
|
||||
BADF("Bad Status move\n");
|
||||
s->dbc = 1;
|
||||
s->msg = s->sense;
|
||||
cpu_physical_memory_write(s->dnad, &s->msg, 1);
|
||||
s->sfbr = s->msg;
|
||||
sense = s->sense;
|
||||
s->sfbr = sense;
|
||||
cpu_physical_memory_write(s->dnad, &sense, 1);
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
s->msg = 0; /* COMMAND COMPLETE */
|
||||
s->msg_action = 1;
|
||||
lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
|
||||
}
|
||||
|
||||
static void lsi_disconnect(LSIState *s)
|
||||
@@ -491,55 +673,114 @@ static void lsi_disconnect(LSIState *s)
|
||||
|
||||
static void lsi_do_msgin(LSIState *s)
|
||||
{
|
||||
DPRINTF("Message in len=%d\n", s->dbc);
|
||||
s->dbc = 1;
|
||||
s->sfbr = s->msg;
|
||||
cpu_physical_memory_write(s->dnad, &s->msg, 1);
|
||||
if (s->msg == 0) {
|
||||
lsi_disconnect(s);
|
||||
int len;
|
||||
DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
|
||||
s->sfbr = s->msg[0];
|
||||
len = s->msg_len;
|
||||
if (len > s->dbc)
|
||||
len = s->dbc;
|
||||
cpu_physical_memory_write(s->dnad, s->msg, len);
|
||||
/* Linux drivers rely on the last byte being in the SIDL. */
|
||||
s->sidl = s->msg[len - 1];
|
||||
s->msg_len -= len;
|
||||
if (s->msg_len) {
|
||||
memmove(s->msg, s->msg + len, s->msg_len);
|
||||
} else {
|
||||
/* ??? Check if ATN (not yet implemented) is asserted and maybe
|
||||
switch to PHASE_MO. */
|
||||
lsi_set_phase(s, PHASE_CMD);
|
||||
switch (s->msg_action) {
|
||||
case 0:
|
||||
lsi_set_phase(s, PHASE_CMD);
|
||||
break;
|
||||
case 1:
|
||||
lsi_disconnect(s);
|
||||
break;
|
||||
case 2:
|
||||
lsi_set_phase(s, PHASE_DO);
|
||||
break;
|
||||
case 3:
|
||||
lsi_set_phase(s, PHASE_DI);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the next byte during a MSGOUT phase. */
|
||||
static uint8_t lsi_get_msgbyte(LSIState *s)
|
||||
{
|
||||
uint8_t data;
|
||||
cpu_physical_memory_read(s->dnad, &data, 1);
|
||||
s->dnad++;
|
||||
s->dbc--;
|
||||
return data;
|
||||
}
|
||||
|
||||
static void lsi_do_msgout(LSIState *s)
|
||||
{
|
||||
uint8_t msg;
|
||||
int len;
|
||||
|
||||
DPRINTF("MSG out len=%d\n", s->dbc);
|
||||
if (s->dbc != 1) {
|
||||
/* Multibyte messages not implemented. */
|
||||
s->msg = 7; /* MESSAGE REJECT */
|
||||
//s->dbc = 1;
|
||||
//lsi_bad_phase(s, 1, PHASE_MI);
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
return;
|
||||
}
|
||||
cpu_physical_memory_read(s->dnad, &msg, 1);
|
||||
s->sfbr = msg;
|
||||
s->dnad++;
|
||||
while (s->dbc) {
|
||||
msg = lsi_get_msgbyte(s);
|
||||
s->sfbr = msg;
|
||||
|
||||
switch (msg) {
|
||||
case 0x00:
|
||||
DPRINTF("Got Disconnect\n");
|
||||
lsi_disconnect(s);
|
||||
return;
|
||||
case 0x08:
|
||||
DPRINTF("Got No Operation\n");
|
||||
lsi_set_phase(s, PHASE_CMD);
|
||||
return;
|
||||
switch (msg) {
|
||||
case 0x00:
|
||||
DPRINTF("MSG: Disconnect\n");
|
||||
lsi_disconnect(s);
|
||||
break;
|
||||
case 0x08:
|
||||
DPRINTF("MSG: No Operation\n");
|
||||
lsi_set_phase(s, PHASE_CMD);
|
||||
break;
|
||||
case 0x01:
|
||||
len = lsi_get_msgbyte(s);
|
||||
msg = lsi_get_msgbyte(s);
|
||||
DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
|
||||
switch (msg) {
|
||||
case 1:
|
||||
DPRINTF("SDTR (ignored)\n");
|
||||
s->dbc -= 2;
|
||||
break;
|
||||
case 3:
|
||||
DPRINTF("WDTR (ignored)\n");
|
||||
s->dbc -= 1;
|
||||
break;
|
||||
default:
|
||||
goto bad;
|
||||
}
|
||||
break;
|
||||
case 0x20: /* SIMPLE queue */
|
||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
|
||||
break;
|
||||
case 0x21: /* HEAD of queue */
|
||||
BADF("HEAD queue not implemented\n");
|
||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
break;
|
||||
case 0x22: /* ORDERED queue */
|
||||
BADF("ORDERED queue not implemented\n");
|
||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
break;
|
||||
default:
|
||||
if ((msg & 0x80) == 0) {
|
||||
goto bad;
|
||||
}
|
||||
s->current_lun = msg & 7;
|
||||
DPRINTF("Select LUN %d\n", s->current_lun);
|
||||
lsi_set_phase(s, PHASE_CMD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((msg & 0x80) == 0) {
|
||||
DPRINTF("Unimplemented message 0x%d\n", msg);
|
||||
s->msg = 7; /* MESSAGE REJECT */
|
||||
lsi_bad_phase(s, 1, PHASE_MI);
|
||||
return;
|
||||
}
|
||||
s->current_lun = msg & 7;
|
||||
DPRINTF("Select LUN %d\n", s->current_lun);
|
||||
lsi_set_phase(s, PHASE_CMD);
|
||||
return;
|
||||
bad:
|
||||
BADF("Unimplemented message 0x%02x\n", msg);
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
|
||||
s->msg_action = 0;
|
||||
}
|
||||
|
||||
/* Sign extend a 24-bit value. */
|
||||
@@ -564,6 +805,23 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
|
||||
}
|
||||
}
|
||||
|
||||
static void lsi_wait_reselect(LSIState *s)
|
||||
{
|
||||
int i;
|
||||
DPRINTF("Wait Reselect\n");
|
||||
if (s->current_dma_len)
|
||||
BADF("Reselect with pending DMA\n");
|
||||
for (i = 0; i < s->active_commands; i++) {
|
||||
if (s->queue[i].pending) {
|
||||
lsi_reselect(s, s->queue[i].tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s->current_dma_len == 0) {
|
||||
s->waiting = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void lsi_execute_script(LSIState *s)
|
||||
{
|
||||
uint32_t insn;
|
||||
@@ -608,10 +866,16 @@ again:
|
||||
s->dnad = addr;
|
||||
switch (s->sstat1 & 0x7) {
|
||||
case PHASE_DO:
|
||||
s->waiting = 2;
|
||||
lsi_do_dma(s, 1);
|
||||
if (s->waiting)
|
||||
s->waiting = 3;
|
||||
break;
|
||||
case PHASE_DI:
|
||||
s->waiting = 2;
|
||||
lsi_do_dma(s, 0);
|
||||
if (s->waiting)
|
||||
s->waiting = 3;
|
||||
break;
|
||||
case PHASE_CMD:
|
||||
lsi_do_command(s);
|
||||
@@ -655,9 +919,13 @@ again:
|
||||
s->dnad = addr;
|
||||
switch (opcode) {
|
||||
case 0: /* Select */
|
||||
s->sdid = id;
|
||||
if (s->current_dma_len && (s->ssid & 0xf) == id) {
|
||||
DPRINTF("Already reselected by target %d\n", id);
|
||||
break;
|
||||
}
|
||||
s->sstat0 |= LSI_SSTAT0_WOA;
|
||||
s->scntl1 &= ~LSI_SCNTL1_IARB;
|
||||
s->sdid = id;
|
||||
if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) {
|
||||
DPRINTF("Selected absent target %d\n", id);
|
||||
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
|
||||
@@ -670,6 +938,7 @@ again:
|
||||
it only applies in low-level mode (unimplemented).
|
||||
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
|
||||
s->current_dev = s->scsi_dev[id];
|
||||
s->current_tag = id << 8;
|
||||
s->scntl1 |= LSI_SCNTL1_CON;
|
||||
if (insn & (1 << 3)) {
|
||||
s->socl |= LSI_SOCL_ATN;
|
||||
@@ -681,8 +950,7 @@ again:
|
||||
s->scntl1 &= ~LSI_SCNTL1_CON;
|
||||
break;
|
||||
case 2: /* Wait Reselect */
|
||||
DPRINTF("Wait Reselect\n");
|
||||
s->waiting = 1;
|
||||
lsi_wait_reselect(s);
|
||||
break;
|
||||
case 3: /* Set */
|
||||
DPRINTF("Set%s%s%s%s\n",
|
||||
@@ -731,9 +999,9 @@ again:
|
||||
data8 = (insn >> 8) & 0xff;
|
||||
opcode = (insn >> 27) & 7;
|
||||
operator = (insn >> 24) & 7;
|
||||
DPRINTF("%s reg 0x%x %s data8 %d%s\n",
|
||||
DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
|
||||
opcode_names[opcode - 5], reg,
|
||||
operator_names[operator], data8,
|
||||
operator_names[operator], data8, s->sfbr,
|
||||
(insn & (1 << 23)) ? " SFBR" : "");
|
||||
op0 = op1 = 0;
|
||||
switch (opcode) {
|
||||
@@ -899,8 +1167,9 @@ again:
|
||||
n = (insn & 7);
|
||||
reg = (insn >> 16) & 0xff;
|
||||
if (insn & (1 << 24)) {
|
||||
DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
|
||||
cpu_physical_memory_read(addr, data, n);
|
||||
DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
|
||||
addr, *(int *)data);
|
||||
for (i = 0; i < n; i++) {
|
||||
lsi_reg_writeb(s, reg + i, data[i]);
|
||||
}
|
||||
@@ -953,6 +1222,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset)
|
||||
return s->sdid;
|
||||
case 0x07: /* GPREG0 */
|
||||
return 0x7f;
|
||||
case 0xa: /* SSID */
|
||||
return s->ssid;
|
||||
case 0xb: /* SBCL */
|
||||
/* ??? This is not correct. However it's (hopefully) only
|
||||
used for diagnostics, so should be ok. */
|
||||
@@ -1041,13 +1312,22 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset)
|
||||
return s->stest2;
|
||||
case 0x4f: /* STEST3 */
|
||||
return s->stest3;
|
||||
case 0x50: /* SIDL */
|
||||
/* This is needed by the linux drivers. We currently only update it
|
||||
during the MSG IN phase. */
|
||||
return s->sidl;
|
||||
case 0x52: /* STEST4 */
|
||||
return 0xe0;
|
||||
case 0x56: /* CCNTL0 */
|
||||
return s->ccntl0;
|
||||
case 0x57: /* CCNTL1 */
|
||||
return s->ccntl1;
|
||||
case 0x58: case 0x59: /* SBDL */
|
||||
case 0x58: /* SBDL */
|
||||
/* Some drivers peek at the data bus during the MSG IN phase. */
|
||||
if ((s->sstat1 & PHASE_MASK) == PHASE_MI)
|
||||
return s->msg[0];
|
||||
return 0;
|
||||
case 0x59: /* SBDL high */
|
||||
return 0;
|
||||
CASE_GET_REG32(mmrs, 0xa0)
|
||||
CASE_GET_REG32(mmws, 0xa4)
|
||||
@@ -1119,8 +1399,18 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
|
||||
case 0x05: /* SXFER */
|
||||
s->sxfer = val;
|
||||
break;
|
||||
case 0x06: /* SDID */
|
||||
if ((val & 0xf) != (s->ssid & 0xf))
|
||||
BADF("Destination ID does not match SSID\n");
|
||||
s->sdid = val & 0xf;
|
||||
break;
|
||||
case 0x07: /* GPREG0 */
|
||||
break;
|
||||
case 0x08: /* SFBR */
|
||||
/* The CPU is not allowed to write to this register. However the
|
||||
SCRIPTS register move instructions are. */
|
||||
s->sfbr = val;
|
||||
break;
|
||||
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
||||
/* Linux writes to these readonly registers on startup. */
|
||||
return;
|
||||
@@ -1134,7 +1424,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
|
||||
s->istat0 &= ~LSI_ISTAT0_INTF;
|
||||
lsi_update_irq(s);
|
||||
}
|
||||
if (s->waiting && val & LSI_ISTAT0_SIGP) {
|
||||
if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
|
||||
DPRINTF("Woken by SIGP\n");
|
||||
s->waiting = 0;
|
||||
s->dsp = s->dnad;
|
||||
@@ -1531,7 +1821,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id)
|
||||
scsi_disk_destroy(s->scsi_dev[id]);
|
||||
}
|
||||
DPRINTF("Attaching block device %d\n", id);
|
||||
s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s);
|
||||
s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
|
||||
}
|
||||
|
||||
void *lsi_scsi_init(PCIBus *bus, int devfn)
|
||||
@@ -1563,6 +1853,9 @@ void *lsi_scsi_init(PCIBus *bus, int devfn)
|
||||
PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc);
|
||||
pci_register_io_region((struct PCIDevice *)s, 2, 0x2000,
|
||||
PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc);
|
||||
s->queue = qemu_malloc(sizeof(lsi_queue));
|
||||
s->queue_len = 1;
|
||||
s->active_commands = 0;
|
||||
|
||||
lsi_soft_reset(s);
|
||||
|
||||
|
||||
@@ -380,6 +380,29 @@ void rtc_set_date(RTCState *s, const struct tm *tm)
|
||||
rtc_copy_date(s);
|
||||
}
|
||||
|
||||
/* PC cmos mappings */
|
||||
#define REG_IBM_CENTURY_BYTE 0x32
|
||||
#define REG_IBM_PS2_CENTURY_BYTE 0x37
|
||||
|
||||
void rtc_set_date_from_host(RTCState *s)
|
||||
{
|
||||
time_t ti;
|
||||
struct tm *tm;
|
||||
int val;
|
||||
|
||||
/* set the CMOS date */
|
||||
time(&ti);
|
||||
if (rtc_utc)
|
||||
tm = gmtime(&ti);
|
||||
else
|
||||
tm = localtime(&ti);
|
||||
rtc_set_date(s, tm);
|
||||
|
||||
val = to_bcd(s, (tm->tm_year / 100) + 19);
|
||||
rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
|
||||
rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
|
||||
}
|
||||
|
||||
static void rtc_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
RTCState *s = opaque;
|
||||
@@ -444,6 +467,8 @@ RTCState *rtc_init(int base, int irq)
|
||||
s->cmos_data[RTC_REG_C] = 0x00;
|
||||
s->cmos_data[RTC_REG_D] = 0x80;
|
||||
|
||||
rtc_set_date_from_host(s);
|
||||
|
||||
s->periodic_timer = qemu_new_timer(vm_clock,
|
||||
rtc_periodic_timer, s);
|
||||
s->second_timer = qemu_new_timer(vm_clock,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "vl.h"
|
||||
#include "cpu.h"
|
||||
|
||||
/* Raise IRQ to CPU if necessary. It must be called every time the active
|
||||
IRQ may change */
|
||||
void cpu_mips_update_irq(CPUState *env)
|
||||
{
|
||||
if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
|
||||
(env->CP0_Status & (1 << CP0St_IE)) &&
|
||||
!(env->hflags & MIPS_HFLAG_EXL) &&
|
||||
!(env->hflags & MIPS_HFLAG_ERL) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) {
|
||||
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
} else {
|
||||
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_irq_request(void *opaque, int irq, int level)
|
||||
{
|
||||
CPUState *env = first_cpu;
|
||||
|
||||
uint32_t mask;
|
||||
|
||||
if (irq >= 16)
|
||||
return;
|
||||
|
||||
mask = 1 << (irq + CP0Ca_IP);
|
||||
|
||||
if (level) {
|
||||
env->CP0_Cause |= mask;
|
||||
} else {
|
||||
env->CP0_Cause &= ~mask;
|
||||
}
|
||||
cpu_mips_update_irq(env);
|
||||
}
|
||||
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
* QEMU Malta board support
|
||||
*
|
||||
* Copyright (c) 2006 Aurelien Jarno
|
||||
*
|
||||
* 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 "vl.h"
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define BIOS_FILENAME "mips_bios.bin"
|
||||
#else
|
||||
#define BIOS_FILENAME "mipsel_bios.bin"
|
||||
#endif
|
||||
|
||||
#ifdef MIPS_HAS_MIPS64
|
||||
#define INITRD_LOAD_ADDR (int64_t)0x80800000
|
||||
#else
|
||||
#define INITRD_LOAD_ADDR (int32_t)0x80800000
|
||||
#endif
|
||||
|
||||
#define ENVP_ADDR (int32_t)0x80002000
|
||||
#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
|
||||
|
||||
#define ENVP_NB_ENTRIES 16
|
||||
#define ENVP_ENTRY_SIZE 256
|
||||
|
||||
|
||||
extern FILE *logfile;
|
||||
|
||||
typedef struct {
|
||||
uint32_t leds;
|
||||
uint32_t brk;
|
||||
uint32_t gpout;
|
||||
uint32_t i2coe;
|
||||
uint32_t i2cout;
|
||||
uint32_t i2csel;
|
||||
CharDriverState *display;
|
||||
char display_text[9];
|
||||
} MaltaFPGAState;
|
||||
|
||||
static PITState *pit;
|
||||
|
||||
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
|
||||
static void pic_irq_request(void *opaque, int level)
|
||||
{
|
||||
cpu_mips_irq_request(opaque, 2, level);
|
||||
}
|
||||
|
||||
/* Malta FPGA */
|
||||
static void malta_fpga_update_display(void *opaque)
|
||||
{
|
||||
char leds_text[9];
|
||||
int i;
|
||||
MaltaFPGAState *s = opaque;
|
||||
|
||||
for (i = 7 ; i >= 0 ; i--) {
|
||||
if (s->leds & (1 << i))
|
||||
leds_text[i] = '#';
|
||||
else
|
||||
leds_text[i] = ' ';
|
||||
}
|
||||
leds_text[8] = '\0';
|
||||
|
||||
qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
|
||||
qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
|
||||
}
|
||||
|
||||
static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
MaltaFPGAState *s = opaque;
|
||||
uint32_t val = 0;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & 0xfffff);
|
||||
|
||||
switch (saddr) {
|
||||
|
||||
/* SWITCH Register */
|
||||
case 0x00200:
|
||||
val = 0x00000000; /* All switches closed */
|
||||
break;
|
||||
|
||||
/* STATUS Register */
|
||||
case 0x00208:
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = 0x00000012;
|
||||
#else
|
||||
val = 0x00000010;
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* JMPRS Register */
|
||||
case 0x00210:
|
||||
val = 0x00;
|
||||
break;
|
||||
|
||||
/* LEDBAR Register */
|
||||
case 0x00408:
|
||||
val = s->leds;
|
||||
break;
|
||||
|
||||
/* BRKRES Register */
|
||||
case 0x00508:
|
||||
val = s->brk;
|
||||
break;
|
||||
|
||||
/* GPOUT Register */
|
||||
case 0x00a00:
|
||||
val = s->gpout;
|
||||
break;
|
||||
|
||||
/* XXX: implement a real I2C controller */
|
||||
|
||||
/* GPINP Register */
|
||||
case 0x00a08:
|
||||
/* IN = OUT until a real I2C control is implemented */
|
||||
if (s->i2csel)
|
||||
val = s->i2cout;
|
||||
else
|
||||
val = 0x00;
|
||||
break;
|
||||
|
||||
/* I2CINP Register */
|
||||
case 0x00b00:
|
||||
val = 0x00000003;
|
||||
break;
|
||||
|
||||
/* I2COE Register */
|
||||
case 0x00b08:
|
||||
val = s->i2coe;
|
||||
break;
|
||||
|
||||
/* I2COUT Register */
|
||||
case 0x00b10:
|
||||
val = s->i2cout;
|
||||
break;
|
||||
|
||||
/* I2CSEL Register */
|
||||
case 0x00b18:
|
||||
val = s->i2cout;
|
||||
break;
|
||||
|
||||
default:
|
||||
#if 0
|
||||
printf ("malta_fpga_read: Bad register offset 0x" TLSZ "\n",
|
||||
addr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
MaltaFPGAState *s = opaque;
|
||||
uint32_t saddr;
|
||||
|
||||
saddr = (addr & 0xfffff);
|
||||
|
||||
switch (saddr) {
|
||||
|
||||
/* SWITCH Register */
|
||||
case 0x00200:
|
||||
break;
|
||||
|
||||
/* JMPRS Register */
|
||||
case 0x00210:
|
||||
break;
|
||||
|
||||
/* LEDBAR Register */
|
||||
/* XXX: implement a 8-LED array */
|
||||
case 0x00408:
|
||||
s->leds = val & 0xff;
|
||||
break;
|
||||
|
||||
/* ASCIIWORD Register */
|
||||
case 0x00410:
|
||||
snprintf(s->display_text, 9, "%08X", val);
|
||||
malta_fpga_update_display(s);
|
||||
break;
|
||||
|
||||
/* ASCIIPOS0 to ASCIIPOS7 Registers */
|
||||
case 0x00418:
|
||||
case 0x00420:
|
||||
case 0x00428:
|
||||
case 0x00430:
|
||||
case 0x00438:
|
||||
case 0x00440:
|
||||
case 0x00448:
|
||||
case 0x00450:
|
||||
s->display_text[(saddr - 0x00418) >> 3] = (char) val;
|
||||
malta_fpga_update_display(s);
|
||||
break;
|
||||
|
||||
/* SOFTRES Register */
|
||||
case 0x00500:
|
||||
if (val == 0x42)
|
||||
qemu_system_reset_request ();
|
||||
break;
|
||||
|
||||
/* BRKRES Register */
|
||||
case 0x00508:
|
||||
s->brk = val & 0xff;
|
||||
break;
|
||||
|
||||
/* GPOUT Register */
|
||||
case 0x00a00:
|
||||
s->gpout = val & 0xff;
|
||||
break;
|
||||
|
||||
/* I2COE Register */
|
||||
case 0x00b08:
|
||||
s->i2coe = val & 0x03;
|
||||
break;
|
||||
|
||||
/* I2COUT Register */
|
||||
case 0x00b10:
|
||||
s->i2cout = val & 0x03;
|
||||
break;
|
||||
|
||||
/* I2CSEL Register */
|
||||
case 0x00b18:
|
||||
s->i2cout = val & 0x01;
|
||||
break;
|
||||
|
||||
default:
|
||||
#if 0
|
||||
printf ("malta_fpga_write: Bad register offset 0x" TLSZ "\n",
|
||||
addr);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *malta_fpga_read[] = {
|
||||
malta_fpga_readl,
|
||||
malta_fpga_readl,
|
||||
malta_fpga_readl
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *malta_fpga_write[] = {
|
||||
malta_fpga_writel,
|
||||
malta_fpga_writel,
|
||||
malta_fpga_writel
|
||||
};
|
||||
|
||||
void malta_fpga_reset(void *opaque)
|
||||
{
|
||||
MaltaFPGAState *s = opaque;
|
||||
|
||||
s->leds = 0x00;
|
||||
s->brk = 0x0a;
|
||||
s->gpout = 0x00;
|
||||
s->i2coe = 0x0;
|
||||
s->i2cout = 0x3;
|
||||
s->i2csel = 0x1;
|
||||
|
||||
s->display_text[8] = '\0';
|
||||
snprintf(s->display_text, 9, " ");
|
||||
malta_fpga_update_display(s);
|
||||
}
|
||||
|
||||
MaltaFPGAState *malta_fpga_init(target_phys_addr_t base)
|
||||
{
|
||||
MaltaFPGAState *s;
|
||||
int malta;
|
||||
|
||||
s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
|
||||
|
||||
malta = cpu_register_io_memory(0, malta_fpga_read,
|
||||
malta_fpga_write, s);
|
||||
cpu_register_physical_memory(base, 0x100000, malta);
|
||||
|
||||
s->display = qemu_chr_open("vc");
|
||||
qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
|
||||
qemu_chr_printf(s->display, "+--------+\r\n");
|
||||
qemu_chr_printf(s->display, "+ +\r\n");
|
||||
qemu_chr_printf(s->display, "+--------+\r\n");
|
||||
qemu_chr_printf(s->display, "\n");
|
||||
qemu_chr_printf(s->display, "Malta ASCII\r\n");
|
||||
qemu_chr_printf(s->display, "+--------+\r\n");
|
||||
qemu_chr_printf(s->display, "+ +\r\n");
|
||||
qemu_chr_printf(s->display, "+--------+\r\n");
|
||||
|
||||
malta_fpga_reset(s);
|
||||
qemu_register_reset(malta_fpga_reset, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Audio support */
|
||||
#ifdef HAS_AUDIO
|
||||
static void audio_init (PCIBus *pci_bus)
|
||||
{
|
||||
struct soundhw *c;
|
||||
int audio_enabled = 0;
|
||||
|
||||
for (c = soundhw; !audio_enabled && c->name; ++c) {
|
||||
audio_enabled = c->enabled;
|
||||
}
|
||||
|
||||
if (audio_enabled) {
|
||||
AudioState *s;
|
||||
|
||||
s = AUD_init ();
|
||||
if (s) {
|
||||
for (c = soundhw; c->name; ++c) {
|
||||
if (c->enabled) {
|
||||
if (c->isa) {
|
||||
fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
if (pci_bus) {
|
||||
c->init.init_pci (pci_bus, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Network support */
|
||||
static void network_init (PCIBus *pci_bus)
|
||||
{
|
||||
int i;
|
||||
NICInfo *nd;
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
nd = &nd_table[i];
|
||||
if (!nd->model) {
|
||||
nd->model = "pcnet";
|
||||
}
|
||||
if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
|
||||
/* The malta board has a PCNet card using PCI SLOT 11 */
|
||||
pci_nic_init(pci_bus, nd, 88);
|
||||
} else {
|
||||
pci_nic_init(pci_bus, nd, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ROM and pseudo bootloader
|
||||
|
||||
The following code implements a very very simple bootloader. It first
|
||||
loads the registers a0 to a3 to the values expected by the OS, and
|
||||
then jump at the kernel address.
|
||||
|
||||
The bootloader should pass the locations of the kernel arguments and
|
||||
environment variables tables. Those tables contain the 32-bit address
|
||||
of NULL terminated strings. The environment variables table should be
|
||||
terminated by a NULL address.
|
||||
|
||||
For a simpler implementation, the number of kernel arguments is fixed
|
||||
to two (the name of the kernel and the command line), and the two
|
||||
tables are actually the same one.
|
||||
|
||||
The registers a0 to a3 should contain the following values:
|
||||
a0 - number of kernel arguments
|
||||
a1 - 32-bit address of the kernel arguments table
|
||||
a2 - 32-bit address of the environment variables table
|
||||
a3 - RAM size in bytes
|
||||
*/
|
||||
|
||||
static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
||||
/* Small bootloader */
|
||||
p = (uint32_t *) (phys_ram_base + bios_offset);
|
||||
stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */
|
||||
stl_raw(p++, 0x00000000); /* nop */
|
||||
|
||||
/* Second part of the bootloader */
|
||||
p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
|
||||
stl_raw(p++, 0x3c040000); /* lui a0, 0 */
|
||||
stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */
|
||||
stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
|
||||
stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */
|
||||
stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
|
||||
stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
|
||||
stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */
|
||||
stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
|
||||
stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */;
|
||||
stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */
|
||||
stl_raw(p++, 0x03e00008); /* jr ra */
|
||||
stl_raw(p++, 0x00000000); /* nop */
|
||||
}
|
||||
|
||||
static void prom_set(int index, const char *string, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int32_t *p;
|
||||
int32_t table_addr;
|
||||
char *s;
|
||||
|
||||
if (index >= ENVP_NB_ENTRIES)
|
||||
return;
|
||||
|
||||
p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
|
||||
p += index;
|
||||
|
||||
if (string == NULL) {
|
||||
stl_raw(p, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
|
||||
s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
|
||||
|
||||
stl_raw(p, table_addr);
|
||||
|
||||
va_start(ap, string);
|
||||
vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Kernel */
|
||||
static int64_t load_kernel (CPUState *env)
|
||||
{
|
||||
int64_t kernel_addr = 0;
|
||||
int index = 0;
|
||||
long initrd_size;
|
||||
|
||||
if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
env->kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
initrd_size = 0;
|
||||
if (env->initrd_filename) {
|
||||
initrd_size = load_image(env->initrd_filename,
|
||||
phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
|
||||
if (initrd_size == (target_ulong) -1) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
env->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store command line. */
|
||||
prom_set(index++, env->kernel_filename);
|
||||
if (initrd_size > 0)
|
||||
prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline);
|
||||
else
|
||||
prom_set(index++, env->kernel_cmdline);
|
||||
|
||||
/* Setup minimum environment variables */
|
||||
prom_set(index++, "memsize");
|
||||
prom_set(index++, "%i", env->ram_size);
|
||||
prom_set(index++, "modetty0");
|
||||
prom_set(index++, "38400n8r");
|
||||
prom_set(index++, NULL);
|
||||
|
||||
return kernel_addr;
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
CPUState *env = opaque;
|
||||
cpu_reset(env);
|
||||
|
||||
/* The bootload does not need to be rewritten as it is located in a
|
||||
read only location. The kernel location and the arguments table
|
||||
location does not change. */
|
||||
if (env->kernel_filename)
|
||||
load_kernel (env);
|
||||
}
|
||||
|
||||
void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
unsigned long bios_offset;
|
||||
int64_t kernel_addr;
|
||||
PCIBus *pci_bus;
|
||||
CPUState *env;
|
||||
RTCState *rtc_state;
|
||||
/* fdctrl_t *floppy_controller; */
|
||||
MaltaFPGAState *malta_fpga;
|
||||
int ret;
|
||||
|
||||
env = cpu_init();
|
||||
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
|
||||
qemu_register_reset(main_cpu_reset, env);
|
||||
|
||||
/* allocate RAM */
|
||||
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
|
||||
|
||||
/* Map the bios at two physical locations, as on the real board */
|
||||
bios_offset = ram_size + vga_ram_size;
|
||||
cpu_register_physical_memory(0x1e000000LL,
|
||||
BIOS_SIZE, bios_offset | IO_MEM_ROM);
|
||||
cpu_register_physical_memory(0x1fc00000LL,
|
||||
BIOS_SIZE, bios_offset | IO_MEM_ROM);
|
||||
|
||||
/* Load a BIOS image except if a kernel image has been specified. In
|
||||
the later case, just write a small bootloader to the flash
|
||||
location. */
|
||||
if (kernel_filename) {
|
||||
env->ram_size = ram_size;
|
||||
env->kernel_filename = kernel_filename;
|
||||
env->kernel_cmdline = kernel_cmdline;
|
||||
env->initrd_filename = initrd_filename;
|
||||
kernel_addr = load_kernel(env);
|
||||
write_bootloader(env, bios_offset, kernel_addr);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
|
||||
ret = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (ret != BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
|
||||
buf);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Board ID = 0x420 (Malta Board with CoreLV)
|
||||
XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
|
||||
map to the board ID. */
|
||||
stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
|
||||
|
||||
/* Init internal devices */
|
||||
cpu_mips_clock_init(env);
|
||||
cpu_mips_irqctrl_init();
|
||||
|
||||
/* FPGA */
|
||||
malta_fpga = malta_fpga_init(0x1f000000LL);
|
||||
|
||||
/* Interrupt controller */
|
||||
isa_pic = pic_init(pic_irq_request, env);
|
||||
|
||||
/* Northbridge */
|
||||
pci_bus = pci_gt64120_init(isa_pic);
|
||||
|
||||
/* Southbridge */
|
||||
piix4_init(pci_bus, 80);
|
||||
pci_piix3_ide_init(pci_bus, bs_table, 81);
|
||||
usb_uhci_init(pci_bus, 82);
|
||||
piix4_pm_init(pci_bus, 83);
|
||||
pit = pit_init(0x40, 0);
|
||||
DMA_init(0);
|
||||
|
||||
/* Super I/O */
|
||||
kbd_init();
|
||||
rtc_state = rtc_init(0x70, 8);
|
||||
serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
|
||||
parallel_init(0x378, 7, parallel_hds[0]);
|
||||
/* XXX: The floppy controller does not work correctly, something is
|
||||
probably wrong.
|
||||
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
|
||||
|
||||
/* Sound card */
|
||||
#ifdef HAS_AUDIO
|
||||
audio_init(pci_bus);
|
||||
#endif
|
||||
|
||||
/* Network card */
|
||||
network_init(pci_bus);
|
||||
}
|
||||
|
||||
QEMUMachine mips_malta_machine = {
|
||||
"malta",
|
||||
"MIPS Malta Core LV",
|
||||
mips_malta_init,
|
||||
};
|
||||
+144
-214
@@ -1,222 +1,165 @@
|
||||
/*
|
||||
* QEMU/MIPS pseudo-board
|
||||
*
|
||||
* emulates a simple machine with ISA-like bus.
|
||||
* ISA IO space mapped to the 0x14000000 (PHYS) and
|
||||
* ISA memory at the 0x10000000 (PHYS, 16Mb in size).
|
||||
* All peripherial devices are attached to this "bus" with
|
||||
* the standard PC ISA addresses.
|
||||
*/
|
||||
#include "vl.h"
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define BIOS_FILENAME "mips_bios.bin"
|
||||
//#define BIOS_FILENAME "system.bin"
|
||||
#define KERNEL_LOAD_ADDR 0x80010000
|
||||
#define INITRD_LOAD_ADDR 0x80800000
|
||||
#else
|
||||
#define BIOS_FILENAME "mipsel_bios.bin"
|
||||
#endif
|
||||
|
||||
#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)
|
||||
#ifdef MIPS_HAS_MIPS64
|
||||
#define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000
|
||||
#else
|
||||
#define INITRD_LOAD_ADDR (int32_t)0x80800000
|
||||
#endif
|
||||
|
||||
#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
|
||||
|
||||
static const int ide_iobase[2] = { 0x1f0, 0x170 };
|
||||
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
|
||||
static const int ide_irq[2] = { 14, 15 };
|
||||
|
||||
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
|
||||
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
|
||||
|
||||
extern FILE *logfile;
|
||||
|
||||
static PITState *pit;
|
||||
static PITState *pit; /* PIT i8254 */
|
||||
|
||||
/*i8254 PIT is attached to the IRQ0 at PIC i8259 */
|
||||
/*The PIC is attached to the MIPS CPU INT0 pin */
|
||||
static void pic_irq_request(void *opaque, int level)
|
||||
{
|
||||
CPUState *env = first_cpu;
|
||||
if (level) {
|
||||
env->CP0_Cause |= 0x00000400;
|
||||
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
cpu_mips_irq_request(opaque, 2, level);
|
||||
}
|
||||
|
||||
static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
if ((addr & 0xffff) == 0 && val == 42)
|
||||
qemu_system_reset_request ();
|
||||
else if ((addr & 0xffff) == 4 && val == 42)
|
||||
qemu_system_shutdown_request ();
|
||||
}
|
||||
|
||||
static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *mips_qemu_write[] = {
|
||||
&mips_qemu_writel,
|
||||
&mips_qemu_writel,
|
||||
&mips_qemu_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *mips_qemu_read[] = {
|
||||
&mips_qemu_readl,
|
||||
&mips_qemu_readl,
|
||||
&mips_qemu_readl,
|
||||
};
|
||||
|
||||
static int mips_qemu_iomemtype = 0;
|
||||
|
||||
void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
int64_t entry = 0;
|
||||
long kernel_size, initrd_size;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
|
||||
if (kernel_size >= 0) {
|
||||
if ((entry & ~0x7fffffffULL) == 0x80000000)
|
||||
entry = (int32_t)entry;
|
||||
env->PC = entry;
|
||||
} else {
|
||||
env->CP0_Cause &= ~0x00000400;
|
||||
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_irqctrl_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* XXX: do not use a global */
|
||||
uint32_t cpu_mips_get_random (CPUState *env)
|
||||
{
|
||||
static uint32_t seed = 0;
|
||||
uint32_t idx;
|
||||
seed = seed * 314159 + 1;
|
||||
idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* MIPS R4K timer */
|
||||
uint32_t cpu_mips_get_count (CPUState *env)
|
||||
{
|
||||
return env->CP0_Count +
|
||||
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
|
||||
100 * 1000 * 1000, ticks_per_sec);
|
||||
}
|
||||
|
||||
static void cpu_mips_update_count (CPUState *env, uint32_t count,
|
||||
uint32_t compare)
|
||||
{
|
||||
uint64_t now, next;
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = count;
|
||||
if (count == compare)
|
||||
tmp++;
|
||||
now = qemu_get_clock(vm_clock);
|
||||
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
|
||||
if (next == now)
|
||||
next++;
|
||||
#if 0
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
|
||||
__func__, now, count, compare, next - now);
|
||||
/* load initrd */
|
||||
initrd_size = 0;
|
||||
if (initrd_filename) {
|
||||
initrd_size = load_image(initrd_filename,
|
||||
phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
|
||||
if (initrd_size == (target_ulong) -1) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Store new count and compare registers */
|
||||
env->CP0_Compare = compare;
|
||||
env->CP0_Count =
|
||||
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
|
||||
/* Adjust timer */
|
||||
qemu_mod_timer(env->timer, next);
|
||||
}
|
||||
|
||||
void cpu_mips_store_count (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_mips_update_count(env, value, env->CP0_Compare);
|
||||
}
|
||||
|
||||
void cpu_mips_store_compare (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
|
||||
env->CP0_Cause &= ~0x00008000;
|
||||
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
|
||||
static void mips_timer_cb (void *opaque)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
env = opaque;
|
||||
#if 0
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s\n", __func__);
|
||||
/* Store command line. */
|
||||
if (initrd_size > 0) {
|
||||
int ret;
|
||||
ret = sprintf(phys_ram_base + (16 << 20) - 256,
|
||||
"rd_start=0x" TLSZ " rd_size=%li ",
|
||||
INITRD_LOAD_ADDR,
|
||||
initrd_size);
|
||||
strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
|
||||
}
|
||||
#endif
|
||||
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
|
||||
env->CP0_Cause |= 0x00008000;
|
||||
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
else {
|
||||
strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
|
||||
}
|
||||
|
||||
*(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
|
||||
*(int32_t *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
|
||||
}
|
||||
|
||||
void cpu_mips_clock_init (CPUState *env)
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
|
||||
env->CP0_Compare = 0;
|
||||
cpu_mips_update_count(env, 1, 0);
|
||||
CPUState *env = opaque;
|
||||
cpu_reset(env);
|
||||
|
||||
if (env->kernel_filename)
|
||||
load_kernel (env, env->ram_size, env->kernel_filename,
|
||||
env->kernel_cmdline, env->initrd_filename);
|
||||
}
|
||||
|
||||
|
||||
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
#if 0
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
|
||||
#endif
|
||||
cpu_outb(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
|
||||
#if 0
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
#if 0
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
|
||||
#endif
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
value = bswap16(value);
|
||||
#endif
|
||||
cpu_outw(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
ret = bswap16(ret);
|
||||
#endif
|
||||
#if 0
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
#if 0
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
|
||||
#endif
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
value = bswap32(value);
|
||||
#endif
|
||||
cpu_outl(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
ret = bswap32(ret);
|
||||
#endif
|
||||
#if 0
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
CPUWriteMemoryFunc *io_write[] = {
|
||||
&io_writeb,
|
||||
&io_writew,
|
||||
&io_writel,
|
||||
};
|
||||
|
||||
CPUReadMemoryFunc *io_read[] = {
|
||||
&io_readb,
|
||||
&io_readw,
|
||||
&io_readl,
|
||||
};
|
||||
|
||||
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
int64_t entry = 0;
|
||||
unsigned long bios_offset;
|
||||
int io_memory;
|
||||
int ret;
|
||||
int bios_size;
|
||||
CPUState *env;
|
||||
long kernel_size;
|
||||
static RTCState *rtc_state;
|
||||
int i;
|
||||
|
||||
env = cpu_init();
|
||||
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
|
||||
qemu_register_reset(main_cpu_reset, env);
|
||||
|
||||
/* allocate RAM */
|
||||
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
|
||||
|
||||
if (!mips_qemu_iomemtype) {
|
||||
mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
|
||||
mips_qemu_write, NULL);
|
||||
}
|
||||
cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
|
||||
|
||||
/* Try to load a BIOS image. If this fails, we continue regardless,
|
||||
but initialize the hardware ourselves. When a kernel gets
|
||||
preloaded we also initialize the hardware, since the BIOS wasn't
|
||||
run. */
|
||||
bios_offset = ram_size + vga_ram_size;
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
|
||||
ret = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (ret == BIOS_SIZE) {
|
||||
cpu_register_physical_memory((uint32_t)(0x1fc00000),
|
||||
bios_size = load_image(buf, phys_ram_base + bios_offset);
|
||||
if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
|
||||
cpu_register_physical_memory(0x1fc00000,
|
||||
BIOS_SIZE, bios_offset | IO_MEM_ROM);
|
||||
} else {
|
||||
/* not fatal */
|
||||
@@ -224,54 +167,37 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
|
||||
buf);
|
||||
}
|
||||
|
||||
kernel_size = 0;
|
||||
if (kernel_filename) {
|
||||
kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
|
||||
if (kernel_size >= 0)
|
||||
env->PC = entry;
|
||||
else {
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
env->PC = KERNEL_LOAD_ADDR;
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
if (load_image(initrd_filename,
|
||||
phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND)
|
||||
== (target_ulong) -1) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store command line. */
|
||||
strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
|
||||
/* FIXME: little endian support */
|
||||
*(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
|
||||
*(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
|
||||
load_kernel (env, ram_size, kernel_filename, kernel_cmdline,
|
||||
initrd_filename);
|
||||
env->ram_size = ram_size;
|
||||
env->kernel_filename = kernel_filename;
|
||||
env->kernel_cmdline = kernel_cmdline;
|
||||
env->initrd_filename = initrd_filename;
|
||||
}
|
||||
|
||||
/* Init internal devices */
|
||||
/* Init CPU internal devices */
|
||||
cpu_mips_clock_init(env);
|
||||
cpu_mips_irqctrl_init();
|
||||
|
||||
rtc_state = rtc_init(0x70, 8);
|
||||
|
||||
/* Register 64 KB of ISA IO space at 0x14000000 */
|
||||
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
|
||||
cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
|
||||
isa_mmio_init(0x14000000, 0x00010000);
|
||||
isa_mem_base = 0x10000000;
|
||||
|
||||
isa_pic = pic_init(pic_irq_request, env);
|
||||
pit = pit_init(0x40, 0);
|
||||
serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
|
||||
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
|
||||
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
serial_init(&pic_set_irq_new, isa_pic,
|
||||
serial_io[i], serial_irq[i], serial_hds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
isa_vga_init(ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size);
|
||||
|
||||
if (nd_table[0].vlan) {
|
||||
if (nd_table[0].model == NULL
|
||||
@@ -282,6 +208,10 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < 2; i++)
|
||||
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
|
||||
bs_table[2 * i], bs_table[2 * i + 1]);
|
||||
}
|
||||
|
||||
QEMUMachine mips_machine = {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "vl.h"
|
||||
|
||||
void cpu_mips_irqctrl_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* XXX: do not use a global */
|
||||
uint32_t cpu_mips_get_random (CPUState *env)
|
||||
{
|
||||
static uint32_t seed = 0;
|
||||
uint32_t idx;
|
||||
seed = seed * 314159 + 1;
|
||||
idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* MIPS R4K timer */
|
||||
uint32_t cpu_mips_get_count (CPUState *env)
|
||||
{
|
||||
return env->CP0_Count +
|
||||
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
|
||||
100 * 1000 * 1000, ticks_per_sec);
|
||||
}
|
||||
|
||||
static void cpu_mips_update_count (CPUState *env, uint32_t count,
|
||||
uint32_t compare)
|
||||
{
|
||||
uint64_t now, next;
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = count;
|
||||
if (count == compare)
|
||||
tmp++;
|
||||
now = qemu_get_clock(vm_clock);
|
||||
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
|
||||
if (next == now)
|
||||
next++;
|
||||
#if 0
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
|
||||
__func__, now, count, compare, next - now);
|
||||
}
|
||||
#endif
|
||||
/* Store new count and compare registers */
|
||||
env->CP0_Compare = compare;
|
||||
env->CP0_Count =
|
||||
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
|
||||
/* Adjust timer */
|
||||
qemu_mod_timer(env->timer, next);
|
||||
}
|
||||
|
||||
void cpu_mips_store_count (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_mips_update_count(env, value, env->CP0_Compare);
|
||||
}
|
||||
|
||||
void cpu_mips_store_compare (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
|
||||
cpu_mips_irq_request(env, 7, 0);
|
||||
}
|
||||
|
||||
static void mips_timer_cb (void *opaque)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
env = opaque;
|
||||
#if 0
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s\n", __func__);
|
||||
}
|
||||
#endif
|
||||
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
|
||||
cpu_mips_irq_request(env, 7, 1);
|
||||
}
|
||||
|
||||
void cpu_mips_clock_init (CPUState *env)
|
||||
{
|
||||
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
|
||||
env->CP0_Compare = 0;
|
||||
cpu_mips_update_count(env, 1, 0);
|
||||
}
|
||||
|
||||
+20
-11
@@ -312,7 +312,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
|
||||
}
|
||||
s->curpag = next >> 8;
|
||||
|
||||
/* now we can signal we have receive something */
|
||||
/* now we can signal we have received something */
|
||||
s->isr |= ENISR_RX;
|
||||
ne2000_update_irq(s);
|
||||
}
|
||||
@@ -648,6 +648,9 @@ static void ne2000_save(QEMUFile* f,void* opaque)
|
||||
{
|
||||
NE2000State* s=(NE2000State*)opaque;
|
||||
|
||||
if (s->pci_dev)
|
||||
pci_device_save(s->pci_dev, f);
|
||||
|
||||
qemu_put_8s(f, &s->rxcr);
|
||||
|
||||
qemu_put_8s(f, &s->cmd);
|
||||
@@ -673,13 +676,21 @@ static void ne2000_save(QEMUFile* f,void* opaque)
|
||||
static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
|
||||
{
|
||||
NE2000State* s=(NE2000State*)opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id == 2) {
|
||||
qemu_get_8s(f, &s->rxcr);
|
||||
} else if (version_id == 1) {
|
||||
s->rxcr = 0x0c;
|
||||
} else {
|
||||
if (version_id > 3)
|
||||
return -EINVAL;
|
||||
|
||||
if (s->pci_dev && version_id >= 3) {
|
||||
ret = pci_device_load(s->pci_dev, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (version_id >= 2) {
|
||||
qemu_get_8s(f, &s->rxcr);
|
||||
} else {
|
||||
s->rxcr = 0x0c;
|
||||
}
|
||||
|
||||
qemu_get_8s(f, &s->cmd);
|
||||
@@ -770,7 +781,7 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num,
|
||||
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
|
||||
}
|
||||
|
||||
void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
|
||||
void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn)
|
||||
{
|
||||
PCINE2000State *d;
|
||||
NE2000State *s;
|
||||
@@ -778,7 +789,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
|
||||
|
||||
d = (PCINE2000State *)pci_register_device(bus,
|
||||
"NE2000", sizeof(PCINE2000State),
|
||||
-1,
|
||||
devfn,
|
||||
NULL, NULL);
|
||||
pci_conf = d->dev.config;
|
||||
pci_conf[0x00] = 0xec; // Realtek 8029
|
||||
@@ -810,7 +821,5 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
|
||||
s->macaddr[5]);
|
||||
|
||||
/* XXX: instance number ? */
|
||||
register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
|
||||
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
|
||||
&d->dev);
|
||||
register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s);
|
||||
}
|
||||
@@ -40,6 +40,7 @@ static fdctrl_t *floppy_controller;
|
||||
static RTCState *rtc_state;
|
||||
static PITState *pit;
|
||||
static IOAPICState *ioapic;
|
||||
static PCIDevice *i440fx_state;
|
||||
|
||||
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
|
||||
{
|
||||
@@ -73,6 +74,14 @@ uint64_t cpu_get_tsc(CPUX86State *env)
|
||||
}
|
||||
}
|
||||
|
||||
/* SMM support */
|
||||
void cpu_smm_update(CPUState *env)
|
||||
{
|
||||
if (i440fx_state && env == first_cpu)
|
||||
i440fx_set_smm(i440fx_state, (env->hflags >> HF_SMM_SHIFT) & 1);
|
||||
}
|
||||
|
||||
|
||||
/* IRQ handling */
|
||||
int cpu_get_pic_interrupt(CPUState *env)
|
||||
{
|
||||
@@ -102,14 +111,6 @@ static void pic_irq_request(void *opaque, int level)
|
||||
/* PC cmos mappings */
|
||||
|
||||
#define REG_EQUIPMENT_BYTE 0x14
|
||||
#define REG_IBM_CENTURY_BYTE 0x32
|
||||
#define REG_IBM_PS2_CENTURY_BYTE 0x37
|
||||
|
||||
|
||||
static inline int to_bcd(RTCState *s, int a)
|
||||
{
|
||||
return ((a / 10) << 4) | (a % 10);
|
||||
}
|
||||
|
||||
static int cmos_get_fd_drive_type(int fd0)
|
||||
{
|
||||
@@ -158,22 +159,8 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
|
||||
RTCState *s = rtc_state;
|
||||
int val;
|
||||
int fd0, fd1, nb;
|
||||
time_t ti;
|
||||
struct tm *tm;
|
||||
int i;
|
||||
|
||||
/* set the CMOS date */
|
||||
time(&ti);
|
||||
if (rtc_utc)
|
||||
tm = gmtime(&ti);
|
||||
else
|
||||
tm = localtime(&ti);
|
||||
rtc_set_date(s, tm);
|
||||
|
||||
val = to_bcd(s, (tm->tm_year / 100) + 19);
|
||||
rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
|
||||
rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
|
||||
|
||||
/* various important CMOS locations needed by PC/Bochs bios */
|
||||
|
||||
/* memory size */
|
||||
@@ -398,156 +385,6 @@ static void main_cpu_reset(void *opaque)
|
||||
cpu_reset(env);
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
|
||||
static void putb(uint8_t **pp, int val)
|
||||
{
|
||||
uint8_t *q;
|
||||
q = *pp;
|
||||
*q++ = val;
|
||||
*pp = q;
|
||||
}
|
||||
|
||||
static void putstr(uint8_t **pp, const char *str)
|
||||
{
|
||||
uint8_t *q;
|
||||
q = *pp;
|
||||
while (*str)
|
||||
*q++ = *str++;
|
||||
*pp = q;
|
||||
}
|
||||
|
||||
static void putle16(uint8_t **pp, int val)
|
||||
{
|
||||
uint8_t *q;
|
||||
q = *pp;
|
||||
*q++ = val;
|
||||
*q++ = val >> 8;
|
||||
*pp = q;
|
||||
}
|
||||
|
||||
static void putle32(uint8_t **pp, int val)
|
||||
{
|
||||
uint8_t *q;
|
||||
q = *pp;
|
||||
*q++ = val;
|
||||
*q++ = val >> 8;
|
||||
*q++ = val >> 16;
|
||||
*q++ = val >> 24;
|
||||
*pp = q;
|
||||
}
|
||||
|
||||
static int mpf_checksum(const uint8_t *data, int len)
|
||||
{
|
||||
int sum, i;
|
||||
sum = 0;
|
||||
for(i = 0; i < len; i++)
|
||||
sum += data[i];
|
||||
return sum & 0xff;
|
||||
}
|
||||
|
||||
/* Build the Multi Processor table in the BIOS. Same values as Bochs. */
|
||||
static void bios_add_mptable(uint8_t *bios_data)
|
||||
{
|
||||
uint8_t *mp_config_table, *q, *float_pointer_struct;
|
||||
int ioapic_id, offset, i, len;
|
||||
|
||||
if (smp_cpus <= 1)
|
||||
return;
|
||||
|
||||
mp_config_table = bios_data + 0xb000;
|
||||
q = mp_config_table;
|
||||
putstr(&q, "PCMP"); /* "PCMP signature */
|
||||
putle16(&q, 0); /* table length (patched later) */
|
||||
putb(&q, 4); /* spec rev */
|
||||
putb(&q, 0); /* checksum (patched later) */
|
||||
putstr(&q, "QEMUCPU "); /* OEM id */
|
||||
putstr(&q, "0.1 "); /* vendor id */
|
||||
putle32(&q, 0); /* OEM table ptr */
|
||||
putle16(&q, 0); /* OEM table size */
|
||||
putle16(&q, 20); /* entry count */
|
||||
putle32(&q, 0xfee00000); /* local APIC addr */
|
||||
putle16(&q, 0); /* ext table length */
|
||||
putb(&q, 0); /* ext table checksum */
|
||||
putb(&q, 0); /* reserved */
|
||||
|
||||
for(i = 0; i < smp_cpus; i++) {
|
||||
putb(&q, 0); /* entry type = processor */
|
||||
putb(&q, i); /* APIC id */
|
||||
putb(&q, 0x11); /* local APIC version number */
|
||||
if (i == 0)
|
||||
putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
|
||||
else
|
||||
putb(&q, 1); /* cpu flags: enabled */
|
||||
putb(&q, 0); /* cpu signature */
|
||||
putb(&q, 6);
|
||||
putb(&q, 0);
|
||||
putb(&q, 0);
|
||||
putle16(&q, 0x201); /* feature flags */
|
||||
putle16(&q, 0);
|
||||
|
||||
putle16(&q, 0); /* reserved */
|
||||
putle16(&q, 0);
|
||||
putle16(&q, 0);
|
||||
putle16(&q, 0);
|
||||
}
|
||||
|
||||
/* isa bus */
|
||||
putb(&q, 1); /* entry type = bus */
|
||||
putb(&q, 0); /* bus ID */
|
||||
putstr(&q, "ISA ");
|
||||
|
||||
/* ioapic */
|
||||
ioapic_id = smp_cpus;
|
||||
putb(&q, 2); /* entry type = I/O APIC */
|
||||
putb(&q, ioapic_id); /* apic ID */
|
||||
putb(&q, 0x11); /* I/O APIC version number */
|
||||
putb(&q, 1); /* enable */
|
||||
putle32(&q, 0xfec00000); /* I/O APIC addr */
|
||||
|
||||
/* irqs */
|
||||
for(i = 0; i < 16; i++) {
|
||||
putb(&q, 3); /* entry type = I/O interrupt */
|
||||
putb(&q, 0); /* interrupt type = vectored interrupt */
|
||||
putb(&q, 0); /* flags: po=0, el=0 */
|
||||
putb(&q, 0);
|
||||
putb(&q, 0); /* source bus ID = ISA */
|
||||
putb(&q, i); /* source bus IRQ */
|
||||
putb(&q, ioapic_id); /* dest I/O APIC ID */
|
||||
putb(&q, i); /* dest I/O APIC interrupt in */
|
||||
}
|
||||
/* patch length */
|
||||
len = q - mp_config_table;
|
||||
mp_config_table[4] = len;
|
||||
mp_config_table[5] = len >> 8;
|
||||
|
||||
mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
|
||||
|
||||
/* align to 16 */
|
||||
offset = q - bios_data;
|
||||
offset = (offset + 15) & ~15;
|
||||
float_pointer_struct = bios_data + offset;
|
||||
|
||||
/* floating pointer structure */
|
||||
q = float_pointer_struct;
|
||||
putstr(&q, "_MP_");
|
||||
/* pointer to MP config table */
|
||||
putle32(&q, mp_config_table - bios_data + 0x000f0000);
|
||||
|
||||
putb(&q, 1); /* length in 16 byte units */
|
||||
putb(&q, 4); /* MP spec revision */
|
||||
putb(&q, 0); /* checksum (patched later) */
|
||||
putb(&q, 0); /* MP feature byte 1 */
|
||||
|
||||
putb(&q, 0);
|
||||
putb(&q, 0);
|
||||
putb(&q, 0);
|
||||
putb(&q, 0);
|
||||
float_pointer_struct[10] =
|
||||
-mpf_checksum(float_pointer_struct, q - float_pointer_struct);
|
||||
}
|
||||
|
||||
|
||||
static const int ide_iobase[2] = { 0x1f0, 0x170 };
|
||||
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
|
||||
static const int ide_irq[2] = { 14, 15 };
|
||||
@@ -614,7 +451,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
{
|
||||
char buf[1024];
|
||||
int ret, linux_boot, initrd_size, i;
|
||||
unsigned long bios_offset, vga_bios_offset;
|
||||
unsigned long bios_offset, vga_bios_offset, option_rom_offset;
|
||||
int bios_size, isa_bios_size;
|
||||
PCIBus *pci_bus;
|
||||
int piix3_devfn = -1;
|
||||
@@ -632,7 +469,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
/* XXX: enable it in all cases */
|
||||
env->cpuid_features |= CPUID_APIC;
|
||||
}
|
||||
register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
|
||||
register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
|
||||
qemu_register_reset(main_cpu_reset, env);
|
||||
if (pci_enabled) {
|
||||
apic_init(env);
|
||||
@@ -659,9 +496,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
if (bios_size == 65536) {
|
||||
bios_add_mptable(phys_ram_base + bios_offset);
|
||||
}
|
||||
|
||||
/* VGA BIOS load */
|
||||
if (cirrus_vga_enabled) {
|
||||
@@ -684,6 +518,23 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
cpu_register_physical_memory(0x100000 - isa_bios_size,
|
||||
isa_bios_size,
|
||||
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
|
||||
|
||||
option_rom_offset = 0;
|
||||
for (i = 0; i < nb_option_roms; i++) {
|
||||
int offset = bios_offset + bios_size + option_rom_offset;
|
||||
int size;
|
||||
|
||||
size = load_image(option_rom[i], phys_ram_base + offset);
|
||||
if ((size + option_rom_offset) > 0x10000) {
|
||||
fprintf(stderr, "Too many option ROMS\n");
|
||||
exit(1);
|
||||
}
|
||||
cpu_register_physical_memory(0xd0000 + option_rom_offset,
|
||||
size, offset | IO_MEM_ROM);
|
||||
option_rom_offset += size + 2047;
|
||||
option_rom_offset -= (option_rom_offset % 2048);
|
||||
}
|
||||
|
||||
/* map all the bios at the top of memory */
|
||||
cpu_register_physical_memory((uint32_t)(-bios_size),
|
||||
bios_size, bios_offset | IO_MEM_ROM);
|
||||
@@ -747,8 +598,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
|
||||
if (pci_enabled) {
|
||||
pci_bus = i440fx_init();
|
||||
piix3_devfn = piix3_init(pci_bus);
|
||||
pci_bus = i440fx_init(&i440fx_state);
|
||||
piix3_devfn = piix3_init(pci_bus, -1);
|
||||
} else {
|
||||
pci_bus = NULL;
|
||||
}
|
||||
@@ -768,8 +619,13 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
vga_ram_size);
|
||||
}
|
||||
} else {
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
if (pci_enabled) {
|
||||
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
} else {
|
||||
isa_vga_init(ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size);
|
||||
}
|
||||
}
|
||||
|
||||
rtc_state = rtc_init(0x70, 8);
|
||||
@@ -812,7 +668,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
if (strcmp(nd->model, "ne2k_isa") == 0) {
|
||||
pc_init_ne2k_isa(nd);
|
||||
} else if (pci_enabled) {
|
||||
pci_nic_init(pci_bus, nd);
|
||||
pci_nic_init(pci_bus, nd, -1);
|
||||
} else {
|
||||
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
|
||||
exit(1);
|
||||
@@ -843,9 +699,18 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
|
||||
if (pci_enabled && acpi_enabled) {
|
||||
uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
|
||||
piix4_pm_init(pci_bus, piix3_devfn + 3);
|
||||
for (i = 0; i < 8; i++) {
|
||||
SMBusDevice *eeprom = smbus_eeprom_device_init(0x50 + i,
|
||||
eeprom_buf + (i * 256));
|
||||
piix4_smbus_register_device(eeprom, 0x50 + i);
|
||||
}
|
||||
}
|
||||
|
||||
if (i440fx_state) {
|
||||
i440fx_init_memory_mappings(i440fx_state);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* ??? Need to figure out some way for the user to
|
||||
specify SCSI devices. */
|
||||
@@ -863,13 +728,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
lsi_scsi_attach(scsi, bdrv, -1);
|
||||
}
|
||||
#endif
|
||||
/* must be done after all PCI devices are instanciated */
|
||||
/* XXX: should be done in the Bochs BIOS */
|
||||
if (pci_enabled) {
|
||||
pci_bios_init();
|
||||
if (acpi_enabled)
|
||||
acpi_bios_init();
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device,
|
||||
|
||||
@@ -29,48 +29,68 @@ struct PCIBus {
|
||||
int bus_num;
|
||||
int devfn_min;
|
||||
pci_set_irq_fn set_irq;
|
||||
pci_map_irq_fn map_irq;
|
||||
uint32_t config_reg; /* XXX: suppress */
|
||||
/* low level pic */
|
||||
SetIRQFunc *low_set_irq;
|
||||
void *irq_opaque;
|
||||
PCIDevice *devices[256];
|
||||
PCIDevice *parent_dev;
|
||||
PCIBus *next;
|
||||
/* The bus IRQ state is the logical OR of the connected devices.
|
||||
Keep a count of the number of devices with raised IRQs. */
|
||||
int irq_count[];
|
||||
};
|
||||
|
||||
static void pci_update_mappings(PCIDevice *d);
|
||||
|
||||
target_phys_addr_t pci_mem_base;
|
||||
static int pci_irq_index;
|
||||
static PCIBus *first_bus;
|
||||
|
||||
PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min)
|
||||
PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
||||
void *pic, int devfn_min, int nirq)
|
||||
{
|
||||
PCIBus *bus;
|
||||
bus = qemu_mallocz(sizeof(PCIBus));
|
||||
bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
|
||||
bus->set_irq = set_irq;
|
||||
bus->map_irq = map_irq;
|
||||
bus->irq_opaque = pic;
|
||||
bus->devfn_min = devfn_min;
|
||||
first_bus = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq)
|
||||
{
|
||||
PCIBus *bus;
|
||||
bus = qemu_mallocz(sizeof(PCIBus));
|
||||
bus->map_irq = map_irq;
|
||||
bus->parent_dev = dev;
|
||||
bus->next = dev->bus->next;
|
||||
dev->bus->next = bus;
|
||||
return bus;
|
||||
}
|
||||
|
||||
int pci_bus_num(PCIBus *s)
|
||||
{
|
||||
return s->bus_num;
|
||||
}
|
||||
|
||||
void generic_pci_save(QEMUFile* f, void *opaque)
|
||||
void pci_device_save(PCIDevice *s, QEMUFile *f)
|
||||
{
|
||||
PCIDevice* s=(PCIDevice*)opaque;
|
||||
|
||||
qemu_put_be32(f, 1); /* PCI device version */
|
||||
qemu_put_buffer(f, s->config, 256);
|
||||
}
|
||||
|
||||
int generic_pci_load(QEMUFile* f, void *opaque, int version_id)
|
||||
int pci_device_load(PCIDevice *s, QEMUFile *f)
|
||||
{
|
||||
PCIDevice* s=(PCIDevice*)opaque;
|
||||
|
||||
uint32_t version_id;
|
||||
version_id = qemu_get_be32(f);
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
qemu_get_buffer(f, s->config, 256);
|
||||
pci_update_mappings(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -99,6 +119,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
|
||||
pci_dev->bus = bus;
|
||||
pci_dev->devfn = devfn;
|
||||
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
|
||||
memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
|
||||
|
||||
if (!config_read)
|
||||
config_read = pci_default_read_config;
|
||||
@@ -221,16 +242,23 @@ uint32_t pci_default_read_config(PCIDevice *d,
|
||||
uint32_t address, int len)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
switch(len) {
|
||||
case 1:
|
||||
val = d->config[address];
|
||||
break;
|
||||
case 2:
|
||||
val = le16_to_cpu(*(uint16_t *)(d->config + address));
|
||||
break;
|
||||
default:
|
||||
case 4:
|
||||
val = le32_to_cpu(*(uint32_t *)(d->config + address));
|
||||
if (address <= 0xfc) {
|
||||
val = le32_to_cpu(*(uint32_t *)(d->config + address));
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 2:
|
||||
if (address <= 0xfe) {
|
||||
val = le16_to_cpu(*(uint16_t *)(d->config + address));
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 1:
|
||||
val = d->config[address];
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
@@ -320,7 +348,8 @@ void pci_default_write_config(PCIDevice *d,
|
||||
if (can_write) {
|
||||
d->config[addr] = val;
|
||||
}
|
||||
addr++;
|
||||
if (++addr > 0xff)
|
||||
break;
|
||||
val >>= 8;
|
||||
}
|
||||
|
||||
@@ -342,7 +371,9 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
|
||||
addr, val, len);
|
||||
#endif
|
||||
bus_num = (addr >> 16) & 0xff;
|
||||
if (bus_num != 0)
|
||||
while (s && s->bus_num != bus_num)
|
||||
s = s->next;
|
||||
if (!s)
|
||||
return;
|
||||
pci_dev = s->devices[(addr >> 8) & 0xff];
|
||||
if (!pci_dev)
|
||||
@@ -363,7 +394,9 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
|
||||
uint32_t val;
|
||||
|
||||
bus_num = (addr >> 16) & 0xff;
|
||||
if (bus_num != 0)
|
||||
while (s && s->bus_num != bus_num)
|
||||
s= s->next;
|
||||
if (!s)
|
||||
goto fail;
|
||||
pci_dev = s->devices[(addr >> 8) & 0xff];
|
||||
if (!pci_dev) {
|
||||
@@ -402,8 +435,23 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
|
||||
/* 0 <= irq_num <= 3. level must be 0 or 1 */
|
||||
void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
|
||||
{
|
||||
PCIBus *bus = pci_dev->bus;
|
||||
bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level);
|
||||
PCIBus *bus;
|
||||
int change;
|
||||
|
||||
change = level - pci_dev->irq_state[irq_num];
|
||||
if (!change)
|
||||
return;
|
||||
|
||||
pci_dev->irq_state[irq_num] = level;
|
||||
for (;;) {
|
||||
bus = pci_dev->bus;
|
||||
irq_num = bus->map_irq(pci_dev, irq_num);
|
||||
if (bus->set_irq)
|
||||
break;
|
||||
pci_dev = bus->parent_dev;
|
||||
}
|
||||
bus->irq_count[irq_num] += change;
|
||||
bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
@@ -416,6 +464,7 @@ typedef struct {
|
||||
|
||||
static pci_class_desc pci_class_descriptions[] =
|
||||
{
|
||||
{ 0x0100, "SCSI controller"},
|
||||
{ 0x0101, "IDE controller"},
|
||||
{ 0x0200, "Ethernet controller"},
|
||||
{ 0x0300, "VGA controller"},
|
||||
@@ -451,6 +500,9 @@ static void pci_info_device(PCIDevice *d)
|
||||
if (d->config[PCI_INTERRUPT_PIN] != 0) {
|
||||
term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
|
||||
}
|
||||
if (class == 0x0604) {
|
||||
term_printf(" BUS %d.\n", d->config[0x19]);
|
||||
}
|
||||
for(i = 0;i < PCI_NUM_REGIONS; i++) {
|
||||
r = &d->io_regions[i];
|
||||
if (r->size != 0) {
|
||||
@@ -464,14 +516,19 @@ static void pci_info_device(PCIDevice *d)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (class == 0x0604 && d->config[0x19] != 0) {
|
||||
pci_for_each_device(d->config[0x19], pci_info_device);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_for_each_device(void (*fn)(PCIDevice *d))
|
||||
void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d))
|
||||
{
|
||||
PCIBus *bus = first_bus;
|
||||
PCIDevice *d;
|
||||
int devfn;
|
||||
|
||||
while (bus && bus->bus_num != bus_num)
|
||||
bus = bus->next;
|
||||
if (bus) {
|
||||
for(devfn = 0; devfn < 256; devfn++) {
|
||||
d = bus->devices[devfn];
|
||||
@@ -483,21 +540,68 @@ void pci_for_each_device(void (*fn)(PCIDevice *d))
|
||||
|
||||
void pci_info(void)
|
||||
{
|
||||
pci_for_each_device(pci_info_device);
|
||||
pci_for_each_device(0, pci_info_device);
|
||||
}
|
||||
|
||||
/* Initialize a PCI NIC. */
|
||||
void pci_nic_init(PCIBus *bus, NICInfo *nd)
|
||||
void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
|
||||
{
|
||||
if (strcmp(nd->model, "ne2k_pci") == 0) {
|
||||
pci_ne2000_init(bus, nd);
|
||||
pci_ne2000_init(bus, nd, devfn);
|
||||
} else if (strcmp(nd->model, "rtl8139") == 0) {
|
||||
pci_rtl8139_init(bus, nd);
|
||||
pci_rtl8139_init(bus, nd, devfn);
|
||||
} else if (strcmp(nd->model, "pcnet") == 0) {
|
||||
pci_pcnet_init(bus, nd);
|
||||
pci_pcnet_init(bus, nd, devfn);
|
||||
} else {
|
||||
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PCIDevice dev;
|
||||
PCIBus *bus;
|
||||
} PCIBridge;
|
||||
|
||||
void pci_bridge_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
PCIBridge *s = (PCIBridge *)d;
|
||||
|
||||
if (address == 0x19 || (address == 0x18 && len > 1)) {
|
||||
if (address == 0x19)
|
||||
s->bus->bus_num = val & 0xff;
|
||||
else
|
||||
s->bus->bus_num = (val >> 8) & 0xff;
|
||||
#if defined(DEBUG_PCI)
|
||||
printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num);
|
||||
#endif
|
||||
}
|
||||
pci_default_write_config(d, address, val, len);
|
||||
}
|
||||
|
||||
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
|
||||
pci_map_irq_fn map_irq, const char *name)
|
||||
{
|
||||
PCIBridge *s;
|
||||
s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
|
||||
devfn, NULL, pci_bridge_write_config);
|
||||
s->dev.config[0x00] = id >> 16;
|
||||
s->dev.config[0x01] = id > 24;
|
||||
s->dev.config[0x02] = id; // device_id
|
||||
s->dev.config[0x03] = id >> 8;
|
||||
s->dev.config[0x04] = 0x06; // command = bus master, pci mem
|
||||
s->dev.config[0x05] = 0x00;
|
||||
s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
|
||||
s->dev.config[0x07] = 0x00; // status = fast devsel
|
||||
s->dev.config[0x08] = 0x00; // revision
|
||||
s->dev.config[0x09] = 0x00; // programming i/f
|
||||
s->dev.config[0x0A] = 0x04; // class_sub = PCI to PCI bridge
|
||||
s->dev.config[0x0B] = 0x06; // class_base = PCI_bridge
|
||||
s->dev.config[0x0D] = 0x10; // latency_timer
|
||||
s->dev.config[0x0E] = 0x81; // header_type
|
||||
s->dev.config[0x1E] = 0xa0; // secondary status
|
||||
|
||||
s->bus = pci_register_secondary_bus(&s->dev, map_irq);
|
||||
return s->bus;
|
||||
}
|
||||
+385
-186
@@ -27,6 +27,16 @@
|
||||
* AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
|
||||
*/
|
||||
|
||||
/*
|
||||
* On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
|
||||
* produced as NCR89C100. See
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
|
||||
* and
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
|
||||
*/
|
||||
|
||||
/* TODO: remove little endian host assumptions */
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
//#define PCNET_DEBUG
|
||||
@@ -46,11 +56,12 @@ typedef struct PCNetState_st PCNetState;
|
||||
|
||||
struct PCNetState_st {
|
||||
PCIDevice dev;
|
||||
PCIDevice *pci_dev;
|
||||
VLANClientState *vc;
|
||||
NICInfo *nd;
|
||||
QEMUTimer *poll_timer;
|
||||
int mmio_io_addr, rap, isr, lnkst;
|
||||
target_phys_addr_t rdra, tdra;
|
||||
int mmio_index, rap, isr, lnkst;
|
||||
uint32_t rdra, tdra;
|
||||
uint8_t prom[16];
|
||||
uint16_t csr[128];
|
||||
uint16_t bcr[32];
|
||||
@@ -58,6 +69,12 @@ struct PCNetState_st {
|
||||
int xmit_pos, recv_pos;
|
||||
uint8_t buffer[4096];
|
||||
int tx_busy;
|
||||
void (*set_irq_cb)(void *s, int isr);
|
||||
void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int do_bswap);
|
||||
void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int do_bswap);
|
||||
void *dma_opaque;
|
||||
};
|
||||
|
||||
/* XXX: using bitfields for target memory structures is almost surely
|
||||
@@ -99,6 +116,7 @@ struct qemu_ether_header {
|
||||
#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)
|
||||
#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)
|
||||
#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)
|
||||
#define CSR_BSWP(S) !!(((S)->csr[3])&0x0004)
|
||||
#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)
|
||||
#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)
|
||||
#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
|
||||
@@ -147,35 +165,19 @@ struct qemu_ether_header {
|
||||
|
||||
struct pcnet_initblk16 {
|
||||
uint16_t mode;
|
||||
uint16_t padr1;
|
||||
uint16_t padr2;
|
||||
uint16_t padr3;
|
||||
uint16_t ladrf1;
|
||||
uint16_t ladrf2;
|
||||
uint16_t ladrf3;
|
||||
uint16_t ladrf4;
|
||||
unsigned PACKED_FIELD(rdra:24);
|
||||
unsigned PACKED_FIELD(res1:5);
|
||||
unsigned PACKED_FIELD(rlen:3);
|
||||
unsigned PACKED_FIELD(tdra:24);
|
||||
unsigned PACKED_FIELD(res2:5);
|
||||
unsigned PACKED_FIELD(tlen:3);
|
||||
uint16_t padr[3];
|
||||
uint16_t ladrf[4];
|
||||
uint32_t rdra;
|
||||
uint32_t tdra;
|
||||
};
|
||||
|
||||
struct pcnet_initblk32 {
|
||||
uint16_t mode;
|
||||
unsigned PACKED_FIELD(res1:4);
|
||||
unsigned PACKED_FIELD(rlen:4);
|
||||
unsigned PACKED_FIELD(res2:4);
|
||||
unsigned PACKED_FIELD(tlen:4);
|
||||
uint16_t padr1;
|
||||
uint16_t padr2;
|
||||
uint16_t padr3;
|
||||
uint8_t rlen;
|
||||
uint8_t tlen;
|
||||
uint16_t padr[3];
|
||||
uint16_t _res;
|
||||
uint16_t ladrf1;
|
||||
uint16_t ladrf2;
|
||||
uint16_t ladrf3;
|
||||
uint16_t ladrf4;
|
||||
uint16_t ladrf[4];
|
||||
uint32_t rdra;
|
||||
uint32_t tdra;
|
||||
};
|
||||
@@ -251,112 +253,153 @@ struct pcnet_RMD {
|
||||
(R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
|
||||
(R)->rmd2.zeros)
|
||||
|
||||
static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
|
||||
static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
if (!BCR_SWSTYLE(s)) {
|
||||
uint16_t xda[4];
|
||||
cpu_physical_memory_read(addr,
|
||||
(void *)&xda[0], sizeof(xda));
|
||||
((uint32_t *)tmd)[0] = (xda[0]&0xffff) |
|
||||
((xda[1]&0x00ff) << 16);
|
||||
((uint32_t *)tmd)[1] = (xda[2]&0xffff)|
|
||||
((xda[1] & 0xff00) << 16);
|
||||
((uint32_t *)tmd)[2] =
|
||||
(xda[3] & 0xffff) << 16;
|
||||
((uint32_t *)tmd)[3] = 0;
|
||||
}
|
||||
else
|
||||
if (BCR_SWSTYLE(s) != 3)
|
||||
cpu_physical_memory_read(addr, (void *)tmd, 16);
|
||||
else {
|
||||
uint32_t xda[4];
|
||||
cpu_physical_memory_read(addr,
|
||||
(void *)&xda[0], sizeof(xda));
|
||||
((uint32_t *)tmd)[0] = xda[2];
|
||||
((uint32_t *)tmd)[1] = xda[1];
|
||||
((uint32_t *)tmd)[2] = xda[0];
|
||||
((uint32_t *)tmd)[3] = xda[3];
|
||||
}
|
||||
}
|
||||
uint32_t *tmd = (uint32_t *)tmd1;
|
||||
|
||||
static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
|
||||
{
|
||||
if (!BCR_SWSTYLE(s)) {
|
||||
uint16_t xda[4];
|
||||
xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
|
||||
xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) |
|
||||
((((uint32_t *)tmd)[1]>>16)&0xff00);
|
||||
xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
|
||||
xda[3] = ((uint32_t *)tmd)[2] >> 16;
|
||||
cpu_physical_memory_write(addr,
|
||||
(void *)&xda[0], sizeof(xda));
|
||||
}
|
||||
else {
|
||||
if (BCR_SWSTYLE(s) != 3)
|
||||
cpu_physical_memory_write(addr, (void *)tmd, 16);
|
||||
else {
|
||||
uint32_t xda[4];
|
||||
xda[0] = ((uint32_t *)tmd)[2];
|
||||
xda[1] = ((uint32_t *)tmd)[1];
|
||||
xda[2] = ((uint32_t *)tmd)[0];
|
||||
xda[3] = ((uint32_t *)tmd)[3];
|
||||
cpu_physical_memory_write(addr,
|
||||
(void *)&xda[0], sizeof(xda));
|
||||
s->phys_mem_read(s->dma_opaque, addr,
|
||||
(void *)&xda[0], sizeof(xda), 0);
|
||||
le16_to_cpus(&xda[0]);
|
||||
le16_to_cpus(&xda[1]);
|
||||
le16_to_cpus(&xda[2]);
|
||||
le16_to_cpus(&xda[3]);
|
||||
tmd[0] = (xda[0]&0xffff) |
|
||||
((xda[1]&0x00ff) << 16);
|
||||
tmd[1] = (xda[2]&0xffff)|
|
||||
((xda[1] & 0xff00) << 16);
|
||||
tmd[2] =
|
||||
(xda[3] & 0xffff) << 16;
|
||||
tmd[3] = 0;
|
||||
} else {
|
||||
uint32_t xda[4];
|
||||
s->phys_mem_read(s->dma_opaque, addr,
|
||||
(void *)&xda[0], sizeof(xda), 0);
|
||||
le32_to_cpus(&xda[0]);
|
||||
le32_to_cpus(&xda[1]);
|
||||
le32_to_cpus(&xda[2]);
|
||||
le32_to_cpus(&xda[3]);
|
||||
if (BCR_SWSTYLE(s) != 3) {
|
||||
memcpy(tmd, xda, sizeof(xda));
|
||||
} else {
|
||||
tmd[0] = xda[2];
|
||||
tmd[1] = xda[1];
|
||||
tmd[2] = xda[0];
|
||||
tmd[3] = xda[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
|
||||
static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
const uint32_t *tmd = (const uint32_t *)tmd1;
|
||||
if (!BCR_SWSTYLE(s)) {
|
||||
uint16_t xda[4];
|
||||
xda[0] = tmd[0] & 0xffff;
|
||||
xda[1] = ((tmd[0]>>16)&0x00ff) |
|
||||
((tmd[1]>>16)&0xff00);
|
||||
xda[2] = tmd[1] & 0xffff;
|
||||
xda[3] = tmd[2] >> 16;
|
||||
cpu_to_le16s(&xda[0]);
|
||||
cpu_to_le16s(&xda[1]);
|
||||
cpu_to_le16s(&xda[2]);
|
||||
cpu_to_le16s(&xda[3]);
|
||||
s->phys_mem_write(s->dma_opaque, addr,
|
||||
(void *)&xda[0], sizeof(xda), 0);
|
||||
} else {
|
||||
uint32_t xda[4];
|
||||
if (BCR_SWSTYLE(s) != 3) {
|
||||
memcpy(xda, tmd, sizeof(xda));
|
||||
} else {
|
||||
xda[0] = tmd[2];
|
||||
xda[1] = tmd[1];
|
||||
xda[2] = tmd[0];
|
||||
xda[3] = tmd[3];
|
||||
}
|
||||
cpu_to_le32s(&xda[0]);
|
||||
cpu_to_le32s(&xda[1]);
|
||||
cpu_to_le32s(&xda[2]);
|
||||
cpu_to_le32s(&xda[3]);
|
||||
s->phys_mem_write(s->dma_opaque, addr,
|
||||
(void *)&xda[0], sizeof(xda), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t *rmd = (uint32_t *)rmd1;
|
||||
|
||||
if (!BCR_SWSTYLE(s)) {
|
||||
uint16_t rda[4];
|
||||
cpu_physical_memory_read(addr,
|
||||
(void *)&rda[0], sizeof(rda));
|
||||
((uint32_t *)rmd)[0] = (rda[0]&0xffff)|
|
||||
((rda[1] & 0x00ff) << 16);
|
||||
((uint32_t *)rmd)[1] = (rda[2]&0xffff)|
|
||||
((rda[1] & 0xff00) << 16);
|
||||
((uint32_t *)rmd)[2] = rda[3] & 0xffff;
|
||||
((uint32_t *)rmd)[3] = 0;
|
||||
}
|
||||
else
|
||||
if (BCR_SWSTYLE(s) != 3)
|
||||
cpu_physical_memory_read(addr, (void *)rmd, 16);
|
||||
else {
|
||||
s->phys_mem_read(s->dma_opaque, addr,
|
||||
(void *)&rda[0], sizeof(rda), 0);
|
||||
le16_to_cpus(&rda[0]);
|
||||
le16_to_cpus(&rda[1]);
|
||||
le16_to_cpus(&rda[2]);
|
||||
le16_to_cpus(&rda[3]);
|
||||
rmd[0] = (rda[0]&0xffff)|
|
||||
((rda[1] & 0x00ff) << 16);
|
||||
rmd[1] = (rda[2]&0xffff)|
|
||||
((rda[1] & 0xff00) << 16);
|
||||
rmd[2] = rda[3] & 0xffff;
|
||||
rmd[3] = 0;
|
||||
} else {
|
||||
uint32_t rda[4];
|
||||
cpu_physical_memory_read(addr,
|
||||
(void *)&rda[0], sizeof(rda));
|
||||
((uint32_t *)rmd)[0] = rda[2];
|
||||
((uint32_t *)rmd)[1] = rda[1];
|
||||
((uint32_t *)rmd)[2] = rda[0];
|
||||
((uint32_t *)rmd)[3] = rda[3];
|
||||
s->phys_mem_read(s->dma_opaque, addr,
|
||||
(void *)&rda[0], sizeof(rda), 0);
|
||||
le32_to_cpus(&rda[0]);
|
||||
le32_to_cpus(&rda[1]);
|
||||
le32_to_cpus(&rda[2]);
|
||||
le32_to_cpus(&rda[3]);
|
||||
if (BCR_SWSTYLE(s) != 3) {
|
||||
memcpy(rmd, rda, sizeof(rda));
|
||||
} else {
|
||||
rmd[0] = rda[2];
|
||||
rmd[1] = rda[1];
|
||||
rmd[2] = rda[0];
|
||||
rmd[3] = rda[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
|
||||
static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
const uint32_t *rmd = (const uint32_t *)rmd1;
|
||||
|
||||
if (!BCR_SWSTYLE(s)) {
|
||||
uint16_t rda[4]; \
|
||||
rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \
|
||||
rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\
|
||||
((((uint32_t *)rmd)[1]>>16)&0xff00);\
|
||||
rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \
|
||||
rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \
|
||||
cpu_physical_memory_write(addr, \
|
||||
(void *)&rda[0], sizeof(rda)); \
|
||||
}
|
||||
else {
|
||||
if (BCR_SWSTYLE(s) != 3)
|
||||
cpu_physical_memory_write(addr, (void *)rmd, 16);
|
||||
else {
|
||||
uint32_t rda[4];
|
||||
rda[0] = ((uint32_t *)rmd)[2];
|
||||
rda[1] = ((uint32_t *)rmd)[1];
|
||||
rda[2] = ((uint32_t *)rmd)[0];
|
||||
rda[3] = ((uint32_t *)rmd)[3];
|
||||
cpu_physical_memory_write(addr,
|
||||
(void *)&rda[0], sizeof(rda));
|
||||
uint16_t rda[4];
|
||||
rda[0] = rmd[0] & 0xffff;
|
||||
rda[1] = ((rmd[0]>>16)&0xff)|
|
||||
((rmd[1]>>16)&0xff00);
|
||||
rda[2] = rmd[1] & 0xffff;
|
||||
rda[3] = rmd[2] & 0xffff;
|
||||
cpu_to_le16s(&rda[0]);
|
||||
cpu_to_le16s(&rda[1]);
|
||||
cpu_to_le16s(&rda[2]);
|
||||
cpu_to_le16s(&rda[3]);
|
||||
s->phys_mem_write(s->dma_opaque, addr,
|
||||
(void *)&rda[0], sizeof(rda), 0);
|
||||
} else {
|
||||
uint32_t rda[4];
|
||||
if (BCR_SWSTYLE(s) != 3) {
|
||||
memcpy(rda, rmd, sizeof(rda));
|
||||
} else {
|
||||
rda[0] = rmd[2];
|
||||
rda[1] = rmd[1];
|
||||
rda[2] = rmd[0];
|
||||
rda[3] = rmd[3];
|
||||
}
|
||||
cpu_to_le32s(&rda[0]);
|
||||
cpu_to_le32s(&rda[1]);
|
||||
cpu_to_le32s(&rda[2]);
|
||||
cpu_to_le32s(&rda[3]);
|
||||
s->phys_mem_write(s->dma_opaque, addr,
|
||||
(void *)&rda[0], sizeof(rda), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,8 +434,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_
|
||||
case 0x00: \
|
||||
do { \
|
||||
uint16_t rda[4]; \
|
||||
cpu_physical_memory_read((ADDR), \
|
||||
(void *)&rda[0], sizeof(rda)); \
|
||||
s->phys_mem_read(s->dma_opaque, (ADDR), \
|
||||
(void *)&rda[0], sizeof(rda), 0); \
|
||||
(RES) |= (rda[2] & 0xf000)!=0xf000; \
|
||||
(RES) |= (rda[3] & 0xf000)!=0x0000; \
|
||||
} while (0); \
|
||||
@@ -401,8 +444,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_
|
||||
case 0x02: \
|
||||
do { \
|
||||
uint32_t rda[4]; \
|
||||
cpu_physical_memory_read((ADDR), \
|
||||
(void *)&rda[0], sizeof(rda)); \
|
||||
s->phys_mem_read(s->dma_opaque, (ADDR), \
|
||||
(void *)&rda[0], sizeof(rda), 0); \
|
||||
(RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
|
||||
(RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
|
||||
} while (0); \
|
||||
@@ -410,8 +453,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_
|
||||
case 0x03: \
|
||||
do { \
|
||||
uint32_t rda[4]; \
|
||||
cpu_physical_memory_read((ADDR), \
|
||||
(void *)&rda[0], sizeof(rda)); \
|
||||
s->phys_mem_read(s->dma_opaque, (ADDR), \
|
||||
(void *)&rda[0], sizeof(rda), 0); \
|
||||
(RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
|
||||
(RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
|
||||
} while (0); \
|
||||
@@ -424,8 +467,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_
|
||||
case 0x00: \
|
||||
do { \
|
||||
uint16_t xda[4]; \
|
||||
cpu_physical_memory_read((ADDR), \
|
||||
(void *)&xda[0], sizeof(xda)); \
|
||||
s->phys_mem_read(s->dma_opaque, (ADDR), \
|
||||
(void *)&xda[0], sizeof(xda), 0); \
|
||||
(RES) |= (xda[2] & 0xf000)!=0xf000;\
|
||||
} while (0); \
|
||||
break; \
|
||||
@@ -434,8 +477,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_
|
||||
case 0x03: \
|
||||
do { \
|
||||
uint32_t xda[4]; \
|
||||
cpu_physical_memory_read((ADDR), \
|
||||
(void *)&xda[0], sizeof(xda)); \
|
||||
s->phys_mem_read(s->dma_opaque, (ADDR), \
|
||||
(void *)&xda[0], sizeof(xda), 0); \
|
||||
(RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
|
||||
} while (0); \
|
||||
break; \
|
||||
@@ -448,13 +491,12 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_
|
||||
struct qemu_ether_header *hdr = (void *)(BUF); \
|
||||
printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
|
||||
"shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
|
||||
"type=0x%04x (bcast=%d)\n", \
|
||||
"type=0x%04x\n", \
|
||||
hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
|
||||
hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
|
||||
hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
|
||||
hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
|
||||
be16_to_cpu(hdr->ether_type), \
|
||||
!!ETHER_IS_MULTICAST(hdr->ether_dhost)); \
|
||||
be16_to_cpu(hdr->ether_type)); \
|
||||
} while (0)
|
||||
|
||||
#define MULTICAST_FILTER_LEN 8
|
||||
@@ -571,7 +613,7 @@ static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
|
||||
|
||||
static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
|
||||
{
|
||||
static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
struct qemu_ether_header *hdr = (void *)buf;
|
||||
int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
|
||||
#ifdef PCNET_DEBUG_MATCH
|
||||
@@ -721,51 +763,65 @@ static void pcnet_update_irq(PCNetState *s)
|
||||
printf("pcnet: INTA=%d\n", isr);
|
||||
#endif
|
||||
}
|
||||
pci_set_irq(&s->dev, 0, isr);
|
||||
s->isr = isr;
|
||||
s->set_irq_cb(s, isr);
|
||||
s->isr = isr;
|
||||
}
|
||||
|
||||
static void pcnet_init(PCNetState *s)
|
||||
{
|
||||
int rlen, tlen;
|
||||
uint16_t *padr, *ladrf, mode;
|
||||
uint32_t rdra, tdra;
|
||||
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
|
||||
#endif
|
||||
|
||||
#define PCNET_INIT() do { \
|
||||
cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \
|
||||
(uint8_t *)&initblk, sizeof(initblk)); \
|
||||
s->csr[15] = le16_to_cpu(initblk.mode); \
|
||||
CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
|
||||
CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
|
||||
s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
|
||||
s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \
|
||||
s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \
|
||||
s->csr[10] = le16_to_cpu(initblk.ladrf3); \
|
||||
s->csr[11] = le16_to_cpu(initblk.ladrf4); \
|
||||
s->csr[12] = le16_to_cpu(initblk.padr1); \
|
||||
s->csr[13] = le16_to_cpu(initblk.padr2); \
|
||||
s->csr[14] = le16_to_cpu(initblk.padr3); \
|
||||
s->rdra = PHYSADDR(s,initblk.rdra); \
|
||||
s->tdra = PHYSADDR(s,initblk.tdra); \
|
||||
} while (0)
|
||||
|
||||
if (BCR_SSIZE32(s)) {
|
||||
struct pcnet_initblk32 initblk;
|
||||
PCNET_INIT();
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
|
||||
initblk.rlen, initblk.tlen);
|
||||
#endif
|
||||
s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
|
||||
(uint8_t *)&initblk, sizeof(initblk), 0);
|
||||
mode = initblk.mode;
|
||||
rlen = initblk.rlen >> 4;
|
||||
tlen = initblk.tlen >> 4;
|
||||
ladrf = initblk.ladrf;
|
||||
padr = initblk.padr;
|
||||
rdra = le32_to_cpu(initblk.rdra);
|
||||
tdra = le32_to_cpu(initblk.tdra);
|
||||
s->rdra = PHYSADDR(s,initblk.rdra);
|
||||
s->tdra = PHYSADDR(s,initblk.tdra);
|
||||
} else {
|
||||
struct pcnet_initblk16 initblk;
|
||||
PCNET_INIT();
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
|
||||
initblk.rlen, initblk.tlen);
|
||||
#endif
|
||||
s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
|
||||
(uint8_t *)&initblk, sizeof(initblk), 0);
|
||||
mode = initblk.mode;
|
||||
ladrf = initblk.ladrf;
|
||||
padr = initblk.padr;
|
||||
rdra = le32_to_cpu(initblk.rdra);
|
||||
tdra = le32_to_cpu(initblk.tdra);
|
||||
rlen = rdra >> 29;
|
||||
tlen = tdra >> 29;
|
||||
rdra &= 0x00ffffff;
|
||||
tdra &= 0x00ffffff;
|
||||
}
|
||||
|
||||
#undef PCNET_INIT
|
||||
|
||||
#if defined(PCNET_DEBUG)
|
||||
printf("rlen=%d tlen=%d\n",
|
||||
rlen, tlen);
|
||||
#endif
|
||||
CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
|
||||
CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
|
||||
s->csr[ 6] = (tlen << 12) | (rlen << 8);
|
||||
s->csr[15] = le16_to_cpu(mode);
|
||||
s->csr[ 8] = le16_to_cpu(ladrf[0]);
|
||||
s->csr[ 9] = le16_to_cpu(ladrf[1]);
|
||||
s->csr[10] = le16_to_cpu(ladrf[2]);
|
||||
s->csr[11] = le16_to_cpu(ladrf[3]);
|
||||
s->csr[12] = le16_to_cpu(padr[0]);
|
||||
s->csr[13] = le16_to_cpu(padr[1]);
|
||||
s->csr[14] = le16_to_cpu(padr[2]);
|
||||
s->rdra = PHYSADDR(s, rdra);
|
||||
s->tdra = PHYSADDR(s, tdra);
|
||||
|
||||
CSR_RCVRC(s) = CSR_RCVRL(s);
|
||||
CSR_XMTRC(s) = CSR_XMTRL(s);
|
||||
@@ -1035,7 +1091,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
|
||||
#define PCNET_RECV_STORE() do { \
|
||||
int count = MIN(4096 - rmd.rmd1.bcnt,size); \
|
||||
target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \
|
||||
cpu_physical_memory_write(rbadr, src, count); \
|
||||
s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
|
||||
src += count; size -= count; \
|
||||
rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
|
||||
RMDSTORE(&rmd, PHYSADDR(s,crda)); \
|
||||
@@ -1125,15 +1181,17 @@ static void pcnet_transmit(PCNetState *s)
|
||||
if (tmd.tmd1.stp) {
|
||||
s->xmit_pos = 0;
|
||||
if (!tmd.tmd1.enp) {
|
||||
cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
|
||||
s->buffer, 4096 - tmd.tmd1.bcnt);
|
||||
s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr),
|
||||
s->buffer, 4096 - tmd.tmd1.bcnt,
|
||||
CSR_BSWP(s));
|
||||
s->xmit_pos += 4096 - tmd.tmd1.bcnt;
|
||||
}
|
||||
xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
|
||||
}
|
||||
if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
|
||||
cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
|
||||
s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
|
||||
s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr),
|
||||
s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt,
|
||||
CSR_BSWP(s));
|
||||
s->xmit_pos += 4096 - tmd.tmd1.bcnt;
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_transmit size=%d\n", s->xmit_pos);
|
||||
@@ -1426,8 +1484,9 @@ static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_h_reset(PCNetState *s)
|
||||
void pcnet_h_reset(void *opaque)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
int i;
|
||||
uint16_t checksum;
|
||||
|
||||
@@ -1703,6 +1762,90 @@ static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
|
||||
}
|
||||
|
||||
|
||||
static void pcnet_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
unsigned int i;
|
||||
|
||||
if (s->pci_dev)
|
||||
pci_device_save(s->pci_dev, f);
|
||||
|
||||
qemu_put_be32s(f, &s->rap);
|
||||
qemu_put_be32s(f, &s->isr);
|
||||
qemu_put_be32s(f, &s->lnkst);
|
||||
qemu_put_be32s(f, &s->rdra);
|
||||
qemu_put_be32s(f, &s->tdra);
|
||||
qemu_put_buffer(f, s->prom, 16);
|
||||
for (i = 0; i < 128; i++)
|
||||
qemu_put_be16s(f, &s->csr[i]);
|
||||
for (i = 0; i < 32; i++)
|
||||
qemu_put_be16s(f, &s->bcr[i]);
|
||||
qemu_put_be64s(f, &s->timer);
|
||||
qemu_put_be32s(f, &s->xmit_pos);
|
||||
qemu_put_be32s(f, &s->recv_pos);
|
||||
qemu_put_buffer(f, s->buffer, 4096);
|
||||
qemu_put_be32s(f, &s->tx_busy);
|
||||
qemu_put_timer(f, s->poll_timer);
|
||||
}
|
||||
|
||||
static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
int i, ret;
|
||||
|
||||
if (version_id != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (s->pci_dev) {
|
||||
ret = pci_device_load(s->pci_dev, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_get_be32s(f, &s->rap);
|
||||
qemu_get_be32s(f, &s->isr);
|
||||
qemu_get_be32s(f, &s->lnkst);
|
||||
qemu_get_be32s(f, &s->rdra);
|
||||
qemu_get_be32s(f, &s->tdra);
|
||||
qemu_get_buffer(f, s->prom, 16);
|
||||
for (i = 0; i < 128; i++)
|
||||
qemu_get_be16s(f, &s->csr[i]);
|
||||
for (i = 0; i < 32; i++)
|
||||
qemu_get_be16s(f, &s->bcr[i]);
|
||||
qemu_get_be64s(f, &s->timer);
|
||||
qemu_get_be32s(f, &s->xmit_pos);
|
||||
qemu_get_be32s(f, &s->recv_pos);
|
||||
qemu_get_buffer(f, s->buffer, 4096);
|
||||
qemu_get_be32s(f, &s->tx_busy);
|
||||
qemu_get_timer(f, s->poll_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str)
|
||||
{
|
||||
d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
|
||||
|
||||
d->nd = nd;
|
||||
|
||||
d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
|
||||
pcnet_can_receive, d);
|
||||
|
||||
snprintf(d->vc->info_str, sizeof(d->vc->info_str),
|
||||
"pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
d->nd->macaddr[0],
|
||||
d->nd->macaddr[1],
|
||||
d->nd->macaddr[2],
|
||||
d->nd->macaddr[3],
|
||||
d->nd->macaddr[4],
|
||||
d->nd->macaddr[5]);
|
||||
|
||||
pcnet_h_reset(d);
|
||||
register_savevm("pcnet", 0, 2, pcnet_save, pcnet_load, d);
|
||||
}
|
||||
|
||||
/* PCI interface */
|
||||
|
||||
static CPUWriteMemoryFunc *pcnet_mmio_write[] = {
|
||||
(CPUWriteMemoryFunc *)&pcnet_mmio_writeb,
|
||||
(CPUWriteMemoryFunc *)&pcnet_mmio_writew,
|
||||
@@ -1724,10 +1867,29 @@ static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
|
||||
printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size);
|
||||
#endif
|
||||
|
||||
cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr);
|
||||
cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index);
|
||||
}
|
||||
|
||||
void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
|
||||
static void pcnet_pci_set_irq_cb(void *opaque, int isr)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
|
||||
pci_set_irq(&s->dev, 0, isr);
|
||||
}
|
||||
|
||||
static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int do_bswap)
|
||||
{
|
||||
cpu_physical_memory_write(addr, buf, len);
|
||||
}
|
||||
|
||||
static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int do_bswap)
|
||||
{
|
||||
cpu_physical_memory_read(addr, buf, len);
|
||||
}
|
||||
|
||||
void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
|
||||
{
|
||||
PCNetState *d;
|
||||
uint8_t *pci_conf;
|
||||
@@ -1738,7 +1900,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
|
||||
#endif
|
||||
|
||||
d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
|
||||
-1, NULL, NULL);
|
||||
devfn, NULL, NULL);
|
||||
|
||||
pci_conf = d->dev.config;
|
||||
|
||||
@@ -1760,7 +1922,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
|
||||
pci_conf[0x3f] = 0xff;
|
||||
|
||||
/* Handler for memory-mapped I/O */
|
||||
d->mmio_io_addr =
|
||||
d->mmio_index =
|
||||
cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
|
||||
|
||||
pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
|
||||
@@ -1769,21 +1931,58 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
|
||||
pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
|
||||
PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
|
||||
|
||||
d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
|
||||
d->set_irq_cb = pcnet_pci_set_irq_cb;
|
||||
d->phys_mem_read = pci_physical_memory_read;
|
||||
d->phys_mem_write = pci_physical_memory_write;
|
||||
d->pci_dev = &d->dev;
|
||||
|
||||
d->nd = nd;
|
||||
|
||||
d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
|
||||
pcnet_can_receive, d);
|
||||
|
||||
snprintf(d->vc->info_str, sizeof(d->vc->info_str),
|
||||
"pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
d->nd->macaddr[0],
|
||||
d->nd->macaddr[1],
|
||||
d->nd->macaddr[2],
|
||||
d->nd->macaddr[3],
|
||||
d->nd->macaddr[4],
|
||||
d->nd->macaddr[5]);
|
||||
|
||||
pcnet_h_reset(d);
|
||||
pcnet_common_init(d, nd, "pcnet");
|
||||
}
|
||||
|
||||
/* SPARC32 interface */
|
||||
|
||||
#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure
|
||||
|
||||
static CPUReadMemoryFunc *lance_mem_read[3] = {
|
||||
(CPUReadMemoryFunc *)&pcnet_ioport_readw,
|
||||
(CPUReadMemoryFunc *)&pcnet_ioport_readw,
|
||||
(CPUReadMemoryFunc *)&pcnet_ioport_readw,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *lance_mem_write[3] = {
|
||||
(CPUWriteMemoryFunc *)&pcnet_ioport_writew,
|
||||
(CPUWriteMemoryFunc *)&pcnet_ioport_writew,
|
||||
(CPUWriteMemoryFunc *)&pcnet_ioport_writew,
|
||||
};
|
||||
|
||||
static void pcnet_sparc_set_irq_cb(void *opaque, int isr)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
|
||||
ledma_set_irq(s->dma_opaque, isr);
|
||||
}
|
||||
|
||||
void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque)
|
||||
{
|
||||
PCNetState *d;
|
||||
int lance_io_memory;
|
||||
|
||||
d = qemu_mallocz(sizeof(PCNetState));
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
lance_io_memory =
|
||||
cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
|
||||
|
||||
d->dma_opaque = dma_opaque;
|
||||
cpu_register_physical_memory(leaddr, 4, lance_io_memory);
|
||||
|
||||
d->set_irq_cb = pcnet_sparc_set_irq_cb;
|
||||
d->phys_mem_read = ledma_memory_read;
|
||||
d->phys_mem_write = ledma_memory_write;
|
||||
|
||||
pcnet_common_init(d, nd, "lance");
|
||||
|
||||
return d;
|
||||
}
|
||||
#endif /* TARGET_SPARC */
|
||||
@@ -135,7 +135,6 @@ static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
|
||||
#else
|
||||
ret = p[offset];
|
||||
ret |= p[offset + 1] << 8;
|
||||
ret |= p[offset + 1] << 8;
|
||||
ret |= p[offset + 2] << 16;
|
||||
ret |= p[offset + 3] << 24;
|
||||
#endif
|
||||
|
||||
+232
-267
@@ -40,16 +40,129 @@ static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
|
||||
return s->config_reg;
|
||||
}
|
||||
|
||||
static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level);
|
||||
static void piix3_set_irq(void *pic, int irq_num, int level);
|
||||
|
||||
PCIBus *i440fx_init(void)
|
||||
/* return the global irq number corresponding to a given device irq
|
||||
pin. We could also use the bus number to have a more precise
|
||||
mapping. */
|
||||
static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
int slot_addend;
|
||||
slot_addend = (pci_dev->devfn >> 3) - 1;
|
||||
return (irq_num + slot_addend) & 3;
|
||||
}
|
||||
|
||||
static uint32_t isa_page_descs[384 / 4];
|
||||
static uint8_t smm_enabled;
|
||||
|
||||
static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
|
||||
{
|
||||
uint32_t addr;
|
||||
|
||||
// printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
|
||||
switch(r) {
|
||||
case 3:
|
||||
/* RAM */
|
||||
cpu_register_physical_memory(start, end - start,
|
||||
start);
|
||||
break;
|
||||
case 1:
|
||||
/* ROM (XXX: not quite correct) */
|
||||
cpu_register_physical_memory(start, end - start,
|
||||
start | IO_MEM_ROM);
|
||||
break;
|
||||
case 2:
|
||||
case 0:
|
||||
/* XXX: should distinguish read/write cases */
|
||||
for(addr = start; addr < end; addr += 4096) {
|
||||
cpu_register_physical_memory(addr, 4096,
|
||||
isa_page_descs[(addr - 0xa0000) >> 12]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void i440fx_update_memory_mappings(PCIDevice *d)
|
||||
{
|
||||
int i, r;
|
||||
uint32_t smram, addr;
|
||||
|
||||
update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3);
|
||||
for(i = 0; i < 12; i++) {
|
||||
r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
|
||||
update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
|
||||
}
|
||||
smram = d->config[0x72];
|
||||
if ((smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
|
||||
cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
|
||||
} else {
|
||||
for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
|
||||
cpu_register_physical_memory(addr, 4096,
|
||||
isa_page_descs[(addr - 0xa0000) >> 12]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void i440fx_set_smm(PCIDevice *d, int val)
|
||||
{
|
||||
val = (val != 0);
|
||||
if (smm_enabled != val) {
|
||||
smm_enabled = val;
|
||||
i440fx_update_memory_mappings(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* XXX: suppress when better memory API. We make the assumption that
|
||||
no device (in particular the VGA) changes the memory mappings in
|
||||
the 0xa0000-0x100000 range */
|
||||
void i440fx_init_memory_mappings(PCIDevice *d)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 96; i++) {
|
||||
isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
|
||||
}
|
||||
}
|
||||
|
||||
static void i440fx_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
/* XXX: implement SMRAM.D_LOCK */
|
||||
pci_default_write_config(d, address, val, len);
|
||||
if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
|
||||
i440fx_update_memory_mappings(d);
|
||||
}
|
||||
|
||||
static void i440fx_save(QEMUFile* f, void *opaque)
|
||||
{
|
||||
PCIDevice *d = opaque;
|
||||
pci_device_save(d, f);
|
||||
qemu_put_8s(f, &smm_enabled);
|
||||
}
|
||||
|
||||
static int i440fx_load(QEMUFile* f, void *opaque, int version_id)
|
||||
{
|
||||
PCIDevice *d = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
ret = pci_device_load(d, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i440fx_update_memory_mappings(d);
|
||||
qemu_get_8s(f, &smm_enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PCIBus *i440fx_init(PCIDevice **pi440fx_state)
|
||||
{
|
||||
PCIBus *b;
|
||||
PCIDevice *d;
|
||||
I440FXState *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(I440FXState));
|
||||
b = pci_register_bus(piix3_set_irq, NULL, 0);
|
||||
b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4);
|
||||
s->bus = b;
|
||||
|
||||
register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
|
||||
@@ -63,7 +176,7 @@ PCIBus *i440fx_init(void)
|
||||
register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
|
||||
|
||||
d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
|
||||
NULL, NULL);
|
||||
NULL, i440fx_write_config);
|
||||
|
||||
d->config[0x00] = 0x86; // vendor_id
|
||||
d->config[0x01] = 0x80;
|
||||
@@ -73,75 +186,41 @@ PCIBus *i440fx_init(void)
|
||||
d->config[0x0a] = 0x00; // class_sub = host2pci
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x00; // header_type
|
||||
|
||||
d->config[0x72] = 0x02; /* SMRAM */
|
||||
|
||||
register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d);
|
||||
*pi440fx_state = d;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* PIIX3 PCI to ISA bridge */
|
||||
|
||||
static PCIDevice *piix3_dev;
|
||||
PCIDevice *piix3_dev;
|
||||
PCIDevice *piix4_dev;
|
||||
|
||||
/* just used for simpler irq handling. */
|
||||
#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
|
||||
|
||||
static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
|
||||
static int pci_irq_levels[4];
|
||||
|
||||
/* return the global irq number corresponding to a given device irq
|
||||
pin. We could also use the bus number to have a more precise
|
||||
mapping. */
|
||||
static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
|
||||
static void piix3_set_irq(void *pic, int irq_num, int level)
|
||||
{
|
||||
int slot_addend;
|
||||
slot_addend = (pci_dev->devfn >> 3) - 1;
|
||||
return (irq_num + slot_addend) & 3;
|
||||
}
|
||||
int i, pic_irq, pic_level;
|
||||
|
||||
static inline int get_pci_irq_level(int irq_num)
|
||||
{
|
||||
int pic_level;
|
||||
#if (PCI_IRQ_WORDS == 2)
|
||||
pic_level = ((pci_irq_levels[irq_num][0] |
|
||||
pci_irq_levels[irq_num][1]) != 0);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
pic_level = 0;
|
||||
for(i = 0; i < PCI_IRQ_WORDS; i++) {
|
||||
if (pci_irq_levels[irq_num][i]) {
|
||||
pic_level = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return pic_level;
|
||||
}
|
||||
|
||||
static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level)
|
||||
{
|
||||
int irq_index, shift, pic_irq, pic_level;
|
||||
uint32_t *p;
|
||||
|
||||
irq_num = pci_slot_get_pirq(pci_dev, irq_num);
|
||||
irq_index = pci_dev->irq_index;
|
||||
p = &pci_irq_levels[irq_num][irq_index >> 5];
|
||||
shift = (irq_index & 0x1f);
|
||||
*p = (*p & ~(1 << shift)) | (level << shift);
|
||||
pci_irq_levels[irq_num] = level;
|
||||
|
||||
/* now we change the pic irq level according to the piix irq mappings */
|
||||
/* XXX: optimize */
|
||||
pic_irq = piix3_dev->config[0x60 + irq_num];
|
||||
if (pic_irq < 16) {
|
||||
/* the pic level is the logical OR of all the PCI irqs mapped
|
||||
/* The pic level is the logical OR of all the PCI irqs mapped
|
||||
to it */
|
||||
pic_level = 0;
|
||||
if (pic_irq == piix3_dev->config[0x60])
|
||||
pic_level |= get_pci_irq_level(0);
|
||||
if (pic_irq == piix3_dev->config[0x61])
|
||||
pic_level |= get_pci_irq_level(1);
|
||||
if (pic_irq == piix3_dev->config[0x62])
|
||||
pic_level |= get_pci_irq_level(2);
|
||||
if (pic_irq == piix3_dev->config[0x63])
|
||||
pic_level |= get_pci_irq_level(3);
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (pic_irq == piix3_dev->config[0x60 + i])
|
||||
pic_level |= pci_irq_levels[i];
|
||||
}
|
||||
pic_set_irq(pic_irq, pic_level);
|
||||
}
|
||||
}
|
||||
@@ -167,6 +246,42 @@ static void piix3_reset(PCIDevice *d)
|
||||
pci_conf[0x80] = 0x00;
|
||||
pci_conf[0x82] = 0x00;
|
||||
pci_conf[0xa0] = 0x08;
|
||||
pci_conf[0xa2] = 0x00;
|
||||
pci_conf[0xa3] = 0x00;
|
||||
pci_conf[0xa4] = 0x00;
|
||||
pci_conf[0xa5] = 0x00;
|
||||
pci_conf[0xa6] = 0x00;
|
||||
pci_conf[0xa7] = 0x00;
|
||||
pci_conf[0xa8] = 0x0f;
|
||||
pci_conf[0xaa] = 0x00;
|
||||
pci_conf[0xab] = 0x00;
|
||||
pci_conf[0xac] = 0x00;
|
||||
pci_conf[0xae] = 0x00;
|
||||
}
|
||||
|
||||
static void piix4_reset(PCIDevice *d)
|
||||
{
|
||||
uint8_t *pci_conf = d->config;
|
||||
|
||||
pci_conf[0x04] = 0x07; // master, memory and I/O
|
||||
pci_conf[0x05] = 0x00;
|
||||
pci_conf[0x06] = 0x00;
|
||||
pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
|
||||
pci_conf[0x4c] = 0x4d;
|
||||
pci_conf[0x4e] = 0x03;
|
||||
pci_conf[0x4f] = 0x00;
|
||||
pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
|
||||
pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
|
||||
pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
|
||||
pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
|
||||
pci_conf[0x69] = 0x02;
|
||||
pci_conf[0x70] = 0x80;
|
||||
pci_conf[0x76] = 0x0c;
|
||||
pci_conf[0x77] = 0x0c;
|
||||
pci_conf[0x78] = 0x02;
|
||||
pci_conf[0x79] = 0x00;
|
||||
pci_conf[0x80] = 0x00;
|
||||
pci_conf[0x82] = 0x00;
|
||||
pci_conf[0xa0] = 0x08;
|
||||
pci_conf[0xa2] = 0x00;
|
||||
pci_conf[0xa3] = 0x00;
|
||||
@@ -181,14 +296,53 @@ static void piix3_reset(PCIDevice *d)
|
||||
pci_conf[0xae] = 0x00;
|
||||
}
|
||||
|
||||
int piix3_init(PCIBus *bus)
|
||||
static void piix_save(QEMUFile* f, void *opaque)
|
||||
{
|
||||
PCIDevice *d = opaque;
|
||||
pci_device_save(d, f);
|
||||
}
|
||||
|
||||
static int piix_load(QEMUFile* f, void *opaque, int version_id)
|
||||
{
|
||||
PCIDevice *d = opaque;
|
||||
if (version_id != 2)
|
||||
return -EINVAL;
|
||||
return pci_device_load(d, f);
|
||||
}
|
||||
|
||||
int piix_init(PCIBus *bus, int devfn)
|
||||
{
|
||||
PCIDevice *d;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
d = pci_register_device(bus, "PIIX", sizeof(PCIDevice),
|
||||
devfn, NULL, NULL);
|
||||
register_savevm("PIIX", 0, 2, piix_save, piix_load, d);
|
||||
|
||||
piix3_dev = d;
|
||||
pci_conf = d->config;
|
||||
|
||||
pci_conf[0x00] = 0x86; // Intel
|
||||
pci_conf[0x01] = 0x80;
|
||||
pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge
|
||||
pci_conf[0x03] = 0x12;
|
||||
pci_conf[0x08] = 0x02; // Step A1
|
||||
pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
|
||||
pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
|
||||
|
||||
piix3_reset(d);
|
||||
return d->devfn;
|
||||
}
|
||||
|
||||
int piix3_init(PCIBus *bus, int devfn)
|
||||
{
|
||||
PCIDevice *d;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
|
||||
-1, NULL, NULL);
|
||||
register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
|
||||
devfn, NULL, NULL);
|
||||
register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
|
||||
|
||||
piix3_dev = d;
|
||||
pci_conf = d->config;
|
||||
@@ -205,215 +359,26 @@ int piix3_init(PCIBus *bus)
|
||||
return d->devfn;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* XXX: the following should be moved to the PC BIOS */
|
||||
|
||||
static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
|
||||
int piix4_init(PCIBus *bus, int devfn)
|
||||
{
|
||||
return cpu_inb(NULL, addr);
|
||||
PCIDevice *d;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice),
|
||||
devfn, NULL, NULL);
|
||||
register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
|
||||
|
||||
piix4_dev = d;
|
||||
pci_conf = d->config;
|
||||
|
||||
pci_conf[0x00] = 0x86; // Intel
|
||||
pci_conf[0x01] = 0x80;
|
||||
pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
|
||||
pci_conf[0x03] = 0x71;
|
||||
pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
|
||||
pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
|
||||
|
||||
piix4_reset(d);
|
||||
return d->devfn;
|
||||
}
|
||||
|
||||
static void isa_outb(uint32_t val, uint32_t addr)
|
||||
{
|
||||
cpu_outb(NULL, addr, val);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
|
||||
{
|
||||
return cpu_inw(NULL, addr);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
|
||||
{
|
||||
cpu_outw(NULL, addr, val);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
|
||||
{
|
||||
return cpu_inl(NULL, addr);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
|
||||
{
|
||||
cpu_outl(NULL, addr, val);
|
||||
}
|
||||
|
||||
static uint32_t pci_bios_io_addr;
|
||||
static uint32_t pci_bios_mem_addr;
|
||||
/* host irqs corresponding to PCI irqs A-D */
|
||||
static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
|
||||
|
||||
static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
pci_data_write(s, addr, val, 4);
|
||||
}
|
||||
|
||||
static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
pci_data_write(s, addr, val, 2);
|
||||
}
|
||||
|
||||
static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
pci_data_write(s, addr, val, 1);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
return pci_data_read(s, addr, 4);
|
||||
}
|
||||
|
||||
static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
return pci_data_read(s, addr, 2);
|
||||
}
|
||||
|
||||
static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
return pci_data_read(s, addr, 1);
|
||||
}
|
||||
|
||||
static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
|
||||
{
|
||||
PCIIORegion *r;
|
||||
uint16_t cmd;
|
||||
uint32_t ofs;
|
||||
|
||||
if ( region_num == PCI_ROM_SLOT ) {
|
||||
ofs = 0x30;
|
||||
}else{
|
||||
ofs = 0x10 + region_num * 4;
|
||||
}
|
||||
|
||||
pci_config_writel(d, ofs, addr);
|
||||
r = &d->io_regions[region_num];
|
||||
|
||||
/* enable memory mappings */
|
||||
cmd = pci_config_readw(d, PCI_COMMAND);
|
||||
if ( region_num == PCI_ROM_SLOT )
|
||||
cmd |= 2;
|
||||
else if (r->type & PCI_ADDRESS_SPACE_IO)
|
||||
cmd |= 1;
|
||||
else
|
||||
cmd |= 2;
|
||||
pci_config_writew(d, PCI_COMMAND, cmd);
|
||||
}
|
||||
|
||||
static void pci_bios_init_device(PCIDevice *d)
|
||||
{
|
||||
int class;
|
||||
PCIIORegion *r;
|
||||
uint32_t *paddr;
|
||||
int i, pin, pic_irq, vendor_id, device_id;
|
||||
|
||||
class = pci_config_readw(d, PCI_CLASS_DEVICE);
|
||||
vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
|
||||
device_id = pci_config_readw(d, PCI_DEVICE_ID);
|
||||
switch(class) {
|
||||
case 0x0101:
|
||||
if (vendor_id == 0x8086 && device_id == 0x7010) {
|
||||
/* PIIX3 IDE */
|
||||
pci_config_writew(d, 0x40, 0x8000); // enable IDE0
|
||||
pci_config_writew(d, 0x42, 0x8000); // enable IDE1
|
||||
goto default_map;
|
||||
} else {
|
||||
/* IDE: we map it as in ISA mode */
|
||||
pci_set_io_region_addr(d, 0, 0x1f0);
|
||||
pci_set_io_region_addr(d, 1, 0x3f4);
|
||||
pci_set_io_region_addr(d, 2, 0x170);
|
||||
pci_set_io_region_addr(d, 3, 0x374);
|
||||
}
|
||||
break;
|
||||
case 0x0300:
|
||||
if (vendor_id != 0x1234)
|
||||
goto default_map;
|
||||
/* VGA: map frame buffer to default Bochs VBE address */
|
||||
pci_set_io_region_addr(d, 0, 0xE0000000);
|
||||
break;
|
||||
case 0x0800:
|
||||
/* PIC */
|
||||
vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
|
||||
device_id = pci_config_readw(d, PCI_DEVICE_ID);
|
||||
if (vendor_id == 0x1014) {
|
||||
/* IBM */
|
||||
if (device_id == 0x0046 || device_id == 0xFFFF) {
|
||||
/* MPIC & MPIC2 */
|
||||
pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xff00:
|
||||
if (vendor_id == 0x0106b &&
|
||||
(device_id == 0x0017 || device_id == 0x0022)) {
|
||||
/* macio bridge */
|
||||
pci_set_io_region_addr(d, 0, 0x80800000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default_map:
|
||||
/* default memory mappings */
|
||||
for(i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||
r = &d->io_regions[i];
|
||||
if (r->size) {
|
||||
if (r->type & PCI_ADDRESS_SPACE_IO)
|
||||
paddr = &pci_bios_io_addr;
|
||||
else
|
||||
paddr = &pci_bios_mem_addr;
|
||||
*paddr = (*paddr + r->size - 1) & ~(r->size - 1);
|
||||
pci_set_io_region_addr(d, i, *paddr);
|
||||
*paddr += r->size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* map the interrupt */
|
||||
pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
|
||||
if (pin != 0) {
|
||||
pin = pci_slot_get_pirq(d, pin - 1);
|
||||
pic_irq = pci_irqs[pin];
|
||||
pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the PCI devices as a normal PCI BIOS
|
||||
* would do. It is provided just in case the BIOS has no support for
|
||||
* PCI.
|
||||
*/
|
||||
void pci_bios_init(void)
|
||||
{
|
||||
int i, irq;
|
||||
uint8_t elcr[2];
|
||||
|
||||
pci_bios_io_addr = 0xc000;
|
||||
pci_bios_mem_addr = 0xf0000000;
|
||||
|
||||
/* activate IRQ mappings */
|
||||
elcr[0] = 0x00;
|
||||
elcr[1] = 0x00;
|
||||
for(i = 0; i < 4; i++) {
|
||||
irq = pci_irqs[i];
|
||||
/* set to trigger level */
|
||||
elcr[irq >> 3] |= (1 << (irq & 7));
|
||||
/* activate irq remapping in PIIX */
|
||||
pci_config_writeb(piix3_dev, 0x60 + i, irq);
|
||||
}
|
||||
isa_outb(elcr[0], 0x4d0);
|
||||
isa_outb(elcr[1], 0x4d1);
|
||||
|
||||
pci_for_each_device(pci_bios_init_device);
|
||||
}
|
||||
|
||||
+2
-2
@@ -243,8 +243,8 @@ void pl011_init(uint32_t base, void *pic, int irq,
|
||||
s->cr = 0x300;
|
||||
s->flags = 0x90;
|
||||
if (chr){
|
||||
qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
|
||||
qemu_chr_add_event_handler(chr, pl011_event);
|
||||
qemu_chr_add_handlers(chr, pl011_can_recieve, pl011_recieve,
|
||||
pl011_event, s);
|
||||
}
|
||||
/* ??? Save/restore. */
|
||||
}
|
||||
|
||||
+24
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Arm PrimeCell PL080 DMA controller
|
||||
* Arm PrimeCell PL080/PL081 DMA controller
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define PL080_NUM_CHANNELS 8
|
||||
#define PL080_MAX_CHANNELS 8
|
||||
#define PL080_CONF_E 0x1
|
||||
#define PL080_CONF_M1 0x2
|
||||
#define PL080_CONF_M2 0x4
|
||||
@@ -45,7 +45,8 @@ typedef struct {
|
||||
uint32_t sync;
|
||||
uint32_t req_single;
|
||||
uint32_t req_burst;
|
||||
pl080_channel chan[PL080_NUM_CHANNELS];
|
||||
pl080_channel chan[PL080_MAX_CHANNELS];
|
||||
int nchannels;
|
||||
/* Flag to avoid recursive DMA invocations. */
|
||||
int running;
|
||||
void *pic;
|
||||
@@ -55,6 +56,9 @@ typedef struct {
|
||||
static const unsigned char pl080_id[] =
|
||||
{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
|
||||
|
||||
static const unsigned char pl081_id[] =
|
||||
{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
|
||||
|
||||
static void pl080_update(pl080_state *s)
|
||||
{
|
||||
if ((s->tc_int & s->tc_mask)
|
||||
@@ -80,7 +84,7 @@ static void pl080_run(pl080_state *s)
|
||||
uint32_t req;
|
||||
|
||||
s->tc_mask = 0;
|
||||
for (c = 0; c < PL080_NUM_CHANNELS; c++) {
|
||||
for (c = 0; c < s->nchannels; c++) {
|
||||
if (s->chan[c].conf & PL080_CCONF_ITC)
|
||||
s->tc_mask |= 1 << c;
|
||||
if (s->chan[c].conf & PL080_CCONF_IE)
|
||||
@@ -99,7 +103,7 @@ cpu_abort(cpu_single_env, "DMA active\n");
|
||||
}
|
||||
s->running = 1;
|
||||
while (s->running) {
|
||||
for (c = 0; c < PL080_NUM_CHANNELS; c++) {
|
||||
for (c = 0; c < s->nchannels; c++) {
|
||||
ch = &s->chan[c];
|
||||
again:
|
||||
/* Test if thiws channel has any pending DMA requests. */
|
||||
@@ -185,10 +189,16 @@ static uint32_t pl080_read(void *opaque, target_phys_addr_t offset)
|
||||
|
||||
offset -= s->base;
|
||||
if (offset >= 0xfe0 && offset < 0x1000) {
|
||||
return pl080_id[(offset - 0xfe0) >> 2];
|
||||
if (s->nchannels == 8) {
|
||||
return pl080_id[(offset - 0xfe0) >> 2];
|
||||
} else {
|
||||
return pl081_id[(offset - 0xfe0) >> 2];
|
||||
}
|
||||
}
|
||||
if (offset >= 0x100 && offset < 0x200) {
|
||||
i = (offset & 0xe0) >> 5;
|
||||
if (i >= s->nchannels)
|
||||
goto bad_offset;
|
||||
switch (offset >> 2) {
|
||||
case 0: /* SrcAddr */
|
||||
return s->chan[i].src;
|
||||
@@ -217,7 +227,7 @@ static uint32_t pl080_read(void *opaque, target_phys_addr_t offset)
|
||||
return s->err_int;
|
||||
case 7: /* EnbldChns */
|
||||
mask = 0;
|
||||
for (i = 0; i < PL080_NUM_CHANNELS; i++) {
|
||||
for (i = 0; i < s->nchannels; i++) {
|
||||
if (s->chan[i].conf & PL080_CCONF_E)
|
||||
mask |= 1 << i;
|
||||
}
|
||||
@@ -248,6 +258,8 @@ static void pl080_write(void *opaque, target_phys_addr_t offset,
|
||||
offset -= s->base;
|
||||
if (offset >= 0x100 && offset < 0x200) {
|
||||
i = (offset & 0xe0) >> 5;
|
||||
if (i >= s->nchannels)
|
||||
goto bad_offset;
|
||||
switch (offset >> 2) {
|
||||
case 0: /* SrcAddr */
|
||||
s->chan[i].src = value;
|
||||
@@ -293,6 +305,7 @@ static void pl080_write(void *opaque, target_phys_addr_t offset,
|
||||
s->sync = value;
|
||||
break;
|
||||
default:
|
||||
bad_offset:
|
||||
cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset);
|
||||
}
|
||||
pl080_update(s);
|
||||
@@ -310,7 +323,9 @@ static CPUWriteMemoryFunc *pl080_writefn[] = {
|
||||
pl080_write
|
||||
};
|
||||
|
||||
void *pl080_init(uint32_t base, void *pic, int irq)
|
||||
/* The PL080 and PL081 are the same except for the number of channels
|
||||
they implement (8 and 2 respectively). */
|
||||
void *pl080_init(uint32_t base, void *pic, int irq, int nchannels)
|
||||
{
|
||||
int iomemtype;
|
||||
pl080_state *s;
|
||||
@@ -322,6 +337,7 @@ void *pl080_init(uint32_t base, void *pic, int irq)
|
||||
s->base = base;
|
||||
s->pic = pic;
|
||||
s->irq = irq;
|
||||
s->nchannels = nchannels;
|
||||
/* ??? Save/restore. */
|
||||
return s;
|
||||
}
|
||||
|
||||
+3
-2
@@ -185,10 +185,11 @@ static void pl110_update_display(void *opaque)
|
||||
addr = base;
|
||||
|
||||
dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
|
||||
new_dirty = dirty;
|
||||
for (i = 0; i < s->rows; i++) {
|
||||
new_dirty = 0;
|
||||
if ((addr & TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
|
||||
if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
|
||||
uint32_t tmp;
|
||||
new_dirty = 0;
|
||||
for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) {
|
||||
new_dirty |= cpu_physical_memory_get_dirty(addr + tmp,
|
||||
VGA_DIRTY_FLAG);
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ static drawfn glue(pl110_draw_fn_,BITS)[18] =
|
||||
#endif
|
||||
|
||||
#define FN_2(x, y) FN(x, y) FN(x+1, y)
|
||||
#define FN_4(x, y) FN_2(x, y) FN_2(x+1, y)
|
||||
#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
|
||||
#define FN_8(y) FN_4(0, y) FN_4(4, y)
|
||||
|
||||
static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
|
||||
|
||||
@@ -201,64 +201,6 @@ void cpu_ppc_reset (CPUState *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
cpu_outb(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
value = bswap16(value);
|
||||
#endif
|
||||
cpu_outw(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
ret = bswap16(ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
value = bswap32(value);
|
||||
#endif
|
||||
cpu_outl(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
ret = bswap32(ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
CPUWriteMemoryFunc *PPC_io_write[] = {
|
||||
&PPC_io_writeb,
|
||||
&PPC_io_writew,
|
||||
&PPC_io_writel,
|
||||
};
|
||||
|
||||
CPUReadMemoryFunc *PPC_io_read[] = {
|
||||
&PPC_io_readb,
|
||||
&PPC_io_readw,
|
||||
&PPC_io_readl,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Debug port */
|
||||
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
|
||||
|
||||
+12
-14
@@ -305,7 +305,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
SetIRQFunc *set_irq;
|
||||
void *pic;
|
||||
m48t59_t *nvram;
|
||||
int PPC_io_memory, unin_memory;
|
||||
int unin_memory;
|
||||
int linux_boot, i;
|
||||
unsigned long bios_offset, vga_bios_offset;
|
||||
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
|
||||
@@ -417,16 +417,15 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
isa_mem_base = 0x80000000;
|
||||
|
||||
/* Register 2 MB of ISA IO space */
|
||||
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
|
||||
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
|
||||
|
||||
isa_mmio_init(0xfe000000, 0x00200000);
|
||||
|
||||
/* init basic PC hardware */
|
||||
pic = heathrow_pic_init(&heathrow_pic_mem_index);
|
||||
set_irq = heathrow_pic_set_irq;
|
||||
pci_bus = pci_grackle_init(0xfec00000, pic);
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
|
||||
ram_size, vga_ram_size,
|
||||
vga_bios_offset, vga_bios_size);
|
||||
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
|
||||
ram_size, vga_ram_size,
|
||||
vga_bios_offset, vga_bios_size);
|
||||
|
||||
/* XXX: suppress that */
|
||||
isa_pic = pic_init(pic_irq_request, NULL);
|
||||
@@ -437,7 +436,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
if (!nd_table[i].model)
|
||||
nd_table[i].model = "ne2k_pci";
|
||||
pci_nic_init(pci_bus, &nd_table[i]);
|
||||
pci_nic_init(pci_bus, &nd_table[i], -1);
|
||||
}
|
||||
|
||||
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
|
||||
@@ -463,8 +462,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
isa_mem_base = 0x80000000;
|
||||
|
||||
/* Register 8 MB of ISA IO space */
|
||||
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
|
||||
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
|
||||
isa_mmio_init(0xf2000000, 0x00800000);
|
||||
|
||||
/* UniN init */
|
||||
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
|
||||
@@ -474,9 +472,9 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
set_irq = openpic_set_irq;
|
||||
pci_bus = pci_pmac_init(pic);
|
||||
/* init basic PC hardware */
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
|
||||
ram_size, vga_ram_size,
|
||||
vga_bios_offset, vga_bios_size);
|
||||
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
|
||||
ram_size, vga_ram_size,
|
||||
vga_bios_offset, vga_bios_size);
|
||||
|
||||
/* XXX: suppress that */
|
||||
isa_pic = pic_init(pic_irq_request, NULL);
|
||||
@@ -485,7 +483,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
pci_ne2000_init(pci_bus, &nd_table[i]);
|
||||
pci_ne2000_init(pci_bus, &nd_table[i], -1);
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
+2
-3
@@ -525,7 +525,6 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
{
|
||||
CPUState *env;
|
||||
char buf[1024];
|
||||
SetIRQFunc *set_irq;
|
||||
m48t59_t *nvram;
|
||||
int PPC_io_memory;
|
||||
int linux_boot, i, nb_nics1, bios_size;
|
||||
@@ -612,8 +611,8 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
|
||||
|
||||
/* init basic PC hardware */
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
rtc_init(0x70, 8);
|
||||
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
|
||||
isa_pic = pic_init(pic_irq_request, first_cpu);
|
||||
|
||||
+9
-5
@@ -117,11 +117,15 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
|
||||
&PPC_PCIIO_readl,
|
||||
};
|
||||
|
||||
static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
/* Don't know if this matches real hardware, but it agrees with OHW. */
|
||||
static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
/* XXX: we do not simulate the hardware - we rely on the BIOS to
|
||||
set correctly for irq line field */
|
||||
pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
|
||||
return (irq_num + (pci_dev->devfn >> 3)) & 1;
|
||||
}
|
||||
|
||||
static void prep_set_irq(void *pic, int irq_num, int level)
|
||||
{
|
||||
pic_set_irq(irq_num ? 11 : 9, level);
|
||||
}
|
||||
|
||||
PCIBus *pci_prep_init(void)
|
||||
@@ -131,7 +135,7 @@ PCIBus *pci_prep_init(void)
|
||||
int PPC_io_memory;
|
||||
|
||||
s = qemu_mallocz(sizeof(PREPPCIState));
|
||||
s->bus = pci_register_bus(prep_set_irq, NULL, 0);
|
||||
s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0, 2);
|
||||
|
||||
register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
|
||||
register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
|
||||
|
||||
@@ -560,7 +560,7 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
|
||||
s->common.update_arg = update_arg;
|
||||
ps2_reset(&s->common);
|
||||
register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
|
||||
qemu_add_mouse_event_handler(ps2_mouse_event, s, 0);
|
||||
qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
|
||||
qemu_register_reset(ps2_reset, &s->common);
|
||||
return s;
|
||||
}
|
||||
Loaded 100 of 221 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user