Compare commits
1 Commits
v0.9.1
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bebe39c387 |
36
.cvsignore
36
.cvsignore
@@ -1,27 +1,29 @@
|
||||
arm-user
|
||||
arm-softmmu
|
||||
armeb-user
|
||||
config-host.*
|
||||
dyngen
|
||||
i386
|
||||
*-softmmu
|
||||
*-darwin-user
|
||||
*-linux-user
|
||||
i386-softmmu
|
||||
i386-user
|
||||
ppc-softmmu
|
||||
ppc64-softmmu
|
||||
ppc-user
|
||||
qemu-doc.html
|
||||
qemu-tech.html
|
||||
qemu-doc.info
|
||||
qemu-tech.info
|
||||
qemu.1
|
||||
qemu.pod
|
||||
qemu-img.1
|
||||
qemu-img.pod
|
||||
sparc-user
|
||||
qemu-img
|
||||
.gdbinit
|
||||
*.aux
|
||||
*.cp
|
||||
*.dvi
|
||||
*.fn
|
||||
*.ky
|
||||
*.log
|
||||
*.pg
|
||||
*.toc
|
||||
*.tp
|
||||
*.vr
|
||||
*.d
|
||||
sparc-softmmu
|
||||
x86_64-softmmu
|
||||
sparc64-user
|
||||
sparc64-softmmu
|
||||
mips-softmmu
|
||||
mipsel-softmmu
|
||||
mips-user
|
||||
mipsel-user
|
||||
sh4-user
|
||||
sh4-softmmu
|
||||
|
||||
81
Changelog
81
Changelog
@@ -1,66 +1,3 @@
|
||||
version 0.9.1:
|
||||
|
||||
- TFTP booting from host directory (Anthony Liguori, Erwan Velu)
|
||||
- Tap device emulation for Solaris (Sittichai Palanisong)
|
||||
- Monitor multiplexing to several I/O channels (Jason Wessel)
|
||||
- ds1225y nvram support (Herve Poussineau)
|
||||
- CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
|
||||
- Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif)
|
||||
- MIPS 64-bit FPU support (Thiemo Seufer)
|
||||
- Xscale PDA emulation (Andrzej Zaborowski)
|
||||
- ColdFire system emulation (Paul Brook)
|
||||
- Improved SH4 support (Magnus Damm)
|
||||
- MIPS64 support (Aurelien Jarno, Thiemo Seufer)
|
||||
- Preliminary Alpha guest support (J. Mayer)
|
||||
- Read-only support for Parallels disk images (Alex Beregszaszi)
|
||||
- SVM (x86 virtualization) support (Alexander Graf)
|
||||
- CRIS emulation (Edgar E. Iglesias)
|
||||
- SPARC32PLUS execution support (Blue Swirl)
|
||||
- MIPS mipssim pseudo machine (Thiemo Seufer)
|
||||
- Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
|
||||
- OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
|
||||
- ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery)
|
||||
- Gumstix boards: connex and verdex emulation (Thorsten Zitterell)
|
||||
- Intel mainstone II board emulation (Armin Kuster)
|
||||
- VMware SVGA II graphics card support (Andrzej Zaborowski)
|
||||
|
||||
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
|
||||
- PC VGA BIOS fixes
|
||||
- switch to OpenBios for SPARC targets (Blue Swirl)
|
||||
- VNC server fixes
|
||||
- MIPS FPU support (Marius Groeger)
|
||||
- Solaris/SPARC host support (Juergen Keil)
|
||||
- PPC breakpoints and single stepping (Jason Wessel)
|
||||
- USB updates (Paul Brook)
|
||||
- UDP/TCP/telnet character devices (Jason Wessel)
|
||||
- Windows sparse file support (Frediano Ziglio)
|
||||
- RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
|
||||
- PCNET NIC support (Antony T Curtis)
|
||||
- Support for variable frequency host CPUs
|
||||
- Workaround for win32 SMP hosts
|
||||
- Support for AMD Flash memories (Jocelyn Mayer)
|
||||
- Audio capture to WAV files support (malc)
|
||||
|
||||
version 0.8.1:
|
||||
|
||||
- USB tablet support (Brad Campbell, Anthony Liguori)
|
||||
@@ -68,7 +5,7 @@ version 0.8.1:
|
||||
- PC speaker support (Joachim Henke)
|
||||
- IDE LBA48 support (Jens Axboe)
|
||||
- SSE3 support
|
||||
- Solaris port (Juergen Keil)
|
||||
- Solaris port (Ben Taylor)
|
||||
- Preliminary SH4 target (Samuel Tardieu)
|
||||
- VNC server (Anthony Liguori)
|
||||
- slirp fixes (Ed Swierk et al.)
|
||||
@@ -98,7 +35,7 @@ version 0.8.0:
|
||||
(Johannes Schindelin)
|
||||
|
||||
version 0.7.2:
|
||||
|
||||
|
||||
- x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
|
||||
- merge self modifying code handling in dirty ram page mecanism.
|
||||
- MIPS fixes (Ralf Baechle)
|
||||
@@ -147,7 +84,7 @@ version 0.6.1:
|
||||
- Mac OS X port (Pierre d'Herbemont)
|
||||
- Virtual console support
|
||||
- Better monitor line edition
|
||||
- New block device layer
|
||||
- New block device layer
|
||||
- New 'qcow' growable disk image support with AES encryption and
|
||||
transparent decompression
|
||||
- VMware 3 and 4 read-only disk image support (untested)
|
||||
@@ -213,7 +150,7 @@ version 0.5.5:
|
||||
- FDC fixes for Win98
|
||||
|
||||
version 0.5.4:
|
||||
|
||||
|
||||
- qemu-fast fixes
|
||||
- BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
|
||||
- keyboard/mouse fix (Mike Nordell)
|
||||
@@ -240,7 +177,7 @@ version 0.5.3:
|
||||
- added accurate CR0.MP/ME/TS emulation
|
||||
- fixed DMA memory write access (Win95 boot floppy fix)
|
||||
- graphical x86 linux loader
|
||||
- command line monitor
|
||||
- command line monitor
|
||||
- generic removable device support
|
||||
- support of CD-ROM change
|
||||
- multiple network interface support
|
||||
@@ -278,7 +215,7 @@ version 0.5.2:
|
||||
- eflags optimisation fix for string operations
|
||||
|
||||
version 0.5.1:
|
||||
|
||||
|
||||
- float access fixes when using soft mmu
|
||||
- PC emulation support on PowerPC
|
||||
- A20 support
|
||||
@@ -293,7 +230,7 @@ version 0.5.1:
|
||||
- Major SPARC target fixes (dynamically linked programs begin to work)
|
||||
|
||||
version 0.5.0:
|
||||
|
||||
|
||||
- full hardware level VGA emulation
|
||||
- graphical display with SDL
|
||||
- added PS/2 mouse and keyboard emulation
|
||||
@@ -331,7 +268,7 @@ version 0.4.2:
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
|
||||
- more accurate timer support in vl.
|
||||
- more reliable NE2000 probe in vl.
|
||||
- added 2.5.66 kernel in vl-test.
|
||||
@@ -417,7 +354,7 @@ version 0.1.3:
|
||||
- added bound, cmpxchg8b, cpuid instructions
|
||||
- added 16 bit addressing support/override for string operations
|
||||
- poll() fix
|
||||
|
||||
|
||||
version 0.1.2:
|
||||
|
||||
- compile fixes
|
||||
|
||||
15
LICENSE
15
LICENSE
@@ -1,14 +1,11 @@
|
||||
The following points clarify the QEMU license:
|
||||
The following points clarify the QEMU licenses:
|
||||
|
||||
1) QEMU as a whole is released under the GNU General Public 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.
|
||||
|
||||
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.
|
||||
2) The Linux user mode QEMU emulator is released under the GNU General
|
||||
Public License.
|
||||
|
||||
3) QEMU is a trademark of Fabrice Bellard.
|
||||
|
||||
|
||||
197
Makefile
197
Makefile
@@ -1,23 +1,15 @@
|
||||
# Makefile for QEMU.
|
||||
|
||||
include config-host.mak
|
||||
|
||||
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
|
||||
speed test html dvi info
|
||||
|
||||
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
|
||||
|
||||
BASE_CFLAGS=
|
||||
BASE_LDFLAGS=
|
||||
|
||||
BASE_CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS)
|
||||
BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS)
|
||||
|
||||
CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP
|
||||
CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I.
|
||||
ifdef CONFIG_DARWIN
|
||||
CFLAGS+= -mdynamic-no-pic
|
||||
endif
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
TOOLS=qemu-img$(EXESUF)
|
||||
ifdef CONFIG_STATIC
|
||||
BASE_LDFLAGS += -static
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
ifdef BUILD_DOCS
|
||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
|
||||
@@ -25,128 +17,21 @@ else
|
||||
DOCS=
|
||||
endif
|
||||
|
||||
LIBS+=$(AIOLIBS)
|
||||
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
|
||||
all: $(TOOLS) $(DOCS) recurse-all
|
||||
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)
|
||||
|
||||
subdir-%: dyngen$(EXESUF) libqemu_common.a
|
||||
$(MAKE) -C $(subst subdir-,,$@) all
|
||||
|
||||
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
|
||||
#######################################################################
|
||||
# BLOCK_OBJS is code used by both qemu system emulation and qemu-img
|
||||
|
||||
BLOCK_OBJS=cutils.o
|
||||
BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
|
||||
BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
|
||||
BLOCK_OBJS+=block-qcow2.o block-parallels.o
|
||||
|
||||
######################################################################
|
||||
# libqemu_common.a: Target indepedent part of system emulation. The
|
||||
# long term path is to suppress *all* target specific code in case of
|
||||
# system emulation, i.e. a single QEMU executable should support all
|
||||
# CPUs and machines.
|
||||
|
||||
OBJS=$(BLOCK_OBJS)
|
||||
OBJS+=readline.o console.o
|
||||
OBJS+=block.o
|
||||
|
||||
OBJS+=irq.o
|
||||
OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
|
||||
OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o
|
||||
OBJS+=scsi-disk.o cdrom.o
|
||||
OBJS+=scsi-generic.o
|
||||
OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o
|
||||
OBJS+=sd.o ssi-sd.o
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
OBJS+=tap-win32.o
|
||||
endif
|
||||
|
||||
AUDIO_OBJS = audio.o noaudio.o wavaudio.o mixeng.o
|
||||
ifdef CONFIG_SDL
|
||||
AUDIO_OBJS += sdlaudio.o
|
||||
endif
|
||||
ifdef CONFIG_OSS
|
||||
AUDIO_OBJS += ossaudio.o
|
||||
endif
|
||||
ifdef CONFIG_COREAUDIO
|
||||
AUDIO_OBJS += coreaudio.o
|
||||
endif
|
||||
ifdef CONFIG_ALSA
|
||||
AUDIO_OBJS += alsaaudio.o
|
||||
endif
|
||||
ifdef CONFIG_DSOUND
|
||||
AUDIO_OBJS += dsoundaudio.o
|
||||
endif
|
||||
ifdef CONFIG_FMOD
|
||||
AUDIO_OBJS += fmodaudio.o
|
||||
audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
|
||||
endif
|
||||
AUDIO_OBJS+= wavcapture.o
|
||||
OBJS+=$(addprefix audio/, $(AUDIO_OBJS))
|
||||
|
||||
ifdef CONFIG_SDL
|
||||
OBJS+=sdl.o x_keymap.o
|
||||
endif
|
||||
OBJS+=vnc.o d3des.o
|
||||
|
||||
ifdef CONFIG_COCOA
|
||||
OBJS+=cocoa.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_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
|
||||
OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
|
||||
endif
|
||||
|
||||
cocoa.o: cocoa.m
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
sdl.o: sdl.c keymaps.c sdl_keysym.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $<
|
||||
|
||||
audio/sdlaudio.o: audio/sdlaudio.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
libqemu_common.a: $(OBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
|
||||
QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS)
|
||||
ifdef CONFIG_WIN32
|
||||
QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o
|
||||
else
|
||||
QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o qemu-img-block.o $(QEMU_IMG_BLOCK_OBJS)
|
||||
$(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
|
||||
|
||||
qemu-img-%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
|
||||
# dyngen host tool
|
||||
dyngen$(EXESUF): dyngen.c
|
||||
$(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
|
||||
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
|
||||
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.d *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~
|
||||
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d
|
||||
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
|
||||
$(MAKE) -C tests clean
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
@@ -154,7 +39,6 @@ clean:
|
||||
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h $(DOCS)
|
||||
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
@@ -173,13 +57,10 @@ endif
|
||||
|
||||
install: all $(if $(BUILD_DOCS),install-doc)
|
||||
mkdir -p "$(DESTDIR)$(bindir)"
|
||||
ifneq ($(TOOLS),)
|
||||
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
endif
|
||||
mkdir -p "$(DESTDIR)$(datadir)"
|
||||
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
|
||||
video.x openbios-sparc32 pxe-ne2k_pci.bin \
|
||||
pxe-rtl8139.bin pxe-pcnet.bin; do \
|
||||
video.x proll.elf linux_boot.bin; do \
|
||||
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
|
||||
done
|
||||
ifndef CONFIG_WIN32
|
||||
@@ -193,10 +74,10 @@ endif
|
||||
done
|
||||
|
||||
# various test targets
|
||||
test speed: all
|
||||
test speed test2: all
|
||||
$(MAKE) -C tests $@
|
||||
|
||||
TAGS:
|
||||
TAGS:
|
||||
etags *.[ch] tests/*.[ch]
|
||||
|
||||
cscope:
|
||||
@@ -222,14 +103,7 @@ qemu-img.1: qemu-img.texi
|
||||
$(SRC_PATH)/texi2pod.pl $< qemu-img.pod
|
||||
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
|
||||
|
||||
info: qemu-doc.info qemu-tech.info
|
||||
|
||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
||||
|
||||
html: qemu-doc.html qemu-tech.html
|
||||
|
||||
VERSION ?= $(shell cat VERSION)
|
||||
FILE = qemu-$(VERSION)
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
tar:
|
||||
@@ -240,49 +114,29 @@ tar:
|
||||
|
||||
# generate a binary distribution
|
||||
tarbin:
|
||||
( cd / ; tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
|
||||
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
|
||||
$(bindir)/qemu \
|
||||
$(bindir)/qemu-system-ppc \
|
||||
$(bindir)/qemu-system-ppc64 \
|
||||
$(bindir)/qemu-system-ppcemb \
|
||||
$(bindir)/qemu-system-sparc \
|
||||
$(bindir)/qemu-system-x86_64 \
|
||||
$(bindir)/qemu-system-mips \
|
||||
$(bindir)/qemu-system-mipsel \
|
||||
$(bindir)/qemu-system-mips64 \
|
||||
$(bindir)/qemu-system-mips64el \
|
||||
$(bindir)/qemu-system-arm \
|
||||
$(bindir)/qemu-system-m68k \
|
||||
$(bindir)/qemu-system-sh4 \
|
||||
$(bindir)/qemu-system-sh4eb \
|
||||
$(bindir)/qemu-system-cris \
|
||||
$(bindir)/qemu-i386 \
|
||||
$(bindir)/qemu-x86_64 \
|
||||
$(bindir)/qemu-arm \
|
||||
$(bindir)/qemu-armeb \
|
||||
$(bindir)/qemu-sparc \
|
||||
$(bindir)/qemu-sparc32plus \
|
||||
$(bindir)/qemu-sparc64 \
|
||||
$(bindir)/qemu-ppc \
|
||||
$(bindir)/qemu-ppc64 \
|
||||
$(bindir)/qemu-ppc64abi32 \
|
||||
$(bindir)/qemu-mips \
|
||||
$(bindir)/qemu-mipsel \
|
||||
$(bindir)/qemu-alpha \
|
||||
$(bindir)/qemu-m68k \
|
||||
$(bindir)/qemu-sh4 \
|
||||
$(bindir)/qemu-sh4eb \
|
||||
$(bindir)/qemu-cris \
|
||||
$(bindir)/qemu-img \
|
||||
$(datadir)/bios.bin \
|
||||
$(datadir)/vgabios.bin \
|
||||
$(datadir)/vgabios-cirrus.bin \
|
||||
$(datadir)/ppc_rom.bin \
|
||||
$(datadir)/video.x \
|
||||
$(datadir)/openbios-sparc32 \
|
||||
$(datadir)/pxe-ne2k_pci.bin \
|
||||
$(datadir)/pxe-rtl8139.bin \
|
||||
$(datadir)/pxe-pcnet.bin \
|
||||
$(datadir)/proll.elf \
|
||||
$(datadir)/linux_boot.bin \
|
||||
$(docdir)/qemu-doc.html \
|
||||
$(docdir)/qemu-tech.html \
|
||||
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
|
||||
@@ -290,6 +144,3 @@ tarbin:
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
# Include automatically generated dependency files
|
||||
-include $(wildcard *.d audio/*.d slirp/*.d)
|
||||
|
||||
499
Makefile.target
499
Makefile.target
@@ -4,73 +4,37 @@ TARGET_BASE_ARCH:=$(TARGET_ARCH)
|
||||
ifeq ($(TARGET_ARCH), x86_64)
|
||||
TARGET_BASE_ARCH:=i386
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), mipsn32)
|
||||
TARGET_BASE_ARCH:=mips
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), mips64)
|
||||
TARGET_BASE_ARCH:=mips
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), ppc64)
|
||||
TARGET_BASE_ARCH:=ppc
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), ppc64h)
|
||||
TARGET_BASE_ARCH:=ppc
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), ppcemb)
|
||||
TARGET_BASE_ARCH:=ppc
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
TARGET_BASE_ARCH:=sparc
|
||||
endif
|
||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
|
||||
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
|
||||
CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MP -DNEED_CPU_H
|
||||
ifdef CONFIG_DARWIN_USER
|
||||
VPATH+=:$(SRC_PATH)/darwin-user
|
||||
CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
|
||||
endif
|
||||
ifdef CONFIG_LINUX_USER
|
||||
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
|
||||
ifndef TARGET_ABI_DIR
|
||||
TARGET_ABI_DIR=$(TARGET_ARCH)
|
||||
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
|
||||
endif
|
||||
CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
|
||||
endif
|
||||
BASE_CFLAGS=
|
||||
BASE_LDFLAGS=
|
||||
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
|
||||
#CFLAGS+=-Werror
|
||||
LDFLAGS=-g
|
||||
LIBS=
|
||||
HELPER_CFLAGS=$(CFLAGS)
|
||||
DYNGEN=../dyngen$(EXESUF)
|
||||
# user emulator name
|
||||
ifndef TARGET_ARCH2
|
||||
TARGET_ARCH2=$(TARGET_ARCH)
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
|
||||
TARGET_ARCH2=armeb
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH),sh4)
|
||||
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
|
||||
TARGET_ARCH2=sh4eb
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH),mips)
|
||||
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
|
||||
TARGET_ARCH2=mipsel
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH),mipsn32)
|
||||
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
|
||||
TARGET_ARCH2=mipsn32el
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH),mips64)
|
||||
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
|
||||
TARGET_ARCH2=mips64el
|
||||
endif
|
||||
endif
|
||||
QEMU_USER=qemu-$(TARGET_ARCH2)
|
||||
# system emulator name
|
||||
ifdef CONFIG_SOFTMMU
|
||||
@@ -93,31 +57,18 @@ endif
|
||||
endif # !CONFIG_USER_ONLY
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
BASE_LDFLAGS+=-static
|
||||
LDFLAGS+=-static
|
||||
endif
|
||||
|
||||
# We require -O2 to avoid the stack setup prologue in EXIT_TB
|
||||
OP_CFLAGS := -Wall -O2 -g -fno-strict-aliasing
|
||||
|
||||
# cc-option
|
||||
# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
|
||||
|
||||
cc-option = $(shell if $(CC) $(OP_CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
|
||||
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
|
||||
|
||||
OP_CFLAGS+=$(call cc-option, -fno-reorder-blocks, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-gcse, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-tree-ch, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-optimize-sibling-calls, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-align-labels, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-align-jumps, "")
|
||||
OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, -malign-functions=0, ""))
|
||||
OP_CFLAGS+=$(call cc-option, -fno-section-anchors, "")
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
HELPER_CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
|
||||
CFLAGS+=-fomit-frame-pointer
|
||||
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
|
||||
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
|
||||
@@ -125,113 +76,84 @@ ifdef CONFIG_STATIC
|
||||
USE_I386_LD=y
|
||||
endif
|
||||
ifdef USE_I386_LD
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.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!
|
||||
BASE_LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
ifneq ($(CONFIG_SOLARIS),yes)
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
OP_CFLAGS=$(CFLAGS) -falign-functions=0
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ppc)
|
||||
CPPFLAGS+= -D__powerpc__
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
CFLAGS+= -D__powerpc__
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),s390)
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc)
|
||||
BASE_CFLAGS+=-ffixed-g2 -ffixed-g3
|
||||
OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
|
||||
ifeq ($(CONFIG_SOLARIS),yes)
|
||||
OP_CFLAGS+=-fno-omit-frame-pointer
|
||||
else
|
||||
BASE_CFLAGS+=-ffixed-g1 -ffixed-g6
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
|
||||
endif
|
||||
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m32
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
|
||||
# -static is used to avoid g1/g3 usage by the dynamic linker
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
BASE_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
|
||||
OP_CFLAGS+=-mcpu=ultrasparc -m64 -fno-delayed-branch -ffixed-i0
|
||||
ifneq ($(CONFIG_SOLARIS),yes)
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
OP_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
|
||||
endif
|
||||
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
|
||||
LDFLAGS+=-m64
|
||||
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),alpha)
|
||||
# -msmall-data is not used for OP_CFLAGS because we want two-instruction
|
||||
# relocations for the constant constructions
|
||||
# -msmall-data is not used because we want two-instruction relocations
|
||||
# for the constant constructions
|
||||
OP_CFLAGS=-Wall -O2 -g
|
||||
# Ensure there's only a single GP
|
||||
BASE_CFLAGS+=-msmall-data
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
CFLAGS += -msmall-data
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),ia64)
|
||||
BASE_CFLAGS+=-mno-sdata
|
||||
OP_CFLAGS+=-mno-sdata
|
||||
BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
CFLAGS += -mno-sdata
|
||||
OP_CFLAGS=$(CFLAGS)
|
||||
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),m68k)
|
||||
OP_CFLAGS+=-fomit-frame-pointer
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
|
||||
LDFLAGS+=-Wl,-T,m68k.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),mips)
|
||||
OP_CFLAGS+=-mabi=32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0
|
||||
ifeq ($(WORDS_BIGENDIAN),yes)
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
else
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),mips64)
|
||||
OP_CFLAGS+=-mabi=n32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0
|
||||
ifeq ($(WORDS_BIGENDIAN),yes)
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
else
|
||||
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
|
||||
endif
|
||||
ifeq ($(HAVE_GCC3_OPTIONS),yes)
|
||||
# very important to generate a return at the end of every operation
|
||||
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
BASE_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS)
|
||||
BASE_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS)
|
||||
OP_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS)
|
||||
OP_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS)
|
||||
|
||||
#########################################################
|
||||
|
||||
CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
LIBS+=-lm
|
||||
ifndef CONFIG_USER_ONLY
|
||||
LIBS+=-lz
|
||||
@@ -241,32 +163,15 @@ LIBS+=-lwinmm -lws2_32 -liphlpapi
|
||||
endif
|
||||
ifdef CONFIG_SOLARIS
|
||||
LIBS+=-lsocket -lnsl -lresolv
|
||||
ifdef NEEDS_LIBSUNMATH
|
||||
LIBS+=-lsunmath
|
||||
LDFLAGS+=-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib
|
||||
OP_CFLAGS+=-I/opt/SUNWspro/prod/include/cc
|
||||
BASE_CFLAGS+=-I/opt/SUNWspro/prod/include/cc
|
||||
endif
|
||||
endif
|
||||
|
||||
# profiling code
|
||||
ifdef TARGET_GPROF
|
||||
BASE_LDFLAGS+=-p
|
||||
main.o: BASE_CFLAGS+=-p
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \
|
||||
elfload.o linuxload.o uaccess.o
|
||||
LIBS+= $(AIOLIBS)
|
||||
ifdef TARGET_HAS_BFLT
|
||||
OBJS+= flatload.o
|
||||
endif
|
||||
ifdef TARGET_HAS_ELFLOAD32
|
||||
OBJS+= elfload32.o
|
||||
elfload32.o: elfload.c
|
||||
LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
OBJS+= vm86.o
|
||||
endif
|
||||
@@ -275,30 +180,24 @@ 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
|
||||
|
||||
# cpu emulator library
|
||||
LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\
|
||||
translate.o op.o host-utils.o
|
||||
translate.o op.o
|
||||
ifdef CONFIG_SOFTFLOAT
|
||||
LIBOBJS+=fpu/softfloat.o
|
||||
else
|
||||
LIBOBJS+=fpu/softfloat-native.o
|
||||
endif
|
||||
CPPFLAGS+=-I$(SRC_PATH)/fpu
|
||||
DEFINES+=-I$(SRC_PATH)/fpu
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=helper.o helper2.o
|
||||
ifeq ($(ARCH), i386)
|
||||
LIBOBJS+=translate-copy.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), x86_64)
|
||||
@@ -309,7 +208,7 @@ ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), mips)
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
@@ -325,25 +224,8 @@ ifeq ($(TARGET_BASE_ARCH), sh4)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), m68k)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), alpha)
|
||||
LIBOBJS+= op_helper.o helper.o alpha_palcode.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), cris)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
LIBOBJS+= cris-dis.o
|
||||
|
||||
ifndef CONFIG_USER_ONLY
|
||||
LIBOBJS+= mmu.o
|
||||
endif
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
LIBOBJS+=disas.o
|
||||
LIBOBJS+=disas.o
|
||||
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
||||
USE_I386_DIS=y
|
||||
endif
|
||||
@@ -359,7 +241,7 @@ endif
|
||||
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips)
|
||||
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
|
||||
LIBOBJS+=mips-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
|
||||
@@ -374,9 +256,6 @@ endif
|
||||
ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
|
||||
LIBOBJS+=sh4-dis.o
|
||||
endif
|
||||
ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390)
|
||||
LIBOBJS+=s390-dis.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_GDBSTUB
|
||||
OBJS+=gdbstub.o
|
||||
@@ -385,7 +264,7 @@ endif
|
||||
all: $(PROGS)
|
||||
|
||||
$(QEMU_USER): $(OBJS)
|
||||
$(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
ifeq ($(ARCH),alpha)
|
||||
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
|
||||
# the address space (31 bit so sign extending doesn't matter)
|
||||
@@ -393,156 +272,119 @@ ifeq ($(ARCH),alpha)
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
VL_OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o
|
||||
# XXX: suppress QEMU_TOOL tests
|
||||
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
|
||||
ifdef CONFIG_WIN32
|
||||
VL_OBJS+=block-raw-win32.o
|
||||
else
|
||||
VL_OBJS+=block-raw-posix.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ALSA
|
||||
LIBS += -lasound
|
||||
endif
|
||||
ifdef CONFIG_DSOUND
|
||||
LIBS += -lole32 -ldxguid
|
||||
endif
|
||||
ifdef CONFIG_FMOD
|
||||
LIBS += $(CONFIG_FMOD_LIB)
|
||||
VL_OBJS+=tap-win32.o
|
||||
endif
|
||||
|
||||
SOUND_HW = sb16.o es1370.o
|
||||
AUDIODRV = audio.o noaudio.o wavaudio.o
|
||||
ifdef CONFIG_SDL
|
||||
AUDIODRV += sdlaudio.o
|
||||
endif
|
||||
ifdef CONFIG_OSS
|
||||
AUDIODRV += ossaudio.o
|
||||
endif
|
||||
ifdef CONFIG_COREAUDIO
|
||||
AUDIODRV += coreaudio.o
|
||||
endif
|
||||
ifdef CONFIG_ALSA
|
||||
AUDIODRV += alsaaudio.o
|
||||
LIBS += -lasound
|
||||
endif
|
||||
ifdef CONFIG_DSOUND
|
||||
AUDIODRV += dsoundaudio.o
|
||||
LIBS += -lole32 -ldxguid
|
||||
endif
|
||||
ifdef CONFIG_FMOD
|
||||
AUDIODRV += fmodaudio.o
|
||||
audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
|
||||
LIBS += $(CONFIG_FMOD_LIB)
|
||||
endif
|
||||
ifdef CONFIG_ADLIB
|
||||
SOUND_HW += fmopl.o adlib.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_VNC_TLS
|
||||
CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
|
||||
LIBS += $(CONFIG_VNC_TLS_LIBS)
|
||||
endif
|
||||
|
||||
# SCSI layer
|
||||
VL_OBJS+= lsi53c895a.o
|
||||
|
||||
# USB layer
|
||||
VL_OBJS+= usb-ohci.o
|
||||
|
||||
# EEPROM emulation
|
||||
VL_OBJS += eeprom93xx.o
|
||||
VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
|
||||
|
||||
# PCI network cards
|
||||
VL_OBJS += eepro100.o
|
||||
VL_OBJS += ne2000.o
|
||||
VL_OBJS += pcnet.o
|
||||
VL_OBJS += rtl8139.o
|
||||
VL_OBJS+= ne2000.o rtl8139.o
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), i386)
|
||||
# Hardware support
|
||||
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
|
||||
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 apic.o parallel.o acpi.o piix_pci.o
|
||||
VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
|
||||
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
|
||||
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
|
||||
DEFINES += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
|
||||
# shared objects
|
||||
VL_OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o
|
||||
# PREP target
|
||||
VL_OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o
|
||||
VL_OBJS+= prep_pci.o ppc_prep.o
|
||||
# Mac shared devices
|
||||
VL_OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o
|
||||
# OldWorld PowerMac
|
||||
VL_OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o
|
||||
# NewWorld PowerMac
|
||||
VL_OBJS+= unin_pci.o ppc_chrp.o
|
||||
# PowerPC 4xx boards
|
||||
VL_OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
|
||||
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
|
||||
DEFINES += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), mips)
|
||||
VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o
|
||||
VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
|
||||
VL_OBJS+= jazz_led.o
|
||||
VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
|
||||
VL_OBJS+= piix_pci.o parallel.o cirrus_vga.o $(SOUND_HW)
|
||||
VL_OBJS+= mipsnet.o
|
||||
VL_OBJS+= pflash_cfi01.o
|
||||
CPPFLAGS += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), cris)
|
||||
VL_OBJS+= etraxfs.o
|
||||
VL_OBJS+= ptimer.o
|
||||
VL_OBJS+= etraxfs_timer.o
|
||||
VL_OBJS+= etraxfs_ser.o
|
||||
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
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sparc)
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
|
||||
VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o
|
||||
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
|
||||
VL_OBJS+= cirrus_vga.o parallel.o ptimer.o
|
||||
VL_OBJS+= cirrus_vga.o parallel.o
|
||||
else
|
||||
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 ptimer.o eccmemctl.o sbi.o sun4c_intctl.o
|
||||
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
|
||||
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 pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
|
||||
VL_OBJS+= versatile_pci.o ptimer.o
|
||||
VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o
|
||||
VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
|
||||
VL_OBJS+= pl061.o
|
||||
VL_OBJS+= arm-semi.o
|
||||
VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
|
||||
VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
|
||||
VL_OBJS+= pflash_cfi01.o gumstix.o
|
||||
VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o
|
||||
VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o
|
||||
VL_OBJS+= palm.o tsc210x.o
|
||||
VL_OBJS+= mst_fpga.o mainstone.o
|
||||
CPPFLAGS += -DHAS_AUDIO
|
||||
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sh4)
|
||||
VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
|
||||
VL_OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), m68k)
|
||||
VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
|
||||
VL_OBJS+= m68k-semi.o dummy_m68k.o
|
||||
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
|
||||
endif
|
||||
ifdef CONFIG_GDBSTUB
|
||||
VL_OBJS+=gdbstub.o
|
||||
VL_OBJS+=gdbstub.o
|
||||
endif
|
||||
ifdef CONFIG_SDL
|
||||
VL_OBJS+=sdl.o
|
||||
endif
|
||||
VL_OBJS+=vnc.o
|
||||
ifdef CONFIG_COCOA
|
||||
VL_OBJS+=cocoa.o
|
||||
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
|
||||
ifdef CONFIG_COREAUDIO
|
||||
COCOA_LIBS+=-framework CoreAudio
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_SLIRP
|
||||
CPPFLAGS+=-I$(SRC_PATH)/slirp
|
||||
DEFINES+=-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
|
||||
VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
|
||||
endif
|
||||
|
||||
VL_LDFLAGS=$(VL_OS_LDFLAGS)
|
||||
VL_LIBS=$(AIOLIBS)
|
||||
VL_LDFLAGS=
|
||||
# specific flags are needed for non soft mmu emulator
|
||||
ifdef CONFIG_STATIC
|
||||
VL_LDFLAGS+=-static
|
||||
endif
|
||||
ifndef CONFIG_SOFTMMU
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
|
||||
endif
|
||||
ifndef CONFIG_DARWIN
|
||||
ifndef CONFIG_WIN32
|
||||
ifndef CONFIG_SOLARIS
|
||||
VL_LIBS+=-lutil
|
||||
VL_LIBS=-lutil
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifdef TARGET_GPROF
|
||||
vl.o: BASE_CFLAGS+=-p
|
||||
vl.o: CFLAGS+=-p
|
||||
VL_LDFLAGS+=-p
|
||||
endif
|
||||
|
||||
@@ -550,34 +392,32 @@ ifeq ($(ARCH),ia64)
|
||||
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
VL_LDFLAGS+=-m64
|
||||
ifneq ($(CONFIG_SOLARIS),yes)
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
VL_LDFLAGS+=-m64
|
||||
ifneq ($(CONFIG_SOLARIS),yes)
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
|
||||
endif
|
||||
|
||||
$(QEMU_SYSTEM): $(VL_OBJS) ../libqemu_common.a libqemu.a
|
||||
$(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
|
||||
$(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 $@ $<
|
||||
|
||||
sdl.o: sdl.c keymaps.c sdl_keysym.h
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
sdlaudio.o: sdlaudio.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
|
||||
vldepend: $(VL_OBJS:.o=.c)
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
|
||||
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
|
||||
|
||||
# libqemu
|
||||
# libqemu
|
||||
|
||||
libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
@@ -599,38 +439,58 @@ gen-op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -g -o $@ $<
|
||||
|
||||
op.o: op.c
|
||||
$(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
$(CC) $(OP_CFLAGS) $(DEFINES) -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) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
else
|
||||
op_helper.o: op_helper.c
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -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
|
||||
endif
|
||||
|
||||
cpu-exec.o: cpu-exec.c
|
||||
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
op.o: op.c op_template.h
|
||||
pl110.o: pl110_template.h
|
||||
endif
|
||||
|
||||
# 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), sparc)
|
||||
op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
|
||||
magic_load.o: elf_op.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
op.o: op.c op_template.h op_mem.h
|
||||
op_helper.o: op_helper_mem.h
|
||||
translate.o: translate.c translate_init.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
op.o: op.c op_template.c op_mem.c
|
||||
op_helper.o: op_helper_mem.c
|
||||
endif
|
||||
|
||||
loader.o: loader.c elf_ops.h
|
||||
|
||||
ifeq ($(TARGET_ARCH), sh4)
|
||||
op.o: op.c op_mem.c cpu.h
|
||||
op_helper.o: op_helper.c exec.h cpu.h
|
||||
helper.o: helper.c exec.h cpu.h
|
||||
sh7750.o: sh7750.c sh7750_regs.h sh7750_regnames.h cpu.h
|
||||
shix.o: shix.c sh7750_regs.h sh7750_regnames.h
|
||||
sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
|
||||
tc58128.o: tc58128.c
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CPPFLAGS) -c -o $@ $<
|
||||
$(CC) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o fpu/*.o
|
||||
rm -f *.d */*.d
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
|
||||
|
||||
install: all
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
$(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
|
||||
endif
|
||||
@@ -644,6 +504,3 @@ audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
|
||||
fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
|
||||
CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
|
||||
endif
|
||||
|
||||
# Include automatically generated dependency files
|
||||
-include $(wildcard *.d */*.d)
|
||||
|
||||
16
README.distrib
Normal file
16
README.distrib
Normal file
@@ -0,0 +1,16 @@
|
||||
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
|
||||
12
TODO
12
TODO
@@ -1,22 +1,26 @@
|
||||
short term:
|
||||
----------
|
||||
- cycle counter for all archs
|
||||
- cpu_interrupt() win32/SMP fix
|
||||
- support variable tsc freq
|
||||
- cpu_interrupt() win32/SMP fix
|
||||
- USB host async
|
||||
- IDE async
|
||||
- debug option in 'configure' script + disable -fomit-frame-pointer
|
||||
- Precise VGA timings for old games/demos (malc patch)
|
||||
- merge PIC spurious interrupt patch
|
||||
- merge Solaris patch
|
||||
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
|
||||
- config file (at least for windows/Mac OS X)
|
||||
- commit message if execution of code in IO memory
|
||||
- update doc: PCI infos.
|
||||
- VNC patch + Synaptic patch.
|
||||
- basic VGA optimizations
|
||||
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
|
||||
- better code fetch (different exception handling + CS.limit support)
|
||||
- do not resize vga if invalid size.
|
||||
- avoid looping if only exceptions
|
||||
- cycle counter for all archs
|
||||
- TLB code protection support for PPC
|
||||
- see openMosix Doc
|
||||
- see openMosix Doc
|
||||
- disable SMC handling for ARM/SPARC/PPC (not finished)
|
||||
- see undefined flags for BTx insn
|
||||
- user/kernel PUSHL/POPL in helper.c
|
||||
@@ -27,10 +31,12 @@ short term:
|
||||
- fix CCOP optimisation
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
|
||||
ppc specific:
|
||||
------------
|
||||
- TLB invalidate not needed if msr_pr changes
|
||||
- SPR_ENCODE() not useful
|
||||
- enable shift optimizations ?
|
||||
|
||||
linux-user specific:
|
||||
|
||||
104
a.out.h
104
a.out.h
@@ -25,9 +25,9 @@ extern "C" {
|
||||
struct external_filehdr {
|
||||
short f_magic; /* magic number */
|
||||
short f_nscns; /* number of sections */
|
||||
host_ulong f_timdat; /* time & date stamp */
|
||||
host_ulong f_symptr; /* file pointer to symtab */
|
||||
host_ulong f_nsyms; /* number of symtab entries */
|
||||
unsigned long f_timdat; /* time & date stamp */
|
||||
unsigned long f_symptr; /* file pointer to symtab */
|
||||
unsigned long f_nsyms; /* number of symtab entries */
|
||||
short f_opthdr; /* sizeof(optional hdr) */
|
||||
short f_flags; /* flags */
|
||||
};
|
||||
@@ -72,12 +72,12 @@ typedef struct
|
||||
{
|
||||
unsigned short magic; /* type of file */
|
||||
unsigned short vstamp; /* version stamp */
|
||||
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
|
||||
host_ulong dsize; /* initialized data " " */
|
||||
host_ulong bsize; /* uninitialized data " " */
|
||||
host_ulong entry; /* entry pt. */
|
||||
host_ulong text_start; /* base of text used for this file */
|
||||
host_ulong data_start; /* base of data used for this file=
|
||||
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
|
||||
unsigned long dsize; /* initialized data " " */
|
||||
unsigned long bsize; /* uninitialized data " " */
|
||||
unsigned long entry; /* entry pt. */
|
||||
unsigned long text_start; /* base of text used for this file */
|
||||
unsigned long data_start; /* base of data used for this file=
|
||||
*/
|
||||
}
|
||||
AOUTHDR;
|
||||
@@ -103,16 +103,16 @@ AOUTHDR;
|
||||
|
||||
struct external_scnhdr {
|
||||
char s_name[8]; /* section name */
|
||||
host_ulong s_paddr; /* physical address, offset
|
||||
unsigned long s_paddr; /* physical address, offset
|
||||
of last addr in scn */
|
||||
host_ulong s_vaddr; /* virtual address */
|
||||
host_ulong s_size; /* section size */
|
||||
host_ulong s_scnptr; /* file ptr to raw data for section */
|
||||
host_ulong s_relptr; /* file ptr to relocation */
|
||||
host_ulong s_lnnoptr; /* file ptr to line numbers */
|
||||
unsigned long s_vaddr; /* virtual address */
|
||||
unsigned long s_size; /* section size */
|
||||
unsigned long s_scnptr; /* file ptr to raw data for section */
|
||||
unsigned long s_relptr; /* file ptr to relocation */
|
||||
unsigned long s_lnnoptr; /* file ptr to line numbers */
|
||||
unsigned short s_nreloc; /* number of relocation entries */
|
||||
unsigned short s_nlnno; /* number of line number entries*/
|
||||
host_ulong s_flags; /* flags */
|
||||
unsigned long s_flags; /* flags */
|
||||
};
|
||||
|
||||
#define SCNHDR struct external_scnhdr
|
||||
@@ -136,8 +136,8 @@ struct external_scnhdr {
|
||||
*/
|
||||
struct external_lineno {
|
||||
union {
|
||||
host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
|
||||
host_ulong l_paddr; /* (physical) address of line number */
|
||||
unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
|
||||
unsigned long l_paddr; /* (physical) address of line number */
|
||||
} l_addr;
|
||||
unsigned short l_lnno; /* line number */
|
||||
};
|
||||
@@ -156,11 +156,11 @@ struct __attribute__((packed)) external_syment
|
||||
union {
|
||||
char e_name[E_SYMNMLEN];
|
||||
struct {
|
||||
host_ulong e_zeroes;
|
||||
host_ulong e_offset;
|
||||
unsigned long e_zeroes;
|
||||
unsigned long e_offset;
|
||||
} e;
|
||||
} e;
|
||||
host_ulong e_value;
|
||||
unsigned long e_value;
|
||||
unsigned short e_scnum;
|
||||
unsigned short e_type;
|
||||
char e_sclass[1];
|
||||
@@ -174,18 +174,18 @@ struct __attribute__((packed)) external_syment
|
||||
|
||||
union external_auxent {
|
||||
struct {
|
||||
host_ulong x_tagndx; /* str, un, or enum tag indx */
|
||||
unsigned long x_tagndx; /* str, un, or enum tag indx */
|
||||
union {
|
||||
struct {
|
||||
unsigned short x_lnno; /* declaration line number */
|
||||
unsigned short x_size; /* str/union/array size */
|
||||
} x_lnsz;
|
||||
host_ulong x_fsize; /* size of function */
|
||||
unsigned long x_fsize; /* size of function */
|
||||
} x_misc;
|
||||
union {
|
||||
struct { /* if ISFCN, tag, or .bb */
|
||||
host_ulong x_lnnoptr;/* ptr to fcn line # */
|
||||
host_ulong x_endndx; /* entry ndx past block end */
|
||||
unsigned long x_lnnoptr;/* ptr to fcn line # */
|
||||
unsigned long x_endndx; /* entry ndx past block end */
|
||||
} x_fcn;
|
||||
struct { /* if ISARY, up to 4 dimen. */
|
||||
char x_dimen[E_DIMNUM][2];
|
||||
@@ -197,22 +197,22 @@ union external_auxent {
|
||||
union {
|
||||
char x_fname[E_FILNMLEN];
|
||||
struct {
|
||||
host_ulong x_zeroes;
|
||||
host_ulong x_offset;
|
||||
unsigned long x_zeroes;
|
||||
unsigned long x_offset;
|
||||
} x_n;
|
||||
} x_file;
|
||||
|
||||
struct {
|
||||
host_ulong x_scnlen; /* section length */
|
||||
unsigned long x_scnlen; /* section length */
|
||||
unsigned short x_nreloc; /* # relocation entries */
|
||||
unsigned short x_nlinno; /* # line numbers */
|
||||
host_ulong x_checksum; /* section COMDAT checksum */
|
||||
unsigned long x_checksum; /* section COMDAT checksum */
|
||||
unsigned short x_associated;/* COMDAT associated section index */
|
||||
char x_comdat[1]; /* COMDAT selection number */
|
||||
} x_scn;
|
||||
|
||||
struct {
|
||||
host_ulong x_tvfill; /* tv fill value */
|
||||
unsigned long x_tvfill; /* tv fill value */
|
||||
unsigned short x_tvlen; /* length of .tv */
|
||||
char x_tvran[2][2]; /* tv range */
|
||||
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
|
||||
@@ -344,7 +344,7 @@ struct external_PE_filehdr
|
||||
unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
|
||||
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
|
||||
char e_res2[10][2]; /* Reserved words, all 0x0 */
|
||||
host_ulong e_lfanew; /* File address of new exe header, 0x80 */
|
||||
unsigned long e_lfanew; /* File address of new exe header, 0x80 */
|
||||
char dos_message[16][4]; /* other stuff, always follow DOS header */
|
||||
unsigned int nt_signature; /* required NT signature, 0x4550 */
|
||||
|
||||
@@ -352,9 +352,9 @@ struct external_PE_filehdr
|
||||
|
||||
unsigned short f_magic; /* magic number */
|
||||
unsigned short f_nscns; /* number of sections */
|
||||
host_ulong f_timdat; /* time & date stamp */
|
||||
host_ulong f_symptr; /* file pointer to symtab */
|
||||
host_ulong f_nsyms; /* number of symtab entries */
|
||||
unsigned long f_timdat; /* time & date stamp */
|
||||
unsigned long f_symptr; /* file pointer to symtab */
|
||||
unsigned long f_nsyms; /* number of symtab entries */
|
||||
unsigned short f_opthdr; /* sizeof(optional hdr) */
|
||||
unsigned short f_flags; /* flags */
|
||||
};
|
||||
@@ -370,17 +370,17 @@ typedef struct
|
||||
{
|
||||
unsigned short magic; /* type of file */
|
||||
unsigned short vstamp; /* version stamp */
|
||||
host_ulong tsize; /* text size in bytes, padded to FW bdry*/
|
||||
host_ulong dsize; /* initialized data " " */
|
||||
host_ulong bsize; /* uninitialized data " " */
|
||||
host_ulong entry; /* entry pt. */
|
||||
host_ulong text_start; /* base of text used for this file */
|
||||
host_ulong data_start; /* base of all data used for this file */
|
||||
unsigned long tsize; /* text size in bytes, padded to FW bdry*/
|
||||
unsigned long dsize; /* initialized data " " */
|
||||
unsigned long bsize; /* uninitialized data " " */
|
||||
unsigned long entry; /* entry pt. */
|
||||
unsigned long text_start; /* base of text used for this file */
|
||||
unsigned long data_start; /* base of all data used for this file */
|
||||
|
||||
/* NT extra fields; see internal.h for descriptions */
|
||||
host_ulong ImageBase;
|
||||
host_ulong SectionAlignment;
|
||||
host_ulong FileAlignment;
|
||||
unsigned long ImageBase;
|
||||
unsigned long SectionAlignment;
|
||||
unsigned long FileAlignment;
|
||||
unsigned short MajorOperatingSystemVersion;
|
||||
unsigned short MinorOperatingSystemVersion;
|
||||
unsigned short MajorImageVersion;
|
||||
@@ -388,17 +388,17 @@ typedef struct
|
||||
unsigned short MajorSubsystemVersion;
|
||||
unsigned short MinorSubsystemVersion;
|
||||
char Reserved1[4];
|
||||
host_ulong SizeOfImage;
|
||||
host_ulong SizeOfHeaders;
|
||||
host_ulong CheckSum;
|
||||
unsigned long SizeOfImage;
|
||||
unsigned long SizeOfHeaders;
|
||||
unsigned long CheckSum;
|
||||
unsigned short Subsystem;
|
||||
unsigned short DllCharacteristics;
|
||||
host_ulong SizeOfStackReserve;
|
||||
host_ulong SizeOfStackCommit;
|
||||
host_ulong SizeOfHeapReserve;
|
||||
host_ulong SizeOfHeapCommit;
|
||||
host_ulong LoaderFlags;
|
||||
host_ulong NumberOfRvaAndSizes;
|
||||
unsigned long SizeOfStackReserve;
|
||||
unsigned long SizeOfStackCommit;
|
||||
unsigned long SizeOfHeapReserve;
|
||||
unsigned long SizeOfHeapCommit;
|
||||
unsigned long LoaderFlags;
|
||||
unsigned long NumberOfRvaAndSizes;
|
||||
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
||||
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
|
||||
|
||||
|
||||
13
aes.c
13
aes.c
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
*
|
||||
*
|
||||
* aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
|
||||
*/
|
||||
/*
|
||||
@@ -27,13 +27,10 @@
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "aes.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
typedef uint32_t u32;
|
||||
@@ -1270,7 +1267,7 @@ void AES_decrypt(const unsigned char *in, unsigned char *out,
|
||||
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const unsigned long length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc)
|
||||
unsigned char *ivec, const int enc)
|
||||
{
|
||||
|
||||
unsigned long n;
|
||||
@@ -1297,7 +1294,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
AES_encrypt(tmp, tmp, key);
|
||||
memcpy(out, tmp, AES_BLOCK_SIZE);
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
@@ -1315,6 +1312,6 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
for(n=0; n < len; ++n)
|
||||
out[n] = tmp[n] ^ ivec[n];
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ const struct alpha_operand alpha_operands[] =
|
||||
|
||||
/* The signed "23-bit" aligned displacement of Branch format insns */
|
||||
#define BDISP (MDISP + 1)
|
||||
{ 21, 0, BFD_RELOC_23_PCREL_S2,
|
||||
{ 21, 0, BFD_RELOC_23_PCREL_S2,
|
||||
AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp },
|
||||
|
||||
/* The 26-bit PALcode function */
|
||||
|
||||
468
arm-semi.c
468
arm-semi.c
@@ -1,468 +0,0 @@
|
||||
/*
|
||||
* 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 "qemu-common.h"
|
||||
#include "sysemu.h"
|
||||
#include "gdbstub.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;
|
||||
}
|
||||
|
||||
#include "softmmu-semi.h"
|
||||
#endif
|
||||
|
||||
static target_ulong arm_semi_syscall_len;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static target_ulong syscall_err;
|
||||
#endif
|
||||
|
||||
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;
|
||||
#else
|
||||
syscall_err = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
|
||||
{
|
||||
/* The size is always stored in big-endian order, extract
|
||||
the value. We assume the size always fit in 32 bits. */
|
||||
uint32_t size;
|
||||
cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
|
||||
env->regs[0] = be32_to_cpu(size);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
((TaskState *)env->opaque)->swi_errno = err;
|
||||
#else
|
||||
syscall_err = err;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ARG(n) \
|
||||
({ \
|
||||
target_ulong __arg; \
|
||||
/* FIXME - handle get_user() failure */ \
|
||||
get_user_ual(__arg, args + (n) * 4); \
|
||||
__arg; \
|
||||
})
|
||||
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
|
||||
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:
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
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)+1, 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;
|
||||
|
||||
if (get_user_u8(c, args))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
/* 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:
|
||||
if (!(s = lock_user_string(args)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
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 {
|
||||
if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-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 {
|
||||
if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
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, "lseek,%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()) {
|
||||
gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
|
||||
ARG(0), env->regs[13]-64);
|
||||
return env->regs[0];
|
||||
} 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)+1);
|
||||
ret = env->regs[0];
|
||||
} else {
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
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)+1, ARG(2), (int)ARG(3)+1);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
char *s2;
|
||||
s = lock_user_string(ARG(0));
|
||||
s2 = lock_user_string(ARG(2));
|
||||
if (!s || !s2)
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
ret = (uint32_t)-1;
|
||||
else
|
||||
ret = set_swi_errno(ts, rename(s, s2));
|
||||
if (s2)
|
||||
unlock_user(s2, ARG(2), 0);
|
||||
if (s)
|
||||
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)+1);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
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 syscall_err;
|
||||
#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(VERIFY_WRITE, ARG(0), len, 0);
|
||||
|
||||
if (!cmdline_buffer)
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
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;
|
||||
if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
25
arm.ld
25
arm.ld
@@ -53,10 +53,6 @@ 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. */
|
||||
@@ -67,28 +63,7 @@ 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)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
*.d
|
||||
@@ -22,8 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "alsa"
|
||||
#include "audio_int.h"
|
||||
@@ -51,44 +50,44 @@ static struct {
|
||||
unsigned int period_size_out;
|
||||
unsigned int threshold;
|
||||
|
||||
int buffer_size_in_overridden;
|
||||
int period_size_in_overridden;
|
||||
int buffer_size_in_overriden;
|
||||
int period_size_in_overriden;
|
||||
|
||||
int buffer_size_out_overridden;
|
||||
int period_size_out_overridden;
|
||||
int buffer_size_out_overriden;
|
||||
int period_size_out_overriden;
|
||||
int verbose;
|
||||
} conf = {
|
||||
#define DEFAULT_BUFFER_SIZE 1024
|
||||
#define DEFAULT_PERIOD_SIZE 256
|
||||
#ifdef HIGH_LATENCY
|
||||
.size_in_usec_in = 1,
|
||||
.size_in_usec_out = 1,
|
||||
#endif
|
||||
.pcm_name_out = "default",
|
||||
.pcm_name_in = "default",
|
||||
.pcm_name_out = "hw:0,0",
|
||||
.pcm_name_in = "hw:0,0",
|
||||
#ifdef HIGH_LATENCY
|
||||
.buffer_size_in = 400000,
|
||||
.period_size_in = 400000 / 4,
|
||||
.buffer_size_out = 400000,
|
||||
.period_size_out = 400000 / 4,
|
||||
#else
|
||||
#define DEFAULT_BUFFER_SIZE 1024
|
||||
#define DEFAULT_PERIOD_SIZE 256
|
||||
.buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
|
||||
.period_size_in = DEFAULT_PERIOD_SIZE * 4,
|
||||
.buffer_size_out = DEFAULT_BUFFER_SIZE,
|
||||
.period_size_out = DEFAULT_PERIOD_SIZE,
|
||||
.buffer_size_in_overridden = 0,
|
||||
.buffer_size_out_overridden = 0,
|
||||
.period_size_in_overridden = 0,
|
||||
.period_size_out_overridden = 0,
|
||||
.buffer_size_in_overriden = 0,
|
||||
.buffer_size_out_overriden = 0,
|
||||
.period_size_in_overriden = 0,
|
||||
.period_size_out_overriden = 0,
|
||||
#endif
|
||||
.threshold = 0,
|
||||
.verbose = 0
|
||||
};
|
||||
|
||||
struct alsa_params_req {
|
||||
unsigned int freq;
|
||||
int freq;
|
||||
audfmt_e fmt;
|
||||
unsigned int nchannels;
|
||||
int nchannels;
|
||||
unsigned int buffer_size;
|
||||
unsigned int period_size;
|
||||
};
|
||||
@@ -158,12 +157,6 @@ static int aud_to_alsafmt (audfmt_e fmt)
|
||||
case AUD_FMT_U16:
|
||||
return SND_PCM_FORMAT_U16_LE;
|
||||
|
||||
case AUD_FMT_S32:
|
||||
return SND_PCM_FORMAT_S32_LE;
|
||||
|
||||
case AUD_FMT_U32:
|
||||
return SND_PCM_FORMAT_U32_LE;
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
#ifdef DEBUG_AUDIO
|
||||
@@ -206,26 +199,6 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
|
||||
*fmt = AUD_FMT_U16;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_S32_LE:
|
||||
*endianness = 0;
|
||||
*fmt = AUD_FMT_S32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_U32_LE:
|
||||
*endianness = 0;
|
||||
*fmt = AUD_FMT_U32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_S32_BE:
|
||||
*endianness = 1;
|
||||
*fmt = AUD_FMT_S32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_U32_BE:
|
||||
*endianness = 1;
|
||||
*fmt = AUD_FMT_U32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Unrecognized audio format %d\n", alsafmt);
|
||||
return -1;
|
||||
@@ -285,8 +258,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
||||
{
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
int err;
|
||||
unsigned int freq, nchannels;
|
||||
int err, freq, nchannels;
|
||||
const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
|
||||
unsigned int period_size, buffer_size;
|
||||
snd_pcm_uframes_t obt_buffer_size;
|
||||
@@ -416,8 +388,8 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
||||
}
|
||||
else {
|
||||
if (period_size < minval) {
|
||||
if ((in && conf.period_size_in_overridden)
|
||||
|| (!in && conf.period_size_out_overridden)) {
|
||||
if ((in && conf.period_size_in_overriden)
|
||||
|| (!in && conf.period_size_out_overriden)) {
|
||||
dolog ("%s period size(%d) is less "
|
||||
"than minmal period size(%ld)\n",
|
||||
typ,
|
||||
@@ -452,8 +424,8 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
||||
}
|
||||
else {
|
||||
if (buffer_size < minval) {
|
||||
if ((in && conf.buffer_size_in_overridden)
|
||||
|| (!in && conf.buffer_size_out_overridden)) {
|
||||
if ((in && conf.buffer_size_in_overriden)
|
||||
|| (!in && conf.buffer_size_out_overriden)) {
|
||||
dolog (
|
||||
"%s buffer size(%d) is less "
|
||||
"than minimal buffer size(%ld)\n",
|
||||
@@ -634,6 +606,7 @@ static int alsa_run_out (HWVoiceOut *hw)
|
||||
}
|
||||
}
|
||||
|
||||
mixeng_clear (src, written);
|
||||
rpos = (rpos + written) % hw->samples;
|
||||
samples -= written;
|
||||
len -= written;
|
||||
@@ -690,9 +663,12 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (endianness)
|
||||
);
|
||||
hw->samples = obt.samples;
|
||||
|
||||
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
|
||||
@@ -776,9 +752,12 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (endianness)
|
||||
);
|
||||
hw->samples = obt.samples;
|
||||
|
||||
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
@@ -947,16 +926,16 @@ static struct audio_option alsa_options[] = {
|
||||
{"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
|
||||
"DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
|
||||
{"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
|
||||
"DAC period size", &conf.period_size_out_overridden, 0},
|
||||
"DAC period size", &conf.period_size_out_overriden, 0},
|
||||
{"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
|
||||
"DAC buffer size", &conf.buffer_size_out_overridden, 0},
|
||||
"DAC buffer size", &conf.buffer_size_out_overriden, 0},
|
||||
|
||||
{"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
|
||||
"ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
|
||||
{"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
|
||||
"ADC period size", &conf.period_size_in_overridden, 0},
|
||||
"ADC period size", &conf.period_size_in_overriden, 0},
|
||||
{"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
|
||||
"ADC buffer size", &conf.buffer_size_in_overridden, 0},
|
||||
"ADC buffer size", &conf.buffer_size_in_overriden, 0},
|
||||
|
||||
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
|
||||
"(undocumented)", NULL, 0},
|
||||
|
||||
573
audio/audio.c
573
audio/audio.c
@@ -21,11 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "hw/hw.h"
|
||||
#include "audio.h"
|
||||
#include "console.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "sysemu.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "audio"
|
||||
#include "audio_int.h"
|
||||
@@ -33,7 +29,6 @@
|
||||
/* #define DEBUG_PLIVE */
|
||||
/* #define DEBUG_LIVE */
|
||||
/* #define DEBUG_OUT */
|
||||
/* #define DEBUG_CAPTURE */
|
||||
|
||||
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
|
||||
|
||||
@@ -84,8 +79,7 @@ static struct {
|
||||
{
|
||||
44100, /* freq */
|
||||
2, /* nchannels */
|
||||
AUD_FMT_S16, /* fmt */
|
||||
AUDIO_HOST_ENDIANNESS
|
||||
AUD_FMT_S16 /* fmt */
|
||||
}
|
||||
},
|
||||
|
||||
@@ -96,8 +90,7 @@ static struct {
|
||||
{
|
||||
44100, /* freq */
|
||||
2, /* nchannels */
|
||||
AUD_FMT_S16, /* fmt */
|
||||
AUDIO_HOST_ENDIANNESS
|
||||
AUD_FMT_S16 /* fmt */
|
||||
}
|
||||
},
|
||||
|
||||
@@ -144,7 +137,7 @@ int audio_bug (const char *funcname, int cond)
|
||||
if (cond) {
|
||||
static int shown;
|
||||
|
||||
AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
|
||||
AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
|
||||
if (!shown) {
|
||||
shown = 1;
|
||||
AUD_log (NULL, "Save all your work and restart without audio\n");
|
||||
@@ -172,25 +165,6 @@ int audio_bug (const char *funcname, int cond)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int audio_bits_to_index (int bits)
|
||||
{
|
||||
switch (bits) {
|
||||
case 8:
|
||||
return 0;
|
||||
|
||||
case 16:
|
||||
return 1;
|
||||
|
||||
case 32:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
audio_bug ("bits_to_index", 1);
|
||||
AUD_log (NULL, "invalid bits %d\n", bits);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *audio_calloc (const char *funcname, int nmemb, size_t size)
|
||||
{
|
||||
int cond;
|
||||
@@ -238,7 +212,7 @@ static char *audio_alloc_prefix (const char *s)
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char *audio_audfmt_to_string (audfmt_e fmt)
|
||||
const char *audio_audfmt_to_string (audfmt_e fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AUD_FMT_U8:
|
||||
@@ -252,20 +226,13 @@ static const char *audio_audfmt_to_string (audfmt_e fmt)
|
||||
|
||||
case AUD_FMT_S16:
|
||||
return "S16";
|
||||
|
||||
case AUD_FMT_U32:
|
||||
return "U32";
|
||||
|
||||
case AUD_FMT_S32:
|
||||
return "S32";
|
||||
}
|
||||
|
||||
dolog ("Bogus audfmt %d returning S16\n", fmt);
|
||||
return "S16";
|
||||
}
|
||||
|
||||
static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
|
||||
int *defaultp)
|
||||
audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
|
||||
{
|
||||
if (!strcasecmp (s, "u8")) {
|
||||
*defaultp = 0;
|
||||
@@ -275,10 +242,6 @@ static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
|
||||
*defaultp = 0;
|
||||
return AUD_FMT_U16;
|
||||
}
|
||||
else if (!strcasecmp (s, "u32")) {
|
||||
*defaultp = 0;
|
||||
return AUD_FMT_U32;
|
||||
}
|
||||
else if (!strcasecmp (s, "s8")) {
|
||||
*defaultp = 0;
|
||||
return AUD_FMT_S8;
|
||||
@@ -287,10 +250,6 @@ static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
|
||||
*defaultp = 0;
|
||||
return AUD_FMT_S16;
|
||||
}
|
||||
else if (!strcasecmp (s, "s32")) {
|
||||
*defaultp = 0;
|
||||
return AUD_FMT_S32;
|
||||
}
|
||||
else {
|
||||
dolog ("Bogus audio format `%s' using %s\n",
|
||||
s, audio_audfmt_to_string (defval));
|
||||
@@ -391,7 +350,7 @@ static void audio_print_options (const char *prefix,
|
||||
const char *state = "default";
|
||||
printf (" %s_%s: ", uprefix, opt->name);
|
||||
|
||||
if (opt->overriddenp && *opt->overriddenp) {
|
||||
if (opt->overridenp && *opt->overridenp) {
|
||||
state = "current";
|
||||
}
|
||||
|
||||
@@ -521,10 +480,10 @@ static void audio_process_options (const char *prefix,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!opt->overriddenp) {
|
||||
opt->overriddenp = &opt->overridden;
|
||||
if (!opt->overridenp) {
|
||||
opt->overridenp = &opt->overriden;
|
||||
}
|
||||
*opt->overriddenp = !def;
|
||||
*opt->overridenp = !def;
|
||||
qemu_free (optname);
|
||||
}
|
||||
}
|
||||
@@ -550,36 +509,20 @@ static void audio_print_settings (audsettings_t *as)
|
||||
AUD_log (NULL, "invalid(%d)", as->fmt);
|
||||
break;
|
||||
}
|
||||
|
||||
AUD_log (NULL, " endianness=");
|
||||
switch (as->endianness) {
|
||||
case 0:
|
||||
AUD_log (NULL, "little");
|
||||
break;
|
||||
case 1:
|
||||
AUD_log (NULL, "big");
|
||||
break;
|
||||
default:
|
||||
AUD_log (NULL, "invalid");
|
||||
break;
|
||||
}
|
||||
AUD_log (NULL, "\n");
|
||||
}
|
||||
|
||||
static int audio_validate_settings (audsettings_t *as)
|
||||
static int audio_validate_settigs (audsettings_t *as)
|
||||
{
|
||||
int invalid;
|
||||
|
||||
invalid = as->nchannels != 1 && as->nchannels != 2;
|
||||
invalid |= as->endianness != 0 && as->endianness != 1;
|
||||
|
||||
switch (as->fmt) {
|
||||
case AUD_FMT_S8:
|
||||
case AUD_FMT_U8:
|
||||
case AUD_FMT_S16:
|
||||
case AUD_FMT_U16:
|
||||
case AUD_FMT_S32:
|
||||
case AUD_FMT_U32:
|
||||
break;
|
||||
default:
|
||||
invalid = 1;
|
||||
@@ -587,7 +530,11 @@ static int audio_validate_settings (audsettings_t *as)
|
||||
}
|
||||
|
||||
invalid |= as->freq <= 0;
|
||||
return invalid ? -1 : 0;
|
||||
|
||||
if (invalid) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
|
||||
@@ -605,23 +552,20 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
|
||||
case AUD_FMT_U16:
|
||||
bits = 16;
|
||||
break;
|
||||
|
||||
case AUD_FMT_S32:
|
||||
sign = 1;
|
||||
case AUD_FMT_U32:
|
||||
bits = 32;
|
||||
break;
|
||||
}
|
||||
return info->freq == as->freq
|
||||
&& info->nchannels == as->nchannels
|
||||
&& info->sign == sign
|
||||
&& info->bits == bits
|
||||
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||
&& info->bits == bits;
|
||||
}
|
||||
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
|
||||
void audio_pcm_init_info (
|
||||
struct audio_pcm_info *info,
|
||||
audsettings_t *as,
|
||||
int swap_endian
|
||||
)
|
||||
{
|
||||
int bits = 8, sign = 0, shift = 0;
|
||||
int bits = 8, sign = 0;
|
||||
|
||||
switch (as->fmt) {
|
||||
case AUD_FMT_S8:
|
||||
@@ -633,14 +577,6 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
|
||||
sign = 1;
|
||||
case AUD_FMT_U16:
|
||||
bits = 16;
|
||||
shift = 1;
|
||||
break;
|
||||
|
||||
case AUD_FMT_S32:
|
||||
sign = 1;
|
||||
case AUD_FMT_U32:
|
||||
bits = 32;
|
||||
shift = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -648,10 +584,10 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
|
||||
info->bits = bits;
|
||||
info->sign = sign;
|
||||
info->nchannels = as->nchannels;
|
||||
info->shift = (as->nchannels == 2) + shift;
|
||||
info->shift = (as->nchannels == 2) + (bits == 16);
|
||||
info->align = (1 << info->shift) - 1;
|
||||
info->bytes_per_second = info->freq << info->shift;
|
||||
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||
info->swap_endian = swap_endian;
|
||||
}
|
||||
|
||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
||||
@@ -661,193 +597,29 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
||||
}
|
||||
|
||||
if (info->sign) {
|
||||
memset (buf, 0x00, len << info->shift);
|
||||
memset (buf, len << info->shift, 0x00);
|
||||
}
|
||||
else {
|
||||
switch (info->bits) {
|
||||
case 8:
|
||||
memset (buf, 0x80, len << info->shift);
|
||||
break;
|
||||
if (info->bits == 8) {
|
||||
memset (buf, len << info->shift, 0x80);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
uint16_t *p = buf;
|
||||
int shift = info->nchannels - 1;
|
||||
short s = INT16_MAX;
|
||||
|
||||
case 16:
|
||||
{
|
||||
int i;
|
||||
uint16_t *p = buf;
|
||||
int shift = info->nchannels - 1;
|
||||
short s = INT16_MAX;
|
||||
|
||||
if (info->swap_endianness) {
|
||||
s = bswap16 (s);
|
||||
}
|
||||
|
||||
for (i = 0; i < len << shift; i++) {
|
||||
p[i] = s;
|
||||
}
|
||||
if (info->swap_endian) {
|
||||
s = bswap16 (s);
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
{
|
||||
int i;
|
||||
uint32_t *p = buf;
|
||||
int shift = info->nchannels - 1;
|
||||
int32_t s = INT32_MAX;
|
||||
|
||||
if (info->swap_endianness) {
|
||||
s = bswap32 (s);
|
||||
}
|
||||
|
||||
for (i = 0; i < len << shift; i++) {
|
||||
p[i] = s;
|
||||
}
|
||||
for (i = 0; i < len << shift; i++) {
|
||||
p[i] = s;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n",
|
||||
info->bits);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Capture
|
||||
*/
|
||||
static void noop_conv (st_sample_t *dst, const void *src,
|
||||
int samples, volume_t *vol)
|
||||
{
|
||||
(void) src;
|
||||
(void) dst;
|
||||
(void) samples;
|
||||
(void) vol;
|
||||
}
|
||||
|
||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
|
||||
AudioState *s,
|
||||
audsettings_t *as
|
||||
)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
if (audio_pcm_info_eq (&cap->hw.info, as)) {
|
||||
return cap;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
|
||||
{
|
||||
struct capture_callback *cb;
|
||||
|
||||
#ifdef DEBUG_CAPTURE
|
||||
dolog ("notification %d sent\n", cmd);
|
||||
#endif
|
||||
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
|
||||
cb->ops.notify (cb->opaque, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
|
||||
{
|
||||
if (cap->hw.enabled != enabled) {
|
||||
audcnotification_e cmd;
|
||||
cap->hw.enabled = enabled;
|
||||
cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
|
||||
audio_notify_capture (cap, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
|
||||
{
|
||||
HWVoiceOut *hw = &cap->hw;
|
||||
SWVoiceOut *sw;
|
||||
int enabled = 0;
|
||||
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (sw->active) {
|
||||
enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
audio_capture_maybe_changed (cap, enabled);
|
||||
}
|
||||
|
||||
static void audio_detach_capture (HWVoiceOut *hw)
|
||||
{
|
||||
SWVoiceCap *sc = hw->cap_head.lh_first;
|
||||
|
||||
while (sc) {
|
||||
SWVoiceCap *sc1 = sc->entries.le_next;
|
||||
SWVoiceOut *sw = &sc->sw;
|
||||
CaptureVoiceOut *cap = sc->cap;
|
||||
int was_active = sw->active;
|
||||
|
||||
if (sw->rate) {
|
||||
st_rate_stop (sw->rate);
|
||||
sw->rate = NULL;
|
||||
}
|
||||
|
||||
LIST_REMOVE (sw, entries);
|
||||
LIST_REMOVE (sc, entries);
|
||||
qemu_free (sc);
|
||||
if (was_active) {
|
||||
/* We have removed soft voice from the capture:
|
||||
this might have changed the overall status of the capture
|
||||
since this might have been the only active voice */
|
||||
audio_recalc_and_notify_capture (cap);
|
||||
}
|
||||
sc = sc1;
|
||||
}
|
||||
}
|
||||
|
||||
static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
audio_detach_capture (hw);
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
SWVoiceCap *sc;
|
||||
SWVoiceOut *sw;
|
||||
HWVoiceOut *hw_cap = &cap->hw;
|
||||
|
||||
sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
|
||||
if (!sc) {
|
||||
dolog ("Could not allocate soft capture voice (%zu bytes)\n",
|
||||
sizeof (*sc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sc->cap = cap;
|
||||
sw = &sc->sw;
|
||||
sw->hw = hw_cap;
|
||||
sw->info = hw->info;
|
||||
sw->empty = 1;
|
||||
sw->active = hw->enabled;
|
||||
sw->conv = noop_conv;
|
||||
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
|
||||
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
|
||||
if (!sw->rate) {
|
||||
dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
|
||||
qemu_free (sw);
|
||||
return -1;
|
||||
}
|
||||
LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
|
||||
LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
|
||||
#ifdef DEBUG_CAPTURE
|
||||
asprintf (&sw->name, "for %p %d,%d,%d",
|
||||
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
|
||||
dolog ("Added %s active = %d\n", sw->name, sw->active);
|
||||
#endif
|
||||
if (sw->active) {
|
||||
audio_capture_maybe_changed (cap, 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hard voice (capture)
|
||||
*/
|
||||
@@ -1024,9 +796,6 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
}
|
||||
|
||||
if (live == hwsamples) {
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("%s is full %d\n", sw->name, live);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1145,14 +914,19 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
hw = sw->hw;
|
||||
if (sw->active != on) {
|
||||
SWVoiceOut *temp_sw;
|
||||
SWVoiceCap *sc;
|
||||
|
||||
if (on) {
|
||||
int total;
|
||||
|
||||
hw->pending_disable = 0;
|
||||
if (!hw->enabled) {
|
||||
hw->enabled = 1;
|
||||
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
|
||||
}
|
||||
|
||||
if (sw->empty) {
|
||||
total = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hw->enabled) {
|
||||
@@ -1166,13 +940,6 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
hw->pending_disable = nb_active == 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
sc->sw.active = hw->enabled;
|
||||
if (hw->enabled) {
|
||||
audio_capture_maybe_changed (sc->cap, 1);
|
||||
}
|
||||
}
|
||||
sw->active = on;
|
||||
}
|
||||
}
|
||||
@@ -1230,7 +997,7 @@ static int audio_get_avail (SWVoiceIn *sw)
|
||||
}
|
||||
|
||||
ldebug (
|
||||
"%s: get_avail live %d ret %" PRId64 "\n",
|
||||
"%s: get_avail live %d ret %lld\n",
|
||||
SW_NAME (sw),
|
||||
live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
|
||||
);
|
||||
@@ -1256,7 +1023,7 @@ static int audio_get_free (SWVoiceOut *sw)
|
||||
dead = sw->hw->samples - live;
|
||||
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
|
||||
dolog ("%s: get_free live %d dead %d ret %lld\n",
|
||||
SW_NAME (sw),
|
||||
live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
|
||||
#endif
|
||||
@@ -1264,43 +1031,6 @@ static int audio_get_free (SWVoiceOut *sw)
|
||||
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
|
||||
}
|
||||
|
||||
static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (hw->enabled) {
|
||||
SWVoiceCap *sc;
|
||||
|
||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
SWVoiceOut *sw = &sc->sw;
|
||||
int rpos2 = rpos;
|
||||
|
||||
n = samples;
|
||||
while (n) {
|
||||
int till_end_of_hw = hw->samples - rpos2;
|
||||
int to_write = audio_MIN (till_end_of_hw, n);
|
||||
int bytes = to_write << hw->info.shift;
|
||||
int written;
|
||||
|
||||
sw->buf = hw->mix_buf + rpos2;
|
||||
written = audio_pcm_sw_write (sw, NULL, bytes);
|
||||
if (written - bytes) {
|
||||
dolog ("Could not mix %d bytes into a capture "
|
||||
"buffer, mixed %d\n",
|
||||
bytes, written);
|
||||
break;
|
||||
}
|
||||
n -= to_write;
|
||||
rpos2 = (rpos2 + to_write) % hw->samples;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = audio_MIN (samples, hw->samples - rpos);
|
||||
mixeng_clear (hw->mix_buf + rpos, n);
|
||||
mixeng_clear (hw->mix_buf, samples - n);
|
||||
}
|
||||
|
||||
static void audio_run_out (AudioState *s)
|
||||
{
|
||||
HWVoiceOut *hw = NULL;
|
||||
@@ -1308,7 +1038,7 @@ static void audio_run_out (AudioState *s)
|
||||
|
||||
while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
|
||||
int played;
|
||||
int live, free, nb_live, cleanup_required, prev_rpos;
|
||||
int live, free, nb_live, cleanup_required;
|
||||
|
||||
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
|
||||
if (!nb_live) {
|
||||
@@ -1321,17 +1051,12 @@ static void audio_run_out (AudioState *s)
|
||||
}
|
||||
|
||||
if (hw->pending_disable && !nb_live) {
|
||||
SWVoiceCap *sc;
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("Disabling voice\n");
|
||||
#endif
|
||||
hw->enabled = 0;
|
||||
hw->pending_disable = 0;
|
||||
hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
|
||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
sc->sw.active = 0;
|
||||
audio_recalc_and_notify_capture (sc->cap);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1347,7 +1072,6 @@ static void audio_run_out (AudioState *s)
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_rpos = hw->rpos;
|
||||
played = hw->pcm_ops->run_out (hw);
|
||||
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
|
||||
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
|
||||
@@ -1361,7 +1085,6 @@ static void audio_run_out (AudioState *s)
|
||||
|
||||
if (played) {
|
||||
hw->ts_helper += played;
|
||||
audio_capture_mix_and_clear (hw, prev_rpos, played);
|
||||
}
|
||||
|
||||
cleanup_required = 0;
|
||||
@@ -1392,18 +1115,15 @@ static void audio_run_out (AudioState *s)
|
||||
}
|
||||
|
||||
if (cleanup_required) {
|
||||
SWVoiceOut *sw1;
|
||||
|
||||
sw = hw->sw_head.lh_first;
|
||||
while (sw) {
|
||||
sw1 = sw->entries.le_next;
|
||||
restart:
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (!sw->active && !sw->callback.fn) {
|
||||
#ifdef DEBUG_PLIVE
|
||||
dolog ("Finishing with old voice\n");
|
||||
#endif
|
||||
audio_close_out (s, sw);
|
||||
goto restart; /* play it safe */
|
||||
}
|
||||
sw = sw1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1438,60 +1158,12 @@ static void audio_run_in (AudioState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_run_capture (AudioState *s)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
int live, rpos, captured;
|
||||
HWVoiceOut *hw = &cap->hw;
|
||||
SWVoiceOut *sw;
|
||||
|
||||
captured = live = audio_pcm_hw_get_live_out (hw);
|
||||
rpos = hw->rpos;
|
||||
while (live) {
|
||||
int left = hw->samples - rpos;
|
||||
int to_capture = audio_MIN (live, left);
|
||||
st_sample_t *src;
|
||||
struct capture_callback *cb;
|
||||
|
||||
src = hw->mix_buf + rpos;
|
||||
hw->clip (cap->buf, src, to_capture);
|
||||
mixeng_clear (src, to_capture);
|
||||
|
||||
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
|
||||
cb->ops.capture (cb->opaque, cap->buf,
|
||||
to_capture << hw->info.shift);
|
||||
}
|
||||
rpos = (rpos + to_capture) % hw->samples;
|
||||
live -= to_capture;
|
||||
}
|
||||
hw->rpos = rpos;
|
||||
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (!sw->active && sw->empty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
|
||||
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
|
||||
captured, sw->total_hw_samples_mixed);
|
||||
captured = sw->total_hw_samples_mixed;
|
||||
}
|
||||
|
||||
sw->total_hw_samples_mixed -= captured;
|
||||
sw->empty = sw->total_hw_samples_mixed == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_timer (void *opaque)
|
||||
{
|
||||
AudioState *s = opaque;
|
||||
|
||||
audio_run_out (s);
|
||||
audio_run_in (s);
|
||||
audio_run_capture (s);
|
||||
|
||||
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
|
||||
}
|
||||
@@ -1655,19 +1327,8 @@ static void audio_atexit (void)
|
||||
HWVoiceIn *hwi = NULL;
|
||||
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
|
||||
SWVoiceCap *sc;
|
||||
|
||||
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
|
||||
hwo->pcm_ops->fini_out (hwo);
|
||||
|
||||
for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
CaptureVoiceOut *cap = sc->cap;
|
||||
struct capture_callback *cb;
|
||||
|
||||
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
|
||||
cb->ops.destroy (cb->opaque);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
|
||||
@@ -1722,7 +1383,6 @@ AudioState *AUD_init (void)
|
||||
|
||||
LIST_INIT (&s->hw_head_out);
|
||||
LIST_INIT (&s->hw_head_in);
|
||||
LIST_INIT (&s->cap_head);
|
||||
atexit (audio_atexit);
|
||||
|
||||
s->ts = qemu_new_timer (vm_clock, audio_timer, s);
|
||||
@@ -1819,136 +1479,3 @@ AudioState *AUD_init (void)
|
||||
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
|
||||
return s;
|
||||
}
|
||||
|
||||
CaptureVoiceOut *AUD_add_capture (
|
||||
AudioState *s,
|
||||
audsettings_t *as,
|
||||
struct audio_capture_ops *ops,
|
||||
void *cb_opaque
|
||||
)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
struct capture_callback *cb;
|
||||
|
||||
if (!s) {
|
||||
/* XXX suppress */
|
||||
s = &glob_audio_state;
|
||||
}
|
||||
|
||||
if (audio_validate_settings (as)) {
|
||||
dolog ("Invalid settings were passed when trying to add capture\n");
|
||||
audio_print_settings (as);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
|
||||
if (!cb) {
|
||||
dolog ("Could not allocate capture callback information, size %zu\n",
|
||||
sizeof (*cb));
|
||||
goto err0;
|
||||
}
|
||||
cb->ops = *ops;
|
||||
cb->opaque = cb_opaque;
|
||||
|
||||
cap = audio_pcm_capture_find_specific (s, as);
|
||||
if (cap) {
|
||||
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
return cap;
|
||||
}
|
||||
else {
|
||||
HWVoiceOut *hw;
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
|
||||
if (!cap) {
|
||||
dolog ("Could not allocate capture voice, size %zu\n",
|
||||
sizeof (*cap));
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hw = &cap->hw;
|
||||
LIST_INIT (&hw->sw_head);
|
||||
LIST_INIT (&cap->cb_head);
|
||||
|
||||
/* XXX find a more elegant way */
|
||||
hw->samples = 4096 * 4;
|
||||
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
|
||||
sizeof (st_sample_t));
|
||||
if (!hw->mix_buf) {
|
||||
dolog ("Could not allocate capture mix buffer (%d samples)\n",
|
||||
hw->samples);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
if (!cap->buf) {
|
||||
dolog ("Could not allocate capture buffer "
|
||||
"(%d samples, each %d bytes)\n",
|
||||
hw->samples, 1 << hw->info.shift);
|
||||
goto err3;
|
||||
}
|
||||
|
||||
hw->clip = mixeng_clip
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
|
||||
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
||||
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
|
||||
hw = NULL;
|
||||
while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
|
||||
audio_attach_capture (s, hw);
|
||||
}
|
||||
return cap;
|
||||
|
||||
err3:
|
||||
qemu_free (cap->hw.mix_buf);
|
||||
err2:
|
||||
qemu_free (cap);
|
||||
err1:
|
||||
qemu_free (cb);
|
||||
err0:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
||||
{
|
||||
struct capture_callback *cb;
|
||||
|
||||
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
|
||||
if (cb->opaque == cb_opaque) {
|
||||
cb->ops.destroy (cb_opaque);
|
||||
LIST_REMOVE (cb, entries);
|
||||
qemu_free (cb);
|
||||
|
||||
if (!cap->cb_head.lh_first) {
|
||||
SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
|
||||
|
||||
while (sw) {
|
||||
SWVoiceCap *sc = (SWVoiceCap *) sw;
|
||||
#ifdef DEBUG_CAPTURE
|
||||
dolog ("freeing %s\n", sw->name);
|
||||
#endif
|
||||
|
||||
sw1 = sw->entries.le_next;
|
||||
if (sw->rate) {
|
||||
st_rate_stop (sw->rate);
|
||||
sw->rate = NULL;
|
||||
}
|
||||
LIST_REMOVE (sw, entries);
|
||||
LIST_REMOVE (sc, entries);
|
||||
qemu_free (sc);
|
||||
sw = sw1;
|
||||
}
|
||||
LIST_REMOVE (cap, entries);
|
||||
qemu_free (cap);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#ifndef QEMU_AUDIO_H
|
||||
#define QEMU_AUDIO_H
|
||||
|
||||
#include "config-host.h"
|
||||
#include "sys-queue.h"
|
||||
|
||||
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
|
||||
@@ -33,48 +32,17 @@ typedef enum {
|
||||
AUD_FMT_U8,
|
||||
AUD_FMT_S8,
|
||||
AUD_FMT_U16,
|
||||
AUD_FMT_S16,
|
||||
AUD_FMT_U32,
|
||||
AUD_FMT_S32
|
||||
AUD_FMT_S16
|
||||
} audfmt_e;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define AUDIO_HOST_ENDIANNESS 1
|
||||
#else
|
||||
#define AUDIO_HOST_ENDIANNESS 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int freq;
|
||||
int nchannels;
|
||||
audfmt_e fmt;
|
||||
int endianness;
|
||||
} audsettings_t;
|
||||
|
||||
typedef enum {
|
||||
AUD_CNOTIFY_ENABLE,
|
||||
AUD_CNOTIFY_DISABLE
|
||||
} audcnotification_e;
|
||||
|
||||
struct audio_capture_ops {
|
||||
void (*notify) (void *opaque, audcnotification_e cmd);
|
||||
void (*capture) (void *opaque, void *buf, int size);
|
||||
void (*destroy) (void *opaque);
|
||||
};
|
||||
|
||||
struct capture_ops {
|
||||
void (*info) (void *opaque);
|
||||
void (*destroy) (void *opaque);
|
||||
};
|
||||
|
||||
typedef struct CaptureState {
|
||||
void *opaque;
|
||||
struct capture_ops ops;
|
||||
LIST_ENTRY (CaptureState) entries;
|
||||
} CaptureState;
|
||||
|
||||
typedef struct AudioState AudioState;
|
||||
typedef struct SWVoiceOut SWVoiceOut;
|
||||
typedef struct CaptureVoiceOut CaptureVoiceOut;
|
||||
typedef struct SWVoiceIn SWVoiceIn;
|
||||
|
||||
typedef struct QEMUSoundCard {
|
||||
@@ -98,13 +66,6 @@ AudioState *AUD_init (void);
|
||||
void AUD_help (void);
|
||||
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
|
||||
void AUD_remove_card (QEMUSoundCard *card);
|
||||
CaptureVoiceOut *AUD_add_capture (
|
||||
AudioState *s,
|
||||
audsettings_t *as,
|
||||
struct audio_capture_ops *ops,
|
||||
void *opaque
|
||||
);
|
||||
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
|
||||
|
||||
SWVoiceOut *AUD_open_out (
|
||||
QEMUSoundCard *card,
|
||||
@@ -112,7 +73,8 @@ SWVoiceOut *AUD_open_out (
|
||||
const char *name,
|
||||
void *callback_opaque,
|
||||
audio_callback_fn_t callback_fn,
|
||||
audsettings_t *settings
|
||||
audsettings_t *settings,
|
||||
int sw_endian
|
||||
);
|
||||
|
||||
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
|
||||
@@ -130,7 +92,8 @@ SWVoiceIn *AUD_open_in (
|
||||
const char *name,
|
||||
void *callback_opaque,
|
||||
audio_callback_fn_t callback_fn,
|
||||
audsettings_t *settings
|
||||
audsettings_t *settings,
|
||||
int sw_endian
|
||||
);
|
||||
|
||||
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
|
||||
@@ -148,7 +111,7 @@ static inline void *advance (void *p, int incr)
|
||||
}
|
||||
|
||||
uint32_t popcount (uint32_t u);
|
||||
uint32_t lsbindex (uint32_t u);
|
||||
inline uint32_t lsbindex (uint32_t u);
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define audio_MIN(a, b) ( __extension__ ({ \
|
||||
|
||||
@@ -44,8 +44,8 @@ struct audio_option {
|
||||
audio_option_tag_e tag;
|
||||
void *valp;
|
||||
const char *descr;
|
||||
int *overriddenp;
|
||||
int overridden;
|
||||
int *overridenp;
|
||||
int overriden;
|
||||
};
|
||||
|
||||
struct audio_callback {
|
||||
@@ -61,14 +61,13 @@ struct audio_pcm_info {
|
||||
int align;
|
||||
int shift;
|
||||
int bytes_per_second;
|
||||
int swap_endianness;
|
||||
int swap_endian;
|
||||
};
|
||||
|
||||
typedef struct SWVoiceCap SWVoiceCap;
|
||||
|
||||
typedef struct HWVoiceOut {
|
||||
int enabled;
|
||||
int pending_disable;
|
||||
int valid;
|
||||
struct audio_pcm_info info;
|
||||
|
||||
f_sample *clip;
|
||||
@@ -80,7 +79,6 @@ typedef struct HWVoiceOut {
|
||||
|
||||
int samples;
|
||||
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
|
||||
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
|
||||
struct audio_pcm_ops *pcm_ops;
|
||||
LIST_ENTRY (HWVoiceOut) entries;
|
||||
} HWVoiceOut;
|
||||
@@ -162,34 +160,14 @@ struct audio_pcm_ops {
|
||||
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
|
||||
};
|
||||
|
||||
struct capture_callback {
|
||||
struct audio_capture_ops ops;
|
||||
void *opaque;
|
||||
LIST_ENTRY (capture_callback) entries;
|
||||
};
|
||||
|
||||
struct CaptureVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
void *buf;
|
||||
LIST_HEAD (cb_listhead, capture_callback) cb_head;
|
||||
LIST_ENTRY (CaptureVoiceOut) entries;
|
||||
};
|
||||
|
||||
struct SWVoiceCap {
|
||||
SWVoiceOut sw;
|
||||
CaptureVoiceOut *cap;
|
||||
LIST_ENTRY (SWVoiceCap) entries;
|
||||
};
|
||||
|
||||
struct AudioState {
|
||||
struct audio_driver *drv;
|
||||
void *drv_opaque;
|
||||
|
||||
QEMUTimer *ts;
|
||||
LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
|
||||
LIST_HEAD (card_head, QEMUSoundCard) card_head;
|
||||
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
|
||||
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
|
||||
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
|
||||
int nb_hw_voices_out;
|
||||
int nb_hw_voices_in;
|
||||
};
|
||||
@@ -204,7 +182,8 @@ extern struct audio_driver coreaudio_audio_driver;
|
||||
extern struct audio_driver dsound_audio_driver;
|
||||
extern volume_t nominal_volume;
|
||||
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
|
||||
int swap_endian);
|
||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
||||
|
||||
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
|
||||
@@ -225,6 +204,15 @@ static inline int audio_ring_dist (int dst, int src, int len)
|
||||
return (dst >= src) ? (dst - src) : (len - src + dst);
|
||||
}
|
||||
|
||||
static inline int audio_need_to_swap_endian (int endianness)
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return endianness != 1;
|
||||
#else
|
||||
return endianness != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined __GNUC__
|
||||
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
|
||||
#define INIT_FIELD(f) . f
|
||||
|
||||
@@ -140,12 +140,13 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
||||
SW *sw,
|
||||
HW *hw,
|
||||
const char *name,
|
||||
audsettings_t *as
|
||||
audsettings_t *as,
|
||||
int endian
|
||||
)
|
||||
{
|
||||
int err;
|
||||
|
||||
audio_pcm_init_info (&sw->info, as);
|
||||
audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian));
|
||||
sw->hw = hw;
|
||||
sw->active = 0;
|
||||
#ifdef DAC
|
||||
@@ -163,8 +164,8 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
||||
#endif
|
||||
[sw->info.nchannels == 2]
|
||||
[sw->info.sign]
|
||||
[sw->info.swap_endianness]
|
||||
[audio_bits_to_index (sw->info.bits)];
|
||||
[sw->info.swap_endian]
|
||||
[sw->info.bits == 16];
|
||||
|
||||
sw->name = qemu_strdup (name);
|
||||
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
||||
@@ -199,9 +200,6 @@ static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
|
||||
HW *hw = *hwp;
|
||||
|
||||
if (!hw->sw_head.lh_first) {
|
||||
#ifdef DAC
|
||||
audio_detach_capture (hw);
|
||||
#endif
|
||||
LIST_REMOVE (hw, entries);
|
||||
glue (s->nb_hw_voices_, TYPE) += 1;
|
||||
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
||||
@@ -268,9 +266,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
|
||||
hw->pcm_ops = drv->pcm_ops;
|
||||
LIST_INIT (&hw->sw_head);
|
||||
#ifdef DAC
|
||||
LIST_INIT (&hw->cap_head);
|
||||
#endif
|
||||
|
||||
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
|
||||
goto err0;
|
||||
}
|
||||
@@ -287,8 +283,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
#endif
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
[hw->info.swap_endian]
|
||||
[hw->info.bits == 16];
|
||||
|
||||
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
|
||||
goto err1;
|
||||
@@ -296,9 +292,6 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
|
||||
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
|
||||
glue (s->nb_hw_voices_, TYPE) -= 1;
|
||||
#ifdef DAC
|
||||
audio_attach_capture (s, hw);
|
||||
#endif
|
||||
return hw;
|
||||
|
||||
err1:
|
||||
@@ -335,7 +328,8 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
AudioState *s,
|
||||
const char *sw_name,
|
||||
audsettings_t *as
|
||||
audsettings_t *as,
|
||||
int sw_endian
|
||||
)
|
||||
{
|
||||
SW *sw;
|
||||
@@ -363,7 +357,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
|
||||
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
|
||||
|
||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
@@ -405,7 +399,8 @@ SW *glue (AUD_open_, TYPE) (
|
||||
const char *name,
|
||||
void *callback_opaque ,
|
||||
audio_callback_fn_t callback_fn,
|
||||
audsettings_t *as
|
||||
audsettings_t *as,
|
||||
int sw_endian
|
||||
)
|
||||
{
|
||||
AudioState *s;
|
||||
@@ -426,7 +421,7 @@ SW *glue (AUD_open_, TYPE) (
|
||||
|
||||
s = card->audio;
|
||||
|
||||
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
||||
if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
|
||||
audio_print_settings (as);
|
||||
goto fail;
|
||||
}
|
||||
@@ -478,12 +473,12 @@ SW *glue (AUD_open_, TYPE) (
|
||||
}
|
||||
|
||||
glue (audio_pcm_sw_fini_, TYPE) (sw);
|
||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
|
||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
|
||||
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian);
|
||||
if (!sw) {
|
||||
dolog ("Failed to create voice `%s'\n", name);
|
||||
return NULL;
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
#include <string.h> /* strerror */
|
||||
#include <pthread.h> /* pthread_X */
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "coreaudio"
|
||||
#include "audio_int.h"
|
||||
@@ -276,6 +275,8 @@ static OSStatus audioDeviceIOProc(
|
||||
#endif
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
mixeng_clear (src, frameCount);
|
||||
rpos = (rpos + frameCount) % hw->samples;
|
||||
core->decr += frameCount;
|
||||
core->rpos = rpos;
|
||||
@@ -295,6 +296,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
UInt32 propertySize;
|
||||
int err;
|
||||
int bits = 8;
|
||||
int endianess = 0;
|
||||
const char *typ = "playback";
|
||||
AudioValueRange frameRange;
|
||||
|
||||
@@ -305,7 +308,18 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
return -1;
|
||||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
|
||||
bits = 16;
|
||||
endianess = 1;
|
||||
}
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
as,
|
||||
/* Following is irrelevant actually since we do not use
|
||||
mixengs clipping routines */
|
||||
audio_need_to_swap_endian (endianess)
|
||||
);
|
||||
|
||||
/* open default output device */
|
||||
propertySize = sizeof(core->outputDeviceID);
|
||||
|
||||
@@ -70,13 +70,7 @@ static int glue (dsound_lock_, TYPE) (
|
||||
int i;
|
||||
LPVOID p1 = NULL, p2 = NULL;
|
||||
DWORD blen1 = 0, blen2 = 0;
|
||||
DWORD flag;
|
||||
|
||||
#ifdef DSBTYPE_IN
|
||||
flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
|
||||
#else
|
||||
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
|
||||
#endif
|
||||
for (i = 0; i < conf.lock_retries; ++i) {
|
||||
hr = glue (IFACE, _Lock) (
|
||||
buf,
|
||||
@@ -86,7 +80,13 @@ static int glue (dsound_lock_, TYPE) (
|
||||
&blen1,
|
||||
&p2,
|
||||
&blen2,
|
||||
flag
|
||||
(entire
|
||||
#ifdef DSBTYPE_IN
|
||||
? DSCBLOCK_ENTIREBUFFER
|
||||
#else
|
||||
? DSBLOCK_ENTIREBUFFER
|
||||
#endif
|
||||
: 0)
|
||||
);
|
||||
|
||||
if (FAILED (hr)) {
|
||||
@@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
}
|
||||
|
||||
ds->first_time = 1;
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
|
||||
|
||||
if (bc.dwBufferBytes & hw->info.align) {
|
||||
dolog (
|
||||
|
||||
@@ -26,15 +26,12 @@
|
||||
* SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "dsound"
|
||||
#include "audio_int.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <objbase.h>
|
||||
#include <dsound.h>
|
||||
|
||||
@@ -456,11 +453,13 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
|
||||
|
||||
if (src_len1) {
|
||||
hw->clip (dst, src1, src_len1);
|
||||
mixeng_clear (src1, src_len1);
|
||||
}
|
||||
|
||||
if (src_len2) {
|
||||
dst = advance (dst, src_len1 << hw->info.shift);
|
||||
hw->clip (dst, src2, src_len2);
|
||||
mixeng_clear (src2, src_len2);
|
||||
}
|
||||
|
||||
hw->rpos = pos % hw->samples;
|
||||
@@ -988,12 +987,6 @@ static void *dsound_audio_init (void)
|
||||
hr = IDirectSound_Initialize (s->dsound, NULL);
|
||||
if (FAILED (hr)) {
|
||||
dsound_logerr (hr, "Could not initialize DirectSound\n");
|
||||
|
||||
hr = IDirectSound_Release (s->dsound);
|
||||
if (FAILED (hr)) {
|
||||
dsound_logerr (hr, "Could not release DirectSound\n");
|
||||
}
|
||||
s->dsound = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
*/
|
||||
#include <fmod.h>
|
||||
#include <fmod_errors.h>
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "fmod"
|
||||
#include "audio_int.h"
|
||||
@@ -154,11 +153,13 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
|
||||
|
||||
if (src_len1) {
|
||||
hw->clip (dst, src1, src_len1);
|
||||
mixeng_clear (src1, src_len1);
|
||||
}
|
||||
|
||||
if (src_len2) {
|
||||
dst = advance (dst, src_len1 << hw->info.shift);
|
||||
hw->clip (dst, src2, src_len2);
|
||||
mixeng_clear (src2, src_len2);
|
||||
}
|
||||
|
||||
hw->rpos = pos % hw->samples;
|
||||
@@ -359,7 +360,6 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
{
|
||||
int bits16, mode, channel;
|
||||
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
|
||||
audsettings_t obt_as = *as;
|
||||
|
||||
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
|
||||
fmd->fmod_sample = FSOUND_Sample_Alloc (
|
||||
@@ -386,8 +386,7 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
fmd->channel = channel;
|
||||
|
||||
/* FMOD always operates on little endian frames? */
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
|
||||
bits16 = (mode & FSOUND_16BITS) != 0;
|
||||
hw->samples = conf.nb_samples;
|
||||
return 0;
|
||||
@@ -421,7 +420,6 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||
{
|
||||
int bits16, mode;
|
||||
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
|
||||
audsettings_t obt_as = *as;
|
||||
|
||||
if (conf.broken_adc) {
|
||||
return -1;
|
||||
@@ -444,8 +442,7 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||
}
|
||||
|
||||
/* FMOD always operates on little endian frames? */
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
|
||||
bits16 = (mode & FSOUND_16BITS) != 0;
|
||||
hw->samples = conf.nb_samples;
|
||||
return 0;
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "mixeng"
|
||||
#include "audio_int.h"
|
||||
@@ -83,7 +82,6 @@
|
||||
#undef IN_T
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 16 bit */
|
||||
#define IN_T uint16_t
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX USHRT_MAX
|
||||
@@ -103,72 +101,26 @@
|
||||
#undef IN_T
|
||||
#undef SHIFT
|
||||
|
||||
/* Signed 32 bit */
|
||||
#define IN_T int32_t
|
||||
#define IN_MIN INT32_MIN
|
||||
#define IN_MAX INT32_MAX
|
||||
#define SIGNED
|
||||
#define SHIFT 32
|
||||
#define ENDIAN_CONVERSION natural
|
||||
#define ENDIAN_CONVERT(v) (v)
|
||||
#include "mixeng_template.h"
|
||||
#undef ENDIAN_CONVERT
|
||||
#undef ENDIAN_CONVERSION
|
||||
#define ENDIAN_CONVERSION swap
|
||||
#define ENDIAN_CONVERT(v) bswap32 (v)
|
||||
#include "mixeng_template.h"
|
||||
#undef ENDIAN_CONVERT
|
||||
#undef ENDIAN_CONVERSION
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 16 bit */
|
||||
#define IN_T uint32_t
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX UINT32_MAX
|
||||
#define SHIFT 32
|
||||
#define ENDIAN_CONVERSION natural
|
||||
#define ENDIAN_CONVERT(v) (v)
|
||||
#include "mixeng_template.h"
|
||||
#undef ENDIAN_CONVERT
|
||||
#undef ENDIAN_CONVERSION
|
||||
#define ENDIAN_CONVERSION swap
|
||||
#define ENDIAN_CONVERT(v) bswap32 (v)
|
||||
#include "mixeng_template.h"
|
||||
#undef ENDIAN_CONVERT
|
||||
#undef ENDIAN_CONVERSION
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef SHIFT
|
||||
|
||||
t_sample *mixeng_conv[2][2][2][3] = {
|
||||
t_sample *mixeng_conv[2][2][2][2] = {
|
||||
{
|
||||
{
|
||||
{
|
||||
conv_natural_uint8_t_to_mono,
|
||||
conv_natural_uint16_t_to_mono,
|
||||
conv_natural_uint32_t_to_mono
|
||||
conv_natural_uint16_t_to_mono
|
||||
},
|
||||
{
|
||||
conv_natural_uint8_t_to_mono,
|
||||
conv_swap_uint16_t_to_mono,
|
||||
conv_swap_uint32_t_to_mono,
|
||||
conv_swap_uint16_t_to_mono
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
conv_natural_int8_t_to_mono,
|
||||
conv_natural_int16_t_to_mono,
|
||||
conv_natural_int32_t_to_mono
|
||||
conv_natural_int16_t_to_mono
|
||||
},
|
||||
{
|
||||
conv_natural_int8_t_to_mono,
|
||||
conv_swap_int16_t_to_mono,
|
||||
conv_swap_int32_t_to_mono
|
||||
conv_swap_int16_t_to_mono
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -176,54 +128,46 @@ t_sample *mixeng_conv[2][2][2][3] = {
|
||||
{
|
||||
{
|
||||
conv_natural_uint8_t_to_stereo,
|
||||
conv_natural_uint16_t_to_stereo,
|
||||
conv_natural_uint32_t_to_stereo
|
||||
conv_natural_uint16_t_to_stereo
|
||||
},
|
||||
{
|
||||
conv_natural_uint8_t_to_stereo,
|
||||
conv_swap_uint16_t_to_stereo,
|
||||
conv_swap_uint32_t_to_stereo
|
||||
conv_swap_uint16_t_to_stereo
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
conv_natural_int8_t_to_stereo,
|
||||
conv_natural_int16_t_to_stereo,
|
||||
conv_natural_int32_t_to_stereo
|
||||
conv_natural_int16_t_to_stereo
|
||||
},
|
||||
{
|
||||
conv_natural_int8_t_to_stereo,
|
||||
conv_swap_int16_t_to_stereo,
|
||||
conv_swap_int32_t_to_stereo,
|
||||
conv_swap_int16_t_to_stereo
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
f_sample *mixeng_clip[2][2][2][3] = {
|
||||
f_sample *mixeng_clip[2][2][2][2] = {
|
||||
{
|
||||
{
|
||||
{
|
||||
clip_natural_uint8_t_from_mono,
|
||||
clip_natural_uint16_t_from_mono,
|
||||
clip_natural_uint32_t_from_mono
|
||||
clip_natural_uint16_t_from_mono
|
||||
},
|
||||
{
|
||||
clip_natural_uint8_t_from_mono,
|
||||
clip_swap_uint16_t_from_mono,
|
||||
clip_swap_uint32_t_from_mono
|
||||
clip_swap_uint16_t_from_mono
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
clip_natural_int8_t_from_mono,
|
||||
clip_natural_int16_t_from_mono,
|
||||
clip_natural_int32_t_from_mono
|
||||
clip_natural_int16_t_from_mono
|
||||
},
|
||||
{
|
||||
clip_natural_int8_t_from_mono,
|
||||
clip_swap_int16_t_from_mono,
|
||||
clip_swap_int32_t_from_mono
|
||||
clip_swap_int16_t_from_mono
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -231,25 +175,21 @@ f_sample *mixeng_clip[2][2][2][3] = {
|
||||
{
|
||||
{
|
||||
clip_natural_uint8_t_from_stereo,
|
||||
clip_natural_uint16_t_from_stereo,
|
||||
clip_natural_uint32_t_from_stereo
|
||||
clip_natural_uint16_t_from_stereo
|
||||
},
|
||||
{
|
||||
clip_natural_uint8_t_from_stereo,
|
||||
clip_swap_uint16_t_from_stereo,
|
||||
clip_swap_uint32_t_from_stereo
|
||||
clip_swap_uint16_t_from_stereo
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
clip_natural_int8_t_from_stereo,
|
||||
clip_natural_int16_t_from_stereo,
|
||||
clip_natural_int32_t_from_stereo
|
||||
clip_natural_int16_t_from_stereo
|
||||
},
|
||||
{
|
||||
clip_natural_int8_t_from_stereo,
|
||||
clip_swap_int16_t_from_stereo,
|
||||
clip_swap_int32_t_from_stereo
|
||||
clip_swap_int16_t_from_stereo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ typedef void (t_sample) (st_sample_t *dst, const void *src,
|
||||
int samples, volume_t *vol);
|
||||
typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
|
||||
|
||||
extern t_sample *mixeng_conv[2][2][2][3];
|
||||
extern f_sample *mixeng_clip[2][2][2][3];
|
||||
extern t_sample *mixeng_conv[2][2][2][2];
|
||||
extern f_sample *mixeng_clip[2][2][2][2];
|
||||
|
||||
void *st_rate_start (int inrate, int outrate);
|
||||
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "noaudio"
|
||||
#include "audio_int.h"
|
||||
@@ -42,21 +40,22 @@ static int no_run_out (HWVoiceOut *hw)
|
||||
{
|
||||
NoVoiceOut *no = (NoVoiceOut *) hw;
|
||||
int live, decr, samples;
|
||||
int64_t now;
|
||||
int64_t ticks;
|
||||
int64_t bytes;
|
||||
int64_t now = qemu_get_clock (vm_clock);
|
||||
int64_t ticks = now - no->old_ticks;
|
||||
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
||||
|
||||
if (bytes > INT_MAX) {
|
||||
samples = INT_MAX >> hw->info.shift;
|
||||
}
|
||||
else {
|
||||
samples = bytes >> hw->info.shift;
|
||||
}
|
||||
|
||||
live = audio_pcm_hw_get_live_out (&no->hw);
|
||||
if (!live) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
now = qemu_get_clock (vm_clock);
|
||||
ticks = now - no->old_ticks;
|
||||
bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
||||
bytes = audio_MIN (bytes, INT_MAX);
|
||||
samples = bytes >> hw->info.shift;
|
||||
|
||||
no->old_ticks = now;
|
||||
decr = audio_MIN (live, samples);
|
||||
hw->rpos = (hw->rpos + decr) % hw->samples;
|
||||
@@ -70,7 +69,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len)
|
||||
|
||||
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
{
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
audio_pcm_init_info (&hw->info, as, 0);
|
||||
hw->samples = 1024;
|
||||
return 0;
|
||||
}
|
||||
@@ -89,7 +88,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
|
||||
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||
{
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
audio_pcm_init_info (&hw->info, as, 0);
|
||||
hw->samples = 1024;
|
||||
return 0;
|
||||
}
|
||||
@@ -102,20 +101,17 @@ static void no_fini_in (HWVoiceIn *hw)
|
||||
static int no_run_in (HWVoiceIn *hw)
|
||||
{
|
||||
NoVoiceIn *no = (NoVoiceIn *) hw;
|
||||
int64_t now = qemu_get_clock (vm_clock);
|
||||
int64_t ticks = now - no->old_ticks;
|
||||
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
||||
int live = audio_pcm_hw_get_live_in (hw);
|
||||
int dead = hw->samples - live;
|
||||
int samples = 0;
|
||||
int samples;
|
||||
|
||||
if (dead) {
|
||||
int64_t now = qemu_get_clock (vm_clock);
|
||||
int64_t ticks = now - no->old_ticks;
|
||||
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
||||
bytes = audio_MIN (bytes, INT_MAX);
|
||||
samples = bytes >> hw->info.shift;
|
||||
samples = audio_MIN (samples, dead);
|
||||
|
||||
no->old_ticks = now;
|
||||
bytes = audio_MIN (bytes, INT_MAX);
|
||||
samples = bytes >> hw->info.shift;
|
||||
samples = audio_MIN (samples, dead);
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,17 +21,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "oss"
|
||||
#include "audio_int.h"
|
||||
@@ -61,14 +55,12 @@ static struct {
|
||||
int fragsize;
|
||||
const char *devpath_out;
|
||||
const char *devpath_in;
|
||||
int debug;
|
||||
} conf = {
|
||||
.try_mmap = 0,
|
||||
.nfrags = 4,
|
||||
.fragsize = 4096,
|
||||
.devpath_out = "/dev/dsp",
|
||||
.devpath_in = "/dev/dsp",
|
||||
.debug = 0
|
||||
.devpath_in = "/dev/dsp"
|
||||
};
|
||||
|
||||
struct oss_params {
|
||||
@@ -332,20 +324,9 @@ static int oss_run_out (HWVoiceOut *hw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (abinfo.bytes > bufsize) {
|
||||
if (conf.debug) {
|
||||
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
|
||||
"please report your OS/audio hw to malc@pulsesoft.com\n",
|
||||
abinfo.bytes, bufsize);
|
||||
}
|
||||
abinfo.bytes = bufsize;
|
||||
}
|
||||
|
||||
if (abinfo.bytes < 0) {
|
||||
if (conf.debug) {
|
||||
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
|
||||
abinfo.bytes, bufsize);
|
||||
}
|
||||
if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
|
||||
ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
|
||||
abinfo.bytes, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -388,12 +369,15 @@ static int oss_run_out (HWVoiceOut *hw)
|
||||
"alignment %d\n",
|
||||
wbytes, written, hw->info.align + 1);
|
||||
}
|
||||
mixeng_clear (src, wsamples);
|
||||
decr -= wsamples;
|
||||
rpos = (rpos + wsamples) % hw->samples;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mixeng_clear (src, convert_samples);
|
||||
|
||||
rpos = (rpos + convert_samples) % hw->samples;
|
||||
samples -= convert_samples;
|
||||
}
|
||||
@@ -459,9 +443,12 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (endianness)
|
||||
);
|
||||
oss->nfrags = obt.nfrags;
|
||||
oss->fragsize = obt.fragsize;
|
||||
|
||||
@@ -600,9 +587,12 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (endianness)
|
||||
);
|
||||
oss->nfrags = obt.nfrags;
|
||||
oss->fragsize = obt.fragsize;
|
||||
|
||||
@@ -740,8 +730,6 @@ static struct audio_option oss_options[] = {
|
||||
"Path to DAC device", NULL, 0},
|
||||
{"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
|
||||
"Path to ADC device", NULL, 0},
|
||||
{"DEBUG", AUD_OPT_BOOL, &conf.debug,
|
||||
"Turn on some debugging messages", NULL, 0},
|
||||
{NULL, 0, NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
|
||||
if (rate->opos_inc == (1ULL + UINT_MAX)) {
|
||||
int i, n = *isamp > *osamp ? *osamp : *isamp;
|
||||
for (i = 0; i < n; i++) {
|
||||
OP (obuf[i].l, ibuf[i].l);
|
||||
OP (obuf[i].l, ibuf[i].r);
|
||||
OP (obuf[i].r, ibuf[i].r);
|
||||
}
|
||||
*isamp = n;
|
||||
|
||||
@@ -23,15 +23,7 @@
|
||||
*/
|
||||
#include <SDL.h>
|
||||
#include <SDL_thread.h>
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef __sun__
|
||||
#define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "sdl"
|
||||
#include "audio_int.h"
|
||||
@@ -185,22 +177,11 @@ static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
|
||||
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
||||
{
|
||||
int status;
|
||||
#ifndef _WIN32
|
||||
sigset_t new, old;
|
||||
|
||||
/* Make sure potential threads created by SDL don't hog signals. */
|
||||
sigfillset (&new);
|
||||
pthread_sigmask (SIG_BLOCK, &new, &old);
|
||||
#endif
|
||||
|
||||
status = SDL_OpenAudio (req, obt);
|
||||
if (status) {
|
||||
sdl_logerr ("SDL_OpenAudio failed\n");
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
pthread_sigmask (SIG_SETMASK, &old, 0);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -259,6 +240,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
|
||||
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||
hw->clip (buf, src, chunk);
|
||||
mixeng_clear (src, chunk);
|
||||
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
||||
to_mix -= chunk;
|
||||
buf += chunk << hw->info.shift;
|
||||
@@ -354,9 +336,12 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.channels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianess;
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (endianess)
|
||||
);
|
||||
hw->samples = obt.samples;
|
||||
|
||||
s->initialized = 1;
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "hw/hw.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "audio.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define AUDIO_CAP "wav"
|
||||
#include "audio_int.h"
|
||||
@@ -43,8 +41,7 @@ static struct {
|
||||
{
|
||||
44100,
|
||||
2,
|
||||
AUD_FMT_S16,
|
||||
AUDIO_HOST_ENDIANNESS
|
||||
AUD_FMT_S16
|
||||
},
|
||||
"qemu.wav"
|
||||
};
|
||||
@@ -84,6 +81,7 @@ static int wav_run_out (HWVoiceOut *hw)
|
||||
|
||||
hw->clip (dst, src, convert_samples);
|
||||
qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
|
||||
mixeng_clear (src, convert_samples);
|
||||
|
||||
rpos = (rpos + convert_samples) % hw->samples;
|
||||
samples -= convert_samples;
|
||||
@@ -134,17 +132,11 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
case AUD_FMT_U16:
|
||||
bits16 = 1;
|
||||
break;
|
||||
|
||||
case AUD_FMT_S32:
|
||||
case AUD_FMT_U32:
|
||||
dolog ("WAVE files can not handle 32bit formats\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr[34] = bits16 ? 0x10 : 0x08;
|
||||
|
||||
wav_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &wav_as);
|
||||
audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0));
|
||||
|
||||
hw->samples = 1024;
|
||||
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
|
||||
@@ -159,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 = qemu_fopen (conf.wav_path, "wb");
|
||||
wav->f = fopen (conf.wav_path, "wb");
|
||||
if (!wav->f) {
|
||||
dolog ("Failed to open wave file `%s'\nReason: %s\n",
|
||||
conf.wav_path, strerror (errno));
|
||||
@@ -193,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw)
|
||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||
qemu_put_buffer (wav->f, dlen, 4);
|
||||
|
||||
qemu_fclose (wav->f);
|
||||
fclose (wav->f);
|
||||
wav->f = NULL;
|
||||
|
||||
qemu_free (wav->pcm_buf);
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
#include "hw/hw.h"
|
||||
#include "console.h"
|
||||
#include "audio.h"
|
||||
|
||||
typedef struct {
|
||||
QEMUFile *f;
|
||||
int bytes;
|
||||
char *path;
|
||||
int freq;
|
||||
int bits;
|
||||
int nchannels;
|
||||
CaptureVoiceOut *cap;
|
||||
} WAVState;
|
||||
|
||||
/* VICE code: Store number as little endian. */
|
||||
static void le_store (uint8_t *buf, uint32_t val, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = (uint8_t) (val & 0xff);
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void wav_notify (void *opaque, audcnotification_e cmd)
|
||||
{
|
||||
(void) opaque;
|
||||
(void) cmd;
|
||||
}
|
||||
|
||||
static void wav_destroy (void *opaque)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
uint8_t rlen[4];
|
||||
uint8_t dlen[4];
|
||||
uint32_t datalen = wav->bytes;
|
||||
uint32_t rifflen = datalen + 36;
|
||||
|
||||
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)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
|
||||
qemu_put_buffer (wav->f, buf, size);
|
||||
wav->bytes += size;
|
||||
}
|
||||
|
||||
static void wav_capture_destroy (void *opaque)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
|
||||
AUD_del_capture (wav->cap, wav);
|
||||
}
|
||||
|
||||
static void wav_capture_info (void *opaque)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
char *path = wav->path;
|
||||
|
||||
term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
|
||||
wav->freq, wav->bits, wav->nchannels,
|
||||
path ? path : "<not available>", wav->bytes);
|
||||
}
|
||||
|
||||
static struct capture_ops wav_capture_ops = {
|
||||
.destroy = wav_capture_destroy,
|
||||
.info = wav_capture_info
|
||||
};
|
||||
|
||||
int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
int bits, int nchannels)
|
||||
{
|
||||
WAVState *wav;
|
||||
uint8_t hdr[] = {
|
||||
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
|
||||
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
|
||||
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
audsettings_t as;
|
||||
struct audio_capture_ops ops;
|
||||
int stereo, bits16, shift;
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
if (bits != 8 && bits != 16) {
|
||||
term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nchannels != 1 && nchannels != 2) {
|
||||
term_printf ("incorrect channel count %d, must be 1 or 2\n",
|
||||
nchannels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
stereo = nchannels == 2;
|
||||
bits16 = bits == 16;
|
||||
|
||||
as.freq = freq;
|
||||
as.nchannels = 1 << stereo;
|
||||
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
|
||||
as.endianness = 0;
|
||||
|
||||
ops.notify = wav_notify;
|
||||
ops.capture = wav_capture;
|
||||
ops.destroy = wav_destroy;
|
||||
|
||||
wav = qemu_mallocz (sizeof (*wav));
|
||||
if (!wav) {
|
||||
term_printf ("Could not allocate memory for wav capture (%zu bytes)",
|
||||
sizeof (*wav));
|
||||
return -1;
|
||||
}
|
||||
|
||||
shift = bits16 + stereo;
|
||||
hdr[34] = bits16 ? 0x10 : 0x08;
|
||||
|
||||
le_store (hdr + 22, as.nchannels, 2);
|
||||
le_store (hdr + 24, freq, 4);
|
||||
le_store (hdr + 28, freq << shift, 4);
|
||||
le_store (hdr + 32, 1 << shift, 2);
|
||||
|
||||
wav->f = qemu_fopen (path, "wb");
|
||||
if (!wav->f) {
|
||||
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
|
||||
path, strerror (errno));
|
||||
qemu_free (wav);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wav->path = qemu_strdup (path);
|
||||
wav->bits = bits;
|
||||
wav->nchannels = nchannels;
|
||||
wav->freq = freq;
|
||||
|
||||
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
wav->cap = cap;
|
||||
s->opaque = wav;
|
||||
s->ops = wav_capture_ops;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Block driver for the various disk image formats used by Bochs
|
||||
* Currently only for "growing" type in read-only mode
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2005 Alex Beregszaszi
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -22,14 +22,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
#define HEADER_MAGIC "Bochs Virtual HD Image"
|
||||
#define HEADER_VERSION 0x00020000
|
||||
#define HEADER_V1 0x00010000
|
||||
#define HEADER_VERSION 0x00010000
|
||||
#define HEADER_SIZE 512
|
||||
|
||||
#define REDOLOG_TYPE "Redolog"
|
||||
@@ -38,13 +37,13 @@
|
||||
// not allocated: 0xffffffff
|
||||
|
||||
// always little-endian
|
||||
struct bochs_header_v1 {
|
||||
struct bochs_header {
|
||||
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
|
||||
@@ -57,35 +56,14 @@ struct bochs_header_v1 {
|
||||
} extra;
|
||||
};
|
||||
|
||||
// always little-endian
|
||||
struct bochs_header {
|
||||
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
|
||||
uint32_t reserved; // for ???
|
||||
uint64_t disk; // disk size
|
||||
char padding[HEADER_SIZE - 64 - 8 - 24];
|
||||
} redolog;
|
||||
char padding[HEADER_SIZE - 64 - 8];
|
||||
} extra;
|
||||
};
|
||||
|
||||
typedef struct BDRVBochsState {
|
||||
int fd;
|
||||
|
||||
uint32_t *catalog_bitmap;
|
||||
int catalog_size;
|
||||
|
||||
|
||||
int data_offset;
|
||||
|
||||
|
||||
int bitmap_blocks;
|
||||
int extent_blocks;
|
||||
int extent_size;
|
||||
@@ -94,36 +72,34 @@ typedef struct BDRVBochsState {
|
||||
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
const struct bochs_header *bochs = (const void *)buf;
|
||||
|
||||
|
||||
if (buf_size < HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
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_V1)))
|
||||
(le32_to_cpu(bochs->version) == HEADER_VERSION))
|
||||
return 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
static int bochs_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int fd, i;
|
||||
struct bochs_header bochs;
|
||||
struct bochs_header_v1 header_v1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_BINARY);
|
||||
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bs->read_only = 1; // no write support yet
|
||||
|
||||
|
||||
s->fd = fd;
|
||||
|
||||
if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
|
||||
@@ -133,17 +109,11 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
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_V1))) {
|
||||
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
|
||||
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
|
||||
|
||||
@@ -161,7 +131,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
|
||||
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
|
||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
|
||||
|
||||
|
||||
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
|
||||
|
||||
return 0;
|
||||
@@ -180,7 +150,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
// seek to sector
|
||||
extent_index = offset / s->extent_size;
|
||||
extent_offset = (offset % s->extent_size) / 512;
|
||||
|
||||
|
||||
if (s->catalog_bitmap[extent_index] == 0xffffffff)
|
||||
{
|
||||
// fprintf(stderr, "page not allocated [%x - %x:%x]\n",
|
||||
@@ -191,17 +161,17 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
|
||||
(s->extent_blocks + s->bitmap_blocks));
|
||||
block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||
|
||||
|
||||
// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
|
||||
// sector_num, extent_index, extent_offset,
|
||||
// le32_to_cpu(s->catalog_bitmap[extent_index]),
|
||||
// bitmap_offset, block_offset);
|
||||
|
||||
|
||||
// read in bitmap for current extent
|
||||
lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
|
||||
|
||||
|
||||
read(s->fd, &bitmap_entry, 1);
|
||||
|
||||
|
||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1))
|
||||
{
|
||||
// fprintf(stderr, "sector (%x) in bitmap not allocated\n",
|
||||
@@ -210,11 +180,11 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
}
|
||||
|
||||
lseek(s->fd, block_offset, SEEK_SET);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QEMU Block driver for CLOOP images
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 Johannes E. Schindelin
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
#include <zlib.h>
|
||||
|
||||
@@ -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, int flags)
|
||||
static int cloop_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
uint32_t offsets_size,max_compressed_block_size=1,i;
|
||||
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY);
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (s->fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
bs->read_only = 1;
|
||||
|
||||
/* read header */
|
||||
@@ -96,7 +96,7 @@ cloop_close:
|
||||
if(inflateInit(&s->zstream) != Z_OK)
|
||||
goto cloop_close;
|
||||
s->current_block=s->n_blocks;
|
||||
|
||||
|
||||
s->sectors_per_block = s->block_size/512;
|
||||
bs->total_sectors = s->n_blocks*s->sectors_per_block;
|
||||
return 0;
|
||||
@@ -107,12 +107,12 @@ static inline int cloop_read_block(BDRVCloopState *s,int block_num)
|
||||
if(s->current_block != block_num) {
|
||||
int ret;
|
||||
uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
|
||||
|
||||
|
||||
lseek(s->fd, s->offsets[block_num], SEEK_SET);
|
||||
ret = read(s->fd, s->compressed_block, bytes);
|
||||
if (ret != bytes)
|
||||
if (ret != bytes)
|
||||
return -1;
|
||||
|
||||
|
||||
s->zstream.next_in = s->compressed_block;
|
||||
s->zstream.avail_in = bytes;
|
||||
s->zstream.next_out = s->uncompressed_block;
|
||||
@@ -123,13 +123,13 @@ static inline int cloop_read_block(BDRVCloopState *s,int block_num)
|
||||
ret = inflate(&s->zstream, Z_FINISH);
|
||||
if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
|
||||
return -1;
|
||||
|
||||
|
||||
s->current_block = block_num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
|
||||
77
block-cow.c
77
block-cow.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Block driver for the COW format
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 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
|
||||
@@ -22,7 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
@@ -56,13 +56,13 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
|
||||
if (buf_size >= sizeof(struct cow_header_v2) &&
|
||||
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
|
||||
be32_to_cpu(cow_header->version) == COW_VERSION)
|
||||
be32_to_cpu(cow_header->version) == COW_VERSION)
|
||||
return 100;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
static int cow_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
int fd;
|
||||
@@ -85,18 +85,34 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
be32_to_cpu(cow_header.version) != COW_VERSION) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* cow image found */
|
||||
size = be64_to_cpu(cow_header.size);
|
||||
bs->total_sectors = size / 512;
|
||||
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
||||
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),
|
||||
s->cow_bitmap_size,
|
||||
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
|
||||
s->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, s->fd, 0);
|
||||
if (s->cow_bitmap_addr == MAP_FAILED)
|
||||
@@ -143,35 +159,28 @@ static inline int is_changed(uint8_t *bitmap,
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
|
||||
}
|
||||
|
||||
static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
int ret, n;
|
||||
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
|
||||
ret = read(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
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;
|
||||
@@ -179,15 +188,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
static int cow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
int ret, i;
|
||||
|
||||
|
||||
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
|
||||
ret = write(s->fd, buf, nb_sectors * 512);
|
||||
if (ret != nb_sectors * 512)
|
||||
if (ret != nb_sectors * 512)
|
||||
return -1;
|
||||
for (i = 0; i < nb_sectors; i++)
|
||||
cow_set_bit(s->cow_bitmap, sector_num + i);
|
||||
@@ -211,7 +220,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,
|
||||
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
if (cow_fd < 0)
|
||||
return -1;
|
||||
@@ -219,23 +228,18 @@ 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);
|
||||
goto mtime_fail;
|
||||
return -1;
|
||||
}
|
||||
if (fstat(fd, &st) != 0) {
|
||||
close(fd);
|
||||
goto mtime_fail;
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
cow_header.mtime = cpu_to_be32(st.st_mtime);
|
||||
mtime_fail:
|
||||
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
|
||||
image_filename);
|
||||
realpath(image_filename, cow_header.backing_file);
|
||||
}
|
||||
cow_header.sectorsize = cpu_to_be32(512);
|
||||
cow_header.size = cpu_to_be64(image_sectors * 512);
|
||||
@@ -246,12 +250,6 @@ static int cow_create(const char *filename, int64_t image_sectors,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cow_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_cow = {
|
||||
"cow",
|
||||
sizeof(BDRVCowState),
|
||||
@@ -261,7 +259,6 @@ BlockDriver bdrv_cow = {
|
||||
cow_write,
|
||||
cow_close,
|
||||
cow_create,
|
||||
cow_flush,
|
||||
cow_is_allocated,
|
||||
};
|
||||
#endif
|
||||
|
||||
24
block-dmg.c
24
block-dmg.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QEMU Block driver for DMG images
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 Johannes E. Schindelin
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -21,14 +21,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
#include "bswap.h"
|
||||
#include <zlib.h>
|
||||
|
||||
typedef struct BDRVDMGState {
|
||||
int fd;
|
||||
|
||||
|
||||
/* each chunk contains a certain number of sectors,
|
||||
* offsets[i] is the offset in the .dmg file,
|
||||
* lengths[i] is the length of the compressed chunk,
|
||||
@@ -73,27 +73,27 @@ static off_t read_uint32(int fd)
|
||||
return be32_to_cpu(buffer);
|
||||
}
|
||||
|
||||
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
static int dmg_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
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);
|
||||
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (s->fd < 0)
|
||||
return -errno;
|
||||
return -1;
|
||||
bs->read_only = 1;
|
||||
s->n_chunks = 0;
|
||||
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
|
||||
|
||||
|
||||
/* read offset of info blocks */
|
||||
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
|
||||
dmg_close:
|
||||
close(s->fd);
|
||||
/* open raw instead */
|
||||
bs->drv=&bdrv_raw;
|
||||
return bs->drv->bdrv_open(bs, filename, flags);
|
||||
return bs->drv->bdrv_open(bs,filename);
|
||||
}
|
||||
info_begin=read_off(s->fd);
|
||||
if(info_begin==0)
|
||||
@@ -167,7 +167,7 @@ dmg_close:
|
||||
goto dmg_close;
|
||||
|
||||
s->current_chunk = s->n_chunks;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
|
||||
|
||||
if (ret != s->lengths[chunk])
|
||||
return -1;
|
||||
|
||||
|
||||
s->zstream.next_in = s->compressed_chunk;
|
||||
s->zstream.avail_in = s->lengths[chunk];
|
||||
s->zstream.next_out = s->uncompressed_chunk;
|
||||
@@ -253,7 +253,7 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Block driver for Parallels disk image format
|
||||
*
|
||||
* Copyright (c) 2007 Alex Beregszaszi
|
||||
*
|
||||
* This code is based on comparing different disk images created by Parallels.
|
||||
*
|
||||
* 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 "qemu-common.h"
|
||||
#include "block_int.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
#define HEADER_MAGIC "WithoutFreeSpace"
|
||||
#define HEADER_VERSION 2
|
||||
#define HEADER_SIZE 64
|
||||
|
||||
// always little-endian
|
||||
struct parallels_header {
|
||||
char magic[16]; // "WithoutFreeSpace"
|
||||
uint32_t version;
|
||||
uint32_t heads;
|
||||
uint32_t cylinders;
|
||||
uint32_t tracks;
|
||||
uint32_t catalog_entries;
|
||||
uint32_t nb_sectors;
|
||||
char padding[24];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct BDRVParallelsState {
|
||||
int fd;
|
||||
|
||||
uint32_t *catalog_bitmap;
|
||||
int catalog_size;
|
||||
|
||||
int tracks;
|
||||
} BDRVParallelsState;
|
||||
|
||||
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
const struct parallels_header *ph = (const void *)buf;
|
||||
|
||||
if (buf_size < HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
if (!memcmp(ph->magic, HEADER_MAGIC, 16) &&
|
||||
(le32_to_cpu(ph->version) == HEADER_VERSION))
|
||||
return 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parallels_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
int fd, i;
|
||||
struct parallels_header ph;
|
||||
|
||||
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; // no write support yet
|
||||
|
||||
s->fd = fd;
|
||||
|
||||
if (read(fd, &ph, sizeof(ph)) != sizeof(ph))
|
||||
goto fail;
|
||||
|
||||
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
|
||||
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
||||
|
||||
if (lseek(s->fd, 64, SEEK_SET) != 64)
|
||||
goto fail;
|
||||
|
||||
s->tracks = le32_to_cpu(ph.tracks);
|
||||
|
||||
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
||||
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
|
||||
if (!s->catalog_bitmap)
|
||||
goto fail;
|
||||
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
|
||||
s->catalog_size * 4)
|
||||
goto fail;
|
||||
for (i = 0; i < s->catalog_size; i++)
|
||||
le32_to_cpus(&s->catalog_bitmap[i]);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (s->catalog_bitmap)
|
||||
qemu_free(s->catalog_bitmap);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
uint32_t index, offset, position;
|
||||
|
||||
index = sector_num / s->tracks;
|
||||
offset = sector_num % s->tracks;
|
||||
|
||||
// not allocated
|
||||
if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
|
||||
return -1;
|
||||
|
||||
position = (s->catalog_bitmap[index] + offset) * 512;
|
||||
|
||||
// fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n",
|
||||
// sector_num, index, offset, s->catalog_bitmap[index], position);
|
||||
|
||||
if (lseek(s->fd, position, SEEK_SET) != position)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parallels_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (!seek_to_sector(bs, sector_num)) {
|
||||
if (read(s->fd, buf, 512) != 512)
|
||||
return -1;
|
||||
} else
|
||||
memset(buf, 0, 512);
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
buf += 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parallels_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
qemu_free(s->catalog_bitmap);
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_parallels = {
|
||||
"parallels",
|
||||
sizeof(BDRVParallelsState),
|
||||
parallels_probe,
|
||||
parallels_open,
|
||||
parallels_read,
|
||||
NULL,
|
||||
parallels_close,
|
||||
};
|
||||
451
block-qcow.c
451
block-qcow.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Block driver for the QCOW format
|
||||
*
|
||||
* Copyright (c) 2004-2006 Fabrice Bellard
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 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
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
#include <zlib.h>
|
||||
#include "aes.h"
|
||||
@@ -53,7 +53,7 @@ typedef struct QCowHeader {
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
typedef struct BDRVQcowState {
|
||||
BlockDriverState *hd;
|
||||
int fd;
|
||||
int cluster_bits;
|
||||
int cluster_size;
|
||||
int cluster_sectors;
|
||||
@@ -80,25 +80,29 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
|
||||
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
const QCowHeader *cow_header = (const void *)buf;
|
||||
|
||||
|
||||
if (buf_size >= sizeof(QCowHeader) &&
|
||||
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
||||
be32_to_cpu(cow_header->version) == QCOW_VERSION)
|
||||
be32_to_cpu(cow_header->version) == QCOW_VERSION)
|
||||
return 100;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
static int qcow_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, shift, ret;
|
||||
int fd, len, i, shift;
|
||||
QCowHeader 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))
|
||||
|
||||
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))
|
||||
goto fail;
|
||||
be32_to_cpus(&header.magic);
|
||||
be32_to_cpus(&header.version);
|
||||
@@ -108,7 +112,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
be64_to_cpus(&header.size);
|
||||
be32_to_cpus(&header.crypt_method);
|
||||
be64_to_cpus(&header.l1_table_offset);
|
||||
|
||||
|
||||
if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
|
||||
goto fail;
|
||||
if (header.size <= 1 || header.cluster_bits < 9)
|
||||
@@ -134,7 +138,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
|
||||
if (!s->l1_table)
|
||||
goto fail;
|
||||
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
lseek(fd, s->l1_table_offset, SEEK_SET);
|
||||
if (read(fd, 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++) {
|
||||
@@ -151,13 +156,14 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
if (!s->cluster_data)
|
||||
goto fail;
|
||||
s->cluster_cache_offset = -1;
|
||||
|
||||
|
||||
/* read the backing file name */
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
|
||||
lseek(fd, header.backing_file_offset, SEEK_SET);
|
||||
if (read(fd, bs->backing_file, len) != len)
|
||||
goto fail;
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
@@ -168,7 +174,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
bdrv_delete(s->hd);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -177,7 +183,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint8_t keybuf[16];
|
||||
int len, i;
|
||||
|
||||
|
||||
memset(keybuf, 0, 16);
|
||||
len = strlen(key);
|
||||
if (len > 16)
|
||||
@@ -231,7 +237,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||
for(i = 0; i < nb_sectors; i++) {
|
||||
ivec.ll[0] = cpu_to_le64(sector_num);
|
||||
ivec.ll[1] = 0;
|
||||
AES_cbc_encrypt(in_buf, out_buf, 512, key,
|
||||
AES_cbc_encrypt(in_buf, out_buf, 512, key,
|
||||
ivec.b, enc);
|
||||
sector_num++;
|
||||
in_buf += 512;
|
||||
@@ -248,7 +254,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||
*
|
||||
* 2 to allocate a compressed cluster of size
|
||||
* 'compressed_size'. 'compressed_size' must be > 0 and <
|
||||
* cluster_size
|
||||
* cluster_size
|
||||
*
|
||||
* return 0 if not allocated.
|
||||
*/
|
||||
@@ -262,7 +268,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t l2_offset, *l2_table, cluster_offset, tmp;
|
||||
uint32_t min_count;
|
||||
int new_l2_table;
|
||||
|
||||
|
||||
l1_index = offset >> (s->l2_bits + s->cluster_bits);
|
||||
l2_offset = s->l1_table[l1_index];
|
||||
new_l2_table = 0;
|
||||
@@ -270,14 +276,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
if (!allocate)
|
||||
return 0;
|
||||
/* allocate a new l2 entry */
|
||||
l2_offset = bdrv_getlength(s->hd);
|
||||
l2_offset = lseek(s->fd, 0, SEEK_END);
|
||||
/* 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);
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
|
||||
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
new_l2_table = 1;
|
||||
}
|
||||
@@ -303,13 +309,14 @@ 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 (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return 0;
|
||||
} else {
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return 0;
|
||||
}
|
||||
@@ -318,7 +325,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
found:
|
||||
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
|
||||
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||
if (!cluster_offset ||
|
||||
if (!cluster_offset ||
|
||||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
|
||||
if (!allocate)
|
||||
return 0;
|
||||
@@ -330,55 +337,56 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
overwritten */
|
||||
if (decompress_cluster(s, cluster_offset) < 0)
|
||||
return 0;
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
/* write the cluster content */
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
|
||||
lseek(s->fd, cluster_offset, SEEK_SET);
|
||||
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
|
||||
s->cluster_size)
|
||||
return -1;
|
||||
} else {
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||
if (allocate == 1) {
|
||||
/* round to cluster size */
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
cluster_offset = (cluster_offset + s->cluster_size - 1) &
|
||||
~(s->cluster_size - 1);
|
||||
bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
|
||||
ftruncate(s->fd, cluster_offset + s->cluster_size);
|
||||
/* if encrypted, we must initialize the cluster
|
||||
content which won't be written */
|
||||
if (s->crypt_method &&
|
||||
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, 0x00, 512);
|
||||
memset(s->cluster_data + 512, 0xaa, 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,
|
||||
encrypt_sectors(s, start_sect + i,
|
||||
s->cluster_data,
|
||||
s->cluster_data + 512, 1, 1,
|
||||
&s->aes_encrypt_key);
|
||||
if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
|
||||
s->cluster_data, 512) != 512)
|
||||
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
|
||||
if (write(s->fd, s->cluster_data, 512) != 512)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
||||
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
||||
(uint64_t)compressed_size << (63 - s->cluster_bits);
|
||||
}
|
||||
}
|
||||
/* update L2 table */
|
||||
tmp = cpu_to_be64(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
if (bdrv_pwrite(s->hd,
|
||||
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
|
||||
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
}
|
||||
return cluster_offset;
|
||||
}
|
||||
|
||||
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
@@ -420,7 +428,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
||||
inflateEnd(strm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
||||
{
|
||||
int ret, csize;
|
||||
@@ -430,8 +438,9 @@ 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);
|
||||
ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
|
||||
if (ret != csize)
|
||||
lseek(s->fd, coffset, SEEK_SET);
|
||||
ret = read(s->fd, s->cluster_data, csize);
|
||||
if (ret != csize)
|
||||
return -1;
|
||||
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
||||
s->cluster_data, csize) < 0) {
|
||||
@@ -442,15 +451,13 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret, index_in_cluster, n;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
@@ -458,24 +465,18 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
if (n > nb_sectors)
|
||||
n = nb_sectors;
|
||||
if (!cluster_offset) {
|
||||
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);
|
||||
}
|
||||
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 {
|
||||
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
ret = read(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
if (s->crypt_method) {
|
||||
encrypt_sectors(s, sector_num, buf, buf, n, 0,
|
||||
encrypt_sectors(s, sector_num, buf, buf, n, 0,
|
||||
&s->aes_decrypt_key);
|
||||
}
|
||||
}
|
||||
@@ -485,34 +486,33 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret, index_in_cluster, n;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
n = s->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors)
|
||||
n = nb_sectors;
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
|
||||
index_in_cluster,
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
|
||||
index_in_cluster,
|
||||
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 = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
|
||||
s->cluster_data, n * 512);
|
||||
ret = write(s->fd, s->cluster_data, n * 512);
|
||||
} else {
|
||||
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
|
||||
ret = write(s->fd, buf, n * 512);
|
||||
}
|
||||
if (ret != n * 512)
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
@@ -522,209 +522,6 @@ 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;
|
||||
@@ -732,7 +529,7 @@ static void qcow_close(BlockDriverState *bs)
|
||||
qemu_free(s->l2_cache);
|
||||
qemu_free(s->cluster_cache);
|
||||
qemu_free(s->cluster_data);
|
||||
bdrv_delete(s->hd);
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
static int qcow_create(const char *filename, int64_t total_size,
|
||||
@@ -740,9 +537,12 @@ 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, 0644);
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
memset(&header, 0, sizeof(header));
|
||||
@@ -752,11 +552,28 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
header_size = sizeof(header);
|
||||
backing_filename_len = 0;
|
||||
if (backing_file) {
|
||||
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);
|
||||
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.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
||||
unmodifyed sectors */
|
||||
header.l2_bits = 12; /* 32 KB L2 tables */
|
||||
@@ -769,16 +586,16 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
|
||||
|
||||
header.l1_table_offset = cpu_to_be64(header_size);
|
||||
if (flags & BLOCK_FLAG_ENCRYPT) {
|
||||
if (flags) {
|
||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
||||
} else {
|
||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
||||
}
|
||||
|
||||
|
||||
/* write all the data */
|
||||
write(fd, &header, sizeof(header));
|
||||
if (backing_file) {
|
||||
write(fd, backing_file, backing_filename_len);
|
||||
write(fd, backing_filename, backing_filename_len);
|
||||
}
|
||||
lseek(fd, header_size, SEEK_SET);
|
||||
tmp = 0;
|
||||
@@ -789,18 +606,16 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcow_make_empty(BlockDriverState *bs)
|
||||
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);
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
||||
lseek(s->fd, s->l1_table_offset, SEEK_SET);
|
||||
if (write(s->fd, s->l1_table, l1_length) < 0)
|
||||
return -1;
|
||||
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ftruncate(s->fd, s->l1_table_offset + l1_length);
|
||||
|
||||
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));
|
||||
@@ -809,10 +624,18 @@ static 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 */
|
||||
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
z_stream strm;
|
||||
@@ -820,8 +643,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *out_buf;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
if (nb_sectors != s->cluster_sectors)
|
||||
return -EINVAL;
|
||||
if (bs->drv != &bdrv_qcow)
|
||||
return -1;
|
||||
|
||||
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
|
||||
if (!out_buf)
|
||||
@@ -830,7 +653,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
/* best compression, small window, no zlib header */
|
||||
memset(&strm, 0, sizeof(strm));
|
||||
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED, -12,
|
||||
Z_DEFLATED, -12,
|
||||
9, Z_DEFAULT_STRATEGY);
|
||||
if (ret != 0) {
|
||||
qemu_free(out_buf);
|
||||
@@ -856,50 +679,32 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
/* could not compress: write normal cluster */
|
||||
qcow_write(bs, sector_num, buf, s->cluster_sectors);
|
||||
} else {
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
|
||||
out_len, 0, 0);
|
||||
cluster_offset &= s->cluster_offset_mask;
|
||||
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
|
||||
lseek(s->fd, cluster_offset, SEEK_SET);
|
||||
if (write(s->fd, out_buf, out_len) != out_len) {
|
||||
qemu_free(out_buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qemu_free(out_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcow_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
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 = {
|
||||
"qcow",
|
||||
sizeof(BDRVQcowState),
|
||||
qcow_probe,
|
||||
qcow_open,
|
||||
NULL,
|
||||
NULL,
|
||||
qcow_read,
|
||||
qcow_write,
|
||||
qcow_close,
|
||||
qcow_create,
|
||||
qcow_flush,
|
||||
qcow_is_allocated,
|
||||
qcow_set_key,
|
||||
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,
|
||||
qcow_make_empty
|
||||
};
|
||||
|
||||
|
||||
|
||||
2252
block-qcow2.c
2252
block-qcow2.c
File diff suppressed because it is too large
Load Diff
@@ -1,926 +0,0 @@
|
||||
/*
|
||||
* Block driver for RAW files (posix)
|
||||
*
|
||||
* 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 "qemu-common.h"
|
||||
#ifndef QEMU_IMG
|
||||
#include "qemu-timer.h"
|
||||
#include "exec-all.h"
|
||||
#endif
|
||||
#include "block_int.h"
|
||||
#include <assert.h>
|
||||
#include <aio.h>
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
#include <paths.h>
|
||||
#include <sys/param.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/IOBSD.h>
|
||||
#include <IOKit/storage/IOMediaBSDClient.h>
|
||||
#include <IOKit/storage/IOMedia.h>
|
||||
#include <IOKit/storage/IOCDMedia.h>
|
||||
//#include <IOKit/storage/IOCDTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#ifdef __sun__
|
||||
#define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#include <signal.h>
|
||||
#include <sys/dkio.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
|
||||
//#define DEBUG_FLOPPY
|
||||
|
||||
//#define DEBUG_BLOCK
|
||||
#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG)
|
||||
#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
|
||||
{ fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
|
||||
#else
|
||||
#define DEBUG_BLOCK_PRINT(formatCstr, args...)
|
||||
#endif
|
||||
|
||||
#define FTYPE_FILE 0
|
||||
#define FTYPE_CD 1
|
||||
#define FTYPE_FD 2
|
||||
|
||||
/* if the FD is not accessed during that time (in ms), we try to
|
||||
reopen it to see if the disk has been changed */
|
||||
#define FD_OPEN_TIMEOUT 1000
|
||||
|
||||
typedef struct BDRVRawState {
|
||||
int fd;
|
||||
int type;
|
||||
unsigned int lseek_err_cnt;
|
||||
#if defined(__linux__)
|
||||
/* linux floppy specific */
|
||||
int fd_open_flags;
|
||||
int64_t fd_open_time;
|
||||
int64_t fd_error_time;
|
||||
int fd_got_error;
|
||||
int fd_media_changed;
|
||||
#endif
|
||||
} BDRVRawState;
|
||||
|
||||
static int fd_open(BlockDriverState *bs);
|
||||
|
||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd, open_flags, ret;
|
||||
|
||||
s->lseek_err_cnt = 0;
|
||||
|
||||
open_flags = O_BINARY;
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
open_flags |= O_RDWR;
|
||||
} else {
|
||||
open_flags |= O_RDONLY;
|
||||
bs->read_only = 1;
|
||||
}
|
||||
if (flags & BDRV_O_CREAT)
|
||||
open_flags |= O_CREAT | O_TRUNC;
|
||||
#ifdef O_DIRECT
|
||||
if (flags & BDRV_O_DIRECT)
|
||||
open_flags |= O_DIRECT;
|
||||
#endif
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
|
||||
fd = open(filename, open_flags, 0644);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
if (ret == -EROFS)
|
||||
ret = -EACCES;
|
||||
return ret;
|
||||
}
|
||||
s->fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: use host sector size if necessary with:
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
{
|
||||
unsigned int sectorsize = 512;
|
||||
if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
|
||||
sectorsize > bufsize)
|
||||
bufsize = sectorsize;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_COCOA
|
||||
u_int32_t blockSize = 512;
|
||||
if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
|
||||
bufsize = blockSize;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
static int raw_pread(BlockDriverState *bs, int64_t offset,
|
||||
uint8_t *buf, int count)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
|
||||
++(s->lseek_err_cnt);
|
||||
if(s->lseek_err_cnt <= 10) {
|
||||
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] lseek failed : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, errno, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
s->lseek_err_cnt=0;
|
||||
|
||||
ret = read(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
goto label__raw_read__success;
|
||||
|
||||
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] read failed %d : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, ret, errno, strerror(errno));
|
||||
|
||||
/* Try harder for CDrom. */
|
||||
if (bs->type == BDRV_TYPE_CDROM) {
|
||||
lseek(s->fd, offset, SEEK_SET);
|
||||
ret = read(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
goto label__raw_read__success;
|
||||
lseek(s->fd, offset, SEEK_SET);
|
||||
ret = read(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
goto label__raw_read__success;
|
||||
|
||||
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] retry read failed %d : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, ret, errno, strerror(errno));
|
||||
}
|
||||
|
||||
label__raw_read__success:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int raw_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
const uint8_t *buf, int count)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
|
||||
++(s->lseek_err_cnt);
|
||||
if(s->lseek_err_cnt) {
|
||||
DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
|
||||
PRId64 "] lseek failed : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, errno, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
s->lseek_err_cnt = 0;
|
||||
|
||||
ret = write(s->fd, buf, count);
|
||||
if (ret == count)
|
||||
goto label__raw_write__success;
|
||||
|
||||
DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
|
||||
"] write failed %d : %d = %s\n",
|
||||
s->fd, bs->filename, offset, buf, count,
|
||||
bs->total_sectors, ret, errno, strerror(errno));
|
||||
|
||||
label__raw_write__success:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Unix AIO using POSIX AIO */
|
||||
|
||||
typedef struct RawAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
struct aiocb aiocb;
|
||||
struct RawAIOCB *next;
|
||||
} RawAIOCB;
|
||||
|
||||
static int aio_sig_num = SIGUSR2;
|
||||
static RawAIOCB *first_aio; /* AIO issued */
|
||||
static int aio_initialized = 0;
|
||||
|
||||
static void aio_signal_handler(int signum)
|
||||
{
|
||||
#ifndef QEMU_IMG
|
||||
CPUState *env = cpu_single_env;
|
||||
if (env) {
|
||||
/* stop the currently executing cpu because a timer occured */
|
||||
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
|
||||
#ifdef USE_KQEMU
|
||||
if (env->kqemu_enabled) {
|
||||
kqemu_cpu_interrupt(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_aio_init(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
aio_initialized = 1;
|
||||
|
||||
sigfillset(&act.sa_mask);
|
||||
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
|
||||
act.sa_handler = aio_signal_handler;
|
||||
sigaction(aio_sig_num, &act, NULL);
|
||||
|
||||
#if defined(__GLIBC__) && defined(__linux__)
|
||||
{
|
||||
/* XXX: aio thread exit seems to hang on RedHat 9 and this init
|
||||
seems to fix the problem. */
|
||||
struct aioinit ai;
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
ai.aio_threads = 1;
|
||||
ai.aio_num = 1;
|
||||
ai.aio_idle_time = 365 * 100000;
|
||||
aio_init(&ai);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_aio_poll(void)
|
||||
{
|
||||
RawAIOCB *acb, **pacb;
|
||||
int ret;
|
||||
|
||||
for(;;) {
|
||||
pacb = &first_aio;
|
||||
for(;;) {
|
||||
acb = *pacb;
|
||||
if (!acb)
|
||||
goto the_end;
|
||||
ret = aio_error(&acb->aiocb);
|
||||
if (ret == ECANCELED) {
|
||||
/* remove the request */
|
||||
*pacb = acb->next;
|
||||
qemu_aio_release(acb);
|
||||
} else if (ret != EINPROGRESS) {
|
||||
/* end of aio */
|
||||
if (ret == 0) {
|
||||
ret = aio_return(&acb->aiocb);
|
||||
if (ret == acb->aiocb.aio_nbytes)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = -ret;
|
||||
}
|
||||
/* remove the request */
|
||||
*pacb = acb->next;
|
||||
/* call the callback */
|
||||
acb->common.cb(acb->common.opaque, ret);
|
||||
qemu_aio_release(acb);
|
||||
break;
|
||||
} else {
|
||||
pacb = &acb->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
the_end: ;
|
||||
}
|
||||
|
||||
/* Wait for all IO requests to complete. */
|
||||
void qemu_aio_flush(void)
|
||||
{
|
||||
qemu_aio_wait_start();
|
||||
qemu_aio_poll();
|
||||
while (first_aio) {
|
||||
qemu_aio_wait();
|
||||
}
|
||||
qemu_aio_wait_end();
|
||||
}
|
||||
|
||||
/* wait until at least one AIO was handled */
|
||||
static sigset_t wait_oset;
|
||||
|
||||
void qemu_aio_wait_start(void)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (!aio_initialized)
|
||||
qemu_aio_init();
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, aio_sig_num);
|
||||
sigprocmask(SIG_BLOCK, &set, &wait_oset);
|
||||
}
|
||||
|
||||
void qemu_aio_wait(void)
|
||||
{
|
||||
sigset_t set;
|
||||
int nb_sigs;
|
||||
|
||||
#ifndef QEMU_IMG
|
||||
if (qemu_bh_poll())
|
||||
return;
|
||||
#endif
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, aio_sig_num);
|
||||
sigwait(&set, &nb_sigs);
|
||||
qemu_aio_poll();
|
||||
}
|
||||
|
||||
void qemu_aio_wait_end(void)
|
||||
{
|
||||
sigprocmask(SIG_SETMASK, &wait_oset, NULL);
|
||||
}
|
||||
|
||||
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawAIOCB *acb;
|
||||
|
||||
if (fd_open(bs) < 0)
|
||||
return NULL;
|
||||
|
||||
acb = qemu_aio_get(bs, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
acb->aiocb.aio_fildes = s->fd;
|
||||
acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
|
||||
acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
|
||||
acb->aiocb.aio_buf = buf;
|
||||
if (nb_sectors < 0)
|
||||
acb->aiocb.aio_nbytes = -nb_sectors;
|
||||
else
|
||||
acb->aiocb.aio_nbytes = nb_sectors * 512;
|
||||
acb->aiocb.aio_offset = sector_num * 512;
|
||||
acb->next = first_aio;
|
||||
first_aio = acb;
|
||||
return acb;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
RawAIOCB *acb;
|
||||
|
||||
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
if (aio_read(&acb->aiocb) < 0) {
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
|
||||
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
RawAIOCB *acb;
|
||||
|
||||
acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
if (aio_write(&acb->aiocb) < 0) {
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
int ret;
|
||||
RawAIOCB *acb = (RawAIOCB *)blockacb;
|
||||
RawAIOCB **pacb;
|
||||
|
||||
ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
|
||||
if (ret == AIO_NOTCANCELED) {
|
||||
/* fail safe: if the aio could not be canceled, we wait for
|
||||
it */
|
||||
while (aio_error(&acb->aiocb) == EINPROGRESS);
|
||||
}
|
||||
|
||||
/* remove the callback from the queue */
|
||||
pacb = &first_aio;
|
||||
for(;;) {
|
||||
if (*pacb == NULL) {
|
||||
break;
|
||||
} else if (*pacb == acb) {
|
||||
*pacb = acb->next;
|
||||
qemu_aio_release(acb);
|
||||
break;
|
||||
}
|
||||
pacb = &acb->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->fd >= 0) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->type != FTYPE_FILE)
|
||||
return -ENOTSUP;
|
||||
if (ftruncate(s->fd, offset) < 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd = s->fd;
|
||||
int64_t size;
|
||||
#ifdef _BSD
|
||||
struct stat sb;
|
||||
#endif
|
||||
#ifdef __sun__
|
||||
struct dk_minfo minfo;
|
||||
int rv;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef _BSD
|
||||
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
|
||||
#ifdef DIOCGMEDIASIZE
|
||||
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
|
||||
#endif
|
||||
#ifdef CONFIG_COCOA
|
||||
size = LONG_LONG_MAX;
|
||||
#else
|
||||
size = lseek(fd, 0LL, SEEK_END);
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
#ifdef __sun__
|
||||
/*
|
||||
* use the DKIOCGMEDIAINFO ioctl to read the size.
|
||||
*/
|
||||
rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
|
||||
if ( rv != -1 ) {
|
||||
size = minfo.dki_lbsize * minfo.dki_capacity;
|
||||
} else /* there are reports that lseek on some devices
|
||||
fails, but irc discussion said that contingency
|
||||
on contingency was overkill */
|
||||
#endif
|
||||
{
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int raw_create(const char *filename, int64_t total_size,
|
||||
const char *backing_file, int flags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (flags || backing_file)
|
||||
return -ENOTSUP;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
0644);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
ftruncate(fd, total_size * 512);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_raw = {
|
||||
"raw",
|
||||
sizeof(BDRVRawState),
|
||||
NULL, /* no probe for protocols */
|
||||
raw_open,
|
||||
NULL,
|
||||
NULL,
|
||||
raw_close,
|
||||
raw_create,
|
||||
raw_flush,
|
||||
|
||||
.bdrv_aio_read = raw_aio_read,
|
||||
.bdrv_aio_write = raw_aio_write,
|
||||
.bdrv_aio_cancel = raw_aio_cancel,
|
||||
.aiocb_size = sizeof(RawAIOCB),
|
||||
.protocol_name = "file",
|
||||
.bdrv_pread = raw_pread,
|
||||
.bdrv_pwrite = raw_pwrite,
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
/* host device */
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
|
||||
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
|
||||
|
||||
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
|
||||
{
|
||||
kern_return_t kernResult;
|
||||
mach_port_t masterPort;
|
||||
CFMutableDictionaryRef classesToMatch;
|
||||
|
||||
kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
|
||||
if ( KERN_SUCCESS != kernResult ) {
|
||||
printf( "IOMasterPort returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
classesToMatch = IOServiceMatching( kIOCDMediaClass );
|
||||
if ( classesToMatch == NULL ) {
|
||||
printf( "IOServiceMatching returned a NULL dictionary.\n" );
|
||||
} else {
|
||||
CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
|
||||
}
|
||||
kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
|
||||
if ( KERN_SUCCESS != kernResult )
|
||||
{
|
||||
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
|
||||
{
|
||||
io_object_t nextMedia;
|
||||
kern_return_t kernResult = KERN_FAILURE;
|
||||
*bsdPath = '\0';
|
||||
nextMedia = IOIteratorNext( mediaIterator );
|
||||
if ( nextMedia )
|
||||
{
|
||||
CFTypeRef bsdPathAsCFString;
|
||||
bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
|
||||
if ( bsdPathAsCFString ) {
|
||||
size_t devPathLength;
|
||||
strcpy( bsdPath, _PATH_DEV );
|
||||
strcat( bsdPath, "r" );
|
||||
devPathLength = strlen( bsdPath );
|
||||
if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
|
||||
kernResult = KERN_SUCCESS;
|
||||
}
|
||||
CFRelease( bsdPathAsCFString );
|
||||
}
|
||||
IOObjectRelease( nextMedia );
|
||||
}
|
||||
|
||||
return kernResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int fd, open_flags, ret;
|
||||
|
||||
#ifdef CONFIG_COCOA
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
kern_return_t kernResult;
|
||||
io_iterator_t mediaIterator;
|
||||
char bsdPath[ MAXPATHLEN ];
|
||||
int fd;
|
||||
|
||||
kernResult = FindEjectableCDMedia( &mediaIterator );
|
||||
kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
|
||||
|
||||
if ( bsdPath[ 0 ] != '\0' ) {
|
||||
strcat(bsdPath,"s0");
|
||||
/* some CDs don't have a partition 0 */
|
||||
fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
bsdPath[strlen(bsdPath)-1] = '1';
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
filename = bsdPath;
|
||||
}
|
||||
|
||||
if ( mediaIterator )
|
||||
IOObjectRelease( mediaIterator );
|
||||
}
|
||||
#endif
|
||||
open_flags = O_BINARY;
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
open_flags |= O_RDWR;
|
||||
} else {
|
||||
open_flags |= O_RDONLY;
|
||||
bs->read_only = 1;
|
||||
}
|
||||
#ifdef O_DIRECT
|
||||
if (flags & BDRV_O_DIRECT)
|
||||
open_flags |= O_DIRECT;
|
||||
#endif
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
#if defined(__linux__)
|
||||
if (strstart(filename, "/dev/cd", NULL)) {
|
||||
/* open will not fail even if no CD is inserted */
|
||||
open_flags |= O_NONBLOCK;
|
||||
s->type = FTYPE_CD;
|
||||
} else if (strstart(filename, "/dev/fd", NULL)) {
|
||||
s->type = FTYPE_FD;
|
||||
s->fd_open_flags = open_flags;
|
||||
/* open will not fail even if no floppy is inserted */
|
||||
open_flags |= O_NONBLOCK;
|
||||
} else if (strstart(filename, "/dev/sg", NULL)) {
|
||||
bs->sg = 1;
|
||||
}
|
||||
#endif
|
||||
fd = open(filename, open_flags, 0644);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
if (ret == -EROFS)
|
||||
ret = -EACCES;
|
||||
return ret;
|
||||
}
|
||||
s->fd = fd;
|
||||
#if defined(__linux__)
|
||||
/* close fd so that we can reopen it as needed */
|
||||
if (s->type == FTYPE_FD) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
s->fd_media_changed = 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__) && !defined(QEMU_IMG)
|
||||
|
||||
/* Note: we do not have a reliable method to detect if the floppy is
|
||||
present. The current method is to try to open the floppy at every
|
||||
I/O and to keep it opened during a few hundreds of ms. */
|
||||
static int fd_open(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int last_media_present;
|
||||
|
||||
if (s->type != FTYPE_FD)
|
||||
return 0;
|
||||
last_media_present = (s->fd >= 0);
|
||||
if (s->fd >= 0 &&
|
||||
(qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy closed\n");
|
||||
#endif
|
||||
}
|
||||
if (s->fd < 0) {
|
||||
if (s->fd_got_error &&
|
||||
(qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy (open delayed)\n");
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
s->fd = open(bs->filename, s->fd_open_flags);
|
||||
if (s->fd < 0) {
|
||||
s->fd_error_time = qemu_get_clock(rt_clock);
|
||||
s->fd_got_error = 1;
|
||||
if (last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy\n");
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy opened\n");
|
||||
#endif
|
||||
}
|
||||
if (!last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
s->fd_open_time = qemu_get_clock(rt_clock);
|
||||
s->fd_got_error = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int fd_open(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_CD:
|
||||
ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
|
||||
if (ret == CDS_DISC_OK)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
case FTYPE_FD:
|
||||
ret = fd_open(bs);
|
||||
return (ret >= 0);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* currently only used by fdc.c, but a CD version would be good too */
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_FD:
|
||||
{
|
||||
int ret;
|
||||
/* XXX: we do not have a true media changed indication. It
|
||||
does not work if the floppy is changed without trying
|
||||
to read it */
|
||||
fd_open(bs);
|
||||
ret = s->fd_media_changed;
|
||||
s->fd_media_changed = 0;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy changed=%d\n", ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_CD:
|
||||
if (eject_flag) {
|
||||
if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
|
||||
perror("CDROMEJECT");
|
||||
} else {
|
||||
if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
|
||||
perror("CDROMEJECT");
|
||||
}
|
||||
break;
|
||||
case FTYPE_FD:
|
||||
{
|
||||
int fd;
|
||||
if (s->fd >= 0) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
}
|
||||
fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
|
||||
if (fd >= 0) {
|
||||
if (ioctl(fd, FDEJECT, 0) < 0)
|
||||
perror("FDEJECT");
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_CD:
|
||||
if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
|
||||
/* Note: an error can happen if the distribution automatically
|
||||
mounts the CD-ROM */
|
||||
// perror("CDROM_LOCKDOOR");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
return ioctl(s->fd, req, buf);
|
||||
}
|
||||
#else
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* !linux */
|
||||
|
||||
BlockDriver bdrv_host_device = {
|
||||
"host_device",
|
||||
sizeof(BDRVRawState),
|
||||
NULL, /* no probe for protocols */
|
||||
hdev_open,
|
||||
NULL,
|
||||
NULL,
|
||||
raw_close,
|
||||
NULL,
|
||||
raw_flush,
|
||||
|
||||
.bdrv_aio_read = raw_aio_read,
|
||||
.bdrv_aio_write = raw_aio_write,
|
||||
.bdrv_aio_cancel = raw_aio_cancel,
|
||||
.aiocb_size = sizeof(RawAIOCB),
|
||||
.bdrv_pread = raw_pread,
|
||||
.bdrv_pwrite = raw_pwrite,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = raw_is_inserted,
|
||||
.bdrv_media_changed = raw_media_changed,
|
||||
.bdrv_eject = raw_eject,
|
||||
.bdrv_set_locked = raw_set_locked,
|
||||
/* generic scsi device */
|
||||
.bdrv_ioctl = raw_ioctl,
|
||||
};
|
||||
@@ -1,548 +0,0 @@
|
||||
/*
|
||||
* Block driver for RAW files (win32)
|
||||
*
|
||||
* 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 "qemu-common.h"
|
||||
#ifndef QEMU_IMG
|
||||
#include "qemu-timer.h"
|
||||
#include "exec-all.h"
|
||||
#endif
|
||||
#include "block_int.h"
|
||||
#include <assert.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#define FTYPE_FILE 0
|
||||
#define FTYPE_CD 1
|
||||
#define FTYPE_HARDDISK 2
|
||||
|
||||
typedef struct BDRVRawState {
|
||||
HANDLE hfile;
|
||||
int type;
|
||||
char drive_path[16]; /* format: "d:\" */
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct RawAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
HANDLE hEvent;
|
||||
OVERLAPPED ov;
|
||||
int count;
|
||||
} RawAIOCB;
|
||||
|
||||
int qemu_ftruncate64(int fd, int64_t length)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
LONG high;
|
||||
HANDLE h;
|
||||
BOOL res;
|
||||
|
||||
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
|
||||
return -1;
|
||||
|
||||
h = (HANDLE)_get_osfhandle(fd);
|
||||
|
||||
/* get current position, ftruncate do not change position */
|
||||
li.HighPart = 0;
|
||||
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
|
||||
if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
|
||||
return -1;
|
||||
|
||||
high = length >> 32;
|
||||
if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
|
||||
return -1;
|
||||
res = SetEndOfFile(h);
|
||||
|
||||
/* back to old position */
|
||||
SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
|
||||
return res ? 0 : -1;
|
||||
}
|
||||
|
||||
static int set_sparse(int fd)
|
||||
{
|
||||
DWORD returned;
|
||||
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
|
||||
NULL, 0, NULL, 0, &returned, NULL);
|
||||
}
|
||||
|
||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags, create_flags;
|
||||
DWORD overlapped;
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||
} else {
|
||||
access_flags = GENERIC_READ;
|
||||
}
|
||||
if (flags & BDRV_O_CREAT) {
|
||||
create_flags = CREATE_ALWAYS;
|
||||
} else {
|
||||
create_flags = OPEN_EXISTING;
|
||||
}
|
||||
#ifdef QEMU_IMG
|
||||
overlapped = FILE_ATTRIBUTE_NORMAL;
|
||||
#else
|
||||
overlapped = FILE_FLAG_OVERLAPPED;
|
||||
#endif
|
||||
if (flags & BDRV_O_DIRECT)
|
||||
overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
|
||||
s->hfile = CreateFile(filename, access_flags,
|
||||
FILE_SHARE_READ, NULL,
|
||||
create_flags, overlapped, NULL);
|
||||
if (s->hfile == INVALID_HANDLE_VALUE) {
|
||||
int err = GetLastError();
|
||||
|
||||
if (err == ERROR_ACCESS_DENIED)
|
||||
return -EACCES;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_pread(BlockDriverState *bs, int64_t offset,
|
||||
uint8_t *buf, int count)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
OVERLAPPED ov;
|
||||
DWORD ret_count;
|
||||
int ret;
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset = offset;
|
||||
ov.OffsetHigh = offset >> 32;
|
||||
ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
|
||||
if (!ret) {
|
||||
ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
|
||||
if (!ret)
|
||||
return -EIO;
|
||||
else
|
||||
return ret_count;
|
||||
}
|
||||
return ret_count;
|
||||
}
|
||||
|
||||
static int raw_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
const uint8_t *buf, int count)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
OVERLAPPED ov;
|
||||
DWORD ret_count;
|
||||
int ret;
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset = offset;
|
||||
ov.OffsetHigh = offset >> 32;
|
||||
ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
|
||||
if (!ret) {
|
||||
ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
|
||||
if (!ret)
|
||||
return -EIO;
|
||||
else
|
||||
return ret_count;
|
||||
}
|
||||
return ret_count;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifndef QEMU_IMG
|
||||
static void raw_aio_cb(void *opaque)
|
||||
{
|
||||
RawAIOCB *acb = opaque;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
BDRVRawState *s = bs->opaque;
|
||||
DWORD ret_count;
|
||||
int ret;
|
||||
|
||||
ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
|
||||
if (!ret || ret_count != acb->count) {
|
||||
acb->common.cb(acb->common.opaque, -EIO);
|
||||
} else {
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
RawAIOCB *acb;
|
||||
int64_t offset;
|
||||
|
||||
acb = qemu_aio_get(bs, cb, opaque);
|
||||
if (acb->hEvent) {
|
||||
acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (!acb->hEvent) {
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
memset(&acb->ov, 0, sizeof(acb->ov));
|
||||
offset = sector_num * 512;
|
||||
acb->ov.Offset = offset;
|
||||
acb->ov.OffsetHigh = offset >> 32;
|
||||
acb->ov.hEvent = acb->hEvent;
|
||||
acb->count = nb_sectors * 512;
|
||||
#ifndef QEMU_IMG
|
||||
qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
|
||||
#endif
|
||||
return acb;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawAIOCB *acb;
|
||||
int ret;
|
||||
|
||||
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
|
||||
if (!ret) {
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef QEMU_IMG
|
||||
qemu_aio_release(acb);
|
||||
#endif
|
||||
return (BlockDriverAIOCB *)acb;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawAIOCB *acb;
|
||||
int ret;
|
||||
|
||||
acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
|
||||
if (!acb)
|
||||
return NULL;
|
||||
ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
|
||||
if (!ret) {
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef QEMU_IMG
|
||||
qemu_aio_release(acb);
|
||||
#endif
|
||||
return (BlockDriverAIOCB *)acb;
|
||||
}
|
||||
|
||||
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
#ifndef QEMU_IMG
|
||||
RawAIOCB *acb = (RawAIOCB *)blockacb;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
|
||||
/* XXX: if more than one async I/O it is not correct */
|
||||
CancelIo(s->hfile);
|
||||
qemu_aio_release(acb);
|
||||
#endif
|
||||
}
|
||||
#endif /* #if 0 */
|
||||
|
||||
static void raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
FlushFileBuffers(s->hfile);
|
||||
}
|
||||
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
CloseHandle(s->hfile);
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
DWORD low, high;
|
||||
|
||||
low = offset;
|
||||
high = offset >> 32;
|
||||
if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
|
||||
return -EIO;
|
||||
if (!SetEndOfFile(s->hfile))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t raw_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
LARGE_INTEGER l;
|
||||
ULARGE_INTEGER available, total, total_free;
|
||||
DISK_GEOMETRY_EX dg;
|
||||
DWORD count;
|
||||
BOOL status;
|
||||
|
||||
switch(s->type) {
|
||||
case FTYPE_FILE:
|
||||
l.LowPart = GetFileSize(s->hfile, &l.HighPart);
|
||||
if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
|
||||
return -EIO;
|
||||
break;
|
||||
case FTYPE_CD:
|
||||
if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
|
||||
return -EIO;
|
||||
l.QuadPart = total.QuadPart;
|
||||
break;
|
||||
case FTYPE_HARDDISK:
|
||||
status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
NULL, 0, &dg, sizeof(dg), &count, NULL);
|
||||
if (status != 0) {
|
||||
l = dg.DiskSize;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
return l.QuadPart;
|
||||
}
|
||||
|
||||
static int raw_create(const char *filename, int64_t total_size,
|
||||
const char *backing_file, int flags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (flags || backing_file)
|
||||
return -ENOTSUP;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
0644);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
set_sparse(fd);
|
||||
ftruncate(fd, total_size * 512);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_aio_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_aio_poll(void)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_aio_flush(void)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_aio_wait_start(void)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_aio_wait(void)
|
||||
{
|
||||
#ifndef QEMU_IMG
|
||||
qemu_bh_poll();
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_aio_wait_end(void)
|
||||
{
|
||||
}
|
||||
|
||||
BlockDriver bdrv_raw = {
|
||||
"raw",
|
||||
sizeof(BDRVRawState),
|
||||
NULL, /* no probe for protocols */
|
||||
raw_open,
|
||||
NULL,
|
||||
NULL,
|
||||
raw_close,
|
||||
raw_create,
|
||||
raw_flush,
|
||||
|
||||
#if 0
|
||||
.bdrv_aio_read = raw_aio_read,
|
||||
.bdrv_aio_write = raw_aio_write,
|
||||
.bdrv_aio_cancel = raw_aio_cancel,
|
||||
.aiocb_size = sizeof(RawAIOCB);
|
||||
#endif
|
||||
.protocol_name = "file",
|
||||
.bdrv_pread = raw_pread,
|
||||
.bdrv_pwrite = raw_pwrite,
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
/* host device */
|
||||
|
||||
static int find_cdrom(char *cdrom_name, int cdrom_name_size)
|
||||
{
|
||||
char drives[256], *pdrv = drives;
|
||||
UINT type;
|
||||
|
||||
memset(drives, 0, sizeof(drives));
|
||||
GetLogicalDriveStrings(sizeof(drives), drives);
|
||||
while(pdrv[0] != '\0') {
|
||||
type = GetDriveType(pdrv);
|
||||
switch(type) {
|
||||
case DRIVE_CDROM:
|
||||
snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
pdrv += lstrlen(pdrv) + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int find_device_type(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
UINT type;
|
||||
const char *p;
|
||||
|
||||
if (strstart(filename, "\\\\.\\", &p) ||
|
||||
strstart(filename, "//./", &p)) {
|
||||
if (stristart(p, "PhysicalDrive", NULL))
|
||||
return FTYPE_HARDDISK;
|
||||
snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
|
||||
type = GetDriveType(s->drive_path);
|
||||
if (type == DRIVE_CDROM)
|
||||
return FTYPE_CD;
|
||||
else
|
||||
return FTYPE_FILE;
|
||||
} else {
|
||||
return FTYPE_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags, create_flags;
|
||||
DWORD overlapped;
|
||||
char device_name[64];
|
||||
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
if (find_cdrom(device_name, sizeof(device_name)) < 0)
|
||||
return -ENOENT;
|
||||
filename = device_name;
|
||||
} else {
|
||||
/* transform drive letters into device name */
|
||||
if (((filename[0] >= 'a' && filename[0] <= 'z') ||
|
||||
(filename[0] >= 'A' && filename[0] <= 'Z')) &&
|
||||
filename[1] == ':' && filename[2] == '\0') {
|
||||
snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
|
||||
filename = device_name;
|
||||
}
|
||||
}
|
||||
s->type = find_device_type(bs, filename);
|
||||
|
||||
if ((flags & BDRV_O_ACCESS) == O_RDWR) {
|
||||
access_flags = GENERIC_READ | GENERIC_WRITE;
|
||||
} else {
|
||||
access_flags = GENERIC_READ;
|
||||
}
|
||||
create_flags = OPEN_EXISTING;
|
||||
|
||||
#ifdef QEMU_IMG
|
||||
overlapped = FILE_ATTRIBUTE_NORMAL;
|
||||
#else
|
||||
overlapped = FILE_FLAG_OVERLAPPED;
|
||||
#endif
|
||||
if (flags & BDRV_O_DIRECT)
|
||||
overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
|
||||
s->hfile = CreateFile(filename, access_flags,
|
||||
FILE_SHARE_READ, NULL,
|
||||
create_flags, overlapped, NULL);
|
||||
if (s->hfile == INVALID_HANDLE_VALUE) {
|
||||
int err = GetLastError();
|
||||
|
||||
if (err == ERROR_ACCESS_DENIED)
|
||||
return -EACCES;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/***********************************************/
|
||||
/* removable device additional commands */
|
||||
|
||||
static int raw_is_inserted(BlockDriverState *bs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int raw_media_changed(BlockDriverState *bs)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
|
||||
{
|
||||
DWORD ret_count;
|
||||
|
||||
if (s->type == FTYPE_FILE)
|
||||
return -ENOTSUP;
|
||||
if (eject_flag) {
|
||||
DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
|
||||
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
|
||||
} else {
|
||||
DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
|
||||
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_set_locked(BlockDriverState *bs, int locked)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
BlockDriver bdrv_host_device = {
|
||||
"host_device",
|
||||
sizeof(BDRVRawState),
|
||||
NULL, /* no probe for protocols */
|
||||
hdev_open,
|
||||
NULL,
|
||||
NULL,
|
||||
raw_close,
|
||||
NULL,
|
||||
raw_flush,
|
||||
|
||||
#if 0
|
||||
.bdrv_aio_read = raw_aio_read,
|
||||
.bdrv_aio_write = raw_aio_write,
|
||||
.bdrv_aio_cancel = raw_aio_cancel,
|
||||
.aiocb_size = sizeof(RawAIOCB);
|
||||
#endif
|
||||
.bdrv_pread = raw_pread,
|
||||
.bdrv_pwrite = raw_pwrite,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
};
|
||||
532
block-vmdk.c
532
block-vmdk.c
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Block driver for the VMDK format
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 Fabrice Bellard
|
||||
* Copyright (c) 2005 Filip Navara
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -22,8 +22,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
|
||||
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
||||
@@ -60,7 +59,7 @@ typedef struct {
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
typedef struct BDRVVmdkState {
|
||||
BlockDriverState *hd;
|
||||
int fd;
|
||||
int64_t l1_table_offset;
|
||||
int64_t l1_backup_table_offset;
|
||||
uint32_t *l1_table;
|
||||
@@ -74,26 +73,8 @@ typedef struct BDRVVmdkState {
|
||||
uint32_t l2_cache_counts[L2_CACHE_SIZE];
|
||||
|
||||
unsigned int cluster_sectors;
|
||||
uint32_t parent_cid;
|
||||
int is_parent;
|
||||
} BDRVVmdkState;
|
||||
|
||||
typedef struct VmdkMetaData {
|
||||
uint32_t offset;
|
||||
unsigned int l1_index;
|
||||
unsigned int l2_index;
|
||||
unsigned int l2_offset;
|
||||
int valid;
|
||||
} VmdkMetaData;
|
||||
|
||||
typedef struct ActiveBDRVState{
|
||||
BlockDriverState *hd; // active image handler
|
||||
uint64_t cluster_offset; // current write offset
|
||||
}ActiveBDRVState;
|
||||
|
||||
static ActiveBDRVState activeBDRV;
|
||||
|
||||
|
||||
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
uint32_t magic;
|
||||
@@ -108,285 +89,27 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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;
|
||||
char desc[DESC_SIZE];
|
||||
uint32_t cid;
|
||||
char *p_name, *cid_str;
|
||||
size_t cid_str_size;
|
||||
|
||||
/* 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 ((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);
|
||||
}
|
||||
|
||||
int parent_open = 0;
|
||||
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;
|
||||
}
|
||||
parent_open = 1;
|
||||
if (bdrv_open(s->hd->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0)
|
||||
goto failure;
|
||||
parent_open = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
static int vmdk_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int fd, i;
|
||||
uint32_t magic;
|
||||
int l1_size, i, ret;
|
||||
int l1_size;
|
||||
|
||||
if (parent_open)
|
||||
// Parent must be opened as RO.
|
||||
flags = BDRV_O_RDONLY;
|
||||
fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename);
|
||||
|
||||
ret = bdrv_file_open(&s->hd, filename, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
|
||||
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;
|
||||
}
|
||||
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
|
||||
goto fail;
|
||||
|
||||
magic = be32_to_cpu(magic);
|
||||
if (magic == VMDK3_MAGIC) {
|
||||
VMDK3Header header;
|
||||
|
||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
if (read(fd, &header, sizeof(header)) !=
|
||||
sizeof(header))
|
||||
goto fail;
|
||||
s->cluster_sectors = le32_to_cpu(header.granularity);
|
||||
s->l2_size = 1 << 9;
|
||||
@@ -397,8 +120,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
|
||||
} else if (magic == VMDK4_MAGIC) {
|
||||
VMDK4Header header;
|
||||
|
||||
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
|
||||
|
||||
if (read(fd, &header, sizeof(header)) != sizeof(header))
|
||||
goto fail;
|
||||
bs->total_sectors = le64_to_cpu(header.capacity);
|
||||
s->cluster_sectors = le64_to_cpu(header.granularity);
|
||||
@@ -406,31 +129,21 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
|
||||
if (s->l1_entry_sectors <= 0)
|
||||
goto fail;
|
||||
s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
|
||||
s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
|
||||
/ 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;
|
||||
|
||||
if (parent_open)
|
||||
s->is_parent = 1;
|
||||
else
|
||||
s->is_parent = 0;
|
||||
|
||||
// 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 (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
|
||||
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (read(fd, s->l1_table, l1_size) != l1_size)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
le32_to_cpus(&s->l1_table[i]);
|
||||
@@ -440,7 +153,9 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->l1_backup_table = qemu_malloc(l1_size);
|
||||
if (!s->l1_backup_table)
|
||||
goto fail;
|
||||
if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
|
||||
if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
|
||||
goto fail;
|
||||
if (read(fd, 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]);
|
||||
@@ -450,80 +165,25 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
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);
|
||||
bdrv_delete(s->hd);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
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, NULL, offset, allocate);
|
||||
|
||||
if (parent_cluster_offset) {
|
||||
BDRVVmdkState *act_s = activeBDRV.hd->opaque;
|
||||
|
||||
if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
|
||||
return -1;
|
||||
|
||||
//Write grain only into the active image
|
||||
if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
/* update L2 table */
|
||||
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
|
||||
return -1;
|
||||
/* update backup L2 table */
|
||||
if (s->l1_backup_table_offset != 0) {
|
||||
m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
|
||||
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset, int allocate)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
unsigned int l1_index, l2_offset, l2_index;
|
||||
int min_index, i, j;
|
||||
uint32_t min_count, *l2_table, tmp = 0;
|
||||
uint32_t min_count, *l2_table, tmp;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
if (m_data)
|
||||
m_data->valid = 0;
|
||||
|
||||
|
||||
l1_index = (offset >> 9) / s->l1_entry_sectors;
|
||||
if (l1_index >= s->l1_size)
|
||||
return 0;
|
||||
@@ -552,59 +212,47 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
}
|
||||
}
|
||||
l2_table = s->l2_cache + (min_index * s->l2_size);
|
||||
if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
|
||||
s->l2_size * sizeof(uint32_t))
|
||||
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))
|
||||
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) {
|
||||
if (!allocate)
|
||||
return 0;
|
||||
// Avoid the L2 tables update for the images that have snapshots.
|
||||
if (!s->is_parent) {
|
||||
cluster_offset = bdrv_getlength(s->hd);
|
||||
bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
|
||||
|
||||
cluster_offset >>= 9;
|
||||
tmp = cpu_to_le32(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
// Save the active image state
|
||||
activeBDRV.cluster_offset = cluster_offset;
|
||||
activeBDRV.hd = bs;
|
||||
}
|
||||
/* First of all we write grain itself, to avoid race condition
|
||||
* that may to corrupt the image.
|
||||
* This problem may occur because of insufficient space on host disk
|
||||
* or inappropriate VM shutdown.
|
||||
*/
|
||||
if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
|
||||
cluster_offset = lseek(s->fd, 0, SEEK_END);
|
||||
ftruncate(s->fd, 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))
|
||||
return 0;
|
||||
|
||||
if (m_data) {
|
||||
m_data->offset = tmp;
|
||||
m_data->l1_index = l1_index;
|
||||
m_data->l2_index = l2_index;
|
||||
m_data->l2_offset = l2_offset;
|
||||
m_data->valid = 1;
|
||||
/* 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))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cluster_offset <<= 9;
|
||||
return cluster_offset;
|
||||
}
|
||||
|
||||
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int index_in_cluster, n;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
|
||||
index_in_cluster = sector_num % s->cluster_sectors;
|
||||
n = s->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors)
|
||||
@@ -613,32 +261,25 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
return (cluster_offset != 0);
|
||||
}
|
||||
|
||||
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int index_in_cluster, n, ret;
|
||||
int ret, index_in_cluster, n;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
|
||||
index_in_cluster = sector_num % s->cluster_sectors;
|
||||
n = s->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors)
|
||||
n = nb_sectors;
|
||||
if (!cluster_offset) {
|
||||
// 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);
|
||||
}
|
||||
memset(buf, 0, 512 * n);
|
||||
} else {
|
||||
if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
ret = read(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
}
|
||||
nb_sectors -= n;
|
||||
@@ -648,48 +289,28 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
VmdkMetaData m_data;
|
||||
int index_in_cluster, n;
|
||||
int ret, index_in_cluster, n;
|
||||
uint64_t cluster_offset;
|
||||
static int cid_update = 0;
|
||||
|
||||
if (sector_num > bs->total_sectors) {
|
||||
fprintf(stderr,
|
||||
"(VMDK) Wrong offset: sector_num=0x%" PRIx64
|
||||
" total_sectors=0x%" PRIx64 "\n",
|
||||
sector_num, bs->total_sectors);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
n = s->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors)
|
||||
n = nb_sectors;
|
||||
cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1);
|
||||
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
|
||||
if (!cluster_offset)
|
||||
return -1;
|
||||
|
||||
if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
|
||||
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
|
||||
ret = write(s->fd, buf, n * 512);
|
||||
if (ret != n * 512)
|
||||
return -1;
|
||||
if (m_data.valid) {
|
||||
/* update L2 tables */
|
||||
if (vmdk_L2update(bs, &m_data) == -1)
|
||||
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;
|
||||
}
|
||||
@@ -713,7 +334,7 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
"# The Disk Data Base \n"
|
||||
"#DDB\n"
|
||||
"\n"
|
||||
"ddb.virtualHWVersion = \"%d\"\n"
|
||||
"ddb.virtualHWVersion = \"3\"\n"
|
||||
"ddb.geometry.cylinders = \"%lu\"\n"
|
||||
"ddb.geometry.heads = \"16\"\n"
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
@@ -722,9 +343,6 @@ 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);
|
||||
@@ -762,8 +380,8 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
header.check_bytes[1] = 0x20;
|
||||
header.check_bytes[2] = 0xd;
|
||||
header.check_bytes[3] = 0xa;
|
||||
|
||||
/* write all the data */
|
||||
|
||||
/* write all the data */
|
||||
write(fd, &magic, sizeof(magic));
|
||||
write(fd, &header, sizeof(header));
|
||||
|
||||
@@ -774,7 +392,7 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
for (i = 0, tmp = header.rgd_offset + gd_size;
|
||||
i < gt_count; i++, tmp += gt_size)
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
|
||||
|
||||
/* write backup grain directory */
|
||||
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
|
||||
for (i = 0, tmp = header.gd_offset + gd_size;
|
||||
@@ -790,7 +408,7 @@ static int vmdk_create(const char *filename, int64_t total_size,
|
||||
if ((temp_str = strrchr(real_filename, ':')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
sprintf(desc, desc_template, time(NULL), (unsigned long)total_size,
|
||||
real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16));
|
||||
real_filename, total_size / (63 * 16));
|
||||
|
||||
/* write the descriptor */
|
||||
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
|
||||
@@ -803,18 +421,9 @@ 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);
|
||||
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;
|
||||
bdrv_flush(s->hd);
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_vmdk = {
|
||||
@@ -826,6 +435,5 @@ BlockDriver bdrv_vmdk = {
|
||||
vmdk_write,
|
||||
vmdk_close,
|
||||
vmdk_create,
|
||||
vmdk_flush,
|
||||
vmdk_is_allocated,
|
||||
};
|
||||
|
||||
39
block-vpc.c
39
block-vpc.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Block driver for Conectix/Microsoft Virtual PC images
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2005 Alex Beregszaszi
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
|
||||
/**************************************************************/
|
||||
@@ -65,7 +65,7 @@ struct vpc_subheader {
|
||||
|
||||
typedef struct BDRVVPCState {
|
||||
int fd;
|
||||
|
||||
|
||||
int pagetable_entries;
|
||||
uint32_t *pagetable;
|
||||
|
||||
@@ -74,30 +74,33 @@ typedef struct BDRVVPCState {
|
||||
uint8_t *pageentry_u8;
|
||||
uint32_t *pageentry_u32;
|
||||
uint16_t *pageentry_u16;
|
||||
|
||||
|
||||
uint64_t last_bitmap;
|
||||
#endif
|
||||
} BDRVVPCState;
|
||||
|
||||
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
|
||||
if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
|
||||
return 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
static int vpc_open(BlockDriverState *bs, const char *filename)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int fd, i;
|
||||
struct vpc_subheader header;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
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; // no write support yet
|
||||
|
||||
|
||||
s->fd = fd;
|
||||
|
||||
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
|
||||
@@ -153,14 +156,14 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
|
||||
pagetable_index = offset / s->pageentry_size;
|
||||
pageentry_index = (offset % s->pageentry_size) / 512;
|
||||
|
||||
|
||||
if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
|
||||
return -1; // not allocated
|
||||
|
||||
bitmap_offset = 512 * s->pagetable[pagetable_index];
|
||||
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
|
||||
|
||||
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
|
||||
|
||||
// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
|
||||
// sector_num, pagetable_index, pageentry_index,
|
||||
// bitmap_offset, block_offset);
|
||||
|
||||
@@ -172,7 +175,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
lseek(s->fd, bitmap_offset, SEEK_SET);
|
||||
|
||||
s->last_bitmap = bitmap_offset;
|
||||
|
||||
|
||||
// Scary! Bitmap is stored as big endian 32bit entries,
|
||||
// while we used to look it up byte by byte
|
||||
read(s->fd, s->pageentry_u8, 512);
|
||||
@@ -184,7 +187,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
return -1;
|
||||
#else
|
||||
lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
|
||||
|
||||
|
||||
read(s->fd, &bitmap_entry, 1);
|
||||
|
||||
if ((bitmap_entry >> (pageentry_index % 8)) & 1)
|
||||
@@ -196,7 +199,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
|
||||
224
block-vvfat.c
224
block-vvfat.c
@@ -1,9 +1,9 @@
|
||||
/* vim:set shiftwidth=4 ts=8: */
|
||||
/*
|
||||
* QEMU Block driver for virtual VFAT (shadows a local directory)
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004,2005 Johannes E. Schindelin
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include "qemu-common.h"
|
||||
#include "vl.h"
|
||||
#include "block_int.h"
|
||||
|
||||
#ifndef S_IWGRP
|
||||
@@ -38,7 +38,7 @@
|
||||
/* TODO: add ":bootsector=blabla.img:" */
|
||||
/* LATER TODO: add automatic boot sector generation from
|
||||
BOOTEASY.ASM and Ranish Partition Manager
|
||||
Note that DOS assumes the system files to be the first files in the
|
||||
Note that DOS assumes the system files to be the first files in the
|
||||
file system (test if the boot sector still relies on that fact)! */
|
||||
/* MAYBE TODO: write block-visofs.c */
|
||||
/* TODO: call try_commit() only after a timeout */
|
||||
@@ -61,7 +61,7 @@ void nonono(const char* file, int line, const char* msg) {
|
||||
exit(-5);
|
||||
}
|
||||
#undef assert
|
||||
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
|
||||
#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -153,7 +153,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
|
||||
index_to<0 || index_to>=array->next ||
|
||||
index_from<0 || index_from>=array->next)
|
||||
return -1;
|
||||
|
||||
|
||||
if(index_to==index_from)
|
||||
return 0;
|
||||
|
||||
@@ -167,7 +167,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
|
||||
memmove(to+is*count,to,from-to);
|
||||
else
|
||||
memmove(from,from+is*count,to-from);
|
||||
|
||||
|
||||
memcpy(to,buf,is*count);
|
||||
|
||||
free(buf);
|
||||
@@ -175,7 +175,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int array_remove_slice(array_t* array,int index, int count)
|
||||
inline int array_remove_slice(array_t* array,int index, int count)
|
||||
{
|
||||
assert(index >=0);
|
||||
assert(count > 0);
|
||||
@@ -186,13 +186,13 @@ static inline int array_remove_slice(array_t* array,int index, int count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int array_remove(array_t* array,int index)
|
||||
int array_remove(array_t* array,int index)
|
||||
{
|
||||
return array_remove_slice(array, index, 1);
|
||||
}
|
||||
|
||||
/* return the index for a given member */
|
||||
static int array_index(array_t* array, void* pointer)
|
||||
int array_index(array_t* array, void* pointer)
|
||||
{
|
||||
size_t offset = (char*)pointer - array->pointer;
|
||||
assert(offset >= 0);
|
||||
@@ -242,25 +242,21 @@ typedef struct bootsector_t {
|
||||
uint8_t magic[2];
|
||||
} __attribute__((packed)) bootsector_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t head;
|
||||
uint8_t sector;
|
||||
uint8_t cylinder;
|
||||
} mbr_chs_t;
|
||||
|
||||
typedef struct partition_t {
|
||||
uint8_t attributes; /* 0x80 = bootable */
|
||||
mbr_chs_t start_CHS;
|
||||
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
|
||||
mbr_chs_t end_CHS;
|
||||
uint8_t start_head;
|
||||
uint8_t start_sector;
|
||||
uint8_t start_cylinder;
|
||||
uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
|
||||
uint8_t end_head;
|
||||
uint8_t end_sector;
|
||||
uint8_t end_cylinder;
|
||||
uint32_t start_sector_long;
|
||||
uint32_t length_sector_long;
|
||||
uint32_t end_sector_long;
|
||||
} __attribute__((packed)) partition_t;
|
||||
|
||||
typedef struct mbr_t {
|
||||
uint8_t ignored[0x1b8];
|
||||
uint32_t nt_id;
|
||||
uint8_t ignored2[2];
|
||||
uint8_t ignored[0x1be];
|
||||
partition_t partition[4];
|
||||
uint8_t magic[2];
|
||||
} __attribute__((packed)) mbr_t;
|
||||
@@ -323,10 +319,10 @@ typedef struct BDRVVVFATState {
|
||||
BlockDriverState* bs; /* pointer to parent */
|
||||
unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
|
||||
unsigned char first_sectors[0x40*0x200];
|
||||
|
||||
|
||||
int fat_type; /* 16 or 32 */
|
||||
array_t fat,directory,mapping;
|
||||
|
||||
|
||||
unsigned int cluster_size;
|
||||
unsigned int sectors_per_cluster;
|
||||
unsigned int sectors_per_fat;
|
||||
@@ -336,7 +332,7 @@ typedef struct BDRVVVFATState {
|
||||
uint32_t sector_count; /* total number of sectors of the partition */
|
||||
uint32_t cluster_count; /* total number of clusters of this partition */
|
||||
uint32_t max_fat_value;
|
||||
|
||||
|
||||
int current_fd;
|
||||
mapping_t* current_mapping;
|
||||
unsigned char* cluster; /* points to current cluster */
|
||||
@@ -354,26 +350,11 @@ typedef struct BDRVVVFATState {
|
||||
int downcase_short_names;
|
||||
} BDRVVVFATState;
|
||||
|
||||
/* take the sector position spos and convert it to Cylinder/Head/Sector position
|
||||
* if the position is outside the specified geometry, fill maximum value for CHS
|
||||
* and return 1 to signal overflow.
|
||||
*/
|
||||
static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
|
||||
int head,sector;
|
||||
sector = spos % (bs->secs); spos/= bs->secs;
|
||||
head = spos % (bs->heads); spos/= bs->heads;
|
||||
if(spos >= bs->cyls){
|
||||
/* Overflow,
|
||||
it happens if 32bit sector positions are used, while CHS is only 24bit.
|
||||
Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
|
||||
chs->head = 0xFF;
|
||||
chs->sector = 0xFF;
|
||||
chs->cylinder = 0xFF;
|
||||
return 1;
|
||||
}
|
||||
chs->head = (uint8_t)head;
|
||||
chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
|
||||
chs->cylinder = (uint8_t)spos;
|
||||
|
||||
static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
if (strstart(filename, "fat:", NULL))
|
||||
return 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -382,29 +363,20 @@ static void init_mbr(BDRVVVFATState* s)
|
||||
/* TODO: if the files mbr.img and bootsect.img exist, use them */
|
||||
mbr_t* real_mbr=(mbr_t*)s->first_sectors;
|
||||
partition_t* partition=&(real_mbr->partition[0]);
|
||||
int lba;
|
||||
|
||||
memset(s->first_sectors,0,512);
|
||||
|
||||
/* Win NT Disk Signature */
|
||||
real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
|
||||
|
||||
|
||||
partition->attributes=0x80; /* bootable */
|
||||
|
||||
/* LBA is used when partition is outside the CHS geometry */
|
||||
lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
|
||||
lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count);
|
||||
|
||||
/*LBA partitions are identified only by start/length_sector_long not by CHS*/
|
||||
partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
|
||||
partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
|
||||
|
||||
partition->start_head=1;
|
||||
partition->start_sector=1;
|
||||
partition->start_cylinder=0;
|
||||
/* FAT12/FAT16/FAT32 */
|
||||
/* DOS uses different types when partition is LBA,
|
||||
probably to prevent older versions from using CHS on them */
|
||||
partition->fs_type= s->fat_type==12 ? 0x1:
|
||||
s->fat_type==16 ? (lba?0xe:0x06):
|
||||
/*fat_tyoe==32*/ (lba?0xc:0x0b);
|
||||
partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
|
||||
partition->end_head=s->bs->heads-1;
|
||||
partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
|
||||
partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
|
||||
partition->start_sector_long=cpu_to_le32(s->bs->secs);
|
||||
partition->end_sector_long=cpu_to_le32(s->sector_count);
|
||||
|
||||
real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
|
||||
}
|
||||
@@ -412,19 +384,17 @@ static void init_mbr(BDRVVVFATState* s)
|
||||
/* direntry functions */
|
||||
|
||||
/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
|
||||
static inline int short2long_name(char* dest,const char* src)
|
||||
static inline int short2long_name(unsigned char* dest,const char* src)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
for(i=0;i<129 && src[i];i++) {
|
||||
dest[2*i]=src[i];
|
||||
dest[2*i+1]=0;
|
||||
}
|
||||
len=2*i;
|
||||
dest[2*i]=dest[2*i+1]=0;
|
||||
for(i=2*i+2;(i%26);i++)
|
||||
dest[i]=0xff;
|
||||
return len;
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
|
||||
@@ -441,7 +411,7 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
|
||||
entry->begin=0;
|
||||
entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
|
||||
}
|
||||
for(i=0;i<26*number_of_entries;i++) {
|
||||
for(i=0;i<length;i++) {
|
||||
int offset=(i%26);
|
||||
if(offset<10) offset=1+offset;
|
||||
else if(offset<22) offset=14+offset-10;
|
||||
@@ -515,7 +485,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
|
||||
for(i=0;i<11;i++)
|
||||
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
|
||||
+(unsigned char)entry->name[i];
|
||||
|
||||
|
||||
return chksum;
|
||||
}
|
||||
|
||||
@@ -567,7 +537,7 @@ static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
|
||||
uint16_t* entry=array_get(&(s->fat),cluster);
|
||||
return le16_to_cpu(*entry);
|
||||
} else {
|
||||
const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
|
||||
const uint8_t* x=s->fat.pointer+cluster*3/2;
|
||||
return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
|
||||
}
|
||||
}
|
||||
@@ -591,7 +561,7 @@ static inline void init_fat(BDRVVVFATState* s)
|
||||
s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
|
||||
}
|
||||
memset(s->fat.pointer,0,s->fat.size);
|
||||
|
||||
|
||||
switch(s->fat_type) {
|
||||
case 12: s->max_fat_value=0xfff; break;
|
||||
case 16: s->max_fat_value=0xffff; break;
|
||||
@@ -616,10 +586,10 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
|
||||
memcpy(entry->name,filename,strlen(filename));
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
entry_long=create_long_filename(s,filename);
|
||||
|
||||
i = strlen(filename);
|
||||
|
||||
i = strlen(filename);
|
||||
for(j = i - 1; j>0 && filename[j]!='.';j--);
|
||||
if (j > 0)
|
||||
i = (j > 8 ? 8 : j);
|
||||
@@ -628,8 +598,8 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
|
||||
|
||||
entry=array_get_next(&(s->directory));
|
||||
memset(entry->name,0x20,11);
|
||||
strncpy((char*)entry->name,filename,i);
|
||||
|
||||
strncpy(entry->name,filename,i);
|
||||
|
||||
if(j > 0)
|
||||
for (i = 0; i < 3 && filename[j+1+i]; i++)
|
||||
entry->extension[i] = filename[j+1+i];
|
||||
@@ -655,7 +625,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
|
||||
if(entry1==entry) /* no dupe found */
|
||||
break;
|
||||
|
||||
/* use all 8 characters of name */
|
||||
/* use all 8 characters of name */
|
||||
if(entry->name[7]==' ') {
|
||||
int j;
|
||||
for(j=6;j>0 && entry->name[j]==' ';j--)
|
||||
@@ -712,11 +682,11 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||||
mapping->end = mapping->begin;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
i = mapping->info.dir.first_dir_index =
|
||||
first_cluster == 0 ? 0 : s->directory.next;
|
||||
|
||||
/* actually read the directory, and allocate the mappings */
|
||||
/* actually read the directory, and allocate the mappings */
|
||||
while((entry=readdir(dir))) {
|
||||
unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
|
||||
char* buffer;
|
||||
@@ -727,7 +697,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||||
|
||||
if(first_cluster == 0 && (is_dotdot || is_dot))
|
||||
continue;
|
||||
|
||||
|
||||
buffer=(char*)malloc(length);
|
||||
assert(buffer);
|
||||
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
|
||||
@@ -802,7 +772,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||||
memset(array_get(&(s->directory), cur), 0,
|
||||
(ROOT_ENTRIES - cur) * sizeof(direntry_t));
|
||||
}
|
||||
|
||||
|
||||
/* reget the mapping, since s->mapping was possibly realloc()ed */
|
||||
mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
|
||||
first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
|
||||
@@ -811,7 +781,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||||
|
||||
direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
|
||||
set_begin_of_direntry(direntry, mapping->begin);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -862,7 +832,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
*/
|
||||
i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
|
||||
s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
|
||||
|
||||
|
||||
array_init(&(s->mapping),sizeof(mapping_t));
|
||||
array_init(&(s->directory),sizeof(direntry_t));
|
||||
|
||||
@@ -870,7 +840,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
{
|
||||
direntry_t* entry=array_get_next(&(s->directory));
|
||||
entry->attributes=0x28; /* archive | volume label */
|
||||
snprintf((char*)entry->name,11,"QEMU VVFAT");
|
||||
snprintf(entry->name,11,"QEMU VVFAT");
|
||||
}
|
||||
|
||||
/* Now build FAT, and write back information into directory */
|
||||
@@ -894,7 +864,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
|
||||
for (i = 0, cluster = 0; i < s->mapping.next; i++) {
|
||||
int j;
|
||||
/* MS-DOS expects the FAT to be 0 for the root directory
|
||||
/* MS-DOS expects the FAT to be 0 for the root directory
|
||||
* (except for the media byte). */
|
||||
/* LATER TODO: still true for FAT32? */
|
||||
int fix_fat = (i != 0);
|
||||
@@ -984,22 +954,18 @@ 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, int flags)
|
||||
static int vvfat_open(BlockDriverState *bs, const char* dirname)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int floppy = 0;
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
vvv = s;
|
||||
#endif
|
||||
|
||||
DLOG(if (stderr == NULL) {
|
||||
stderr = fopen("vvfat.log", "a");
|
||||
@@ -1010,9 +976,10 @@ DLOG(if (stderr == NULL) {
|
||||
|
||||
s->fat_type=16;
|
||||
/* LATER TODO: if FAT32, adjust */
|
||||
s->sector_count=0xec04f;
|
||||
s->sectors_per_cluster=0x10;
|
||||
/* 504MB disk*/
|
||||
bs->cyls=1024; bs->heads=16; bs->secs=63;
|
||||
/* LATER TODO: this could be wrong for FAT32 */
|
||||
bs->cyls=1023; bs->heads=15; bs->secs=63;
|
||||
|
||||
s->current_cluster=0xffffffff;
|
||||
|
||||
@@ -1023,10 +990,16 @@ DLOG(if (stderr == NULL) {
|
||||
s->qcow_filename = NULL;
|
||||
s->fat2 = NULL;
|
||||
s->downcase_short_names = 1;
|
||||
|
||||
|
||||
if (!strstart(dirname, "fat:", NULL))
|
||||
return -1;
|
||||
|
||||
if (strstr(dirname, ":rw:")) {
|
||||
if (enable_write_target(s))
|
||||
return -1;
|
||||
bs->read_only = 0;
|
||||
}
|
||||
|
||||
if (strstr(dirname, ":floppy:")) {
|
||||
floppy = 1;
|
||||
s->fat_type = 12;
|
||||
@@ -1035,8 +1008,6 @@ DLOG(if (stderr == NULL) {
|
||||
bs->cyls = 80; bs->heads = 2; bs->secs = 36;
|
||||
}
|
||||
|
||||
s->sector_count=bs->cyls*bs->heads*bs->secs;
|
||||
|
||||
if (strstr(dirname, ":32:")) {
|
||||
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
|
||||
s->fat_type = 32;
|
||||
@@ -1047,12 +1018,6 @@ DLOG(if (stderr == NULL) {
|
||||
s->sector_count=2880;
|
||||
}
|
||||
|
||||
if (strstr(dirname, ":rw:")) {
|
||||
if (enable_write_target(s))
|
||||
return -1;
|
||||
bs->read_only = 0;
|
||||
}
|
||||
|
||||
i = strrchr(dirname, ':') - dirname;
|
||||
assert(i >= 3);
|
||||
if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
|
||||
@@ -1062,12 +1027,11 @@ DLOG(if (stderr == NULL) {
|
||||
dirname += i+1;
|
||||
|
||||
bs->total_sectors=bs->cyls*bs->heads*bs->secs;
|
||||
|
||||
if (s->sector_count > bs->total_sectors)
|
||||
s->sector_count = bs->total_sectors;
|
||||
if(init_directories(s, dirname))
|
||||
return -1;
|
||||
|
||||
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
|
||||
|
||||
if(s->first_sectors_number==0x40)
|
||||
init_mbr(s);
|
||||
|
||||
@@ -1076,6 +1040,7 @@ DLOG(if (stderr == NULL) {
|
||||
bs->heads = bs->cyls = bs->secs = 0;
|
||||
|
||||
// assert(is_consistent(s));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1080,7 @@ static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num
|
||||
assert(index1<=index2);
|
||||
DLOG(mapping=array_get(&(s->mapping),index1);
|
||||
assert(mapping->begin<=cluster_num);
|
||||
assert(index2 >= s->mapping.next ||
|
||||
assert(index2 >= s->mapping.next ||
|
||||
((mapping = array_get(&(s->mapping),index2)) &&
|
||||
mapping->end>cluster_num)));
|
||||
}
|
||||
@@ -1189,7 +1154,7 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
|
||||
s->current_mapping = mapping;
|
||||
read_cluster_directory:
|
||||
offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
|
||||
s->cluster = (unsigned char*)s->directory.pointer+offset
|
||||
s->cluster = s->directory.pointer+offset
|
||||
+ 0x20*s->current_mapping->info.dir.first_dir_index;
|
||||
assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
|
||||
assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
|
||||
@@ -1278,7 +1243,7 @@ static void print_mapping(const mapping_t* mapping)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
@@ -1459,7 +1424,7 @@ static int parse_long_name(long_file_name* lfn,
|
||||
}
|
||||
|
||||
if (pointer[0] & 0x40)
|
||||
lfn->len = offset + strlen((char*)lfn->name + offset);
|
||||
lfn->len = offset + strlen(lfn->name + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1498,7 +1463,7 @@ static int parse_short_name(BDRVVVFATState* s,
|
||||
} else
|
||||
lfn->name[i + j + 1] = '\0';
|
||||
|
||||
lfn->len = strlen((char*)lfn->name);
|
||||
lfn->len = strlen(lfn->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1713,7 +1678,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
||||
}
|
||||
|
||||
/*
|
||||
* This function looks at the modified data (qcow).
|
||||
* This function looks at the modified data (qcow).
|
||||
* It returns 0 upon inconsistency or error, and the number of clusters
|
||||
* used by the directory, its subdirectories and their files.
|
||||
*/
|
||||
@@ -1748,7 +1713,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
||||
} else
|
||||
/* new directory */
|
||||
schedule_mkdir(s, cluster_num, strdup(path));
|
||||
|
||||
|
||||
lfn_init(&lfn);
|
||||
do {
|
||||
int i;
|
||||
@@ -1794,8 +1759,8 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
|
||||
fprintf(stderr, "Error in short name (%d)\n", subret);
|
||||
goto fail;
|
||||
}
|
||||
if (subret > 0 || !strcmp((char*)lfn.name, ".")
|
||||
|| !strcmp((char*)lfn.name, ".."))
|
||||
if (subret > 0 || !strcmp(lfn.name, ".")
|
||||
|| !strcmp(lfn.name, ".."))
|
||||
continue;
|
||||
}
|
||||
lfn.checksum = 0x100; /* cannot use long name twice */
|
||||
@@ -1804,7 +1769,7 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i)
|
||||
fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
|
||||
goto fail;
|
||||
}
|
||||
strcpy(path2 + path_len + 1, (char*)lfn.name);
|
||||
strcpy(path2 + path_len + 1, lfn.name);
|
||||
|
||||
if (is_directory(direntries + i)) {
|
||||
if (begin_of_direntry(direntries + i) == 0) {
|
||||
@@ -2088,7 +2053,7 @@ static int commit_mappings(BDRVVVFATState* s,
|
||||
}
|
||||
|
||||
next_mapping->dir_index = mapping->dir_index;
|
||||
next_mapping->first_mapping_index =
|
||||
next_mapping->first_mapping_index =
|
||||
mapping->first_mapping_index < 0 ?
|
||||
array_index(&(s->mapping), mapping) :
|
||||
mapping->first_mapping_index;
|
||||
@@ -2108,7 +2073,7 @@ static int commit_mappings(BDRVVVFATState* s,
|
||||
|
||||
mapping = next_mapping;
|
||||
}
|
||||
|
||||
|
||||
cluster = c1;
|
||||
}
|
||||
|
||||
@@ -2213,7 +2178,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 | O_BINARY, 0666);
|
||||
fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
|
||||
strerror(errno), errno);
|
||||
@@ -2236,7 +2201,7 @@ static int commit_one_file(BDRVVVFATState* s,
|
||||
assert(size >= 0);
|
||||
|
||||
ret = vvfat_read(s->bs, cluster2sector(s, c),
|
||||
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
|
||||
cluster, (rest_size + 0x1ff) / 0x200);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -2594,7 +2559,7 @@ static int do_commit(BDRVVVFATState* s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* copy FAT (with bdrv_read) */
|
||||
/* copy FAT (with bdrv_read) */
|
||||
memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
|
||||
|
||||
/* recurse direntries from root (using bs->bdrv_read) */
|
||||
@@ -2636,10 +2601,10 @@ DLOG(checkpoint());
|
||||
return do_commit(s);
|
||||
}
|
||||
|
||||
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
|
||||
static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int i, ret;
|
||||
|
||||
DLOG(checkpoint());
|
||||
@@ -2678,7 +2643,7 @@ DLOG(checkpoint());
|
||||
begin = sector_num;
|
||||
if (end > sector_num + nb_sectors)
|
||||
end = sector_num + nb_sectors;
|
||||
dir_index = mapping->dir_index +
|
||||
dir_index = mapping->dir_index +
|
||||
0x10 * (begin - mapping->begin * s->sectors_per_cluster);
|
||||
direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
|
||||
|
||||
@@ -2737,7 +2702,7 @@ static int vvfat_is_allocated(BlockDriverState *bs,
|
||||
*n = nb_sectors;
|
||||
else if (*n < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -2767,7 +2732,8 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
array_init(&(s->commits), sizeof(commit_t));
|
||||
|
||||
s->qcow_filename = malloc(1024);
|
||||
get_tmp_filename(s->qcow_filename, 1024);
|
||||
strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
|
||||
get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
|
||||
if (bdrv_create(&bdrv_qcow,
|
||||
s->qcow_filename, s->sector_count, "fat:", 0) < 0)
|
||||
return -1;
|
||||
@@ -2801,15 +2767,13 @@ static void vvfat_close(BlockDriverState *bs)
|
||||
BlockDriver bdrv_vvfat = {
|
||||
"vvfat",
|
||||
sizeof(BDRVVVFATState),
|
||||
NULL, /* no probe for protocols */
|
||||
vvfat_probe,
|
||||
vvfat_open,
|
||||
vvfat_read,
|
||||
vvfat_write,
|
||||
vvfat_close,
|
||||
NULL, /* ??? Not sure if we can do any meaningful flushing. */
|
||||
NULL,
|
||||
vvfat_is_allocated,
|
||||
.protocol_name = "fat",
|
||||
vvfat_is_allocated
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
160
block.h
160
block.h
@@ -1,160 +0,0 @@
|
||||
#ifndef BLOCK_H
|
||||
#define BLOCK_H
|
||||
|
||||
/* block.c */
|
||||
typedef struct BlockDriver BlockDriver;
|
||||
|
||||
extern BlockDriver bdrv_raw;
|
||||
extern BlockDriver bdrv_host_device;
|
||||
extern BlockDriver bdrv_cow;
|
||||
extern BlockDriver bdrv_qcow;
|
||||
extern BlockDriver bdrv_vmdk;
|
||||
extern BlockDriver bdrv_cloop;
|
||||
extern BlockDriver bdrv_dmg;
|
||||
extern BlockDriver bdrv_bochs;
|
||||
extern BlockDriver bdrv_vpc;
|
||||
extern BlockDriver bdrv_vvfat;
|
||||
extern BlockDriver bdrv_qcow2;
|
||||
extern BlockDriver bdrv_parallels;
|
||||
|
||||
typedef struct BlockDriverInfo {
|
||||
/* in bytes, 0 if irrelevant */
|
||||
int cluster_size;
|
||||
/* offset at which the VM state can be saved (0 if not possible) */
|
||||
int64_t vm_state_offset;
|
||||
} BlockDriverInfo;
|
||||
|
||||
typedef struct QEMUSnapshotInfo {
|
||||
char id_str[128]; /* unique snapshot id */
|
||||
/* the following fields are informative. They are not needed for
|
||||
the consistency of the snapshot */
|
||||
char name[256]; /* user choosen name */
|
||||
uint32_t vm_state_size; /* VM state info size */
|
||||
uint32_t date_sec; /* UTC date of the snapshot */
|
||||
uint32_t date_nsec;
|
||||
uint64_t vm_clock_nsec; /* VM clock relative to boot */
|
||||
} QEMUSnapshotInfo;
|
||||
|
||||
#define BDRV_O_RDONLY 0x0000
|
||||
#define BDRV_O_RDWR 0x0002
|
||||
#define BDRV_O_ACCESS 0x0003
|
||||
#define BDRV_O_CREAT 0x0004 /* create an empty file */
|
||||
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
||||
#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to
|
||||
use a disk image format on top of
|
||||
it (default for
|
||||
bdrv_file_open()) */
|
||||
#define BDRV_O_DIRECT 0x0020
|
||||
|
||||
#ifndef QEMU_IMG
|
||||
void bdrv_info(void);
|
||||
void bdrv_info_stats(void);
|
||||
#endif
|
||||
|
||||
void bdrv_init(void);
|
||||
BlockDriver *bdrv_find_format(const char *format_name);
|
||||
int bdrv_create(BlockDriver *drv,
|
||||
const char *filename, int64_t size_in_sectors,
|
||||
const char *backing_file, int flags);
|
||||
BlockDriverState *bdrv_new(const char *device_name);
|
||||
void bdrv_delete(BlockDriverState *bs);
|
||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
|
||||
int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
|
||||
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||
BlockDriver *drv);
|
||||
void bdrv_close(BlockDriverState *bs);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
void *buf, int count);
|
||||
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
const void *buf, int count);
|
||||
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
|
||||
int64_t bdrv_getlength(BlockDriverState *bs);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
|
||||
/* async block I/O */
|
||||
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
|
||||
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
|
||||
|
||||
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);
|
||||
|
||||
void qemu_aio_init(void);
|
||||
void qemu_aio_poll(void);
|
||||
void qemu_aio_flush(void);
|
||||
void qemu_aio_wait_start(void);
|
||||
void qemu_aio_wait(void);
|
||||
void qemu_aio_wait_end(void);
|
||||
|
||||
int qemu_key_check(BlockDriverState *bs, const char *name);
|
||||
|
||||
/* Ensure contents are flushed to disk. */
|
||||
void bdrv_flush(BlockDriverState *bs);
|
||||
|
||||
#define BDRV_TYPE_HD 0
|
||||
#define BDRV_TYPE_CDROM 1
|
||||
#define BDRV_TYPE_FLOPPY 2
|
||||
#define BIOS_ATA_TRANSLATION_AUTO 0
|
||||
#define BIOS_ATA_TRANSLATION_NONE 1
|
||||
#define BIOS_ATA_TRANSLATION_LBA 2
|
||||
#define BIOS_ATA_TRANSLATION_LARGE 3
|
||||
#define BIOS_ATA_TRANSLATION_RECHS 4
|
||||
|
||||
void bdrv_set_geometry_hint(BlockDriverState *bs,
|
||||
int cyls, int heads, int secs);
|
||||
void bdrv_set_type_hint(BlockDriverState *bs, int type);
|
||||
void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
|
||||
void bdrv_get_geometry_hint(BlockDriverState *bs,
|
||||
int *pcyls, int *pheads, int *psecs);
|
||||
int bdrv_get_type_hint(BlockDriverState *bs);
|
||||
int bdrv_get_translation_hint(BlockDriverState *bs);
|
||||
int bdrv_is_removable(BlockDriverState *bs);
|
||||
int bdrv_is_read_only(BlockDriverState *bs);
|
||||
int bdrv_is_sg(BlockDriverState *bs);
|
||||
int bdrv_is_inserted(BlockDriverState *bs);
|
||||
int bdrv_media_changed(BlockDriverState *bs);
|
||||
int bdrv_is_locked(BlockDriverState *bs);
|
||||
void bdrv_set_locked(BlockDriverState *bs, int locked);
|
||||
void bdrv_eject(BlockDriverState *bs, int eject_flag);
|
||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
||||
void (*change_cb)(void *opaque), void *opaque);
|
||||
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
|
||||
BlockDriverState *bdrv_find(const char *name);
|
||||
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque);
|
||||
int bdrv_is_encrypted(BlockDriverState *bs);
|
||||
int bdrv_set_key(BlockDriverState *bs, const char *key);
|
||||
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
|
||||
void *opaque);
|
||||
const char *bdrv_get_device_name(BlockDriverState *bs);
|
||||
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||
|
||||
void bdrv_get_backing_filename(BlockDriverState *bs,
|
||||
char *filename, int filename_size);
|
||||
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);
|
||||
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
|
||||
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
|
||||
|
||||
char *get_human_readable_size(char *buf, int buf_size, int64_t size);
|
||||
int path_is_absolute(const char *path);
|
||||
void path_combine(char *dest, int dest_size,
|
||||
const char *base_path,
|
||||
const char *filename);
|
||||
|
||||
#endif
|
||||
92
block_int.h
92
block_int.h
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QEMU System Emulator block driver
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
@@ -24,84 +24,37 @@
|
||||
#ifndef BLOCK_INT_H
|
||||
#define BLOCK_INT_H
|
||||
|
||||
#include "block.h"
|
||||
|
||||
#define BLOCK_FLAG_ENCRYPT 1
|
||||
#define BLOCK_FLAG_COMPRESS 2
|
||||
#define BLOCK_FLAG_COMPAT6 4
|
||||
|
||||
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 flags);
|
||||
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
||||
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
|
||||
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
void (*bdrv_close)(BlockDriverState *bs);
|
||||
int (*bdrv_create)(const char *filename, int64_t total_sectors,
|
||||
int (*bdrv_create)(const char *filename, int64_t total_sectors,
|
||||
const char *backing_file, int flags);
|
||||
void (*bdrv_flush)(BlockDriverState *bs);
|
||||
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
|
||||
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);
|
||||
|
||||
/* to control generic scsi devices */
|
||||
int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
|
||||
|
||||
BlockDriverAIOCB *free_aiocb;
|
||||
struct BlockDriver *next;
|
||||
};
|
||||
|
||||
struct BlockDriverState {
|
||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
||||
size in sectors */
|
||||
int64_t total_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 */
|
||||
int sg; /* if true, the device is a /dev/sg* */
|
||||
/* event callback when inserting/removing */
|
||||
void (*change_cb)(void *opaque);
|
||||
void *change_opaque;
|
||||
|
||||
BlockDriver *drv; /* NULL means no media */
|
||||
BlockDriver *drv;
|
||||
void *opaque;
|
||||
|
||||
int boot_sector_enabled;
|
||||
@@ -111,19 +64,9 @@ 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;
|
||||
|
||||
/* I/O stats (display with "info blockstats"). */
|
||||
uint64_t rd_bytes;
|
||||
uint64_t wr_bytes;
|
||||
uint64_t rd_ops;
|
||||
uint64_t wr_ops;
|
||||
|
||||
|
||||
/* NOTE: the following infos are only hints for real hardware
|
||||
drivers. They are not used by the block driver */
|
||||
int cyls, heads, secs, translation;
|
||||
@@ -132,19 +75,6 @@ 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);
|
||||
|
||||
BlockDriverState *bdrv_first;
|
||||
|
||||
#endif /* BLOCK_INT_H */
|
||||
|
||||
4
bswap.h
4
bswap.h
@@ -48,12 +48,12 @@ static inline uint16_t bswap16(uint16_t x)
|
||||
return bswap_16(x);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
static inline uint32_t bswap32(uint32_t x)
|
||||
{
|
||||
return bswap_32(x);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
static inline uint64_t bswap64(uint64_t x)
|
||||
{
|
||||
return bswap_64(x);
|
||||
}
|
||||
|
||||
50
check_ops.sh
50
check_ops.sh
@@ -1,50 +0,0 @@
|
||||
#! /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'
|
||||
;;
|
||||
s390*)
|
||||
ret='\tbr.*'
|
||||
;;
|
||||
*)
|
||||
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_.*!!'
|
||||
281
cocoa.m
281
cocoa.m
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* QEMU Cocoa display driver
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2005 Pierre d'Herbemont
|
||||
* many code/inspiration from SDL 1.2 code (LGPL)
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -23,7 +23,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
Todo : x miniaturize window
|
||||
Todo : x miniaturize window
|
||||
x center the window
|
||||
- save window position
|
||||
- handle keyboard event
|
||||
@@ -37,9 +37,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "console.h"
|
||||
#include "sysemu.h"
|
||||
#include "vl.h"
|
||||
|
||||
NSWindow *window = NULL;
|
||||
NSQuickDrawView *qd_view = NULL;
|
||||
@@ -86,7 +84,7 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
|
||||
MacSetRectRgn (temp, x, y,
|
||||
x + w, y + h);
|
||||
MacUnionRgn (dirty, temp, dirty);
|
||||
|
||||
|
||||
/* Flush the dirty region */
|
||||
QDFlushPortBuffer ( [ qd_view qdPort ], dirty );
|
||||
DisposeRgn (dirty);
|
||||
@@ -104,9 +102,9 @@ static void cocoa_resize(DisplayState *ds, int w, int h)
|
||||
static void *screen_pixels;
|
||||
static int screen_pitch;
|
||||
NSRect contentRect;
|
||||
|
||||
|
||||
//printf("resizing to %d %d\n", w, h);
|
||||
|
||||
|
||||
contentRect = NSMakeRect (0, 0, w, h);
|
||||
if(window)
|
||||
{
|
||||
@@ -121,44 +119,44 @@ static void cocoa_resize(DisplayState *ds, int w, int h)
|
||||
fprintf(stderr, "(cocoa) can't create window\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if(qd_view)
|
||||
[qd_view release];
|
||||
|
||||
|
||||
qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
|
||||
|
||||
|
||||
if(!qd_view)
|
||||
{
|
||||
fprintf(stderr, "(cocoa) can't create qd_view\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
[ window setAcceptsMouseMovedEvents:YES ];
|
||||
[ window setTitle:@"Qemu" ];
|
||||
[ window setReleasedWhenClosed:NO ];
|
||||
|
||||
|
||||
/* Set screen to black */
|
||||
[ window setBackgroundColor: [NSColor blackColor] ];
|
||||
|
||||
|
||||
/* set window position */
|
||||
[ window center ];
|
||||
|
||||
|
||||
[ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
|
||||
[ [ window contentView ] addSubview:qd_view ];
|
||||
[ qd_view release ];
|
||||
[ window makeKeyAndOrderFront:nil ];
|
||||
|
||||
|
||||
/* Careful here, the window seems to have to be onscreen to do that */
|
||||
LockPortBits ( [ qd_view qdPort ] );
|
||||
screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
|
||||
screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
|
||||
UnlockPortBits ( [ qd_view qdPort ] );
|
||||
{
|
||||
int vOffset = [ window frame ].size.height -
|
||||
{
|
||||
int vOffset = [ window frame ].size.height -
|
||||
[ qd_view frame ].size.height - [ qd_view frame ].origin.y;
|
||||
|
||||
|
||||
int hOffset = [ qd_view frame ].origin.x;
|
||||
|
||||
|
||||
screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
|
||||
}
|
||||
ds->data = screen_pixels;
|
||||
@@ -166,12 +164,7 @@ static void cocoa_resize(DisplayState *ds, int w, int h)
|
||||
ds->depth = device_bpp;
|
||||
ds->width = w;
|
||||
ds->height = h;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
ds->bgr = 1;
|
||||
#else
|
||||
ds->bgr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
current_ds = *ds;
|
||||
}
|
||||
|
||||
@@ -312,38 +305,38 @@ int keymap[] =
|
||||
208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN
|
||||
200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP
|
||||
/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
|
||||
|
||||
|
||||
/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
|
||||
/*
|
||||
219 // 0xdb e0,5b L GUI
|
||||
220 // 0xdc e0,5c R GUI
|
||||
221 // 0xdd e0,5d APPS
|
||||
// E0,2A,E0,37 PRNT SCRN
|
||||
// E1,1D,45,E1,9D,C5 PAUSE
|
||||
83 // 0x53 0x53 KP .
|
||||
// ACPI Scan Codes
|
||||
222 // 0xde E0, 5E Power
|
||||
223 // 0xdf E0, 5F Sleep
|
||||
227 // 0xe3 E0, 63 Wake
|
||||
// Windows Multimedia Scan Codes
|
||||
153 // 0x99 E0, 19 Next Track
|
||||
144 // 0x90 E0, 10 Previous Track
|
||||
164 // 0xa4 E0, 24 Stop
|
||||
162 // 0xa2 E0, 22 Play/Pause
|
||||
160 // 0xa0 E0, 20 Mute
|
||||
176 // 0xb0 E0, 30 Volume Up
|
||||
174 // 0xae E0, 2E Volume Down
|
||||
237 // 0xed E0, 6D Media Select
|
||||
236 // 0xec E0, 6C E-Mail
|
||||
161 // 0xa1 E0, 21 Calculator
|
||||
235 // 0xeb E0, 6B My Computer
|
||||
229 // 0xe5 E0, 65 WWW Search
|
||||
178 // 0xb2 E0, 32 WWW Home
|
||||
234 // 0xea E0, 6A WWW Back
|
||||
233 // 0xe9 E0, 69 WWW Forward
|
||||
232 // 0xe8 E0, 68 WWW Stop
|
||||
231 // 0xe7 E0, 67 WWW Refresh
|
||||
230 // 0xe6 E0, 66 WWW Favorites
|
||||
219 // 0xdb e0,5b L GUI
|
||||
220 // 0xdc e0,5c R GUI
|
||||
221 // 0xdd e0,5d APPS
|
||||
// E0,2A,E0,37 PRNT SCRN
|
||||
// E1,1D,45,E1,9D,C5 PAUSE
|
||||
83 // 0x53 0x53 KP .
|
||||
// ACPI Scan Codes
|
||||
222 // 0xde E0, 5E Power
|
||||
223 // 0xdf E0, 5F Sleep
|
||||
227 // 0xe3 E0, 63 Wake
|
||||
// Windows Multimedia Scan Codes
|
||||
153 // 0x99 E0, 19 Next Track
|
||||
144 // 0x90 E0, 10 Previous Track
|
||||
164 // 0xa4 E0, 24 Stop
|
||||
162 // 0xa2 E0, 22 Play/Pause
|
||||
160 // 0xa0 E0, 20 Mute
|
||||
176 // 0xb0 E0, 30 Volume Up
|
||||
174 // 0xae E0, 2E Volume Down
|
||||
237 // 0xed E0, 6D Media Select
|
||||
236 // 0xec E0, 6C E-Mail
|
||||
161 // 0xa1 E0, 21 Calculator
|
||||
235 // 0xeb E0, 6B My Computer
|
||||
229 // 0xe5 E0, 65 WWW Search
|
||||
178 // 0xb2 E0, 32 WWW Home
|
||||
234 // 0xea E0, 6A WWW Back
|
||||
233 // 0xe9 E0, 69 WWW Forward
|
||||
232 // 0xe8 E0, 68 WWW Stop
|
||||
231 // 0xe7 E0, 67 WWW Refresh
|
||||
230 // 0xe6 E0, 66 WWW Favorites
|
||||
*/
|
||||
};
|
||||
|
||||
@@ -368,10 +361,10 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
NSDate *distantPast;
|
||||
NSEvent *event;
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
|
||||
pool = [ [ NSAutoreleasePool alloc ] init ];
|
||||
distantPast = [ NSDate distantPast ];
|
||||
|
||||
|
||||
vga_hw_update();
|
||||
|
||||
do {
|
||||
@@ -417,8 +410,8 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
|
||||
case NSKeyDown:
|
||||
{
|
||||
int keycode = cocoa_keycode_to_qemu([event keyCode]);
|
||||
|
||||
int keycode = cocoa_keycode_to_qemu([event keyCode]);
|
||||
|
||||
/* handle command Key Combos */
|
||||
if ([event modifierFlags] & NSCommandKeyMask) {
|
||||
switch ([event keyCode]) {
|
||||
@@ -429,7 +422,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* handle control + alt Key Combos */
|
||||
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
|
||||
switch (keycode) {
|
||||
@@ -446,48 +439,31 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
|
||||
/* handle monitor key events */
|
||||
} else {
|
||||
int keysym = 0;
|
||||
|
||||
switch([event keyCode]) {
|
||||
case 115:
|
||||
keysym = QEMU_KEY_HOME;
|
||||
break;
|
||||
case 117:
|
||||
keysym = QEMU_KEY_DELETE;
|
||||
break;
|
||||
case 119:
|
||||
keysym = QEMU_KEY_END;
|
||||
break;
|
||||
case 123:
|
||||
keysym = QEMU_KEY_LEFT;
|
||||
break;
|
||||
case 124:
|
||||
keysym = QEMU_KEY_RIGHT;
|
||||
break;
|
||||
case 125:
|
||||
keysym = QEMU_KEY_DOWN;
|
||||
break;
|
||||
case 126:
|
||||
keysym = QEMU_KEY_UP;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
NSString *ks = [event characters];
|
||||
|
||||
if ([ks length] > 0)
|
||||
keysym = [ks characterAtIndex:0];
|
||||
}
|
||||
case 123:
|
||||
kbd_put_keysym(QEMU_KEY_LEFT);
|
||||
break;
|
||||
case 124:
|
||||
kbd_put_keysym(QEMU_KEY_RIGHT);
|
||||
break;
|
||||
case 125:
|
||||
kbd_put_keysym(QEMU_KEY_DOWN);
|
||||
break;
|
||||
case 126:
|
||||
kbd_put_keysym(QEMU_KEY_UP);
|
||||
break;
|
||||
default:
|
||||
kbd_put_keysym([[event characters] characterAtIndex:0]);
|
||||
break;
|
||||
}
|
||||
if (keysym)
|
||||
kbd_put_keysym(keysym);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSKeyUp:
|
||||
{
|
||||
int keycode = cocoa_keycode_to_qemu([event keyCode]);
|
||||
int keycode = cocoa_keycode_to_qemu([event keyCode]);
|
||||
if (is_graphic_console()) {
|
||||
if (keycode & 0x80)
|
||||
kbd_put_keycode(0xe0);
|
||||
@@ -495,7 +471,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSMouseMoved:
|
||||
if (grab) {
|
||||
int dx = [event deltaX];
|
||||
@@ -505,11 +481,11 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
kbd_mouse_event(dx, dy, dz, buttons);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSLeftMouseDown:
|
||||
if (grab) {
|
||||
int buttons = 0;
|
||||
|
||||
|
||||
/* leftclick+command simulates rightclick */
|
||||
if ([event modifierFlags] & NSCommandKeyMask) {
|
||||
buttons |= MOUSE_EVENT_RBUTTON;
|
||||
@@ -521,7 +497,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
[NSApp sendEvent: event];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSLeftMouseDragged:
|
||||
if (grab) {
|
||||
int dx = [event deltaX];
|
||||
@@ -536,7 +512,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
kbd_mouse_event(dx, dy, dz, buttons);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSLeftMouseUp:
|
||||
if (grab) {
|
||||
kbd_mouse_event(0, 0, 0, 0);
|
||||
@@ -548,18 +524,18 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
//[NSApp sendEvent: event];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSRightMouseDown:
|
||||
if (grab) {
|
||||
int buttons = 0;
|
||||
|
||||
|
||||
buttons |= MOUSE_EVENT_RBUTTON;
|
||||
kbd_mouse_event(0, 0, 0, buttons);
|
||||
} else {
|
||||
[NSApp sendEvent: event];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSRightMouseDragged:
|
||||
if (grab) {
|
||||
int dx = [event deltaX];
|
||||
@@ -570,7 +546,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
kbd_mouse_event(dx, dy, dz, buttons);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSRightMouseUp:
|
||||
if (grab) {
|
||||
kbd_mouse_event(0, 0, 0, 0);
|
||||
@@ -578,7 +554,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
[NSApp sendEvent: event];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSOtherMouseDragged:
|
||||
if (grab) {
|
||||
int dx = [event deltaX];
|
||||
@@ -589,7 +565,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
kbd_mouse_event(dx, dy, dz, buttons);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSOtherMouseDown:
|
||||
if (grab) {
|
||||
int buttons = 0;
|
||||
@@ -599,7 +575,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
[NSApp sendEvent:event];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSOtherMouseUp:
|
||||
if (grab) {
|
||||
kbd_mouse_event(0, 0, 0, 0);
|
||||
@@ -607,14 +583,14 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
[NSApp sendEvent: event];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NSScrollWheel:
|
||||
if (grab) {
|
||||
int dz = [event deltaY];
|
||||
kbd_mouse_event(0, 0, -dz, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: [NSApp sendEvent:event];
|
||||
}
|
||||
}
|
||||
@@ -627,7 +603,7 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void cocoa_cleanup(void)
|
||||
static void cocoa_cleanup(void)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -643,9 +619,9 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
|
||||
ds->dpy_update = cocoa_update;
|
||||
ds->dpy_resize = cocoa_resize;
|
||||
ds->dpy_refresh = cocoa_refresh;
|
||||
|
||||
|
||||
cocoa_resize(ds, 640, 400);
|
||||
|
||||
|
||||
atexit(cocoa_cleanup);
|
||||
}
|
||||
|
||||
@@ -663,17 +639,17 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
|
||||
------------------------------------------------------
|
||||
*/
|
||||
static void QZ_SetPortAlphaOpaque ()
|
||||
{
|
||||
{
|
||||
/* Assume 32 bit if( bpp == 32 )*/
|
||||
if ( 1 ) {
|
||||
|
||||
|
||||
uint32_t *pixels = (uint32_t*) current_ds.data;
|
||||
uint32_t rowPixels = current_ds.linesize / 4;
|
||||
uint32_t i, j;
|
||||
|
||||
|
||||
for (i = 0; i < current_ds.height; i++)
|
||||
for (j = 0; j < current_ds.width; j++) {
|
||||
|
||||
|
||||
pixels[ (i * rowPixels) + j ] |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
@@ -682,32 +658,32 @@ static void QZ_SetPortAlphaOpaque ()
|
||||
@implementation QemuWindow
|
||||
- (void)miniaturize:(id)sender
|
||||
{
|
||||
|
||||
|
||||
/* make the alpha channel opaque so anim won't have holes in it */
|
||||
QZ_SetPortAlphaOpaque ();
|
||||
|
||||
|
||||
[ super miniaturize:sender ];
|
||||
|
||||
|
||||
}
|
||||
- (void)display
|
||||
{
|
||||
/*
|
||||
{
|
||||
/*
|
||||
This method fires just before the window deminaturizes from the Dock.
|
||||
|
||||
|
||||
We'll save the current visible surface, let the window manager redraw any
|
||||
UI elements, and restore the SDL surface. This way, no expose event
|
||||
UI elements, and restore the SDL surface. This way, no expose event
|
||||
is required, and the deminiaturize works perfectly.
|
||||
*/
|
||||
|
||||
|
||||
/* make sure pixels are fully opaque */
|
||||
QZ_SetPortAlphaOpaque ();
|
||||
|
||||
|
||||
/* save current visible SDL surface */
|
||||
[ self cacheImageInRect:[ qd_view frame ] ];
|
||||
|
||||
|
||||
/* let the window manager redraw controls, border, etc */
|
||||
[ super display ];
|
||||
|
||||
|
||||
/* restore visible SDL surface */
|
||||
[ self restoreCachedImage ];
|
||||
}
|
||||
@@ -744,13 +720,13 @@ static void QZ_SetPortAlphaOpaque ()
|
||||
if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
|
||||
{
|
||||
NSOpenPanel *op = [[NSOpenPanel alloc] init];
|
||||
|
||||
|
||||
cocoa_resize(¤t_ds, 640, 400);
|
||||
|
||||
|
||||
[op setPrompt:@"Boot image"];
|
||||
|
||||
|
||||
[op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
|
||||
|
||||
|
||||
[op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
|
||||
modalForWindow:window modalDelegate:self
|
||||
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
|
||||
@@ -776,20 +752,20 @@ static void QZ_SetPortAlphaOpaque ()
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
if(returnCode == NSOKButton)
|
||||
{
|
||||
char *bin = "qemu";
|
||||
char *img = (char*)[ [ sheet filename ] cString];
|
||||
|
||||
|
||||
char **argv = (char**)malloc( sizeof(char*)*3 );
|
||||
|
||||
|
||||
asprintf(&argv[0], "%s", bin);
|
||||
asprintf(&argv[1], "-hda");
|
||||
asprintf(&argv[2], "%s", img);
|
||||
|
||||
|
||||
printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
|
||||
|
||||
|
||||
[self startEmulationWithArgc:3 argv:(char**)argv];
|
||||
}
|
||||
}
|
||||
@@ -829,10 +805,10 @@ static void setApplicationMenu(void)
|
||||
NSMenuItem *menuItem;
|
||||
NSString *title;
|
||||
NSString *appName;
|
||||
|
||||
|
||||
appName = @"Qemu";
|
||||
appleMenu = [[NSMenu alloc] initWithTitle:@""];
|
||||
|
||||
|
||||
/* Add menu items */
|
||||
title = [@"About " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
|
||||
@@ -852,7 +828,7 @@ static void setApplicationMenu(void)
|
||||
title = [@"Quit " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
|
||||
|
||||
|
||||
/* Put menu into the menubar */
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
[menuItem setSubmenu:appleMenu];
|
||||
@@ -874,38 +850,39 @@ static void setupWindowMenu(void)
|
||||
NSMenuItem *menuItem;
|
||||
|
||||
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
|
||||
|
||||
/* "Minimize" item */
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
|
||||
[windowMenu addItem:menuItem];
|
||||
[menuItem release];
|
||||
|
||||
|
||||
/* Put menu into the menubar */
|
||||
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
|
||||
[windowMenuItem setSubmenu:windowMenu];
|
||||
[[NSApp mainMenu] addItem:windowMenuItem];
|
||||
|
||||
|
||||
/* Tell the application object that this is now the window menu */
|
||||
[NSApp setWindowsMenu:windowMenu];
|
||||
|
||||
/* Finally give up our references to the objects */
|
||||
[windowMenu release];
|
||||
[windowMenuItem release];
|
||||
|
||||
}
|
||||
|
||||
static void CustomApplicationMain(void)
|
||||
static void CustomApplicationMain (argc, argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
QemuCocoaGUIController *gui_controller;
|
||||
CPSProcessSerNum PSN;
|
||||
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
|
||||
if (!CPSGetCurrentProcess(&PSN))
|
||||
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
|
||||
if (!CPSSetFrontProcess(&PSN))
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
|
||||
/* Set up the menubar */
|
||||
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
||||
setApplicationMenu();
|
||||
@@ -914,10 +891,10 @@ static void CustomApplicationMain(void)
|
||||
/* Create SDLMain and make it the app delegate */
|
||||
gui_controller = [[QemuCocoaGUIController alloc] init];
|
||||
[NSApp setDelegate:gui_controller];
|
||||
|
||||
|
||||
/* Start the main event loop */
|
||||
[NSApp run];
|
||||
|
||||
|
||||
[gui_controller release];
|
||||
[pool release];
|
||||
}
|
||||
@@ -927,8 +904,8 @@ int main(int argc, char **argv)
|
||||
{
|
||||
gArgc = argc;
|
||||
gArgv = argv;
|
||||
|
||||
CustomApplicationMain();
|
||||
|
||||
|
||||
CustomApplicationMain (argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
501
console.c
501
console.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QEMU graphical console
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 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
|
||||
@@ -21,16 +21,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "console.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "vl.h"
|
||||
|
||||
//#define DEBUG_CONSOLE
|
||||
#define DEFAULT_BACKSCROLL 512
|
||||
#define MAX_CONSOLES 12
|
||||
|
||||
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
|
||||
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
|
||||
#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
|
||||
#define RGB(r, g, b) RGBA(r, g, b, 0xff)
|
||||
|
||||
typedef struct TextAttributes {
|
||||
uint8_t fgcol:4;
|
||||
@@ -55,67 +53,10 @@ enum TTYState {
|
||||
TTY_STATE_CSI,
|
||||
};
|
||||
|
||||
typedef struct QEMUFIFO {
|
||||
uint8_t *buf;
|
||||
int buf_size;
|
||||
int count, wptr, rptr;
|
||||
} QEMUFIFO;
|
||||
|
||||
static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
|
||||
{
|
||||
int l, len;
|
||||
|
||||
l = f->buf_size - f->count;
|
||||
if (len1 > l)
|
||||
len1 = l;
|
||||
len = len1;
|
||||
while (len > 0) {
|
||||
l = f->buf_size - f->wptr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
memcpy(f->buf + f->wptr, buf, l);
|
||||
f->wptr += l;
|
||||
if (f->wptr >= f->buf_size)
|
||||
f->wptr = 0;
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
f->count += len1;
|
||||
return len1;
|
||||
}
|
||||
|
||||
static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
|
||||
{
|
||||
int l, len;
|
||||
|
||||
if (len1 > f->count)
|
||||
len1 = f->count;
|
||||
len = len1;
|
||||
while (len > 0) {
|
||||
l = f->buf_size - f->rptr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
memcpy(buf, f->buf + f->rptr, l);
|
||||
f->rptr += l;
|
||||
if (f->rptr >= f->buf_size)
|
||||
f->rptr = 0;
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
f->count -= len1;
|
||||
return len1;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
GRAPHIC_CONSOLE,
|
||||
TEXT_CONSOLE,
|
||||
TEXT_CONSOLE_FIXED_SIZE
|
||||
} console_type_t;
|
||||
|
||||
/* ??? This is mis-named.
|
||||
It is used for both text and graphical consoles. */
|
||||
struct TextConsole {
|
||||
console_type_t console_type;
|
||||
int text_console; /* true if text console */
|
||||
DisplayState *ds;
|
||||
/* Graphic console state. */
|
||||
vga_hw_update_ptr hw_update;
|
||||
@@ -129,7 +70,6 @@ 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 */
|
||||
@@ -140,11 +80,9 @@ struct TextConsole {
|
||||
int esc_params[MAX_ESC_PARAMS];
|
||||
int nb_esc_params;
|
||||
|
||||
CharDriverState *chr;
|
||||
/* fifo for key pressed */
|
||||
QEMUFIFO out_fifo;
|
||||
uint8_t out_fifo_buf[16];
|
||||
QEMUTimer *kbd_timer;
|
||||
/* kbd read handler */
|
||||
IOReadHandler *fd_read;
|
||||
void *fd_opaque;
|
||||
};
|
||||
|
||||
static TextConsole *active_console;
|
||||
@@ -153,7 +91,7 @@ static int nb_consoles = 0;
|
||||
|
||||
void vga_hw_update(void)
|
||||
{
|
||||
if (active_console && active_console->hw_update)
|
||||
if (active_console->hw_update)
|
||||
active_console->hw_update(active_console->hw);
|
||||
}
|
||||
|
||||
@@ -182,8 +120,8 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
|
||||
r = (rgba >> 16) & 0xff;
|
||||
g = (rgba >> 8) & 0xff;
|
||||
b = (rgba) & 0xff;
|
||||
color = (rgb_to_index[r] * 6 * 6) +
|
||||
(rgb_to_index[g] * 6) +
|
||||
color = (rgb_to_index[r] * 6 * 6) +
|
||||
(rgb_to_index[g] * 6) +
|
||||
(rgb_to_index[b]);
|
||||
break;
|
||||
#endif
|
||||
@@ -207,14 +145,14 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
|
||||
return color;
|
||||
}
|
||||
|
||||
static void vga_fill_rect (DisplayState *ds,
|
||||
static void vga_fill_rect (DisplayState *ds,
|
||||
int posx, int posy, int width, int height, uint32_t color)
|
||||
{
|
||||
uint8_t *d, *d1;
|
||||
int x, y, bpp;
|
||||
|
||||
|
||||
bpp = (ds->depth + 7) >> 3;
|
||||
d1 = ds->data +
|
||||
d1 = ds->data +
|
||||
ds->linesize * posy + bpp * posx;
|
||||
for (y = 0; y < height; y++) {
|
||||
d = d1;
|
||||
@@ -252,9 +190,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
|
||||
bpp = (ds->depth + 7) >> 3;
|
||||
wb = w * bpp;
|
||||
if (yd <= ys) {
|
||||
s = ds->data +
|
||||
s = ds->data +
|
||||
ds->linesize * ys + bpp * xs;
|
||||
d = ds->data +
|
||||
d = ds->data +
|
||||
ds->linesize * yd + bpp * xd;
|
||||
for (y = 0; y < h; y++) {
|
||||
memmove(d, s, wb);
|
||||
@@ -262,9 +200,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
|
||||
s += ds->linesize;
|
||||
}
|
||||
} else {
|
||||
s = ds->data +
|
||||
s = ds->data +
|
||||
ds->linesize * (ys + h - 1) + bpp * xs;
|
||||
d = ds->data +
|
||||
d = ds->data +
|
||||
ds->linesize * (yd + h - 1) + bpp * xd;
|
||||
for (y = 0; y < h; y++) {
|
||||
memmove(d, s, wb);
|
||||
@@ -336,24 +274,24 @@ enum color_names {
|
||||
|
||||
static const uint32_t color_table_rgb[2][8] = {
|
||||
{ /* dark */
|
||||
QEMU_RGB(0x00, 0x00, 0x00), /* black */
|
||||
QEMU_RGB(0xaa, 0x00, 0x00), /* red */
|
||||
QEMU_RGB(0x00, 0xaa, 0x00), /* green */
|
||||
QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
|
||||
QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
|
||||
QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
|
||||
QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
|
||||
QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
|
||||
RGB(0x00, 0x00, 0x00), /* black */
|
||||
RGB(0xaa, 0x00, 0x00), /* red */
|
||||
RGB(0x00, 0xaa, 0x00), /* green */
|
||||
RGB(0xaa, 0xaa, 0x00), /* yellow */
|
||||
RGB(0x00, 0x00, 0xaa), /* blue */
|
||||
RGB(0xaa, 0x00, 0xaa), /* magenta */
|
||||
RGB(0x00, 0xaa, 0xaa), /* cyan */
|
||||
RGB(0xaa, 0xaa, 0xaa), /* white */
|
||||
},
|
||||
{ /* bright */
|
||||
QEMU_RGB(0x00, 0x00, 0x00), /* black */
|
||||
QEMU_RGB(0xff, 0x00, 0x00), /* red */
|
||||
QEMU_RGB(0x00, 0xff, 0x00), /* green */
|
||||
QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
|
||||
QEMU_RGB(0x00, 0x00, 0xff), /* blue */
|
||||
QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
|
||||
QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
|
||||
QEMU_RGB(0xff, 0xff, 0xff), /* white */
|
||||
RGB(0x00, 0x00, 0x00), /* black */
|
||||
RGB(0xff, 0x00, 0x00), /* red */
|
||||
RGB(0x00, 0xff, 0x00), /* green */
|
||||
RGB(0xff, 0xff, 0x00), /* yellow */
|
||||
RGB(0x00, 0x00, 0xff), /* blue */
|
||||
RGB(0xff, 0x00, 0xff), /* magenta */
|
||||
RGB(0x00, 0xff, 0xff), /* cyan */
|
||||
RGB(0xff, 0xff, 0xff), /* white */
|
||||
}
|
||||
};
|
||||
|
||||
@@ -407,7 +345,7 @@ static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
|
||||
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
|
||||
TextAttributes *t_attrib)
|
||||
{
|
||||
uint8_t *d;
|
||||
@@ -430,7 +368,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
|
||||
}
|
||||
|
||||
bpp = (ds->depth + 7) >> 3;
|
||||
d = ds->data +
|
||||
d = ds->data +
|
||||
ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
|
||||
linesize = ds->linesize;
|
||||
font_ptr = vgafont16 + FONT_HEIGHT * ch;
|
||||
@@ -511,7 +449,7 @@ static void text_console_resize(TextConsole *s)
|
||||
c++;
|
||||
}
|
||||
}
|
||||
qemu_free(s->cells);
|
||||
free(s->cells);
|
||||
s->cells = cells;
|
||||
}
|
||||
|
||||
@@ -527,9 +465,9 @@ static void update_xy(TextConsole *s, int x, int y)
|
||||
y2 += s->total_height;
|
||||
if (y2 < s->height) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
vga_putcharxy(s->ds, x, y2, c->ch,
|
||||
vga_putcharxy(s->ds, x, y2, c->ch,
|
||||
&(c->t_attrib));
|
||||
dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
|
||||
dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
|
||||
FONT_WIDTH, FONT_HEIGHT);
|
||||
}
|
||||
}
|
||||
@@ -541,24 +479,21 @@ static void console_show_cursor(TextConsole *s, int show)
|
||||
int y, y1;
|
||||
|
||||
if (s == active_console) {
|
||||
int x = s->x;
|
||||
if (x >= s->width) {
|
||||
x = s->width - 1;
|
||||
}
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
y = y1 - s->y_displayed;
|
||||
if (y < 0)
|
||||
y += s->total_height;
|
||||
if (y < s->height) {
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
c = &s->cells[y1 * s->width + s->x];
|
||||
if (show) {
|
||||
TextAttributes t_attrib = s->t_attrib_default;
|
||||
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
|
||||
vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
|
||||
vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
|
||||
} else {
|
||||
vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
|
||||
vga_putcharxy(s->ds, s->x, y, c->ch,
|
||||
&(c->t_attrib));
|
||||
}
|
||||
dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
|
||||
dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
|
||||
FONT_WIDTH, FONT_HEIGHT);
|
||||
}
|
||||
}
|
||||
@@ -569,7 +504,7 @@ static void console_refresh(TextConsole *s)
|
||||
TextCell *c;
|
||||
int x, y, y1;
|
||||
|
||||
if (s != active_console)
|
||||
if (s != active_console)
|
||||
return;
|
||||
|
||||
vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
|
||||
@@ -578,7 +513,7 @@ static void console_refresh(TextConsole *s)
|
||||
for(y = 0; y < s->height; y++) {
|
||||
c = s->cells + y1 * s->width;
|
||||
for(x = 0; x < s->width; x++) {
|
||||
vga_putcharxy(s->ds, x, y, c->ch,
|
||||
vga_putcharxy(s->ds, x, y, c->ch,
|
||||
&(c->t_attrib));
|
||||
c++;
|
||||
}
|
||||
@@ -593,9 +528,9 @@ static void console_scroll(int ydelta)
|
||||
{
|
||||
TextConsole *s;
|
||||
int i, y1;
|
||||
|
||||
|
||||
s = active_console;
|
||||
if (!s || (s->console_type == GRAPHIC_CONSOLE))
|
||||
if (!s || !s->text_console)
|
||||
return;
|
||||
|
||||
if (ydelta > 0) {
|
||||
@@ -628,6 +563,7 @@ static void console_put_lf(TextConsole *s)
|
||||
TextCell *c;
|
||||
int x, y1;
|
||||
|
||||
s->x = 0;
|
||||
s->y++;
|
||||
if (s->y >= s->height) {
|
||||
s->y = s->height - 1;
|
||||
@@ -648,13 +584,13 @@ static void console_put_lf(TextConsole *s)
|
||||
c++;
|
||||
}
|
||||
if (s == active_console && s->y_displayed == s->y_base) {
|
||||
vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
|
||||
s->width * FONT_WIDTH,
|
||||
vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
|
||||
s->width * FONT_WIDTH,
|
||||
(s->height - 1) * FONT_HEIGHT);
|
||||
vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
|
||||
s->width * FONT_WIDTH, FONT_HEIGHT,
|
||||
s->width * FONT_WIDTH, FONT_HEIGHT,
|
||||
color_table[0][s->t_attrib_default.bgcol]);
|
||||
dpy_update(s->ds, 0, 0,
|
||||
dpy_update(s->ds, 0, 0,
|
||||
s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
|
||||
}
|
||||
}
|
||||
@@ -668,6 +604,10 @@ 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 */
|
||||
@@ -757,21 +697,10 @@ 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;
|
||||
int x, y;
|
||||
int y1, i, x;
|
||||
|
||||
switch(s->state) {
|
||||
case TTY_STATE_NORM:
|
||||
@@ -783,12 +712,15 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
console_put_lf(s);
|
||||
break;
|
||||
case '\b': /* backspace */
|
||||
if (s->x > 0)
|
||||
s->x--;
|
||||
if(s->x > 0) s->x--;
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
c = &s->cells[y1 * s->width + s->x];
|
||||
c->ch = ' ';
|
||||
c->t_attrib = s->t_attrib;
|
||||
update_xy(s, s->x, s->y);
|
||||
break;
|
||||
case '\t': /* tabspace */
|
||||
if (s->x + (8 - (s->x % 8)) > s->width) {
|
||||
s->x = 0;
|
||||
console_put_lf(s);
|
||||
} else {
|
||||
s->x = s->x + (8 - (s->x % 8));
|
||||
@@ -797,27 +729,18 @@ 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) {
|
||||
/* line wrap */
|
||||
s->x = 0;
|
||||
console_put_lf(s);
|
||||
}
|
||||
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 (s->x >= s->width)
|
||||
console_put_lf(s);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -834,156 +757,38 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
case TTY_STATE_CSI: /* handle escape sequence parameters */
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
if (s->nb_esc_params < MAX_ESC_PARAMS) {
|
||||
s->esc_params[s->nb_esc_params] =
|
||||
s->esc_params[s->nb_esc_params] =
|
||||
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
|
||||
}
|
||||
} else {
|
||||
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 '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;
|
||||
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;
|
||||
}
|
||||
case 'D':
|
||||
if (s->x > 0)
|
||||
s->x--;
|
||||
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;
|
||||
}
|
||||
if (s->x < (s->width - 1))
|
||||
s->x++;
|
||||
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 */
|
||||
y1 = (s->y_base + s->y) % s->total_height;
|
||||
for(x = s->x; x < s->width; x++) {
|
||||
console_clear_xy(s, x, s->y);
|
||||
c = &s->cells[y1 * s->width + x];
|
||||
c->ch = ' ';
|
||||
c->t_attrib = s->t_attrib_default;
|
||||
c++;
|
||||
update_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;
|
||||
}
|
||||
console_handle_escape(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -998,17 +803,13 @@ void console_select(unsigned int index)
|
||||
s = consoles[index];
|
||||
if (s) {
|
||||
active_console = s;
|
||||
if (s->console_type != GRAPHIC_CONSOLE) {
|
||||
if (s->text_console) {
|
||||
if (s->g_width != s->ds->width ||
|
||||
s->g_height != s->ds->height) {
|
||||
if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) {
|
||||
dpy_resize(s->ds, s->g_width, s->g_height);
|
||||
} else {
|
||||
s->g_width = s->ds->width;
|
||||
s->g_height = s->ds->height;
|
||||
text_console_resize(s);
|
||||
}
|
||||
}
|
||||
console_refresh(s);
|
||||
} else {
|
||||
vga_hw_invalidate();
|
||||
@@ -1029,6 +830,15 @@ 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_read = fd_read;
|
||||
s->fd_opaque = opaque;
|
||||
}
|
||||
|
||||
static void console_send_event(CharDriverState *chr, int event)
|
||||
{
|
||||
TextConsole *s = chr->opaque;
|
||||
@@ -1044,28 +854,6 @@ static void console_send_event(CharDriverState *chr, int event)
|
||||
}
|
||||
}
|
||||
|
||||
static void kbd_send_chars(void *opaque)
|
||||
{
|
||||
TextConsole *s = opaque;
|
||||
int len;
|
||||
uint8_t buf[16];
|
||||
|
||||
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);
|
||||
qemu_chr_read(s->chr, buf, len);
|
||||
}
|
||||
/* characters are pending: we send them a bit later (XXX:
|
||||
horrible, should change char device API) */
|
||||
if (s->out_fifo.count > 0) {
|
||||
qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* called when an ascii key is pressed */
|
||||
void kbd_put_keysym(int keysym)
|
||||
{
|
||||
@@ -1074,7 +862,7 @@ void kbd_put_keysym(int keysym)
|
||||
int c;
|
||||
|
||||
s = active_console;
|
||||
if (!s || (s->console_type == GRAPHIC_CONSOLE))
|
||||
if (!s || !s->text_console)
|
||||
return;
|
||||
|
||||
switch(keysym) {
|
||||
@@ -1091,32 +879,31 @@ void kbd_put_keysym(int keysym)
|
||||
console_scroll(10);
|
||||
break;
|
||||
default:
|
||||
/* convert the QEMU keysym to VT100 key string */
|
||||
q = buf;
|
||||
if (keysym >= 0xe100 && keysym <= 0xe11f) {
|
||||
*q++ = '\033';
|
||||
*q++ = '[';
|
||||
c = keysym - 0xe100;
|
||||
if (c >= 10)
|
||||
*q++ = '0' + (c / 10);
|
||||
*q++ = '0' + (c % 10);
|
||||
*q++ = '~';
|
||||
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
|
||||
*q++ = '\033';
|
||||
*q++ = '[';
|
||||
*q++ = keysym & 0xff;
|
||||
} else {
|
||||
if (s->fd_read) {
|
||||
/* convert the QEMU keysym to VT100 key string */
|
||||
q = buf;
|
||||
if (keysym >= 0xe100 && keysym <= 0xe11f) {
|
||||
*q++ = '\033';
|
||||
*q++ = '[';
|
||||
c = keysym - 0xe100;
|
||||
if (c >= 10)
|
||||
*q++ = '0' + (c / 10);
|
||||
*q++ = '0' + (c % 10);
|
||||
*q++ = '~';
|
||||
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
|
||||
*q++ = '\033';
|
||||
*q++ = '[';
|
||||
*q++ = keysym & 0xff;
|
||||
} else {
|
||||
*q++ = keysym;
|
||||
}
|
||||
if (s->chr->chr_read) {
|
||||
qemu_fifo_write(&s->out_fifo, buf, q - buf);
|
||||
kbd_send_chars(s);
|
||||
}
|
||||
s->fd_read(s->fd_opaque, buf, q - buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
static TextConsole *new_console(DisplayState *ds, int text)
|
||||
{
|
||||
TextConsole *s;
|
||||
int i;
|
||||
@@ -1127,18 +914,16 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
|
||||
(console_type == GRAPHIC_CONSOLE))) {
|
||||
if (!active_console || (active_console->text_console && !text))
|
||||
active_console = s;
|
||||
}
|
||||
s->ds = ds;
|
||||
s->console_type = console_type;
|
||||
if (console_type != GRAPHIC_CONSOLE) {
|
||||
s->text_console = text;
|
||||
if (text) {
|
||||
consoles[nb_consoles++] = s;
|
||||
} else {
|
||||
/* HACK: Put graphical consoles before text consoles. */
|
||||
for (i = nb_consoles; i > 0; i--) {
|
||||
if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
|
||||
if (!consoles[i - 1]->text_console)
|
||||
break;
|
||||
consoles[i] = consoles[i - 1];
|
||||
}
|
||||
@@ -1154,7 +939,7 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
|
||||
{
|
||||
TextConsole *s;
|
||||
|
||||
s = new_console(ds, GRAPHIC_CONSOLE);
|
||||
s = new_console(ds, 0);
|
||||
if (!s)
|
||||
return NULL;
|
||||
s->hw_update = update;
|
||||
@@ -1166,73 +951,45 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
|
||||
|
||||
int is_graphic_console(void)
|
||||
{
|
||||
return active_console->console_type == GRAPHIC_CONSOLE;
|
||||
return !active_console->text_console;
|
||||
}
|
||||
|
||||
void console_color_init(DisplayState *ds)
|
||||
{
|
||||
int i, j;
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
color_table[j][i] = col_expand(ds,
|
||||
vga_get_color(ds, color_table_rgb[j][i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CharDriverState *text_console_init(DisplayState *ds, const char *p)
|
||||
CharDriverState *text_console_init(DisplayState *ds)
|
||||
{
|
||||
CharDriverState *chr;
|
||||
TextConsole *s;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
int i,j;
|
||||
static int color_inited;
|
||||
|
||||
chr = qemu_mallocz(sizeof(CharDriverState));
|
||||
if (!chr)
|
||||
return NULL;
|
||||
s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
|
||||
s = new_console(ds, 1);
|
||||
if (!s) {
|
||||
free(chr);
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
|
||||
if (!color_inited) {
|
||||
color_inited = 1;
|
||||
console_color_init(s->ds);
|
||||
for(j = 0; j < 2; j++) {
|
||||
for(i = 0; i < 8; i++) {
|
||||
color_table[j][i] = col_expand(s->ds,
|
||||
vga_get_color(s->ds, color_table_rgb[j][i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
s->y_displayed = 0;
|
||||
s->y_base = 0;
|
||||
s->total_height = DEFAULT_BACKSCROLL;
|
||||
s->x = 0;
|
||||
s->y = 0;
|
||||
width = s->ds->width;
|
||||
height = s->ds->height;
|
||||
if (p != 0) {
|
||||
width = strtoul(p, (char **)&p, 10);
|
||||
if (*p == 'C') {
|
||||
p++;
|
||||
width *= FONT_WIDTH;
|
||||
}
|
||||
if (*p == 'x') {
|
||||
p++;
|
||||
height = strtoul(p, (char **)&p, 10);
|
||||
if (*p == 'C') {
|
||||
p++;
|
||||
height *= FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->g_width = width;
|
||||
s->g_height = height;
|
||||
s->g_width = s->ds->width;
|
||||
s->g_height = s->ds->height;
|
||||
|
||||
/* Set text attribute defaults */
|
||||
s->t_attrib_default.bold = 0;
|
||||
@@ -1247,7 +1004,5 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p)
|
||||
s->t_attrib = s->t_attrib_default;
|
||||
text_console_resize(s);
|
||||
|
||||
qemu_chr_reset(chr);
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
||||
154
console.h
154
console.h
@@ -1,154 +0,0 @@
|
||||
#ifndef CONSOLE_H
|
||||
#define CONSOLE_H
|
||||
|
||||
#include "qemu-char.h"
|
||||
|
||||
/* keyboard/mouse support */
|
||||
|
||||
#define MOUSE_EVENT_LBUTTON 0x01
|
||||
#define MOUSE_EVENT_RBUTTON 0x02
|
||||
#define MOUSE_EVENT_MBUTTON 0x04
|
||||
|
||||
typedef void QEMUPutKBDEvent(void *opaque, int keycode);
|
||||
typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
|
||||
|
||||
typedef struct QEMUPutMouseEntry {
|
||||
QEMUPutMouseEvent *qemu_put_mouse_event;
|
||||
void *qemu_put_mouse_event_opaque;
|
||||
int qemu_put_mouse_event_absolute;
|
||||
char *qemu_put_mouse_event_name;
|
||||
|
||||
/* used internally by qemu for handling mice */
|
||||
struct QEMUPutMouseEntry *next;
|
||||
} QEMUPutMouseEntry;
|
||||
|
||||
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
|
||||
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
|
||||
void *opaque, int absolute,
|
||||
const char *name);
|
||||
void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry);
|
||||
|
||||
void kbd_put_keycode(int keycode);
|
||||
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
|
||||
int kbd_mouse_is_absolute(void);
|
||||
|
||||
void do_info_mice(void);
|
||||
void do_mouse_set(int index);
|
||||
|
||||
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
|
||||
constants) */
|
||||
#define QEMU_KEY_ESC1(c) ((c) | 0xe100)
|
||||
#define QEMU_KEY_BACKSPACE 0x007f
|
||||
#define QEMU_KEY_UP QEMU_KEY_ESC1('A')
|
||||
#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B')
|
||||
#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C')
|
||||
#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D')
|
||||
#define QEMU_KEY_HOME QEMU_KEY_ESC1(1)
|
||||
#define QEMU_KEY_END QEMU_KEY_ESC1(4)
|
||||
#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5)
|
||||
#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6)
|
||||
#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3)
|
||||
|
||||
#define QEMU_KEY_CTRL_UP 0xe400
|
||||
#define QEMU_KEY_CTRL_DOWN 0xe401
|
||||
#define QEMU_KEY_CTRL_LEFT 0xe402
|
||||
#define QEMU_KEY_CTRL_RIGHT 0xe403
|
||||
#define QEMU_KEY_CTRL_HOME 0xe404
|
||||
#define QEMU_KEY_CTRL_END 0xe405
|
||||
#define QEMU_KEY_CTRL_PAGEUP 0xe406
|
||||
#define QEMU_KEY_CTRL_PAGEDOWN 0xe407
|
||||
|
||||
void kbd_put_keysym(int keysym);
|
||||
|
||||
/* consoles */
|
||||
|
||||
struct DisplayState {
|
||||
uint8_t *data;
|
||||
int linesize;
|
||||
int depth;
|
||||
int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */
|
||||
int width;
|
||||
int height;
|
||||
void *opaque;
|
||||
struct QEMUTimer *gui_timer;
|
||||
|
||||
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
|
||||
void (*dpy_resize)(struct DisplayState *s, int w, int h);
|
||||
void (*dpy_refresh)(struct DisplayState *s);
|
||||
void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h);
|
||||
void (*dpy_fill)(struct DisplayState *s, int x, int y,
|
||||
int w, int h, uint32_t c);
|
||||
void (*mouse_set)(int x, int y, int on);
|
||||
void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
|
||||
uint8_t *image, uint8_t *mask);
|
||||
};
|
||||
|
||||
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
|
||||
{
|
||||
s->dpy_update(s, x, y, w, h);
|
||||
}
|
||||
|
||||
static inline void dpy_resize(DisplayState *s, int w, int h)
|
||||
{
|
||||
s->dpy_resize(s, w, h);
|
||||
}
|
||||
|
||||
typedef void (*vga_hw_update_ptr)(void *);
|
||||
typedef void (*vga_hw_invalidate_ptr)(void *);
|
||||
typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
|
||||
|
||||
TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
|
||||
vga_hw_invalidate_ptr invalidate,
|
||||
vga_hw_screen_dump_ptr screen_dump,
|
||||
void *opaque);
|
||||
void vga_hw_update(void);
|
||||
void vga_hw_invalidate(void);
|
||||
void vga_hw_screen_dump(const char *filename);
|
||||
|
||||
int is_graphic_console(void);
|
||||
CharDriverState *text_console_init(DisplayState *ds, const char *p);
|
||||
void console_select(unsigned int index);
|
||||
void console_color_init(DisplayState *ds);
|
||||
|
||||
/* sdl.c */
|
||||
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
|
||||
|
||||
/* cocoa.m */
|
||||
void cocoa_display_init(DisplayState *ds, int full_screen);
|
||||
|
||||
/* vnc.c */
|
||||
void vnc_display_init(DisplayState *ds);
|
||||
void vnc_display_close(DisplayState *ds);
|
||||
int vnc_display_open(DisplayState *ds, const char *display);
|
||||
int vnc_display_password(DisplayState *ds, const char *password);
|
||||
void do_info_vnc(void);
|
||||
|
||||
/* x_keymap.c */
|
||||
extern uint8_t _translate_keycode(const int key);
|
||||
|
||||
/* FIXME: term_printf et al should probably go elsewhere so everything
|
||||
does not need to include console.h */
|
||||
/* monitor.c */
|
||||
void monitor_init(CharDriverState *hd, int show_banner);
|
||||
void term_puts(const char *str);
|
||||
void term_vprintf(const char *fmt, va_list ap);
|
||||
void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
void term_print_filename(const char *filename);
|
||||
void term_flush(void);
|
||||
void term_print_help(void);
|
||||
void monitor_readline(const char *prompt, int is_password,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/* readline.c */
|
||||
typedef void ReadLineFunc(void *opaque, const char *str);
|
||||
|
||||
extern int completion_index;
|
||||
void add_completion(const char *str);
|
||||
void readline_handle_byte(int ch);
|
||||
void readline_find_completion(const char *cmdline);
|
||||
const char *readline_get_history(unsigned int index);
|
||||
void readline_start(const char *prompt, int is_password,
|
||||
ReadLineFunc *readline_func, void *opaque);
|
||||
|
||||
#endif
|
||||
282
cpu-all.h
282
cpu-all.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* defines common to all virtual CPUs
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@@ -20,20 +20,20 @@
|
||||
#ifndef CPU_ALL_H
|
||||
#define CPU_ALL_H
|
||||
|
||||
#if defined(__arm__) || defined(__sparc__) || defined(__mips__)
|
||||
#if defined(__arm__) || defined(__sparc__)
|
||||
#define WORDS_ALIGNED
|
||||
#endif
|
||||
|
||||
/* some important defines:
|
||||
*
|
||||
/* some important defines:
|
||||
*
|
||||
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
|
||||
* memory accesses.
|
||||
*
|
||||
*
|
||||
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
|
||||
* otherwise little endian.
|
||||
*
|
||||
*
|
||||
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
|
||||
*
|
||||
*
|
||||
* TARGET_WORDS_BIGENDIAN : same for target cpu
|
||||
*/
|
||||
|
||||
@@ -135,36 +135,6 @@ typedef union {
|
||||
uint64_t ll;
|
||||
} CPU_DoubleU;
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
typedef union {
|
||||
float128 q;
|
||||
#if defined(WORDS_BIGENDIAN) \
|
||||
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
|
||||
struct {
|
||||
uint32_t upmost;
|
||||
uint32_t upper;
|
||||
uint32_t lower;
|
||||
uint32_t lowest;
|
||||
} l;
|
||||
struct {
|
||||
uint64_t upper;
|
||||
uint64_t lower;
|
||||
} ll;
|
||||
#else
|
||||
struct {
|
||||
uint32_t lowest;
|
||||
uint32_t lower;
|
||||
uint32_t upper;
|
||||
uint32_t upmost;
|
||||
} l;
|
||||
struct {
|
||||
uint64_t lower;
|
||||
uint64_t upper;
|
||||
} ll;
|
||||
#endif
|
||||
} CPU_QuadU;
|
||||
#endif
|
||||
|
||||
/* CPU memory access without any memory or io remapping */
|
||||
|
||||
/*
|
||||
@@ -177,7 +147,7 @@ typedef union {
|
||||
* type is:
|
||||
* (empty): integer access
|
||||
* f : float access
|
||||
*
|
||||
*
|
||||
* sign is:
|
||||
* (empty): for floats or 32 bit size
|
||||
* u : unsigned
|
||||
@@ -188,7 +158,7 @@ typedef union {
|
||||
* w: 16 bits
|
||||
* l: 32 bits
|
||||
* q: 64 bits
|
||||
*
|
||||
*
|
||||
* endian is:
|
||||
* (empty): target cpu endianness or 8 bit access
|
||||
* r : reversed target cpu endianness (not implemented yet)
|
||||
@@ -651,7 +621,7 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
||||
#define stfq_raw(p, v) stfq_p(saddr((p)), v)
|
||||
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* if user mode, no other memory access functions */
|
||||
#define ldub(p) ldub_raw(p)
|
||||
@@ -674,14 +644,12 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
||||
#define lduw_code(p) lduw_raw(p)
|
||||
#define ldsw_code(p) ldsw_raw(p)
|
||||
#define ldl_code(p) ldl_raw(p)
|
||||
#define ldq_code(p) ldq_raw(p)
|
||||
|
||||
#define ldub_kernel(p) ldub_raw(p)
|
||||
#define ldsb_kernel(p) ldsb_raw(p)
|
||||
#define lduw_kernel(p) lduw_raw(p)
|
||||
#define ldsw_kernel(p) ldsw_raw(p)
|
||||
#define ldl_kernel(p) ldl_raw(p)
|
||||
#define ldq_kernel(p) ldq_raw(p)
|
||||
#define ldfl_kernel(p) ldfl_raw(p)
|
||||
#define ldfq_kernel(p) ldfq_raw(p)
|
||||
#define stb_kernel(p, v) stb_raw(p, v)
|
||||
@@ -715,26 +683,75 @@ extern unsigned long qemu_host_page_mask;
|
||||
#define PAGE_VALID 0x0008
|
||||
/* original state of the write flag (used when tracking self-modifying
|
||||
code */
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
#define PAGE_RESERVED 0x0020
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
|
||||
void page_dump(FILE *f);
|
||||
int page_get_flags(target_ulong address);
|
||||
void page_set_flags(target_ulong start, target_ulong end, int flags);
|
||||
int page_check_range(target_ulong start, target_ulong len, int flags);
|
||||
void page_unprotect_range(target_ulong data, target_ulong data_size);
|
||||
|
||||
CPUState *cpu_copy(CPUState *env);
|
||||
#define SINGLE_CPU_DEFINES
|
||||
#ifdef SINGLE_CPU_DEFINES
|
||||
|
||||
void cpu_dump_state(CPUState *env, FILE *f,
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
#define CPUState CPUX86State
|
||||
#define cpu_init cpu_x86_init
|
||||
#define cpu_exec cpu_x86_exec
|
||||
#define cpu_gen_code cpu_x86_gen_code
|
||||
#define cpu_signal_handler cpu_x86_signal_handler
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
#define CPUState CPUARMState
|
||||
#define cpu_init cpu_arm_init
|
||||
#define cpu_exec cpu_arm_exec
|
||||
#define cpu_gen_code cpu_arm_gen_code
|
||||
#define cpu_signal_handler cpu_arm_signal_handler
|
||||
|
||||
#elif defined(TARGET_SPARC)
|
||||
|
||||
#define CPUState CPUSPARCState
|
||||
#define cpu_init cpu_sparc_init
|
||||
#define cpu_exec cpu_sparc_exec
|
||||
#define cpu_gen_code cpu_sparc_gen_code
|
||||
#define cpu_signal_handler cpu_sparc_signal_handler
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
#define CPUState CPUPPCState
|
||||
#define cpu_init cpu_ppc_init
|
||||
#define cpu_exec cpu_ppc_exec
|
||||
#define cpu_gen_code cpu_ppc_gen_code
|
||||
#define cpu_signal_handler cpu_ppc_signal_handler
|
||||
|
||||
#elif defined(TARGET_MIPS)
|
||||
#define CPUState CPUMIPSState
|
||||
#define cpu_init cpu_mips_init
|
||||
#define cpu_exec cpu_mips_exec
|
||||
#define cpu_gen_code cpu_mips_gen_code
|
||||
#define cpu_signal_handler cpu_mips_signal_handler
|
||||
|
||||
#elif defined(TARGET_SH4)
|
||||
#define CPUState CPUSH4State
|
||||
#define cpu_init cpu_sh4_init
|
||||
#define cpu_exec cpu_sh4_exec
|
||||
#define cpu_gen_code cpu_sh4_gen_code
|
||||
#define cpu_signal_handler cpu_sh4_signal_handler
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported target CPU
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SINGLE_CPU_DEFINES */
|
||||
|
||||
void cpu_dump_state(CPUState *env, FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
int flags);
|
||||
void cpu_dump_statistics (CPUState *env, FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
int flags);
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...)
|
||||
__attribute__ ((__format__ (__printf__, 2, 3)))
|
||||
__attribute__ ((__noreturn__));
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||
extern CPUState *first_cpu;
|
||||
extern CPUState *cpu_single_env;
|
||||
extern int code_copy_enabled;
|
||||
@@ -745,15 +762,10 @@ 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 */
|
||||
#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */
|
||||
#define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */
|
||||
|
||||
void cpu_interrupt(CPUState *s, int mask);
|
||||
void cpu_reset_interrupt(CPUState *env, int mask);
|
||||
|
||||
int cpu_watchpoint_insert(CPUState *env, target_ulong addr);
|
||||
int cpu_watchpoint_remove(CPUState *env, target_ulong addr);
|
||||
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
|
||||
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
|
||||
void cpu_single_step(CPUState *env, int enabled);
|
||||
@@ -762,9 +774,9 @@ void cpu_reset(CPUState *s);
|
||||
/* Return the physical page corresponding to a virtual one. Use it
|
||||
only for debugging because no protection checks are done. Return -1
|
||||
if no page found. */
|
||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
|
||||
|
||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||
#define CPU_LOG_TB_OP (1 << 2)
|
||||
#define CPU_LOG_TB_OP_OPT (1 << 3)
|
||||
@@ -816,22 +828,13 @@ extern uint8_t *phys_ram_dirty;
|
||||
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
|
||||
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
|
||||
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
|
||||
/* acts like a ROM when read and like a device when written. As an
|
||||
exception, the write memory callback gets the ram offset instead of
|
||||
the physical address */
|
||||
#define IO_MEM_ROMD (1)
|
||||
#define IO_MEM_SUBPAGE (2)
|
||||
#define IO_MEM_SUBWIDTH (4)
|
||||
|
||||
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
|
||||
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
||||
|
||||
void cpu_register_physical_memory(target_phys_addr_t start_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);
|
||||
ram_addr_t qemu_ram_alloc(unsigned int size);
|
||||
void qemu_ram_free(ram_addr_t addr);
|
||||
int cpu_register_io_memory(int io_index,
|
||||
CPUReadMemoryFunc **mem_read,
|
||||
CPUWriteMemoryFunc **mem_write,
|
||||
@@ -841,12 +844,12 @@ CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
|
||||
|
||||
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
int len, int is_write);
|
||||
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
|
||||
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
cpu_physical_memory_rw(addr, buf, len, 0);
|
||||
}
|
||||
static inline void cpu_physical_memory_write(target_phys_addr_t addr,
|
||||
static inline void cpu_physical_memory_write(target_phys_addr_t addr,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
|
||||
@@ -856,15 +859,14 @@ uint32_t lduw_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_phys(target_phys_addr_t addr);
|
||||
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
|
||||
void stb_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_phys(target_phys_addr_t addr, uint64_t val);
|
||||
|
||||
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
const uint8_t *buf, int len);
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
uint8_t *buf, int len, int is_write);
|
||||
|
||||
#define VGA_DIRTY_FLAG 0x01
|
||||
@@ -876,7 +878,7 @@ static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
|
||||
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
|
||||
}
|
||||
|
||||
static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
|
||||
static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
|
||||
int dirty_flags)
|
||||
{
|
||||
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
|
||||
@@ -894,135 +896,13 @@ void cpu_tlb_update_dirty(CPUState *env);
|
||||
void dump_exec_info(FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
|
||||
|
||||
/*******************************************/
|
||||
/* host CPU ticks (if available) */
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
static inline uint32_t get_tbl(void)
|
||||
{
|
||||
uint32_t tbl;
|
||||
asm volatile("mftb %0" : "=r" (tbl));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
static inline uint32_t get_tbu(void)
|
||||
{
|
||||
uint32_t tbl;
|
||||
asm volatile("mftbu %0" : "=r" (tbl));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t l, h, h1;
|
||||
/* NOTE: we test if wrapping has occurred */
|
||||
do {
|
||||
h = get_tbu();
|
||||
l = get_tbl();
|
||||
h1 = get_tbu();
|
||||
} while (h != h1);
|
||||
return ((int64_t)h << 32) | l;
|
||||
}
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t low,high;
|
||||
int64_t val;
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
val = high;
|
||||
val <<= 32;
|
||||
val |= low;
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__ia64)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks (void)
|
||||
{
|
||||
#if defined(_LP64)
|
||||
uint64_t rval;
|
||||
asm volatile("rd %%tick,%0" : "=r"(rval));
|
||||
return rval;
|
||||
#else
|
||||
union {
|
||||
uint64_t i64;
|
||||
struct {
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
} i32;
|
||||
} rval;
|
||||
asm volatile("rd %%tick,%1; srlx %1,32,%0"
|
||||
: "=r"(rval.i32.high), "=r"(rval.i32.low));
|
||||
return rval.i64;
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
#if __mips_isa_rev >= 2
|
||||
uint32_t count;
|
||||
static uint32_t cyc_per_count = 0;
|
||||
|
||||
if (!cyc_per_count)
|
||||
__asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count));
|
||||
|
||||
__asm__ __volatile__("rdhwr %1, $2" : "=r" (count));
|
||||
return (int64_t)(count * cyc_per_count);
|
||||
#else
|
||||
/* FIXME */
|
||||
static int64_t ticks = 0;
|
||||
return ticks++;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
/* The host CPU doesn't have an easily accessible cycle counter.
|
||||
Just return a monotonically increasing value. 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 */
|
||||
#ifdef CONFIG_PROFILER
|
||||
static inline int64_t profile_getclock(void)
|
||||
{
|
||||
return cpu_get_real_ticks();
|
||||
int64_t val;
|
||||
asm volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
extern int64_t kqemu_time, kqemu_time_start;
|
||||
|
||||
50
cpu-defs.h
50
cpu-defs.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* common defines for all CPUs
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@@ -20,10 +20,6 @@
|
||||
#ifndef CPU_DEFS_H
|
||||
#define CPU_DEFS_H
|
||||
|
||||
#ifndef NEED_CPU_H
|
||||
#error cpu.h included from common code
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <setjmp.h>
|
||||
#include <inttypes.h>
|
||||
@@ -33,7 +29,7 @@
|
||||
#error TARGET_LONG_BITS must be defined before including this header
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_PHYS_ADDR_BITS
|
||||
#ifndef TARGET_PHYS_ADDR_BITS
|
||||
#if TARGET_LONG_BITS >= HOST_LONG_BITS
|
||||
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
|
||||
#else
|
||||
@@ -48,14 +44,10 @@
|
||||
typedef int32_t target_long;
|
||||
typedef uint32_t target_ulong;
|
||||
#define TARGET_FMT_lx "%08x"
|
||||
#define TARGET_FMT_ld "%d"
|
||||
#define TARGET_FMT_lu "%u"
|
||||
#elif TARGET_LONG_SIZE == 8
|
||||
typedef int64_t target_long;
|
||||
typedef uint64_t target_ulong;
|
||||
#define TARGET_FMT_lx "%016" PRIx64
|
||||
#define TARGET_FMT_ld "%" PRId64
|
||||
#define TARGET_FMT_lu "%" PRIu64
|
||||
#define TARGET_FMT_lx "%016llx"
|
||||
#else
|
||||
#error TARGET_LONG_SIZE undefined
|
||||
#endif
|
||||
@@ -68,10 +60,8 @@ typedef uint64_t target_ulong;
|
||||
|
||||
#if TARGET_PHYS_ADDR_BITS == 32
|
||||
typedef uint32_t target_phys_addr_t;
|
||||
#define TARGET_FMT_plx "%08x"
|
||||
#elif TARGET_PHYS_ADDR_BITS == 64
|
||||
typedef uint64_t target_phys_addr_t;
|
||||
#define TARGET_FMT_plx "%016" PRIx64
|
||||
#else
|
||||
#error TARGET_PHYS_ADDR_BITS undefined
|
||||
#endif
|
||||
@@ -86,34 +76,25 @@ typedef unsigned long ram_addr_t;
|
||||
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
||||
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
|
||||
#define MAX_BREAKPOINTS 32
|
||||
#define MAX_WATCHPOINTS 32
|
||||
|
||||
#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)
|
||||
|
||||
typedef struct CPUTLBEntry {
|
||||
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||
/* bit 31 to TARGET_PAGE_BITS : virtual address
|
||||
bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
|
||||
zone number
|
||||
bit 3 : indicates that the entry is invalid
|
||||
bit 2..0 : zero
|
||||
*/
|
||||
target_ulong addr_read;
|
||||
target_ulong addr_write;
|
||||
target_ulong addr_code;
|
||||
target_ulong addr_read;
|
||||
target_ulong addr_write;
|
||||
target_ulong addr_code;
|
||||
/* addend to virtual address to get physical address */
|
||||
target_phys_addr_t addend;
|
||||
target_phys_addr_t addend;
|
||||
} CPUTLBEntry;
|
||||
|
||||
#define CPU_COMMON \
|
||||
@@ -126,8 +107,8 @@ typedef struct CPUTLBEntry {
|
||||
written */ \
|
||||
target_ulong mem_write_vaddr; /* target virtual addr at which the \
|
||||
memory was written */ \
|
||||
/* The meaning of the MMU modes is defined in the target code. */ \
|
||||
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
|
||||
/* 0 = kernel, 1 = user */ \
|
||||
CPUTLBEntry tlb_table[2][CPU_TLB_SIZE]; \
|
||||
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
|
||||
\
|
||||
/* from this point: preserved by CPU reset */ \
|
||||
@@ -136,18 +117,9 @@ typedef struct CPUTLBEntry {
|
||||
int nb_breakpoints; \
|
||||
int singlestep_enabled; \
|
||||
\
|
||||
struct { \
|
||||
target_ulong vaddr; \
|
||||
target_phys_addr_t addend; \
|
||||
} watchpoint[MAX_WATCHPOINTS]; \
|
||||
int nb_watchpoints; \
|
||||
int watchpoint_hit; \
|
||||
\
|
||||
void *next_cpu; /* next CPU sharing TB cache */ \
|
||||
int cpu_index; /* CPU index (informative) */ \
|
||||
/* user data */ \
|
||||
void *opaque; \
|
||||
\
|
||||
const char *cpu_model_str;
|
||||
void *opaque;
|
||||
|
||||
#endif
|
||||
|
||||
945
cpu-exec.c
945
cpu-exec.c
File diff suppressed because it is too large
Load Diff
2907
cris-dis.c
2907
cris-dis.c
File diff suppressed because it is too large
Load Diff
97
cutils.c
97
cutils.c
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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 "qemu-common.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;
|
||||
}
|
||||
|
||||
time_t mktimegm(struct tm *tm)
|
||||
{
|
||||
time_t t;
|
||||
int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
|
||||
if (m < 3) {
|
||||
m += 12;
|
||||
y--;
|
||||
}
|
||||
t = 86400 * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 +
|
||||
y / 400 - 719469);
|
||||
t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
|
||||
return t;
|
||||
}
|
||||
434
d3des.c
434
d3des.c
@@ -1,434 +0,0 @@
|
||||
/*
|
||||
* This is D3DES (V5.09) by Richard Outerbridge with the double and
|
||||
* triple-length support removed for use in VNC. Also the bytebit[] array
|
||||
* has been reversed so that the most significant bit in each byte of the
|
||||
* key is ignored, not the least significant.
|
||||
*
|
||||
* These changes are:
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This software 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.
|
||||
*/
|
||||
|
||||
/* D3DES (V5.09) -
|
||||
*
|
||||
* A portable, public domain, version of the Data Encryption Standard.
|
||||
*
|
||||
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
|
||||
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
|
||||
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
|
||||
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
|
||||
* for humouring me on.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
|
||||
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
|
||||
*/
|
||||
|
||||
#include "d3des.h"
|
||||
|
||||
static void scrunch(unsigned char *, unsigned long *);
|
||||
static void unscrun(unsigned long *, unsigned char *);
|
||||
static void desfunc(unsigned long *, unsigned long *);
|
||||
static void cookey(unsigned long *);
|
||||
|
||||
static unsigned long KnL[32] = { 0L };
|
||||
|
||||
static unsigned short bytebit[8] = {
|
||||
01, 02, 04, 010, 020, 040, 0100, 0200 };
|
||||
|
||||
static unsigned long bigbyte[24] = {
|
||||
0x800000L, 0x400000L, 0x200000L, 0x100000L,
|
||||
0x80000L, 0x40000L, 0x20000L, 0x10000L,
|
||||
0x8000L, 0x4000L, 0x2000L, 0x1000L,
|
||||
0x800L, 0x400L, 0x200L, 0x100L,
|
||||
0x80L, 0x40L, 0x20L, 0x10L,
|
||||
0x8L, 0x4L, 0x2L, 0x1L };
|
||||
|
||||
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
|
||||
|
||||
static unsigned char pc1[56] = {
|
||||
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
|
||||
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
|
||||
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
|
||||
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
|
||||
|
||||
static unsigned char totrot[16] = {
|
||||
1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
|
||||
|
||||
static unsigned char pc2[48] = {
|
||||
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
|
||||
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
|
||||
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
|
||||
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
|
||||
|
||||
void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */
|
||||
unsigned char *key;
|
||||
int edf;
|
||||
{
|
||||
register int i, j, l, m, n;
|
||||
unsigned char pc1m[56], pcr[56];
|
||||
unsigned long kn[32];
|
||||
|
||||
for ( j = 0; j < 56; j++ ) {
|
||||
l = pc1[j];
|
||||
m = l & 07;
|
||||
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
|
||||
}
|
||||
for( i = 0; i < 16; i++ ) {
|
||||
if( edf == DE1 ) m = (15 - i) << 1;
|
||||
else m = i << 1;
|
||||
n = m + 1;
|
||||
kn[m] = kn[n] = 0L;
|
||||
for( j = 0; j < 28; j++ ) {
|
||||
l = j + totrot[i];
|
||||
if( l < 28 ) pcr[j] = pc1m[l];
|
||||
else pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for( j = 28; j < 56; j++ ) {
|
||||
l = j + totrot[i];
|
||||
if( l < 56 ) pcr[j] = pc1m[l];
|
||||
else pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for( j = 0; j < 24; j++ ) {
|
||||
if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
|
||||
if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
|
||||
}
|
||||
}
|
||||
cookey(kn);
|
||||
return;
|
||||
}
|
||||
|
||||
static void cookey(raw1)
|
||||
register unsigned long *raw1;
|
||||
{
|
||||
register unsigned long *cook, *raw0;
|
||||
unsigned long dough[32];
|
||||
register int i;
|
||||
|
||||
cook = dough;
|
||||
for( i = 0; i < 16; i++, raw1++ ) {
|
||||
raw0 = raw1++;
|
||||
*cook = (*raw0 & 0x00fc0000L) << 6;
|
||||
*cook |= (*raw0 & 0x00000fc0L) << 10;
|
||||
*cook |= (*raw1 & 0x00fc0000L) >> 10;
|
||||
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
|
||||
*cook = (*raw0 & 0x0003f000L) << 12;
|
||||
*cook |= (*raw0 & 0x0000003fL) << 16;
|
||||
*cook |= (*raw1 & 0x0003f000L) >> 4;
|
||||
*cook++ |= (*raw1 & 0x0000003fL);
|
||||
}
|
||||
usekey(dough);
|
||||
return;
|
||||
}
|
||||
|
||||
void cpkey(into)
|
||||
register unsigned long *into;
|
||||
{
|
||||
register unsigned long *from, *endp;
|
||||
|
||||
from = KnL, endp = &KnL[32];
|
||||
while( from < endp ) *into++ = *from++;
|
||||
return;
|
||||
}
|
||||
|
||||
void usekey(from)
|
||||
register unsigned long *from;
|
||||
{
|
||||
register unsigned long *to, *endp;
|
||||
|
||||
to = KnL, endp = &KnL[32];
|
||||
while( to < endp ) *to++ = *from++;
|
||||
return;
|
||||
}
|
||||
|
||||
void des(inblock, outblock)
|
||||
unsigned char *inblock, *outblock;
|
||||
{
|
||||
unsigned long work[2];
|
||||
|
||||
scrunch(inblock, work);
|
||||
desfunc(work, KnL);
|
||||
unscrun(work, outblock);
|
||||
return;
|
||||
}
|
||||
|
||||
static void scrunch(outof, into)
|
||||
register unsigned char *outof;
|
||||
register unsigned long *into;
|
||||
{
|
||||
*into = (*outof++ & 0xffL) << 24;
|
||||
*into |= (*outof++ & 0xffL) << 16;
|
||||
*into |= (*outof++ & 0xffL) << 8;
|
||||
*into++ |= (*outof++ & 0xffL);
|
||||
*into = (*outof++ & 0xffL) << 24;
|
||||
*into |= (*outof++ & 0xffL) << 16;
|
||||
*into |= (*outof++ & 0xffL) << 8;
|
||||
*into |= (*outof & 0xffL);
|
||||
return;
|
||||
}
|
||||
|
||||
static void unscrun(outof, into)
|
||||
register unsigned long *outof;
|
||||
register unsigned char *into;
|
||||
{
|
||||
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
|
||||
*into++ = (unsigned char)(*outof++ & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
|
||||
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
|
||||
*into = (unsigned char)(*outof & 0xffL);
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned long SP1[64] = {
|
||||
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
|
||||
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
|
||||
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
|
||||
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
|
||||
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
|
||||
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
|
||||
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
|
||||
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
|
||||
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
|
||||
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
|
||||
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
|
||||
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
|
||||
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
|
||||
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
|
||||
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
|
||||
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
|
||||
|
||||
static unsigned long SP2[64] = {
|
||||
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
|
||||
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
|
||||
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
|
||||
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
|
||||
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
|
||||
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
|
||||
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
|
||||
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
|
||||
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
|
||||
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
|
||||
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
|
||||
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
|
||||
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
|
||||
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
|
||||
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
|
||||
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
|
||||
|
||||
static unsigned long SP3[64] = {
|
||||
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
|
||||
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
|
||||
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
|
||||
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
|
||||
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
|
||||
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
|
||||
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
|
||||
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
|
||||
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
|
||||
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
|
||||
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
|
||||
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
|
||||
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
|
||||
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
|
||||
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
|
||||
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
|
||||
|
||||
static unsigned long SP4[64] = {
|
||||
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
|
||||
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
|
||||
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
|
||||
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
|
||||
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
|
||||
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
|
||||
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
|
||||
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
|
||||
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
|
||||
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
|
||||
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
|
||||
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
|
||||
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
|
||||
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
|
||||
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
|
||||
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
|
||||
|
||||
static unsigned long SP5[64] = {
|
||||
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
|
||||
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
|
||||
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
|
||||
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
|
||||
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
|
||||
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
|
||||
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
|
||||
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
|
||||
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
|
||||
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
|
||||
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
|
||||
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
|
||||
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
|
||||
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
|
||||
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
|
||||
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
|
||||
|
||||
static unsigned long SP6[64] = {
|
||||
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
|
||||
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
|
||||
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
|
||||
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
|
||||
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
|
||||
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
|
||||
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
|
||||
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
|
||||
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
|
||||
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
|
||||
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
|
||||
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
|
||||
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
|
||||
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
|
||||
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
|
||||
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
|
||||
|
||||
static unsigned long SP7[64] = {
|
||||
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
|
||||
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
|
||||
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
|
||||
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
|
||||
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
|
||||
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
|
||||
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
|
||||
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
|
||||
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
|
||||
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
|
||||
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
|
||||
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
|
||||
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
|
||||
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
|
||||
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
|
||||
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
|
||||
|
||||
static unsigned long SP8[64] = {
|
||||
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
|
||||
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
|
||||
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
|
||||
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
|
||||
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
|
||||
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
|
||||
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
|
||||
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
|
||||
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
|
||||
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
|
||||
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
|
||||
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
|
||||
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
|
||||
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
|
||||
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
|
||||
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
|
||||
|
||||
static void desfunc(block, keys)
|
||||
register unsigned long *block, *keys;
|
||||
{
|
||||
register unsigned long fval, work, right, leftt;
|
||||
register int round;
|
||||
|
||||
leftt = block[0];
|
||||
right = block[1];
|
||||
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 4);
|
||||
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 16);
|
||||
work = ((right >> 2) ^ leftt) & 0x33333333L;
|
||||
leftt ^= work;
|
||||
right ^= (work << 2);
|
||||
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 8);
|
||||
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
|
||||
work = (leftt ^ right) & 0xaaaaaaaaL;
|
||||
leftt ^= work;
|
||||
right ^= work;
|
||||
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
|
||||
|
||||
for( round = 0; round < 8; round++ ) {
|
||||
work = (right << 28) | (right >> 4);
|
||||
work ^= *keys++;
|
||||
fval = SP7[ work & 0x3fL];
|
||||
fval |= SP5[(work >> 8) & 0x3fL];
|
||||
fval |= SP3[(work >> 16) & 0x3fL];
|
||||
fval |= SP1[(work >> 24) & 0x3fL];
|
||||
work = right ^ *keys++;
|
||||
fval |= SP8[ work & 0x3fL];
|
||||
fval |= SP6[(work >> 8) & 0x3fL];
|
||||
fval |= SP4[(work >> 16) & 0x3fL];
|
||||
fval |= SP2[(work >> 24) & 0x3fL];
|
||||
leftt ^= fval;
|
||||
work = (leftt << 28) | (leftt >> 4);
|
||||
work ^= *keys++;
|
||||
fval = SP7[ work & 0x3fL];
|
||||
fval |= SP5[(work >> 8) & 0x3fL];
|
||||
fval |= SP3[(work >> 16) & 0x3fL];
|
||||
fval |= SP1[(work >> 24) & 0x3fL];
|
||||
work = leftt ^ *keys++;
|
||||
fval |= SP8[ work & 0x3fL];
|
||||
fval |= SP6[(work >> 8) & 0x3fL];
|
||||
fval |= SP4[(work >> 16) & 0x3fL];
|
||||
fval |= SP2[(work >> 24) & 0x3fL];
|
||||
right ^= fval;
|
||||
}
|
||||
|
||||
right = (right << 31) | (right >> 1);
|
||||
work = (leftt ^ right) & 0xaaaaaaaaL;
|
||||
leftt ^= work;
|
||||
right ^= work;
|
||||
leftt = (leftt << 31) | (leftt >> 1);
|
||||
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 8);
|
||||
work = ((leftt >> 2) ^ right) & 0x33333333L;
|
||||
right ^= work;
|
||||
leftt ^= (work << 2);
|
||||
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 16);
|
||||
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 4);
|
||||
*block++ = right;
|
||||
*block = leftt;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validation sets:
|
||||
*
|
||||
* Single-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : c957 4425 6a5e d31d
|
||||
*
|
||||
* Double-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : 7f1d 0a77 826b 8aff
|
||||
*
|
||||
* Double-length key, double-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
|
||||
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
|
||||
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
|
||||
*
|
||||
* Triple-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : de0b 7c06 ae5e 0ed5
|
||||
*
|
||||
* Triple-length key, double-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
|
||||
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
|
||||
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
|
||||
*
|
||||
* d3des V5.0a rwo 9208.07 18:44 Graven Imagery
|
||||
**********************************************************************/
|
||||
51
d3des.h
51
d3des.h
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This is D3DES (V5.09) by Richard Outerbridge with the double and
|
||||
* triple-length support removed for use in VNC.
|
||||
*
|
||||
* These changes are:
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* This software 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.
|
||||
*/
|
||||
|
||||
/* d3des.h -
|
||||
*
|
||||
* Headers and defines for d3des.c
|
||||
* Graven Imagery, 1992.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
|
||||
* (GEnie : OUTER; CIS : [71755,204])
|
||||
*/
|
||||
|
||||
#define EN0 0 /* MODE == encrypt */
|
||||
#define DE1 1 /* MODE == decrypt */
|
||||
|
||||
extern void deskey(unsigned char *, int);
|
||||
/* hexkey[8] MODE
|
||||
* Sets the internal key register according to the hexadecimal
|
||||
* key contained in the 8 bytes of hexkey, according to the DES,
|
||||
* for encryption or decryption according to MODE.
|
||||
*/
|
||||
|
||||
extern void usekey(unsigned long *);
|
||||
/* cookedkey[32]
|
||||
* Loads the internal key register with the data in cookedkey.
|
||||
*/
|
||||
|
||||
extern void cpkey(unsigned long *);
|
||||
/* cookedkey[32]
|
||||
* Copies the contents of the internal key register into the storage
|
||||
* located at &cookedkey[0].
|
||||
*/
|
||||
|
||||
extern void des(unsigned char *, unsigned char *);
|
||||
/* from[8] to[8]
|
||||
* Encrypts/Decrypts (according to the key currently loaded in the
|
||||
* internal key register) one block of eight bytes at address 'from'
|
||||
* into the block at address 'to'. They can be the same.
|
||||
*/
|
||||
|
||||
/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
|
||||
********************************************************************/
|
||||
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/* emulated ioctl list */
|
||||
|
||||
IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
|
||||
@@ -1 +0,0 @@
|
||||
STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)
|
||||
@@ -1,903 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
1045
darwin-user/main.c
1045
darwin-user/main.c
File diff suppressed because it is too large
Load Diff
@@ -1,411 +0,0 @@
|
||||
/*
|
||||
* 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 kernel 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);
|
||||
}
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
#ifndef GEMU_H
|
||||
#define GEMU_H
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#include "thunk.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
|
||||
@@ -1,459 +0,0 @@
|
||||
/*
|
||||
* 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 (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
@@ -1,384 +0,0 @@
|
||||
/* 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, pipe, 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, listxattr, 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 */
|
||||
42
dis-asm.h
42
dis-asm.h
@@ -44,7 +44,7 @@ enum bfd_flavour {
|
||||
|
||||
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
|
||||
|
||||
enum bfd_architecture
|
||||
enum bfd_architecture
|
||||
{
|
||||
bfd_arch_unknown, /* File arch not known */
|
||||
bfd_arch_obscure, /* Arch known, not one of these */
|
||||
@@ -67,14 +67,14 @@ enum bfd_architecture
|
||||
#define bfd_mach_mcf5249 16
|
||||
#define bfd_mach_mcf547x 17
|
||||
#define bfd_mach_mcf548x 18
|
||||
bfd_arch_vax, /* DEC Vax */
|
||||
bfd_arch_vax, /* DEC Vax */
|
||||
bfd_arch_i960, /* Intel 960 */
|
||||
/* The order of the following is important.
|
||||
lower number indicates a machine type that
|
||||
lower number indicates a machine type that
|
||||
only accepts a subset of the instructions
|
||||
available to machines with higher numbers.
|
||||
The exception is the "ca", which is
|
||||
incompatible with all other machines except
|
||||
incompatible with all other machines except
|
||||
"core". */
|
||||
|
||||
#define bfd_mach_i960_core 1
|
||||
@@ -181,22 +181,13 @@ enum bfd_architecture
|
||||
#define bfd_mach_sh4al_dsp 0x4d
|
||||
#define bfd_mach_sh5 0x50
|
||||
bfd_arch_alpha, /* Dec Alpha */
|
||||
#define bfd_mach_alpha 1
|
||||
bfd_arch_arm, /* Advanced Risc Machines ARM */
|
||||
#define bfd_mach_arm_unknown 0
|
||||
#define bfd_mach_arm_2 1
|
||||
#define bfd_mach_arm_2a 2
|
||||
#define bfd_mach_arm_3 3
|
||||
#define bfd_mach_arm_3M 4
|
||||
#define bfd_mach_arm_4 5
|
||||
#define bfd_mach_arm_4T 6
|
||||
#define bfd_mach_arm_5 7
|
||||
#define bfd_mach_arm_5T 8
|
||||
#define bfd_mach_arm_5TE 9
|
||||
#define bfd_mach_arm_XScale 10
|
||||
#define bfd_mach_arm_ep9312 11
|
||||
#define bfd_mach_arm_iWMMXt 12
|
||||
#define bfd_mach_arm_iWMMXt2 13
|
||||
#define bfd_mach_arm_2 1
|
||||
#define bfd_mach_arm_2a 2
|
||||
#define bfd_mach_arm_3 3
|
||||
#define bfd_mach_arm_3M 4
|
||||
#define bfd_mach_arm_4 5
|
||||
#define bfd_mach_arm_4T 6
|
||||
bfd_arch_ns32k, /* National Semiconductors ns32000 */
|
||||
bfd_arch_w65, /* WDC 65816 */
|
||||
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
|
||||
@@ -208,14 +199,8 @@ enum bfd_architecture
|
||||
#define bfd_mach_m32r 0 /* backwards compatibility */
|
||||
bfd_arch_mn10200, /* Matsushita MN10200 */
|
||||
bfd_arch_mn10300, /* Matsushita MN10300 */
|
||||
bfd_arch_cris, /* Axis CRIS */
|
||||
#define bfd_mach_cris_v0_v10 255
|
||||
#define bfd_mach_cris_v32 32
|
||||
#define bfd_mach_cris_v10_v32 1032
|
||||
bfd_arch_last
|
||||
};
|
||||
#define bfd_mach_s390_31 31
|
||||
#define bfd_mach_s390_64 64
|
||||
|
||||
typedef struct symbol_cache_entry
|
||||
{
|
||||
@@ -240,7 +225,7 @@ enum dis_insn_type {
|
||||
dis_dref2 /* Two data references in instruction */
|
||||
};
|
||||
|
||||
/* This struct is passed into the instruction decoding routine,
|
||||
/* This struct is passed into the instruction decoding routine,
|
||||
and is passed back out into each callback. The various fields are used
|
||||
for conveying information from your main routine into your callbacks,
|
||||
for passing information into the instruction decoders (such as the
|
||||
@@ -392,9 +377,6 @@ extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*));
|
||||
extern int print_insn_crisv32 PARAMS ((bfd_vma, disassemble_info*));
|
||||
|
||||
#if 0
|
||||
/* Fetch the disassembler for a given BFD, if that support is available. */
|
||||
@@ -437,7 +419,7 @@ extern int generic_symbol_at_address
|
||||
/* Call this macro to initialize only the internal variables for the
|
||||
disassembler. Architecture dependent things such as byte order, or machine
|
||||
variant are not touched by this macro. This makes things much easier for
|
||||
GDB which must initialize these things separately. */
|
||||
GDB which must initialize these things seperatly. */
|
||||
|
||||
#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
|
||||
(INFO).fprintf_func = (FPRINTF_FUNC), \
|
||||
|
||||
63
disas.c
63
disas.c
@@ -58,7 +58,7 @@ perror_memory (status, memaddr, info)
|
||||
/* Actually, address between memaddr and memaddr + len was
|
||||
out of bounds. */
|
||||
(*info->fprintf_func) (info->stream,
|
||||
"Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
|
||||
"Address 0x%llx is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
@@ -73,7 +73,7 @@ generic_print_address (addr, info)
|
||||
bfd_vma addr;
|
||||
struct disassemble_info *info;
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
|
||||
(*info->fprintf_func) (info->stream, "0x%llx", addr);
|
||||
}
|
||||
|
||||
/* Just return the given address. */
|
||||
@@ -134,10 +134,10 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disassemble this for me please... (debugging). 'flags' has the following
|
||||
/* Disassemble this for me please... (debugging). 'flags' has teh following
|
||||
values:
|
||||
i386 - nonzero means 16 bit code
|
||||
arm - nonzero means thumb code
|
||||
arm - nonzero means thumb code
|
||||
ppc - nonzero means little endian
|
||||
other targets - unused
|
||||
*/
|
||||
@@ -162,7 +162,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
||||
#if defined(TARGET_I386)
|
||||
if (flags == 2)
|
||||
disasm_info.mach = bfd_mach_x86_64;
|
||||
else if (flags == 1)
|
||||
else if (flags == 1)
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
@@ -176,38 +176,27 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
||||
print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
if (flags >> 16)
|
||||
if (flags)
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
if (flags & 0xFFFF) {
|
||||
/* If we have a precise definitions of the instructions set, use it */
|
||||
disasm_info.mach = flags & 0xFFFF;
|
||||
} else {
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
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;
|
||||
#elif defined(TARGET_ALPHA)
|
||||
disasm_info.mach = bfd_mach_alpha;
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(TARGET_CRIS)
|
||||
disasm_info.mach = bfd_mach_cris_v32;
|
||||
print_insn = print_insn_crisv32;
|
||||
#else
|
||||
fprintf(out, "0x" TARGET_FMT_lx
|
||||
": Asm output not supported on this arch\n", code);
|
||||
@@ -266,10 +255,7 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
print_insn = print_insn_sparc;
|
||||
#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(__arm__)
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(__MIPSEB__)
|
||||
print_insn = print_insn_big_mips;
|
||||
@@ -277,8 +263,6 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
print_insn = print_insn_little_mips;
|
||||
#elif defined(__m68k__)
|
||||
print_insn = print_insn_m68k;
|
||||
#elif defined(__s390__)
|
||||
print_insn = print_insn_s390;
|
||||
#else
|
||||
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
|
||||
(long) code);
|
||||
@@ -287,9 +271,11 @@ 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 is included in the code, it is better to
|
||||
/* since data are included in the code, it is better to
|
||||
display code data too */
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
if (is_host) {
|
||||
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
|
||||
}
|
||||
#endif
|
||||
count = print_insn(pc, &disasm_info);
|
||||
fprintf(out, "\n");
|
||||
@@ -306,7 +292,7 @@ const char *lookup_symbol(target_ulong orig_addr)
|
||||
Elf32_Sym *sym;
|
||||
struct syminfo *s;
|
||||
target_ulong addr;
|
||||
|
||||
|
||||
for (s = syminfos; s; s = s->next) {
|
||||
sym = s->disas_symtab;
|
||||
for (i = 0; i < s->disas_num_syms; i++) {
|
||||
@@ -318,8 +304,8 @@ const char *lookup_symbol(target_ulong orig_addr)
|
||||
continue;
|
||||
|
||||
addr = sym[i].st_value;
|
||||
#if defined(TARGET_ARM) || defined (TARGET_MIPS)
|
||||
/* The bottom address bit marks a Thumb or MIPS16 symbol. */
|
||||
#ifdef TARGET_ARM
|
||||
/* The bottom address bit marks a Thumb symbol. */
|
||||
addr &= ~(target_ulong)1;
|
||||
#endif
|
||||
if (orig_addr >= addr
|
||||
@@ -385,20 +371,15 @@ void monitor_disas(CPUState *env,
|
||||
#if defined(TARGET_I386)
|
||||
if (flags == 2)
|
||||
disasm_info.mach = bfd_mach_x86_64;
|
||||
else if (flags == 1)
|
||||
else if (flags == 1)
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_ALPHA)
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
@@ -406,14 +387,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);
|
||||
|
||||
131
dyngen-exec.h
131
dyngen-exec.h
@@ -35,15 +35,12 @@
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
// Linux/Sparc64 defines uint64_t
|
||||
#if !(defined (__sparc_v9__) && defined(__linux__))
|
||||
/* XXX may be done for all 64 bits targets ? */
|
||||
#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__)
|
||||
#if defined (__x86_64__) || defined(__ia64)
|
||||
typedef unsigned long uint64_t;
|
||||
#else
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
|
||||
prior to this and will cause an error in compliation, conflicting
|
||||
@@ -53,17 +50,11 @@ typedef signed char int8_t;
|
||||
#endif
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
// Linux/Sparc64 defines int64_t
|
||||
#if !(defined (__sparc_v9__) && defined(__linux__))
|
||||
#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__)
|
||||
#if defined (__x86_64__) || defined(__ia64)
|
||||
typedef signed long int64_t;
|
||||
#else
|
||||
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)
|
||||
@@ -78,30 +69,27 @@ typedef void * host_reg_t;
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#define UINT64_MAX ((uint64_t)(18446744073709551615))
|
||||
|
||||
#ifdef _BSD
|
||||
typedef struct __sFILE FILE;
|
||||
#else
|
||||
typedef struct FILE FILE;
|
||||
#endif
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int fputs(const char *, FILE *);
|
||||
extern int printf(const char *, ...);
|
||||
#undef NULL
|
||||
#define NULL 0
|
||||
|
||||
#if defined(__i386__)
|
||||
#ifdef __i386__
|
||||
#define AREG0 "ebp"
|
||||
#define AREG1 "ebx"
|
||||
#define AREG2 "esi"
|
||||
#define AREG3 "edi"
|
||||
#elif defined(__x86_64__)
|
||||
#define AREG0 "r14"
|
||||
#define AREG1 "r15"
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
#define AREG0 "rbp"
|
||||
#define AREG1 "rbx"
|
||||
#define AREG2 "r12"
|
||||
#define AREG3 "r13"
|
||||
//#define AREG4 "rbp"
|
||||
//#define AREG5 "rbx"
|
||||
#elif defined(__powerpc__)
|
||||
//#define AREG4 "r14"
|
||||
//#define AREG5 "r15"
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define AREG0 "r27"
|
||||
#define AREG1 "r24"
|
||||
#define AREG2 "r25"
|
||||
@@ -119,35 +107,20 @@ extern int printf(const char *, ...);
|
||||
#endif
|
||||
#define USE_INT_TO_FLOAT_HELPERS
|
||||
#define BUGGY_GCC_DIV64
|
||||
#elif defined(__arm__)
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define AREG0 "r7"
|
||||
#define AREG1 "r4"
|
||||
#define AREG2 "r5"
|
||||
#define AREG3 "r6"
|
||||
#elif defined(__mips__)
|
||||
#define AREG0 "fp"
|
||||
#endif
|
||||
#ifdef __mips__
|
||||
#define AREG0 "s3"
|
||||
#define AREG1 "s0"
|
||||
#define AREG2 "s1"
|
||||
#define AREG3 "s2"
|
||||
#define AREG4 "s3"
|
||||
#define AREG5 "s4"
|
||||
#define AREG6 "s5"
|
||||
#define AREG7 "s6"
|
||||
#define AREG8 "s7"
|
||||
#elif defined(__sparc__)
|
||||
#ifdef HOST_SOLARIS
|
||||
#define AREG0 "g2"
|
||||
#define AREG1 "g3"
|
||||
#define AREG2 "g4"
|
||||
#define AREG3 "g5"
|
||||
#define AREG4 "g6"
|
||||
#else
|
||||
#ifdef __sparc_v9__
|
||||
#define AREG0 "g1"
|
||||
#define AREG1 "g4"
|
||||
#define AREG2 "g5"
|
||||
#define AREG3 "g7"
|
||||
#else
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define AREG0 "g6"
|
||||
#define AREG1 "g1"
|
||||
#define AREG2 "g2"
|
||||
@@ -160,15 +133,15 @@ extern int printf(const char *, ...);
|
||||
#define AREG9 "l5"
|
||||
#define AREG10 "l6"
|
||||
#define AREG11 "l7"
|
||||
#endif
|
||||
#endif
|
||||
#define USE_FP_CONVERT
|
||||
#elif defined(__s390__)
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define AREG0 "r10"
|
||||
#define AREG1 "r7"
|
||||
#define AREG2 "r8"
|
||||
#define AREG3 "r9"
|
||||
#elif defined(__alpha__)
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
/* Note $15 is the frame pointer, so anything in op-i386.c that would
|
||||
require a frame pointer, like alloca, would probably loose. */
|
||||
#define AREG0 "$15"
|
||||
@@ -178,23 +151,23 @@ extern int printf(const char *, ...);
|
||||
#define AREG4 "$12"
|
||||
#define AREG5 "$13"
|
||||
#define AREG6 "$14"
|
||||
#elif defined(__mc68000)
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define AREG0 "%a5"
|
||||
#define AREG1 "%a4"
|
||||
#define AREG2 "%d7"
|
||||
#define AREG3 "%d6"
|
||||
#define AREG4 "%d5"
|
||||
#elif defined(__ia64__)
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define AREG0 "r7"
|
||||
#define AREG1 "r4"
|
||||
#define AREG2 "r5"
|
||||
#define AREG3 "r6"
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
/* force GCC to generate only one epilog at the end of the function */
|
||||
#define FORCE_RET() __asm__ __volatile__("" : : : "memory");
|
||||
#define FORCE_RET() asm volatile ("");
|
||||
|
||||
#ifndef OPPROTO
|
||||
#define OPPROTO
|
||||
@@ -205,11 +178,11 @@ extern int printf(const char *, ...);
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
|
||||
#if defined(__alpha__) || defined(__s390__)
|
||||
#ifdef __alpha__
|
||||
/* the symbols are considered non exported so a br immediate is generated */
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define __hidden
|
||||
#define __hidden
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__)
|
||||
@@ -224,13 +197,6 @@ extern int __op_param3 __hidden;
|
||||
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
|
||||
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
|
||||
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
|
||||
#elif defined(__s390__)
|
||||
extern int __op_param1 __hidden;
|
||||
extern int __op_param2 __hidden;
|
||||
extern int __op_param3 __hidden;
|
||||
#define PARAM1 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param1) "; l %0,0(%0)" : "=r"(_r) : ); _r; })
|
||||
#define PARAM2 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param2) "; l %0,0(%0)" : "=r"(_r) : ); _r; })
|
||||
#define PARAM3 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param3) "; l %0,0(%0)" : "=r"(_r) : ); _r; })
|
||||
#else
|
||||
#if defined(__APPLE__)
|
||||
static int __op_param1, __op_param2, __op_param3;
|
||||
@@ -250,37 +216,42 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
#define ASM_NAME(x) #x
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
#ifdef __i386__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
|
||||
#elif defined(__x86_64__)
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
|
||||
#elif defined(__powerpc__)
|
||||
#endif
|
||||
#ifdef __powerpc__
|
||||
#define EXIT_TB() asm volatile ("blr")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
|
||||
#elif defined(__s390__)
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define EXIT_TB() asm volatile ("br %r14")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("larl %r7,12; l %r7,0(%r7); br %r7; .long " ASM_NAME(__op_gen_label) #n)
|
||||
#elif defined(__alpha__)
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
#elif defined(__ia64__)
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("br.sptk.many " \
|
||||
ASM_NAME(__op_gen_label) #n)
|
||||
#elif defined(__sparc__)
|
||||
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
|
||||
#elif defined(__arm__)
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
|
||||
"nop")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ( \
|
||||
"set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop")
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
#define EXIT_TB() asm volatile ("b exec_loop")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
|
||||
#elif defined(__mc68000)
|
||||
#endif
|
||||
#ifdef __mc68000
|
||||
#define EXIT_TB() asm volatile ("rts")
|
||||
#elif defined(__mips__)
|
||||
#define EXIT_TB() asm volatile ("jr $ra")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at")
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DYNGEN_EXEC_H__) */
|
||||
|
||||
150
dyngen.h
150
dyngen.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* dyngen helpers
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@@ -19,20 +19,28 @@
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
#if defined(__sparc__) || defined(__arm__)
|
||||
void __op_gen_label1(){}
|
||||
void __op_gen_label2(){}
|
||||
void __op_gen_label3(){}
|
||||
#else
|
||||
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
|
||||
#endif
|
||||
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
|
||||
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__s390__)
|
||||
#ifdef __i386__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#elif defined(__ia64__)
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
while (start < stop) {
|
||||
@@ -41,17 +49,19 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
}
|
||||
asm volatile (";;sync.i;;srlz.i;;");
|
||||
}
|
||||
#elif defined(__powerpc__)
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
start &= ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
@@ -62,13 +72,18 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#elif defined(__alpha__)
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
static void inline flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
@@ -78,7 +93,10 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
#elif defined(__arm__)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
register unsigned long _beg __asm ("a1") = start;
|
||||
@@ -86,22 +104,14 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
register unsigned long _flg __asm ("a3") = 0;
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
}
|
||||
#elif defined(__mc68000)
|
||||
#endif
|
||||
|
||||
# include <asm/cachectl.h>
|
||||
#ifdef __mc68000
|
||||
#include <asm/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
||||
}
|
||||
#elif defined(__mips__)
|
||||
|
||||
#include <sys/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
_flush_cache ((void *)start, stop - start, BCACHE);
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
@@ -129,16 +139,18 @@ void fix_bsr(void *p, int offset) {
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define ARM_LDR_TABLE_SIZE 1024
|
||||
#define MAX_OP_SIZE (128 * 4) /* in bytes */
|
||||
/* max size of the code that can be generated without calling arm_flush_ldr */
|
||||
#define MAX_FRAG_SIZE (1024 * 4)
|
||||
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
unsigned type:2;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
|
||||
static uint32_t arm_data_table[1024];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
@@ -148,8 +160,8 @@ static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
@@ -157,9 +169,8 @@ 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 = (data_end - data_start) << 2;
|
||||
|
||||
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
|
||||
|
||||
if (gen_jmp) {
|
||||
/* generate branch to skip the data */
|
||||
@@ -169,60 +180,29 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
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) {
|
||||
fprintf(stderr, "Negative constant pool offset\n");
|
||||
offset = - offset;
|
||||
} else {
|
||||
insn |= 0x00800000;
|
||||
}
|
||||
if (offset > 0xfff) {
|
||||
fprintf(stderr, "Error ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
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;
|
||||
}
|
||||
insn |= offset;
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
@@ -232,6 +212,7 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
|
||||
#ifdef __ia64
|
||||
|
||||
|
||||
/* Patch instruction with "val" where "mask" has 1 bits. */
|
||||
static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
|
||||
{
|
||||
@@ -392,8 +373,7 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
|
||||
};
|
||||
uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start;
|
||||
uint64_t *vp;
|
||||
uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp;
|
||||
struct ia64_fixup *fixup;
|
||||
unsigned int offset = 0;
|
||||
struct fdesc {
|
||||
@@ -430,12 +410,12 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
|
||||
/* First, create the GOT: */
|
||||
for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
|
||||
/* first check if we already have this value in the GOT: */
|
||||
for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
|
||||
if (*vp == fixup->value)
|
||||
for (vp = got_start; vp < gen_code_ptr; ++vp)
|
||||
if (*(uint64_t *) vp == fixup->value)
|
||||
break;
|
||||
if (vp == (uint64_t *) gen_code_ptr) {
|
||||
if (vp == gen_code_ptr) {
|
||||
/* Nope, we need to put the value in the GOT: */
|
||||
*vp = fixup->value;
|
||||
*(uint64_t *) vp = fixup->value;
|
||||
gen_code_ptr += 8;
|
||||
}
|
||||
ia64_imm22(fixup->addr, (long) vp - gp);
|
||||
|
||||
11
elf.h
11
elf.h
@@ -227,7 +227,6 @@ typedef struct {
|
||||
|
||||
#define ELF64_R_SYM(i) ((i) >> 32)
|
||||
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
|
||||
#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
|
||||
|
||||
#define R_386_NONE 0
|
||||
#define R_386_32 1
|
||||
@@ -327,10 +326,6 @@ typedef struct {
|
||||
#define R_SPARC_10 30
|
||||
#define R_SPARC_11 31
|
||||
#define R_SPARC_64 32
|
||||
#define R_SPARC_OLO10 33
|
||||
#define R_SPARC_HH22 34
|
||||
#define R_SPARC_HM10 35
|
||||
#define R_SPARC_LM22 36
|
||||
#define R_SPARC_WDISP16 40
|
||||
#define R_SPARC_WDISP19 41
|
||||
#define R_SPARC_7 43
|
||||
@@ -505,8 +500,6 @@ 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 */
|
||||
@@ -1045,7 +1038,7 @@ typedef struct elf64_phdr {
|
||||
#define SHN_COMMON 0xfff2
|
||||
#define SHN_HIRESERVE 0xffff
|
||||
#define SHN_MIPS_ACCOMON 0xff00
|
||||
|
||||
|
||||
typedef struct elf32_shdr {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
@@ -1130,7 +1123,6 @@ typedef struct elf64_note {
|
||||
#define elf_note elf32_note
|
||||
#define elf_shdr elf32_shdr
|
||||
#define elf_sym elf32_sym
|
||||
#define elf_addr_t Elf32_Off
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
# define ELF_RELOC Elf32_Rela
|
||||
@@ -1145,7 +1137,6 @@ typedef struct elf64_note {
|
||||
#define elf_note elf64_note
|
||||
#define elf_shdr elf64_shdr
|
||||
#define elf_sym elf64_sym
|
||||
#define elf_addr_t Elf64_Off
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
# define ELF_RELOC Elf64_Rela
|
||||
|
||||
32
elf_ops.h
32
elf_ops.h
@@ -49,7 +49,7 @@ static void glue(bswap_sym, SZ)(struct elf_sym *sym)
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
|
||||
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
|
||||
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
|
||||
int n, int type)
|
||||
{
|
||||
int i;
|
||||
@@ -71,17 +71,17 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
|
||||
int nsyms, i;
|
||||
char *str = NULL;
|
||||
|
||||
shdr_table = load_at(fd, ehdr->e_shoff,
|
||||
shdr_table = load_at(fd, ehdr->e_shoff,
|
||||
sizeof(struct elf_shdr) * ehdr->e_shnum);
|
||||
if (!shdr_table)
|
||||
return -1;
|
||||
|
||||
|
||||
if (must_swab) {
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
glue(bswap_shdr, SZ)(shdr_table + i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
|
||||
if (!symtab)
|
||||
goto fail;
|
||||
@@ -138,15 +138,13 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
|
||||
int must_swab, uint64_t *pentry,
|
||||
uint64_t *lowaddr, uint64_t *highaddr)
|
||||
int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
|
||||
int must_swab, uint64_t *pentry)
|
||||
{
|
||||
struct elfhdr ehdr;
|
||||
struct elf_phdr *phdr = NULL, *ph;
|
||||
int size, i, total_size;
|
||||
elf_word mem_size;
|
||||
uint64_t addr, low = 0, high = 0;
|
||||
elf_word mem_size, addr;
|
||||
uint8_t *data = NULL;
|
||||
|
||||
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
|
||||
@@ -155,11 +153,8 @@ static 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)(elf_sword)ehdr.e_entry;
|
||||
*pentry = (uint64_t)ehdr.e_entry;
|
||||
|
||||
glue(load_symbols, SZ)(&ehdr, fd, must_swab);
|
||||
|
||||
@@ -176,7 +171,7 @@ static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
|
||||
glue(bswap_phdr, SZ)(ph);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
total_size = 0;
|
||||
for(i = 0; i < ehdr.e_phnum; i++) {
|
||||
ph = &phdr[i];
|
||||
@@ -195,23 +190,16 @@ static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
|
||||
cpu_physical_memory_write_rom(addr, data, mem_size);
|
||||
|
||||
total_size += mem_size;
|
||||
if (!low || addr < low)
|
||||
low = addr;
|
||||
if (!high || (addr + mem_size) > high)
|
||||
high = addr + mem_size;
|
||||
|
||||
qemu_free(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
qemu_free(phdr);
|
||||
if (lowaddr)
|
||||
*lowaddr = (uint64_t)(elf_sword)low;
|
||||
if (highaddr)
|
||||
*highaddr = (uint64_t)(elf_sword)high;
|
||||
return total_size;
|
||||
fail:
|
||||
qemu_free(data);
|
||||
qemu_free(phdr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
187
exec-all.h
187
exec-all.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* internal execution defines for qemu
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@@ -21,6 +21,23 @@
|
||||
/* allow to see translation results - the slowdown should be negligible, so we leave it */
|
||||
#define DEBUG_DISAS
|
||||
|
||||
#ifndef glue
|
||||
#define xglue(x, y) x ## y
|
||||
#define glue(x, y) xglue(x, y)
|
||||
#define stringify(s) tostring(s)
|
||||
#define tostring(s) #s
|
||||
#endif
|
||||
|
||||
#if __GNUC__ < 3
|
||||
#define __builtin_expect(x, n) (x)
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#define REGPARM(n) __attribute((regparm(n)))
|
||||
#else
|
||||
#define REGPARM(n)
|
||||
#endif
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
@@ -51,7 +68,7 @@ typedef void (GenOpFunc)(void);
|
||||
typedef void (GenOpFunc1)(long);
|
||||
typedef void (GenOpFunc2)(long, long);
|
||||
typedef void (GenOpFunc3)(long, long, long);
|
||||
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
|
||||
void optimize_flags_init(void);
|
||||
@@ -64,37 +81,37 @@ extern int loglevel;
|
||||
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
unsigned long code_gen_max_block_size(void);
|
||||
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
|
||||
int *gen_code_size_ptr);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *puc);
|
||||
int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
|
||||
int max_code_size, int *gen_code_size_ptr);
|
||||
int cpu_restore_state_copy(struct TranslationBlock *tb,
|
||||
int cpu_restore_state_copy(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *puc);
|
||||
void cpu_resume_from_signal(CPUState *env1, void *puc);
|
||||
void cpu_exec_init(CPUState *env);
|
||||
int page_unprotect(target_ulong address, unsigned long pc, void *puc);
|
||||
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
|
||||
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
|
||||
int is_cpu_write_access);
|
||||
void tb_invalidate_page_range(target_ulong start, target_ulong end);
|
||||
void tlb_flush_page(CPUState *env, target_ulong addr);
|
||||
void tlb_flush(CPUState *env, int flush_global);
|
||||
int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
|
||||
target_phys_addr_t paddr, int prot,
|
||||
int mmu_idx, int is_softmmu);
|
||||
static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
target_phys_addr_t paddr, int prot,
|
||||
int mmu_idx, int is_softmmu)
|
||||
int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
|
||||
target_phys_addr_t paddr, int prot,
|
||||
int is_user, int is_softmmu);
|
||||
static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
target_phys_addr_t paddr, int prot,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
if (prot & PAGE_READ)
|
||||
prot |= PAGE_EXEC;
|
||||
return tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
|
||||
return tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
|
||||
}
|
||||
|
||||
#define CODE_GEN_MAX_SIZE 65536
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
||||
#define CODE_GEN_PHYS_HASH_BITS 15
|
||||
@@ -136,7 +153,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
|
||||
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#if defined(__powerpc__)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
#if defined(__i386__) && !defined(_WIN32)
|
||||
@@ -146,7 +163,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
typedef struct TranslationBlock {
|
||||
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
target_ulong cs_base; /* CS base for this block */
|
||||
uint64_t flags; /* flags defining in which context the code was generated */
|
||||
unsigned int flags; /* flags defining in which context the code was generated */
|
||||
uint16_t size; /* size of target code for this block (1 <=
|
||||
size <= TARGET_PAGE_SIZE) */
|
||||
uint16_t cflags; /* compile flags */
|
||||
@@ -157,11 +174,11 @@ typedef struct TranslationBlock {
|
||||
|
||||
uint8_t *tc_ptr; /* pointer to the translated code */
|
||||
/* next matching tb for physical address. */
|
||||
struct TranslationBlock *phys_hash_next;
|
||||
struct TranslationBlock *phys_hash_next;
|
||||
/* first and second physical page containing code. The lower bit
|
||||
of the pointer tells the index in page_next[] */
|
||||
struct TranslationBlock *page_next[2];
|
||||
target_ulong page_addr[2];
|
||||
struct TranslationBlock *page_next[2];
|
||||
target_ulong page_addr[2];
|
||||
|
||||
/* the following data are used to directly call another TB from
|
||||
the code of this one. */
|
||||
@@ -175,23 +192,13 @@ typedef struct TranslationBlock {
|
||||
the two least significant bits of the pointers to tell what is
|
||||
the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
|
||||
jmp_first */
|
||||
struct TranslationBlock *jmp_next[2];
|
||||
struct TranslationBlock *jmp_next[2];
|
||||
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)
|
||||
{
|
||||
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));
|
||||
return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1);
|
||||
}
|
||||
|
||||
static inline unsigned int tb_phys_hash_func(unsigned long pc)
|
||||
@@ -201,7 +208,7 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc)
|
||||
|
||||
TranslationBlock *tb_alloc(target_ulong pc);
|
||||
void tb_flush(CPUState *env);
|
||||
void tb_link_phys(TranslationBlock *tb,
|
||||
void tb_link_phys(TranslationBlock *tb,
|
||||
target_ulong phys_pc, target_ulong phys_page2);
|
||||
|
||||
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
|
||||
@@ -237,7 +244,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
unsigned long offset;
|
||||
@@ -252,7 +259,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
#else
|
||||
|
||||
/* set the jump target */
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
int n, unsigned long addr)
|
||||
{
|
||||
tb->tb_next[n] = addr;
|
||||
@@ -260,14 +267,14 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
|
||||
#endif
|
||||
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
TranslationBlock *tb_next)
|
||||
{
|
||||
/* NOTE: this test is only needed for thread safety */
|
||||
if (!tb->jmp_next[n]) {
|
||||
/* patch the native jump address */
|
||||
tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
|
||||
|
||||
|
||||
/* add in TB jmp circular list */
|
||||
tb->jmp_next[n] = tb_next->jmp_first;
|
||||
tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
|
||||
@@ -326,8 +333,8 @@ do {\
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define GOTO_TB(opname, tbparam, n)\
|
||||
do {\
|
||||
static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\
|
||||
static void __attribute__((used)) *__op_label ## n \
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
static void __attribute__((unused)) *__op_label ## n \
|
||||
__asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n: ;\
|
||||
@@ -340,7 +347,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#ifdef __powerpc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
@@ -356,29 +363,35 @@ static inline int testandset (int *p)
|
||||
: "cr0", "memory");
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
long int readval = 0;
|
||||
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
|
||||
: "+m" (*p), "+a" (readval)
|
||||
: "r" (1)
|
||||
: "cc");
|
||||
return readval;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
long int readval = 0;
|
||||
|
||||
|
||||
__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
|
||||
: "+m" (*p), "+a" (readval)
|
||||
: "r" (1)
|
||||
: "cc");
|
||||
return readval;
|
||||
}
|
||||
#elif defined(__s390__)
|
||||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
@@ -386,11 +399,13 @@ static inline int testandset (int *p)
|
||||
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
|
||||
" jl 0b"
|
||||
: "=&d" (ret)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "r" (1), "a" (p), "0" (*p)
|
||||
: "cc", "memory" );
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__alpha__)
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
@@ -407,7 +422,9 @@ static inline int testandset (int *p)
|
||||
: "m" (*p));
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
@@ -419,17 +436,21 @@ static inline int testandset (int *p)
|
||||
|
||||
return (ret ? 1 : 0);
|
||||
}
|
||||
#elif defined(__arm__)
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
static inline int testandset (int *spinlock)
|
||||
{
|
||||
register unsigned int ret;
|
||||
__asm__ __volatile__("swp %0, %1, [%2]"
|
||||
: "=r"(ret)
|
||||
: "0"(1), "r"(spinlock));
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__mc68000)
|
||||
#endif
|
||||
|
||||
#ifdef __mc68000
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
char ret;
|
||||
@@ -439,36 +460,15 @@ static inline int testandset (int *p)
|
||||
: "cc","memory");
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__ia64)
|
||||
#endif
|
||||
|
||||
#ifdef __ia64
|
||||
#include <ia64intrin.h>
|
||||
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
return __sync_lock_test_and_set (p, 1);
|
||||
}
|
||||
#elif defined(__mips__)
|
||||
static inline int testandset (int *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
" .set push \n"
|
||||
" .set noat \n"
|
||||
" .set mips2 \n"
|
||||
"1: li $1, 1 \n"
|
||||
" ll %0, %1 \n"
|
||||
" sc $1, %1 \n"
|
||||
" beqz $1, 1b \n"
|
||||
" .set pop "
|
||||
: "=r" (ret), "+R" (*p)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#error unimplemented CPU support
|
||||
#endif
|
||||
|
||||
typedef int spinlock_t;
|
||||
@@ -511,10 +511,10 @@ extern int tb_invalidated_flag;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
|
||||
void tlb_fill(target_ulong addr, int is_write, int is_user,
|
||||
void *retaddr);
|
||||
|
||||
#define ACCESS_TYPE (NB_MMU_MODES + 1)
|
||||
#define ACCESS_TYPE 3
|
||||
#define MEMSUFFIX _code
|
||||
#define env cpu_single_env
|
||||
|
||||
@@ -547,26 +547,37 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
is the offset relative to phys_ram_base */
|
||||
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
{
|
||||
int mmu_idx, index, pd;
|
||||
int is_user, index, pd;
|
||||
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
mmu_idx = cpu_mmu_index(env);
|
||||
if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_code !=
|
||||
#if defined(TARGET_I386)
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
#elif defined (TARGET_PPC)
|
||||
is_user = msr_pr;
|
||||
#elif defined (TARGET_MIPS)
|
||||
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
|
||||
#elif defined (TARGET_SPARC)
|
||||
is_user = (env->psrs == 0);
|
||||
#elif defined (TARGET_ARM)
|
||||
is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
|
||||
#elif defined (TARGET_SH4)
|
||||
is_user = ((env->sr & SR_MD) == 0);
|
||||
#else
|
||||
#error unimplemented CPU
|
||||
#endif
|
||||
if (__builtin_expect(env->tlb_table[is_user][index].addr_code !=
|
||||
(addr & TARGET_PAGE_MASK), 0)) {
|
||||
ldub_code(addr);
|
||||
}
|
||||
pd = env->tlb_table[mmu_idx][index].addr_code & ~TARGET_PAGE_MASK;
|
||||
if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
|
||||
#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
|
||||
do_unassigned_access(addr, 0, 1, 0);
|
||||
#else
|
||||
cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
|
||||
#endif
|
||||
pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
|
||||
if (pd > IO_MEM_ROM) {
|
||||
cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
|
||||
}
|
||||
return addr + env->tlb_table[mmu_idx][index].addend - (unsigned long)phys_ram_base;
|
||||
return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_KQEMU
|
||||
#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
|
||||
|
||||
@@ -582,11 +593,11 @@ void kqemu_record_dump(void);
|
||||
static inline int kqemu_is_ok(CPUState *env)
|
||||
{
|
||||
return(env->kqemu_enabled &&
|
||||
(env->cr[0] & CR0_PE_MASK) &&
|
||||
(env->cr[0] & CR0_PE_MASK) &&
|
||||
!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
|
||||
(env->eflags & IF_MASK) &&
|
||||
!(env->eflags & VM_MASK) &&
|
||||
(env->kqemu_enabled == 2 ||
|
||||
(env->kqemu_enabled == 2 ||
|
||||
((env->hflags & HF_CPL_MASK) == 3 &&
|
||||
(env->eflags & IOPL_MASK) != IOPL_MASK)));
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
void set_float_rounding_mode(int val STATUS_PARAM)
|
||||
{
|
||||
STATUS(float_rounding_mode) = val;
|
||||
#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
|
||||
#if defined(_BSD) && !defined(__APPLE__)
|
||||
fpsetround(val);
|
||||
#elif defined(__arm__)
|
||||
/* nothing to do */
|
||||
@@ -22,33 +22,9 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
|
||||
#define lrint(d) ((int32_t)rint(d))
|
||||
#define llrint(d) ((int64_t)rint(d))
|
||||
#define lrintf(f) ((int32_t)rint(f))
|
||||
#define llrintf(f) ((int64_t)rint(f))
|
||||
#define sqrtf(f) ((float)sqrt(f))
|
||||
#define remainderf(fa, fb) ((float)remainder(fa, fb))
|
||||
#define rintf(f) ((float)rint(f))
|
||||
#if !defined(__sparc__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10
|
||||
extern long double rintl(long double);
|
||||
extern long double scalbnl(long double, int);
|
||||
|
||||
long long
|
||||
llrintl(long double x) {
|
||||
return ((long long) rintl(x));
|
||||
}
|
||||
|
||||
long
|
||||
lrintl(long double x) {
|
||||
return ((long) rintl(x));
|
||||
}
|
||||
|
||||
long double
|
||||
ldexpl(long double x, int n) {
|
||||
return (scalbnl(x, n));
|
||||
}
|
||||
#endif
|
||||
#if defined(_BSD)
|
||||
#define lrint(d) ((long)rint(d))
|
||||
#define llrint(d) ((long long)rint(d))
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__)
|
||||
@@ -59,7 +35,7 @@ double qemu_rint(double x)
|
||||
double y = 4503599627370496.0;
|
||||
if (fabs(x) >= y)
|
||||
return x;
|
||||
if (x < 0)
|
||||
if (x < 0)
|
||||
y = -y;
|
||||
y = (x + y) - y;
|
||||
if (y == 0.0)
|
||||
@@ -78,21 +54,11 @@ float32 int32_to_float32(int v STATUS_PARAM)
|
||||
return (float32)v;
|
||||
}
|
||||
|
||||
float32 uint32_to_float32(unsigned int v STATUS_PARAM)
|
||||
{
|
||||
return (float32)v;
|
||||
}
|
||||
|
||||
float64 int32_to_float64(int v STATUS_PARAM)
|
||||
{
|
||||
return (float64)v;
|
||||
}
|
||||
|
||||
float64 uint32_to_float64(unsigned int v STATUS_PARAM)
|
||||
{
|
||||
return (float64)v;
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
floatx80 int32_to_floatx80(int v STATUS_PARAM)
|
||||
{
|
||||
@@ -103,18 +69,10 @@ float32 int64_to_float32( int64_t v STATUS_PARAM)
|
||||
{
|
||||
return (float32)v;
|
||||
}
|
||||
float32 uint64_to_float32( uint64_t v STATUS_PARAM)
|
||||
{
|
||||
return (float32)v;
|
||||
}
|
||||
float64 int64_to_float64( int64_t v STATUS_PARAM)
|
||||
{
|
||||
return (float64)v;
|
||||
}
|
||||
float64 uint64_to_float64( uint64_t v STATUS_PARAM)
|
||||
{
|
||||
return (float64)v;
|
||||
}
|
||||
#ifdef FLOATX80
|
||||
floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
|
||||
{
|
||||
@@ -131,7 +89,7 @@ static inline int long_to_int32(long a)
|
||||
#else
|
||||
static inline int long_to_int32(long a)
|
||||
{
|
||||
if (a != (int32_t)a)
|
||||
if (a != (int32_t)a)
|
||||
a = 0x80000000;
|
||||
return a;
|
||||
}
|
||||
@@ -169,37 +127,6 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM)
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int float32_to_uint32( float32 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
unsigned int res;
|
||||
|
||||
v = llrintf(a);
|
||||
if (v < 0) {
|
||||
res = 0;
|
||||
} else if (v > 0xffffffff) {
|
||||
res = 0xffffffff;
|
||||
} else {
|
||||
res = v;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
unsigned int res;
|
||||
|
||||
v = (int64_t)a;
|
||||
if (v < 0) {
|
||||
res = 0;
|
||||
} else if (v > 0xffffffff) {
|
||||
res = 0xffffffff;
|
||||
} else {
|
||||
res = v;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE single-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
@@ -217,7 +144,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM)
|
||||
{
|
||||
return sqrtf(a);
|
||||
}
|
||||
int float32_compare( float32 a, float32 b STATUS_PARAM )
|
||||
char float32_compare( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
if (a < b) {
|
||||
return -1;
|
||||
@@ -229,7 +156,7 @@ int float32_compare( float32 a, float32 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
if (isless(a, b)) {
|
||||
return -1;
|
||||
@@ -241,7 +168,7 @@ int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int float32_is_signaling_nan( float32 a1)
|
||||
char float32_is_signaling_nan( float32 a1)
|
||||
{
|
||||
float32u u;
|
||||
uint32_t a;
|
||||
@@ -286,67 +213,9 @@ float128 float64_to_float128( float64 a STATUS_PARAM)
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int float64_to_uint32( float64 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
unsigned int res;
|
||||
|
||||
v = llrint(a);
|
||||
if (v < 0) {
|
||||
res = 0;
|
||||
} else if (v > 0xffffffff) {
|
||||
res = 0xffffffff;
|
||||
} else {
|
||||
res = v;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
unsigned int res;
|
||||
|
||||
v = (int64_t)a;
|
||||
if (v < 0) {
|
||||
res = 0;
|
||||
} else if (v > 0xffffffff) {
|
||||
res = 0xffffffff;
|
||||
} else {
|
||||
res = v;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
|
||||
v = llrint(a + (float64)INT64_MIN);
|
||||
|
||||
return v - INT64_MIN;
|
||||
}
|
||||
uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
|
||||
v = (int64_t)(a + (float64)INT64_MIN);
|
||||
|
||||
return v - INT64_MIN;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined(__sun__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10
|
||||
static inline float64 trunc(float64 x)
|
||||
{
|
||||
return x < 0 ? -floor(-x) : floor(x);
|
||||
}
|
||||
#endif
|
||||
float64 float64_trunc_to_int( float64 a STATUS_PARAM )
|
||||
{
|
||||
return trunc(a);
|
||||
}
|
||||
|
||||
float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
{
|
||||
#if defined(__arm__)
|
||||
@@ -379,7 +248,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM)
|
||||
{
|
||||
return sqrt(a);
|
||||
}
|
||||
int float64_compare( float64 a, float64 b STATUS_PARAM )
|
||||
char float64_compare( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
if (a < b) {
|
||||
return -1;
|
||||
@@ -391,7 +260,7 @@ int float64_compare( float64 a, float64 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
if (isless(a, b)) {
|
||||
return -1;
|
||||
@@ -403,7 +272,7 @@ int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int float64_is_signaling_nan( float64 a1)
|
||||
char float64_is_signaling_nan( float64 a1)
|
||||
{
|
||||
float64u u;
|
||||
uint64_t a;
|
||||
@@ -415,17 +284,6 @@ int 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
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -471,7 +329,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
|
||||
{
|
||||
return sqrtl(a);
|
||||
}
|
||||
int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
if (a < b) {
|
||||
return -1;
|
||||
@@ -483,7 +341,7 @@ int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
if (isless(a, b)) {
|
||||
return -1;
|
||||
@@ -495,7 +353,7 @@ int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
int floatx80_is_signaling_nan( floatx80 a1)
|
||||
char floatx80_is_signaling_nan( floatx80 a1)
|
||||
{
|
||||
floatx80u u;
|
||||
u.f = a1;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Solaris 10 with GCC4 does not need these macros as they
|
||||
* are defined in <iso/math_c99.h> with a compiler directive
|
||||
*/
|
||||
#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) && (__GNUC__ <= 4)))
|
||||
#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) ))
|
||||
/*
|
||||
* C99 7.12.3 classification macros
|
||||
* and
|
||||
@@ -33,29 +33,6 @@
|
||||
#define isunordered(x,y) unordered(x, y)
|
||||
#endif
|
||||
|
||||
#if defined(__sun__) && !defined(NEED_LIBSUNMATH)
|
||||
|
||||
#ifndef isnan
|
||||
# define isnan(x) \
|
||||
(sizeof (x) == sizeof (long double) ? isnan_ld (x) \
|
||||
: sizeof (x) == sizeof (double) ? isnan_d (x) \
|
||||
: isnan_f (x))
|
||||
static inline int isnan_f (float x) { return x != x; }
|
||||
static inline int isnan_d (double x) { return x != x; }
|
||||
static inline int isnan_ld (long double x) { return x != x; }
|
||||
#endif
|
||||
|
||||
#ifndef isinf
|
||||
# define isinf(x) \
|
||||
(sizeof (x) == sizeof (long double) ? isinf_ld (x) \
|
||||
: sizeof (x) == sizeof (double) ? isinf_d (x) \
|
||||
: isinf_f (x))
|
||||
static inline int isinf_f (float x) { return isnan (x - x); }
|
||||
static inline int isinf_d (double x) { return isnan (x - x); }
|
||||
static inline int isinf_ld (long double x) { return isnan (x - x); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef float float32;
|
||||
typedef double float64;
|
||||
#ifdef FLOATX80
|
||||
@@ -122,9 +99,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM);
|
||||
| Software IEC/IEEE integer-to-floating-point conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 int32_to_float32( int STATUS_PARAM);
|
||||
float32 uint32_to_float32( unsigned int STATUS_PARAM);
|
||||
float64 int32_to_float64( int STATUS_PARAM);
|
||||
float64 uint32_to_float64( unsigned int STATUS_PARAM);
|
||||
#ifdef FLOATX80
|
||||
floatx80 int32_to_floatx80( int STATUS_PARAM);
|
||||
#endif
|
||||
@@ -132,9 +107,7 @@ floatx80 int32_to_floatx80( int STATUS_PARAM);
|
||||
float128 int32_to_float128( int STATUS_PARAM);
|
||||
#endif
|
||||
float32 int64_to_float32( int64_t STATUS_PARAM);
|
||||
float32 uint64_to_float32( uint64_t STATUS_PARAM);
|
||||
float64 int64_to_float64( int64_t STATUS_PARAM);
|
||||
float64 uint64_to_float64( uint64_t v STATUS_PARAM);
|
||||
#ifdef FLOATX80
|
||||
floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
|
||||
#endif
|
||||
@@ -147,8 +120,6 @@ float128 int64_to_float128( int64_t STATUS_PARAM);
|
||||
*----------------------------------------------------------------------------*/
|
||||
int float32_to_int32( float32 STATUS_PARAM);
|
||||
int float32_to_int32_round_to_zero( float32 STATUS_PARAM);
|
||||
unsigned int float32_to_uint32( float32 a STATUS_PARAM);
|
||||
unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM);
|
||||
int64_t float32_to_int64( float32 STATUS_PARAM);
|
||||
int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM);
|
||||
float64 float32_to_float64( float32 STATUS_PARAM);
|
||||
@@ -181,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 int float32_eq( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_eq( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
INLINE int float32_le( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_le( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
INLINE int float32_lt( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_lt( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b && a >= b;
|
||||
}
|
||||
INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return islessequal(a, b);
|
||||
}
|
||||
INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return isless(a, b);
|
||||
}
|
||||
INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
|
||||
INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
return isunordered(a, b);
|
||||
|
||||
}
|
||||
int float32_compare( float32, float32 STATUS_PARAM );
|
||||
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_is_signaling_nan( float32 );
|
||||
char float32_compare( float32, float32 STATUS_PARAM );
|
||||
char float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
char float32_is_signaling_nan( float32 );
|
||||
|
||||
INLINE float32 float32_abs(float32 a)
|
||||
{
|
||||
@@ -224,22 +195,13 @@ INLINE float32 float32_chs(float32 a)
|
||||
return -a;
|
||||
}
|
||||
|
||||
INLINE float32 float32_scalbn(float32 a, int n)
|
||||
{
|
||||
return scalbnf(a, n);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int float64_to_int32( float64 STATUS_PARAM );
|
||||
int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
|
||||
unsigned int float64_to_uint32( float64 STATUS_PARAM );
|
||||
unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
|
||||
int64_t float64_to_int64( float64 STATUS_PARAM );
|
||||
int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
|
||||
uint64_t float64_to_uint64( float64 STATUS_PARAM );
|
||||
uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM );
|
||||
float32 float64_to_float32( float64 STATUS_PARAM );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
|
||||
@@ -252,7 +214,6 @@ 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;
|
||||
@@ -271,40 +232,39 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
|
||||
}
|
||||
float64 float64_rem( float64, float64 STATUS_PARAM );
|
||||
float64 float64_sqrt( float64 STATUS_PARAM );
|
||||
INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_eq( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
INLINE int float64_le( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_le( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
INLINE int float64_lt( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_lt( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b && a >= b;
|
||||
}
|
||||
INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return islessequal(a, b);
|
||||
}
|
||||
INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return isless(a, b);
|
||||
|
||||
}
|
||||
INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
|
||||
INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
return isunordered(a, b);
|
||||
|
||||
}
|
||||
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 );
|
||||
char float64_compare( float64, float64 STATUS_PARAM );
|
||||
char float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
char float64_is_signaling_nan( float64 );
|
||||
|
||||
INLINE float64 float64_abs(float64 a)
|
||||
{
|
||||
@@ -316,11 +276,6 @@ INLINE float64 float64_chs(float64 a)
|
||||
return -a;
|
||||
}
|
||||
|
||||
INLINE float64 float64_scalbn(float64 a, int n)
|
||||
{
|
||||
return scalbn(a, n);
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -358,39 +313,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 int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return a <= b && a >= b;
|
||||
}
|
||||
INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return islessequal(a, b);
|
||||
}
|
||||
INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return isless(a, b);
|
||||
|
||||
}
|
||||
INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
return isunordered(a, b);
|
||||
|
||||
}
|
||||
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_is_signaling_nan( floatx80 );
|
||||
char floatx80_compare( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
char floatx80_is_signaling_nan( floatx80 );
|
||||
|
||||
INLINE floatx80 floatx80_abs(floatx80 a)
|
||||
{
|
||||
@@ -401,10 +356,4 @@ INLINE floatx80 floatx80_chs(floatx80 a)
|
||||
{
|
||||
return -a;
|
||||
}
|
||||
|
||||
INLINE floatx80 floatx80_scalbn(floatx80 a, int n)
|
||||
{
|
||||
return scalbnl(a, n);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,12 +30,6 @@ these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
|
||||
#define SNAN_BIT_IS_ONE 1
|
||||
#else
|
||||
#define SNAN_BIT_IS_ONE 0
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Underflow tininess-detection mode, statically initialized to default value.
|
||||
| (The declaration in `softfloat.h' must match the `int8' type here.)
|
||||
@@ -51,7 +45,9 @@ int8 float_detect_tininess = float_tininess_after_rounding;
|
||||
|
||||
void float_raise( int8 flags STATUS_PARAM )
|
||||
{
|
||||
|
||||
STATUS(float_exception_flags) |= flags;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -65,31 +61,18 @@ typedef struct {
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated single-precision NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined(TARGET_SPARC)
|
||||
#define float32_default_nan make_float32(0x7FFFFFFF)
|
||||
#elif defined(TARGET_POWERPC)
|
||||
#define float32_default_nan make_float32(0x7FC00000)
|
||||
#elif defined(TARGET_HPPA)
|
||||
#define float32_default_nan make_float32(0x7FA00000)
|
||||
#elif SNAN_BIT_IS_ONE
|
||||
#define float32_default_nan make_float32(0x7FBFFFFF)
|
||||
#else
|
||||
#define float32_default_nan make_float32(0xFFC00000)
|
||||
#endif
|
||||
#define float32_default_nan 0xFFC00000
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the single-precision floating-point value `a' is a quiet
|
||||
| NaN; otherwise returns 0.
|
||||
| Returns 1 if the single-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_is_nan( float32 a_ )
|
||||
flag float32_is_nan( float32 a )
|
||||
{
|
||||
uint32_t a = float32_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
|
||||
#else
|
||||
return ( 0xFF800000 <= (bits32) ( a<<1 ) );
|
||||
#endif
|
||||
|
||||
return ( 0xFF000000 < (bits32) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -97,14 +80,11 @@ int float32_is_nan( float32 a_ )
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_is_signaling_nan( float32 a_ )
|
||||
flag float32_is_signaling_nan( float32 a )
|
||||
{
|
||||
uint32_t a = float32_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return ( 0xFF800000 <= (bits32) ( a<<1 ) );
|
||||
#else
|
||||
|
||||
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -118,10 +98,11 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
|
||||
commonNaNT z;
|
||||
|
||||
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
|
||||
z.sign = float32_val(a)>>31;
|
||||
z.sign = a>>31;
|
||||
z.low = 0;
|
||||
z.high = ( (bits64) float32_val(a) )<<41;
|
||||
z.high = ( (bits64) a )<<41;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -131,12 +112,9 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
|
||||
|
||||
static float32 commonNaNToFloat32( commonNaNT a )
|
||||
{
|
||||
bits32 mantissa = a.high>>41;
|
||||
if ( mantissa )
|
||||
return make_float32(
|
||||
( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
|
||||
else
|
||||
return float32_default_nan;
|
||||
|
||||
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -148,75 +126,46 @@ static float32 commonNaNToFloat32( commonNaNT a )
|
||||
static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
bits32 av, bv, res;
|
||||
|
||||
aIsNaN = float32_is_nan( a );
|
||||
aIsSignalingNaN = float32_is_signaling_nan( a );
|
||||
bIsNaN = float32_is_nan( b );
|
||||
bIsSignalingNaN = float32_is_signaling_nan( b );
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
av &= ~0x00400000;
|
||||
bv &= ~0x00400000;
|
||||
#else
|
||||
av |= 0x00400000;
|
||||
bv |= 0x00400000;
|
||||
#endif
|
||||
a |= 0x00400000;
|
||||
b |= 0x00400000;
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
res = bIsNaN ? bv : av;
|
||||
return bIsNaN ? b : a;
|
||||
}
|
||||
else if ( aIsNaN ) {
|
||||
if ( bIsSignalingNaN | ! bIsNaN )
|
||||
res = av;
|
||||
else {
|
||||
if ( bIsSignalingNaN | ! bIsNaN ) return a;
|
||||
returnLargerSignificand:
|
||||
if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) )
|
||||
res = bv;
|
||||
else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) )
|
||||
res = av;
|
||||
else
|
||||
res = ( av < bv ) ? av : bv;
|
||||
}
|
||||
if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
|
||||
if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
|
||||
return ( a < b ) ? a : b;
|
||||
}
|
||||
else {
|
||||
res = bv;
|
||||
return b;
|
||||
}
|
||||
return make_float32(res);
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated double-precision NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined(TARGET_SPARC)
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
|
||||
#elif defined(TARGET_POWERPC)
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
|
||||
#elif defined(TARGET_HPPA)
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 ))
|
||||
#elif SNAN_BIT_IS_ONE
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
|
||||
#else
|
||||
#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
|
||||
#endif
|
||||
#define float64_default_nan LIT64( 0xFFF8000000000000 )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the double-precision floating-point value `a' is a quiet
|
||||
| NaN; otherwise returns 0.
|
||||
| Returns 1 if the double-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_is_nan( float64 a_ )
|
||||
flag float64_is_nan( float64 a )
|
||||
{
|
||||
bits64 a = float64_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return
|
||||
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
|
||||
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
|
||||
#else
|
||||
return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
|
||||
#endif
|
||||
|
||||
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -224,16 +173,13 @@ int float64_is_nan( float64 a_ )
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_is_signaling_nan( float64 a_ )
|
||||
flag float64_is_signaling_nan( float64 a )
|
||||
{
|
||||
bits64 a = float64_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
|
||||
#else
|
||||
|
||||
return
|
||||
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
|
||||
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -247,10 +193,11 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
|
||||
commonNaNT z;
|
||||
|
||||
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
z.sign = float64_val(a)>>63;
|
||||
z.sign = a>>63;
|
||||
z.low = 0;
|
||||
z.high = float64_val(a)<<12;
|
||||
z.high = a<<12;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -260,15 +207,12 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
|
||||
|
||||
static float64 commonNaNToFloat64( commonNaNT a )
|
||||
{
|
||||
bits64 mantissa = a.high>>12;
|
||||
|
||||
if ( mantissa )
|
||||
return make_float64(
|
||||
( ( (bits64) a.sign )<<63 )
|
||||
| LIT64( 0x7FF0000000000000 )
|
||||
| ( a.high>>12 ));
|
||||
else
|
||||
return float64_default_nan;
|
||||
return
|
||||
( ( (bits64) a.sign )<<63 )
|
||||
| LIT64( 0x7FF8000000000000 )
|
||||
| ( a.high>>12 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -280,43 +224,29 @@ static float64 commonNaNToFloat64( commonNaNT a )
|
||||
static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
bits64 av, bv, res;
|
||||
|
||||
aIsNaN = float64_is_nan( a );
|
||||
aIsSignalingNaN = float64_is_signaling_nan( a );
|
||||
bIsNaN = float64_is_nan( b );
|
||||
bIsSignalingNaN = float64_is_signaling_nan( b );
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
av &= ~LIT64( 0x0008000000000000 );
|
||||
bv &= ~LIT64( 0x0008000000000000 );
|
||||
#else
|
||||
av |= LIT64( 0x0008000000000000 );
|
||||
bv |= LIT64( 0x0008000000000000 );
|
||||
#endif
|
||||
a |= LIT64( 0x0008000000000000 );
|
||||
b |= LIT64( 0x0008000000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
res = bIsNaN ? bv : av;
|
||||
return bIsNaN ? b : a;
|
||||
}
|
||||
else if ( aIsNaN ) {
|
||||
if ( bIsSignalingNaN | ! bIsNaN )
|
||||
res = av;
|
||||
else {
|
||||
if ( bIsSignalingNaN | ! bIsNaN ) return a;
|
||||
returnLargerSignificand:
|
||||
if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) )
|
||||
res = bv;
|
||||
else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) )
|
||||
res = av;
|
||||
else
|
||||
res = ( av < bv ) ? av : bv;
|
||||
}
|
||||
if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
|
||||
if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
|
||||
return ( a < b ) ? a : b;
|
||||
}
|
||||
else {
|
||||
res = bv;
|
||||
return b;
|
||||
}
|
||||
return make_float64(res);
|
||||
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
@@ -326,32 +256,19 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
|
||||
| `high' and `low' values hold the most- and least-significant bits,
|
||||
| respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if SNAN_BIT_IS_ONE
|
||||
#define floatx80_default_nan_high 0x7FFF
|
||||
#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF )
|
||||
#else
|
||||
#define floatx80_default_nan_high 0xFFFF
|
||||
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the extended double-precision floating-point value `a' is a
|
||||
| quiet NaN; otherwise returns 0.
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_is_nan( floatx80 a )
|
||||
flag floatx80_is_nan( floatx80 a )
|
||||
{
|
||||
#if SNAN_BIT_IS_ONE
|
||||
bits64 aLow;
|
||||
|
||||
aLow = a.low & ~ LIT64( 0x4000000000000000 );
|
||||
return
|
||||
( ( a.high & 0x7FFF ) == 0x7FFF )
|
||||
&& (bits64) ( aLow<<1 )
|
||||
&& ( a.low == aLow );
|
||||
#else
|
||||
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -359,11 +276,8 @@ int floatx80_is_nan( floatx80 a )
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_is_signaling_nan( floatx80 a )
|
||||
flag floatx80_is_signaling_nan( floatx80 a )
|
||||
{
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
|
||||
#else
|
||||
bits64 aLow;
|
||||
|
||||
aLow = a.low & ~ LIT64( 0x4000000000000000 );
|
||||
@@ -371,7 +285,7 @@ int floatx80_is_signaling_nan( floatx80 a )
|
||||
( ( a.high & 0x7FFF ) == 0x7FFF )
|
||||
&& (bits64) ( aLow<<1 )
|
||||
&& ( a.low == aLow );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -387,8 +301,9 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
|
||||
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
z.sign = a.high>>15;
|
||||
z.low = 0;
|
||||
z.high = a.low;
|
||||
z.high = a.low<<1;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -400,12 +315,10 @@ static floatx80 commonNaNToFloatx80( commonNaNT a )
|
||||
{
|
||||
floatx80 z;
|
||||
|
||||
if (a.high)
|
||||
z.low = a.high;
|
||||
else
|
||||
z.low = floatx80_default_nan_low;
|
||||
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
|
||||
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -422,13 +335,8 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
aIsSignalingNaN = floatx80_is_signaling_nan( a );
|
||||
bIsNaN = floatx80_is_nan( b );
|
||||
bIsSignalingNaN = floatx80_is_signaling_nan( b );
|
||||
#if SNAN_BIT_IS_ONE
|
||||
a.low &= ~LIT64( 0xC000000000000000 );
|
||||
b.low &= ~LIT64( 0xC000000000000000 );
|
||||
#else
|
||||
a.low |= LIT64( 0xC000000000000000 );
|
||||
b.low |= LIT64( 0xC000000000000000 );
|
||||
#endif
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
@@ -444,6 +352,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -454,30 +363,21 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
| The pattern for a default generated quadruple-precision NaN. The `high' and
|
||||
| `low' values hold the most- and least-significant bits, respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if SNAN_BIT_IS_ONE
|
||||
#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
|
||||
#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
#else
|
||||
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
|
||||
#define float128_default_nan_low LIT64( 0x0000000000000000 )
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
|
||||
| NaN; otherwise returns 0.
|
||||
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_is_nan( float128 a )
|
||||
flag float128_is_nan( float128 a )
|
||||
{
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return
|
||||
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
|
||||
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
|
||||
#else
|
||||
|
||||
return
|
||||
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
|
||||
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -485,17 +385,13 @@ int float128_is_nan( float128 a )
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_is_signaling_nan( float128 a )
|
||||
flag float128_is_signaling_nan( float128 a )
|
||||
{
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return
|
||||
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
|
||||
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
|
||||
#else
|
||||
|
||||
return
|
||||
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
|
||||
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -512,6 +408,7 @@ static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM)
|
||||
z.sign = a.high>>63;
|
||||
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -524,8 +421,9 @@ static float128 commonNaNToFloat128( commonNaNT a )
|
||||
float128 z;
|
||||
|
||||
shift128Right( a.high, a.low, 16, &z.high, &z.low );
|
||||
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
|
||||
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -542,13 +440,8 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
|
||||
aIsSignalingNaN = float128_is_signaling_nan( a );
|
||||
bIsNaN = float128_is_nan( b );
|
||||
bIsSignalingNaN = float128_is_signaling_nan( b );
|
||||
#if SNAN_BIT_IS_ONE
|
||||
a.high &= ~LIT64( 0x0000800000000000 );
|
||||
b.high &= ~LIT64( 0x0000800000000000 );
|
||||
#else
|
||||
a.high |= LIT64( 0x0000800000000000 );
|
||||
b.high |= LIT64( 0x0000800000000000 );
|
||||
#endif
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
@@ -564,6 +457,8 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
395
fpu/softfloat.c
395
fpu/softfloat.c
@@ -175,7 +175,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA
|
||||
INLINE bits32 extractFloat32Frac( float32 a )
|
||||
{
|
||||
|
||||
return float32_val(a) & 0x007FFFFF;
|
||||
return a & 0x007FFFFF;
|
||||
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ INLINE bits32 extractFloat32Frac( float32 a )
|
||||
INLINE int16 extractFloat32Exp( float32 a )
|
||||
{
|
||||
|
||||
return ( float32_val(a)>>23 ) & 0xFF;
|
||||
return ( a>>23 ) & 0xFF;
|
||||
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ INLINE int16 extractFloat32Exp( float32 a )
|
||||
INLINE flag extractFloat32Sign( float32 a )
|
||||
{
|
||||
|
||||
return float32_val(a)>>31;
|
||||
return a>>31;
|
||||
|
||||
}
|
||||
|
||||
@@ -233,8 +233,7 @@ static void
|
||||
INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
|
||||
{
|
||||
|
||||
return make_float32(
|
||||
( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig);
|
||||
return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
|
||||
|
||||
}
|
||||
|
||||
@@ -291,7 +290,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
|
||||
&& ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
|
||||
) {
|
||||
float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
|
||||
return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
|
||||
return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
|
||||
}
|
||||
if ( zExp < 0 ) {
|
||||
isTiny =
|
||||
@@ -338,7 +337,7 @@ static float32
|
||||
INLINE bits64 extractFloat64Frac( float64 a )
|
||||
{
|
||||
|
||||
return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF );
|
||||
return a & LIT64( 0x000FFFFFFFFFFFFF );
|
||||
|
||||
}
|
||||
|
||||
@@ -349,7 +348,7 @@ INLINE bits64 extractFloat64Frac( float64 a )
|
||||
INLINE int16 extractFloat64Exp( float64 a )
|
||||
{
|
||||
|
||||
return ( float64_val(a)>>52 ) & 0x7FF;
|
||||
return ( a>>52 ) & 0x7FF;
|
||||
|
||||
}
|
||||
|
||||
@@ -360,7 +359,7 @@ INLINE int16 extractFloat64Exp( float64 a )
|
||||
INLINE flag extractFloat64Sign( float64 a )
|
||||
{
|
||||
|
||||
return float64_val(a)>>63;
|
||||
return a>>63;
|
||||
|
||||
}
|
||||
|
||||
@@ -396,8 +395,7 @@ static void
|
||||
INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig )
|
||||
{
|
||||
|
||||
return make_float64(
|
||||
( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig);
|
||||
return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig;
|
||||
|
||||
}
|
||||
|
||||
@@ -454,7 +452,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
|
||||
&& ( (sbits64) ( zSig + roundIncrement ) < 0 ) )
|
||||
) {
|
||||
float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);
|
||||
return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
|
||||
return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 );
|
||||
}
|
||||
if ( zExp < 0 ) {
|
||||
isTiny =
|
||||
@@ -1052,7 +1050,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM )
|
||||
{
|
||||
flag zSign;
|
||||
|
||||
if ( a == 0 ) return float32_zero;
|
||||
if ( a == 0 ) return 0;
|
||||
if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
|
||||
zSign = ( a < 0 );
|
||||
return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR );
|
||||
@@ -1072,7 +1070,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM )
|
||||
int8 shiftCount;
|
||||
bits64 zSig;
|
||||
|
||||
if ( a == 0 ) return float64_zero;
|
||||
if ( a == 0 ) return 0;
|
||||
zSign = ( a < 0 );
|
||||
absA = zSign ? - a : a;
|
||||
shiftCount = countLeadingZeros32( absA ) + 21;
|
||||
@@ -1146,7 +1144,7 @@ float32 int64_to_float32( int64 a STATUS_PARAM )
|
||||
uint64 absA;
|
||||
int8 shiftCount;
|
||||
|
||||
if ( a == 0 ) return float32_zero;
|
||||
if ( a == 0 ) return 0;
|
||||
zSign = ( a < 0 );
|
||||
absA = zSign ? - a : a;
|
||||
shiftCount = countLeadingZeros64( absA ) - 40;
|
||||
@@ -1166,27 +1164,6 @@ float32 int64_to_float32( int64 a STATUS_PARAM )
|
||||
|
||||
}
|
||||
|
||||
float32 uint64_to_float32( uint64 a STATUS_PARAM )
|
||||
{
|
||||
int8 shiftCount;
|
||||
|
||||
if ( a == 0 ) return float32_zero;
|
||||
shiftCount = countLeadingZeros64( a ) - 40;
|
||||
if ( 0 <= shiftCount ) {
|
||||
return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount );
|
||||
}
|
||||
else {
|
||||
shiftCount += 7;
|
||||
if ( shiftCount < 0 ) {
|
||||
shift64RightJamming( a, - shiftCount, &a );
|
||||
}
|
||||
else {
|
||||
a <<= shiftCount;
|
||||
}
|
||||
return roundAndPackFloat32( 1 > 0, 0x9C - shiftCount, a STATUS_VAR );
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the 64-bit two's complement integer `a'
|
||||
| to the double-precision floating-point format. The conversion is performed
|
||||
@@ -1197,7 +1174,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM )
|
||||
{
|
||||
flag zSign;
|
||||
|
||||
if ( a == 0 ) return float64_zero;
|
||||
if ( a == 0 ) return 0;
|
||||
if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) {
|
||||
return packFloat64( 1, 0x43E, 0 );
|
||||
}
|
||||
@@ -1206,13 +1183,6 @@ float64 int64_to_float64( int64 a STATUS_PARAM )
|
||||
|
||||
}
|
||||
|
||||
float64 uint64_to_float64( uint64 a STATUS_PARAM )
|
||||
{
|
||||
if ( a == 0 ) return float64_zero;
|
||||
return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR );
|
||||
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -1327,7 +1297,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
|
||||
aSign = extractFloat32Sign( a );
|
||||
shiftCount = aExp - 0x9E;
|
||||
if ( 0 <= shiftCount ) {
|
||||
if ( float32_val(a) != 0xCF000000 ) {
|
||||
if ( a != 0xCF000000 ) {
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
|
||||
}
|
||||
@@ -1406,7 +1376,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
|
||||
aSign = extractFloat32Sign( a );
|
||||
shiftCount = aExp - 0xBE;
|
||||
if ( 0 <= shiftCount ) {
|
||||
if ( float32_val(a) != 0xDF000000 ) {
|
||||
if ( a != 0xDF000000 ) {
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
|
||||
return LIT64( 0x7FFFFFFFFFFFFFFF );
|
||||
@@ -1537,7 +1507,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
|
||||
int16 aExp;
|
||||
bits32 lastBitMask, roundBitsMask;
|
||||
int8 roundingMode;
|
||||
bits32 z;
|
||||
float32 z;
|
||||
|
||||
aExp = extractFloat32Exp( a );
|
||||
if ( 0x96 <= aExp ) {
|
||||
@@ -1547,7 +1517,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
|
||||
return a;
|
||||
}
|
||||
if ( aExp <= 0x7E ) {
|
||||
if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a;
|
||||
if ( (bits32) ( a<<1 ) == 0 ) return a;
|
||||
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||
aSign = extractFloat32Sign( a );
|
||||
switch ( STATUS(float_rounding_mode) ) {
|
||||
@@ -1557,29 +1527,29 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
|
||||
}
|
||||
break;
|
||||
case float_round_down:
|
||||
return make_float32(aSign ? 0xBF800000 : 0);
|
||||
return aSign ? 0xBF800000 : 0;
|
||||
case float_round_up:
|
||||
return make_float32(aSign ? 0x80000000 : 0x3F800000);
|
||||
return aSign ? 0x80000000 : 0x3F800000;
|
||||
}
|
||||
return packFloat32( aSign, 0, 0 );
|
||||
}
|
||||
lastBitMask = 1;
|
||||
lastBitMask <<= 0x96 - aExp;
|
||||
roundBitsMask = lastBitMask - 1;
|
||||
z = float32_val(a);
|
||||
z = a;
|
||||
roundingMode = STATUS(float_rounding_mode);
|
||||
if ( roundingMode == float_round_nearest_even ) {
|
||||
z += lastBitMask>>1;
|
||||
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
|
||||
}
|
||||
else if ( roundingMode != float_round_to_zero ) {
|
||||
if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) {
|
||||
if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
|
||||
z += roundBitsMask;
|
||||
}
|
||||
}
|
||||
z &= ~ roundBitsMask;
|
||||
if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact;
|
||||
return make_float32(z);
|
||||
if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
@@ -2010,7 +1980,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
if ( aExp == 0xFF ) {
|
||||
if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
|
||||
if ( aSig ) return propagateFloat32NaN( a, 0 STATUS_VAR );
|
||||
if ( ! aSign ) return a;
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
return float32_default_nan;
|
||||
@@ -2021,7 +1991,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
|
||||
return float32_default_nan;
|
||||
}
|
||||
if ( aExp == 0 ) {
|
||||
if ( aSig == 0 ) return float32_zero;
|
||||
if ( aSig == 0 ) return 0;
|
||||
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
|
||||
}
|
||||
zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
|
||||
@@ -2053,7 +2023,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
flag float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
@@ -2064,8 +2034,7 @@ int float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return ( float32_val(a) == float32_val(b) ) ||
|
||||
( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 );
|
||||
return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
|
||||
|
||||
}
|
||||
|
||||
@@ -2076,10 +2045,9 @@ int float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
flag float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@@ -2089,10 +2057,8 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat32Sign( a );
|
||||
bSign = extractFloat32Sign( b );
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( av == bv ) || ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
|
||||
return ( a == b ) || ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -2102,10 +2068,9 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
flag float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@@ -2115,10 +2080,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat32Sign( a );
|
||||
bSign = extractFloat32Sign( b );
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 );
|
||||
return ( av != bv ) && ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
|
||||
return ( a != b ) && ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -2129,9 +2092,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
bits32 av, bv;
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@@ -2139,9 +2101,7 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
return 0;
|
||||
}
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
|
||||
|
||||
}
|
||||
|
||||
@@ -2152,10 +2112,9 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
flag float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@@ -2167,10 +2126,8 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat32Sign( a );
|
||||
bSign = extractFloat32Sign( b );
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( av == bv ) || ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
|
||||
return ( a == b ) || ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -2181,10 +2138,9 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
| Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@@ -2196,10 +2152,8 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat32Sign( a );
|
||||
bSign = extractFloat32Sign( b );
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 );
|
||||
return ( av != bv ) && ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
|
||||
return ( a != b ) && ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -2342,7 +2296,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
|
||||
shiftCount = aExp - 0x433;
|
||||
if ( 0 <= shiftCount ) {
|
||||
if ( 0x43E <= aExp ) {
|
||||
if ( float64_val(a) != LIT64( 0xC3E0000000000000 ) ) {
|
||||
if ( a != LIT64( 0xC3E0000000000000 ) ) {
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( ! aSign
|
||||
|| ( ( aExp == 0x7FF )
|
||||
@@ -2482,7 +2436,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits64 lastBitMask, roundBitsMask;
|
||||
int8 roundingMode;
|
||||
bits64 z;
|
||||
float64 z;
|
||||
|
||||
aExp = extractFloat64Exp( a );
|
||||
if ( 0x433 <= aExp ) {
|
||||
@@ -2492,7 +2446,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
return a;
|
||||
}
|
||||
if ( aExp < 0x3FF ) {
|
||||
if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a;
|
||||
if ( (bits64) ( a<<1 ) == 0 ) return a;
|
||||
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||
aSign = extractFloat64Sign( a );
|
||||
switch ( STATUS(float_rounding_mode) ) {
|
||||
@@ -2502,45 +2456,33 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
}
|
||||
break;
|
||||
case float_round_down:
|
||||
return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0);
|
||||
return aSign ? LIT64( 0xBFF0000000000000 ) : 0;
|
||||
case float_round_up:
|
||||
return make_float64(
|
||||
aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ));
|
||||
return
|
||||
aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 );
|
||||
}
|
||||
return packFloat64( aSign, 0, 0 );
|
||||
}
|
||||
lastBitMask = 1;
|
||||
lastBitMask <<= 0x433 - aExp;
|
||||
roundBitsMask = lastBitMask - 1;
|
||||
z = float64_val(a);
|
||||
z = a;
|
||||
roundingMode = STATUS(float_rounding_mode);
|
||||
if ( roundingMode == float_round_nearest_even ) {
|
||||
z += lastBitMask>>1;
|
||||
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
|
||||
}
|
||||
else if ( roundingMode != float_round_to_zero ) {
|
||||
if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) {
|
||||
if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) {
|
||||
z += roundBitsMask;
|
||||
}
|
||||
}
|
||||
z &= ~ roundBitsMask;
|
||||
if ( z != float64_val(a) )
|
||||
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||
return make_float64(z);
|
||||
if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
@@ -2970,7 +2912,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
|
||||
return float64_default_nan;
|
||||
}
|
||||
if ( aExp == 0 ) {
|
||||
if ( aSig == 0 ) return float64_zero;
|
||||
if ( aSig == 0 ) return 0;
|
||||
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
|
||||
}
|
||||
zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
|
||||
@@ -2999,9 +2941,8 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
flag float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
bits64 av, bv;
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@@ -3011,9 +2952,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
|
||||
|
||||
}
|
||||
|
||||
@@ -3024,10 +2963,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
flag float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@@ -3037,10 +2975,8 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat64Sign( a );
|
||||
bSign = extractFloat64Sign( b );
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( av == bv ) || ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
|
||||
return ( a == b ) || ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -3050,10 +2986,9 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
flag float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@@ -3063,10 +2998,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat64Sign( a );
|
||||
bSign = extractFloat64Sign( b );
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 );
|
||||
return ( av != bv ) && ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
|
||||
return ( a != b ) && ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -3077,9 +3010,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
bits64 av, bv;
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@@ -3087,9 +3019,7 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
return 0;
|
||||
}
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
|
||||
|
||||
}
|
||||
|
||||
@@ -3100,10 +3030,9 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
flag float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@@ -3115,10 +3044,8 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat64Sign( a );
|
||||
bSign = extractFloat64Sign( b );
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 );
|
||||
return ( av == bv ) || ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
|
||||
return ( a == b ) || ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -3129,10 +3056,9 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
| Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@@ -3144,10 +3070,8 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
}
|
||||
aSign = extractFloat64Sign( a );
|
||||
bSign = extractFloat64Sign( b );
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 );
|
||||
return ( av != bv ) && ( aSign ^ ( av < bv ) );
|
||||
if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
|
||||
return ( a != b ) && ( aSign ^ ( a < b ) );
|
||||
|
||||
}
|
||||
|
||||
@@ -3955,7 +3879,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
@@ -3985,7 +3909,7 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -4018,7 +3942,7 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -4051,7 +3975,7 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
@@ -4078,7 +4002,7 @@ int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -4114,7 +4038,7 @@ int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
flag floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5075,7 +4999,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_eq( float128 a, float128 b STATUS_PARAM )
|
||||
flag float128_eq( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
|
||||
@@ -5105,7 +5029,7 @@ int float128_eq( float128 a, float128 b STATUS_PARAM )
|
||||
| Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_le( float128 a, float128 b STATUS_PARAM )
|
||||
flag float128_le( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5137,7 +5061,7 @@ int float128_le( float128 a, float128 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_lt( float128 a, float128 b STATUS_PARAM )
|
||||
flag float128_lt( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5170,7 +5094,7 @@ int float128_lt( float128 a, float128 b STATUS_PARAM )
|
||||
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|
||||
flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
|
||||
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
|
||||
@@ -5197,7 +5121,7 @@ int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|
||||
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
flag float128_le_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5233,7 +5157,7 @@ int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
| Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
@@ -5347,35 +5271,11 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
|
||||
return res;
|
||||
}
|
||||
|
||||
/* FIXME: This looks broken. */
|
||||
uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
|
||||
v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR));
|
||||
v += float64_val(a);
|
||||
v = float64_to_int64(make_float64(v) STATUS_VAR);
|
||||
|
||||
return v - INT64_MIN;
|
||||
}
|
||||
|
||||
uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
|
||||
{
|
||||
int64_t v;
|
||||
|
||||
v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR));
|
||||
v += float64_val(a);
|
||||
v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR);
|
||||
|
||||
return v - INT64_MIN;
|
||||
}
|
||||
|
||||
#define COMPARE(s, nan_exp) \
|
||||
INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
int is_quiet STATUS_PARAM ) \
|
||||
{ \
|
||||
flag aSign, bSign; \
|
||||
bits ## s av, bv; \
|
||||
\
|
||||
if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \
|
||||
extractFloat ## s ## Frac( a ) ) || \
|
||||
@@ -5390,152 +5290,31 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
} \
|
||||
aSign = extractFloat ## s ## Sign( a ); \
|
||||
bSign = extractFloat ## s ## Sign( b ); \
|
||||
av = float ## s ## _val(a); \
|
||||
bv = float ## s ## _val(b); \
|
||||
if ( aSign != bSign ) { \
|
||||
if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \
|
||||
if ( (bits ## s) ( ( a | b )<<1 ) == 0 ) { \
|
||||
/* zero case */ \
|
||||
return float_relation_equal; \
|
||||
} else { \
|
||||
return 1 - (2 * aSign); \
|
||||
} \
|
||||
} else { \
|
||||
if (av == bv) { \
|
||||
if (a == b) { \
|
||||
return float_relation_equal; \
|
||||
} else { \
|
||||
return 1 - 2 * (aSign ^ ( av < bv )); \
|
||||
return 1 - 2 * (aSign ^ ( a < b )); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
char float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
{ \
|
||||
return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
char float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
|
||||
{ \
|
||||
return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \
|
||||
}
|
||||
|
||||
COMPARE(32, 0xff)
|
||||
COMPARE(64, 0x7ff)
|
||||
|
||||
INLINE int float128_compare_internal( float128 a, float128 b,
|
||||
int is_quiet STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (( ( extractFloat128Exp( a ) == 0x7fff ) &&
|
||||
( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) ||
|
||||
( ( extractFloat128Exp( b ) == 0x7fff ) &&
|
||||
( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
|
||||
if (!is_quiet ||
|
||||
float128_is_signaling_nan( a ) ||
|
||||
float128_is_signaling_nan( b ) ) {
|
||||
float_raise( float_flag_invalid STATUS_VAR);
|
||||
}
|
||||
return float_relation_unordered;
|
||||
}
|
||||
aSign = extractFloat128Sign( a );
|
||||
bSign = extractFloat128Sign( b );
|
||||
if ( aSign != bSign ) {
|
||||
if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) {
|
||||
/* zero case */
|
||||
return float_relation_equal;
|
||||
} else {
|
||||
return 1 - (2 * aSign);
|
||||
}
|
||||
} else {
|
||||
if (a.low == b.low && a.high == b.high) {
|
||||
return float_relation_equal;
|
||||
} else {
|
||||
return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int float128_compare( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
return float128_compare_internal(a, b, 0 STATUS_VAR);
|
||||
}
|
||||
|
||||
int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
{
|
||||
return float128_compare_internal(a, b, 1 STATUS_VAR);
|
||||
}
|
||||
|
||||
/* Multiply A by 2 raised to the power N. */
|
||||
float32 float32_scalbn( float32 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
bits32 aSig;
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
|
||||
if ( aExp == 0xFF ) {
|
||||
return a;
|
||||
}
|
||||
aExp += n;
|
||||
return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
|
||||
}
|
||||
|
||||
float64 float64_scalbn( float64 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
bits64 aSig;
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
aSign = extractFloat64Sign( a );
|
||||
|
||||
if ( aExp == 0x7FF ) {
|
||||
return a;
|
||||
}
|
||||
aExp += n;
|
||||
return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
bits64 aSig;
|
||||
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
|
||||
if ( aExp == 0x7FF ) {
|
||||
return a;
|
||||
}
|
||||
aExp += n;
|
||||
return roundAndPackFloatx80( STATUS(floatx80_rounding_precision),
|
||||
aSign, aExp, aSig, 0 STATUS_VAR );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT128
|
||||
float128 float128_scalbn( float128 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int32 aExp;
|
||||
bits64 aSig0, aSig1;
|
||||
|
||||
aSig1 = extractFloat128Frac1( a );
|
||||
aSig0 = extractFloat128Frac0( a );
|
||||
aExp = extractFloat128Exp( a );
|
||||
aSign = extractFloat128Sign( a );
|
||||
if ( aExp == 0x7FFF ) {
|
||||
return a;
|
||||
}
|
||||
aExp += n;
|
||||
return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR );
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
120
fpu/softfloat.h
120
fpu/softfloat.h
@@ -32,10 +32,6 @@ these four paragraphs for those parts of this code that are retained.
|
||||
#ifndef SOFTFLOAT_H
|
||||
#define SOFTFLOAT_H
|
||||
|
||||
#if defined(HOST_SOLARIS) && defined(NEEDS_LIBSUNMATH)
|
||||
#include <sunmath.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
|
||||
@@ -47,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 uint8_t flag;
|
||||
typedef char flag;
|
||||
typedef uint8_t uint8;
|
||||
typedef int8_t int8;
|
||||
typedef int uint16;
|
||||
@@ -111,31 +107,8 @@ enum {
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point types.
|
||||
*----------------------------------------------------------------------------*/
|
||||
/* Use structures for soft-float types. This prevents accidentally mixing
|
||||
them with native int/float types. A sufficiently clever compiler and
|
||||
sane ABI should be able to see though these structs. However
|
||||
x86/gcc 3.x seems to struggle a bit, so leave them disabled by default. */
|
||||
//#define USE_SOFTFLOAT_STRUCT_TYPES
|
||||
#ifdef USE_SOFTFLOAT_STRUCT_TYPES
|
||||
typedef struct {
|
||||
uint32_t v;
|
||||
} float32;
|
||||
/* The cast ensures an error if the wrong type is passed. */
|
||||
#define float32_val(x) (((float32)(x)).v)
|
||||
#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; })
|
||||
typedef struct {
|
||||
uint64_t v;
|
||||
} float64;
|
||||
#define float64_val(x) (((float64)(x)).v)
|
||||
#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; })
|
||||
#else
|
||||
typedef uint32_t float32;
|
||||
typedef uint64_t float64;
|
||||
#define float32_val(x) (x)
|
||||
#define float64_val(x) (x)
|
||||
#define make_float32(x) (x)
|
||||
#define make_float64(x) (x)
|
||||
#endif
|
||||
#ifdef FLOATX80
|
||||
typedef struct {
|
||||
uint64_t low;
|
||||
@@ -220,9 +193,7 @@ floatx80 int32_to_floatx80( int STATUS_PARAM );
|
||||
float128 int32_to_float128( int STATUS_PARAM );
|
||||
#endif
|
||||
float32 int64_to_float32( int64_t STATUS_PARAM );
|
||||
float32 uint64_to_float32( uint64_t STATUS_PARAM );
|
||||
float64 int64_to_float64( int64_t STATUS_PARAM );
|
||||
float64 uint64_to_float64( uint64_t STATUS_PARAM );
|
||||
#ifdef FLOATX80
|
||||
floatx80 int64_to_floatx80( int64_t STATUS_PARAM );
|
||||
#endif
|
||||
@@ -257,30 +228,26 @@ 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 );
|
||||
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_nan( float32 );
|
||||
int float32_is_signaling_nan( float32 );
|
||||
float32 float32_scalbn( float32, int 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 );
|
||||
|
||||
INLINE float32 float32_abs(float32 a)
|
||||
{
|
||||
return make_float32(float32_val(a) & 0x7fffffff);
|
||||
return a & 0x7fffffff;
|
||||
}
|
||||
|
||||
INLINE float32 float32_chs(float32 a)
|
||||
{
|
||||
return make_float32(float32_val(a) ^ 0x80000000);
|
||||
return a ^ 0x80000000;
|
||||
}
|
||||
|
||||
#define float32_zero make_float32(0)
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
@@ -290,8 +257,6 @@ unsigned int float64_to_uint32( float64 STATUS_PARAM );
|
||||
unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
|
||||
int64_t float64_to_int64( float64 STATUS_PARAM );
|
||||
int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
|
||||
uint64_t float64_to_uint64 (float64 a STATUS_PARAM);
|
||||
uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM);
|
||||
float32 float64_to_float32( float64 STATUS_PARAM );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
|
||||
@@ -304,37 +269,32 @@ 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 );
|
||||
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_nan( float64 a );
|
||||
int float64_is_signaling_nan( float64 );
|
||||
float64 float64_scalbn( float64, int 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 );
|
||||
|
||||
INLINE float64 float64_abs(float64 a)
|
||||
{
|
||||
return make_float64(float64_val(a) & 0x7fffffffffffffffLL);
|
||||
return a & 0x7fffffffffffffffLL;
|
||||
}
|
||||
|
||||
INLINE float64 float64_chs(float64 a)
|
||||
{
|
||||
return make_float64(float64_val(a) ^ 0x8000000000000000LL);
|
||||
return a ^ 0x8000000000000000LL;
|
||||
}
|
||||
|
||||
#define float64_zero make_float64(0)
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -360,15 +320,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 );
|
||||
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_nan( floatx80 );
|
||||
int floatx80_is_signaling_nan( floatx80 );
|
||||
floatx80 floatx80_scalbn( floatx80, int 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 );
|
||||
|
||||
INLINE floatx80 floatx80_abs(floatx80 a)
|
||||
{
|
||||
@@ -409,17 +367,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 );
|
||||
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_compare( float128, float128 STATUS_PARAM );
|
||||
int float128_compare_quiet( float128, float128 STATUS_PARAM );
|
||||
int float128_is_nan( float128 );
|
||||
int float128_is_signaling_nan( float128 );
|
||||
float128 float128_scalbn( float128, int 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 );
|
||||
|
||||
INLINE float128 float128_abs(float128 a)
|
||||
{
|
||||
|
||||
11
gdbstub.h
11
gdbstub.h
@@ -1,19 +1,12 @@
|
||||
#ifndef GDBSTUB_H
|
||||
#define GDBSTUB_H
|
||||
|
||||
#define DEFAULT_GDBSTUB_PORT "1234"
|
||||
#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);
|
||||
int gdbserver_start(int);
|
||||
#else
|
||||
int gdbserver_start(const char *port);
|
||||
#endif
|
||||
int gdbserver_start(int);
|
||||
|
||||
#endif
|
||||
|
||||
104
host-utils.c
104
host-utils.c
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Utility compute operations used by translated code.
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 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 "exec.h"
|
||||
#include "host-utils.h"
|
||||
|
||||
//#define DEBUG_MULDIV
|
||||
|
||||
/* Long integer helpers */
|
||||
#if !defined(__x86_64__)
|
||||
static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
*plow += a;
|
||||
/* carry test */
|
||||
if (*plow < a)
|
||||
(*phigh)++;
|
||||
*phigh += b;
|
||||
}
|
||||
|
||||
static void neg128 (uint64_t *plow, uint64_t *phigh)
|
||||
{
|
||||
*plow = ~*plow;
|
||||
*phigh = ~*phigh;
|
||||
add128(plow, phigh, 1, 0);
|
||||
}
|
||||
|
||||
static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
uint32_t a0, a1, b0, b1;
|
||||
uint64_t v;
|
||||
|
||||
a0 = a;
|
||||
a1 = a >> 32;
|
||||
|
||||
b0 = b;
|
||||
b1 = b >> 32;
|
||||
|
||||
v = (uint64_t)a0 * (uint64_t)b0;
|
||||
*plow = v;
|
||||
*phigh = 0;
|
||||
|
||||
v = (uint64_t)a0 * (uint64_t)b1;
|
||||
add128(plow, phigh, v << 32, v >> 32);
|
||||
|
||||
v = (uint64_t)a1 * (uint64_t)b0;
|
||||
add128(plow, phigh, v << 32, v >> 32);
|
||||
|
||||
v = (uint64_t)a1 * (uint64_t)b1;
|
||||
*phigh += v;
|
||||
}
|
||||
|
||||
/* Unsigned 64x64 -> 128 multiplication */
|
||||
void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
mul64(plow, phigh, a, b);
|
||||
#if defined(DEBUG_MULDIV)
|
||||
printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
|
||||
a, b, *phigh, *plow);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Signed 64x64 -> 128 multiplication */
|
||||
void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
|
||||
{
|
||||
int sa, sb;
|
||||
|
||||
sa = (a < 0);
|
||||
if (sa)
|
||||
a = -a;
|
||||
sb = (b < 0);
|
||||
if (sb)
|
||||
b = -b;
|
||||
mul64(plow, phigh, a, b);
|
||||
if (sa ^ sb) {
|
||||
neg128(plow, phigh);
|
||||
}
|
||||
#if defined(DEBUG_MULDIV)
|
||||
printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
|
||||
a, b, *phigh, *plow);
|
||||
#endif
|
||||
}
|
||||
#endif /* !defined(__x86_64__) */
|
||||
202
host-utils.h
202
host-utils.h
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Utility compute operations used by translated code.
|
||||
*
|
||||
* Copyright (c) 2007 Thiemo Seufer
|
||||
* Copyright (c) 2007 Jocelyn Mayer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define __HAVE_FAST_MULU64__
|
||||
static always_inline void mulu64 (uint64_t *plow, uint64_t *phigh,
|
||||
uint64_t a, uint64_t b)
|
||||
{
|
||||
__asm__ ("mul %0\n\t"
|
||||
: "=d" (*phigh), "=a" (*plow)
|
||||
: "a" (a), "0" (b));
|
||||
}
|
||||
#define __HAVE_FAST_MULS64__
|
||||
static always_inline void muls64 (uint64_t *plow, uint64_t *phigh,
|
||||
int64_t a, int64_t b)
|
||||
{
|
||||
__asm__ ("imul %0\n\t"
|
||||
: "=d" (*phigh), "=a" (*plow)
|
||||
: "a" (a), "0" (b));
|
||||
}
|
||||
#else
|
||||
void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b);
|
||||
void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
|
||||
#endif
|
||||
|
||||
/* Note that some of those functions may end up calling libgcc functions,
|
||||
depending on the host machine. It is up to the target emulation to
|
||||
cope with that. */
|
||||
|
||||
/* Binary search for leading zeros. */
|
||||
|
||||
static always_inline int clz32(uint32_t val)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
if (!(val & 0xFFFF0000U)) {
|
||||
cnt += 16;
|
||||
val <<= 16;
|
||||
}
|
||||
if (!(val & 0xFF000000U)) {
|
||||
cnt += 8;
|
||||
val <<= 8;
|
||||
}
|
||||
if (!(val & 0xF0000000U)) {
|
||||
cnt += 4;
|
||||
val <<= 4;
|
||||
}
|
||||
if (!(val & 0xC0000000U)) {
|
||||
cnt += 2;
|
||||
val <<= 2;
|
||||
}
|
||||
if (!(val & 0x80000000U)) {
|
||||
cnt++;
|
||||
val <<= 1;
|
||||
}
|
||||
if (!(val & 0x80000000U)) {
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static always_inline int clo32(uint32_t val)
|
||||
{
|
||||
return clz32(~val);
|
||||
}
|
||||
|
||||
static always_inline int clz64(uint64_t val)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
if (!(val >> 32)) {
|
||||
cnt += 32;
|
||||
} else {
|
||||
val >>= 32;
|
||||
}
|
||||
|
||||
return cnt + clz32(val);
|
||||
}
|
||||
|
||||
static always_inline int clo64(uint64_t val)
|
||||
{
|
||||
return clz64(~val);
|
||||
}
|
||||
|
||||
static always_inline int ctz32 (uint32_t val)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
cnt = 0;
|
||||
if (!(val & 0x0000FFFFUL)) {
|
||||
cnt += 16;
|
||||
val >>= 16;
|
||||
}
|
||||
if (!(val & 0x000000FFUL)) {
|
||||
cnt += 8;
|
||||
val >>= 8;
|
||||
}
|
||||
if (!(val & 0x0000000FUL)) {
|
||||
cnt += 4;
|
||||
val >>= 4;
|
||||
}
|
||||
if (!(val & 0x00000003UL)) {
|
||||
cnt += 2;
|
||||
val >>= 2;
|
||||
}
|
||||
if (!(val & 0x00000001UL)) {
|
||||
cnt++;
|
||||
val >>= 1;
|
||||
}
|
||||
if (!(val & 0x00000001UL)) {
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static always_inline int cto32 (uint32_t val)
|
||||
{
|
||||
return ctz32(~val);
|
||||
}
|
||||
|
||||
static always_inline int ctz64 (uint64_t val)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
cnt = 0;
|
||||
if (!((uint32_t)val)) {
|
||||
cnt += 32;
|
||||
val >>= 32;
|
||||
}
|
||||
|
||||
return cnt + ctz32(val);
|
||||
}
|
||||
|
||||
static always_inline int cto64 (uint64_t val)
|
||||
{
|
||||
return ctz64(~val);
|
||||
}
|
||||
|
||||
static always_inline int ctpop8 (uint8_t val)
|
||||
{
|
||||
val = (val & 0x55) + ((val >> 1) & 0x55);
|
||||
val = (val & 0x33) + ((val >> 2) & 0x33);
|
||||
val = (val & 0x0f) + ((val >> 4) & 0x0f);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static always_inline int ctpop16 (uint16_t val)
|
||||
{
|
||||
val = (val & 0x5555) + ((val >> 1) & 0x5555);
|
||||
val = (val & 0x3333) + ((val >> 2) & 0x3333);
|
||||
val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f);
|
||||
val = (val & 0x00ff) + ((val >> 8) & 0x00ff);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static always_inline int ctpop32 (uint32_t val)
|
||||
{
|
||||
val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
|
||||
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
|
||||
val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
|
||||
val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
|
||||
val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static always_inline int ctpop64 (uint64_t val)
|
||||
{
|
||||
val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
|
||||
val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
|
||||
val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
|
||||
val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & 0x00ff00ff00ff00ffULL);
|
||||
val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & 0x0000ffff0000ffffULL);
|
||||
val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL);
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
22
hpet.h
22
hpet.h
@@ -1,22 +0,0 @@
|
||||
#ifndef __HPET__
|
||||
#define __HPET__ 1
|
||||
|
||||
|
||||
|
||||
struct hpet_info {
|
||||
unsigned long hi_ireqfreq; /* Hz */
|
||||
unsigned long hi_flags; /* information */
|
||||
unsigned short hi_hpet;
|
||||
unsigned short hi_timer;
|
||||
};
|
||||
|
||||
#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */
|
||||
|
||||
#define HPET_IE_ON _IO('h', 0x01) /* interrupt on */
|
||||
#define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */
|
||||
#define HPET_INFO _IOR('h', 0x03, struct hpet_info)
|
||||
#define HPET_EPI _IO('h', 0x04) /* enable periodic */
|
||||
#define HPET_DPI _IO('h', 0x05) /* disable periodic */
|
||||
#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */
|
||||
|
||||
#endif /* !__HPET__ */
|
||||
518
hw/acpi.c
518
hw/acpi.c
@@ -1,518 +0,0 @@
|
||||
/*
|
||||
* ACPI implementation
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "pci.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "sysemu.h"
|
||||
#include "i2c.h"
|
||||
#include "smbus.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
/* i82731AB (PIIX4) compatible power management function */
|
||||
#define PM_FREQ 3579545
|
||||
|
||||
#define ACPI_DBG_IO_ADDR 0xb044
|
||||
|
||||
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;
|
||||
i2c_bus *smbus;
|
||||
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)
|
||||
#define PWRBTN_EN (1 << 8)
|
||||
#define GBL_EN (1 << 5)
|
||||
#define TMROF_EN (1 << 0)
|
||||
|
||||
#define SCI_EN (1 << 0)
|
||||
|
||||
#define SUS_EN (1 << 13)
|
||||
|
||||
#define ACPI_ENABLE 0xf1
|
||||
#define ACPI_DISABLE 0xf0
|
||||
|
||||
#define SMBHSTSTS 0x00
|
||||
#define SMBHSTCNT 0x02
|
||||
#define SMBHSTCMD 0x03
|
||||
#define SMBHSTADD 0x04
|
||||
#define SMBHSTDAT0 0x05
|
||||
#define SMBHSTDAT1 0x06
|
||||
#define SMBBLKDAT 0x07
|
||||
|
||||
static uint32_t get_pmtmr(PIIX4PMState *s)
|
||||
{
|
||||
uint32_t d;
|
||||
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
|
||||
return d & 0xffffff;
|
||||
}
|
||||
|
||||
static int get_pmsts(PIIX4PMState *s)
|
||||
{
|
||||
int64_t d;
|
||||
int pmsts;
|
||||
pmsts = s->pmsts;
|
||||
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
|
||||
if (d >= s->tmr_overflow_time)
|
||||
s->pmsts |= TMROF_EN;
|
||||
return pmsts;
|
||||
}
|
||||
|
||||
static void pm_update_sci(PIIX4PMState *s)
|
||||
{
|
||||
int sci_level, pmsts;
|
||||
int64_t expire_time;
|
||||
|
||||
pmsts = get_pmsts(s);
|
||||
sci_level = (((pmsts & s->pmen) &
|
||||
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
|
||||
qemu_set_irq(s->dev.irq[0], sci_level);
|
||||
/* schedule a timer interruption if needed */
|
||||
if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
|
||||
expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
|
||||
qemu_mod_timer(s->tmr_timer, expire_time);
|
||||
} else {
|
||||
qemu_del_timer(s->tmr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_tmr_timer(void *opaque)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
pm_update_sci(s);
|
||||
}
|
||||
|
||||
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
{
|
||||
int64_t d;
|
||||
int pmsts;
|
||||
pmsts = get_pmsts(s);
|
||||
if (pmsts & val & TMROF_EN) {
|
||||
/* if TMRSTS is reset, then compute the new overflow time */
|
||||
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
|
||||
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
|
||||
}
|
||||
s->pmsts &= ~val;
|
||||
pm_update_sci(s);
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
s->pmen = val;
|
||||
pm_update_sci(s);
|
||||
break;
|
||||
case 0x04:
|
||||
{
|
||||
int sus_typ;
|
||||
s->pmcntrl = val & ~(SUS_EN);
|
||||
if (val & SUS_EN) {
|
||||
/* change suspend type */
|
||||
sus_typ = (val >> 10) & 3;
|
||||
switch(sus_typ) {
|
||||
case 0: /* soft power off */
|
||||
qemu_system_shutdown_request();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
val = get_pmsts(s);
|
||||
break;
|
||||
case 0x02:
|
||||
val = s->pmen;
|
||||
break;
|
||||
case 0x04:
|
||||
val = s->pmcntrl;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
// PIIX4PMState *s = opaque;
|
||||
addr &= 0x3f;
|
||||
#ifdef DEBUG
|
||||
printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x08:
|
||||
val = get_pmtmr(s);
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
addr &= 1;
|
||||
#ifdef DEBUG
|
||||
printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
if (addr == 0) {
|
||||
s->apmc = val;
|
||||
|
||||
/* ACPI specs 3.0, 4.7.2.5 */
|
||||
if (val == ACPI_ENABLE) {
|
||||
s->pmcntrl |= SCI_EN;
|
||||
} else if (val == ACPI_DISABLE) {
|
||||
s->pmcntrl &= ~SCI_EN;
|
||||
}
|
||||
|
||||
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)
|
||||
printf("ACPI: DBG: 0x%08x\n", val);
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
i2c_bus *bus = s->smbus;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
|
||||
#endif
|
||||
switch(prot) {
|
||||
case 0x0:
|
||||
smbus_quick_command(bus, addr, read);
|
||||
break;
|
||||
case 0x1:
|
||||
if (read) {
|
||||
s->smb_data0 = smbus_receive_byte(bus, addr);
|
||||
} else {
|
||||
smbus_send_byte(bus, addr, cmd);
|
||||
}
|
||||
break;
|
||||
case 0x2:
|
||||
if (read) {
|
||||
s->smb_data0 = smbus_read_byte(bus, addr, cmd);
|
||||
} else {
|
||||
smbus_write_byte(bus, addr, cmd, s->smb_data0);
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
if (read) {
|
||||
uint16_t val;
|
||||
val = smbus_read_word(bus, addr, cmd);
|
||||
s->smb_data0 = val;
|
||||
s->smb_data1 = val >> 8;
|
||||
} else {
|
||||
smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
|
||||
}
|
||||
break;
|
||||
case 0x5:
|
||||
if (read) {
|
||||
s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
|
||||
} else {
|
||||
smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
|
||||
}
|
||||
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 &= 0xffc0;
|
||||
|
||||
/* 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_be64(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);
|
||||
s->tmr_overflow_time=qemu_get_be64(f);
|
||||
|
||||
pm_io_space_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
|
||||
{
|
||||
PIIX4PMState *s;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
s = (PIIX4PMState *)pci_register_device(bus,
|
||||
"PM", sizeof(PIIX4PMState),
|
||||
devfn, NULL, pm_write_config);
|
||||
pci_conf = s->dev.config;
|
||||
pci_conf[0x00] = 0x86;
|
||||
pci_conf[0x01] = 0x80;
|
||||
pci_conf[0x02] = 0x13;
|
||||
pci_conf[0x03] = 0x71;
|
||||
pci_conf[0x06] = 0x80;
|
||||
pci_conf[0x07] = 0x02;
|
||||
pci_conf[0x08] = 0x00; // revision number
|
||||
pci_conf[0x09] = 0x00;
|
||||
pci_conf[0x0a] = 0x80; // other bridge device
|
||||
pci_conf[0x0b] = 0x06; // bridge device
|
||||
pci_conf[0x0e] = 0x00; // header_type
|
||||
pci_conf[0x3d] = 0x01; // interrupt pin 1
|
||||
|
||||
pci_conf[0x40] = 0x01; /* PM io base read only bit */
|
||||
|
||||
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
|
||||
mappings */
|
||||
pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
|
||||
pci_conf[0x63] = 0x60;
|
||||
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
|
||||
(serial_hds[1] != NULL ? 0x90 : 0);
|
||||
|
||||
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);
|
||||
|
||||
s->smbus = i2c_init_bus();
|
||||
return s->smbus;
|
||||
}
|
||||
30
hw/adb.c
30
hw/adb.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QEMU ADB support
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004 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
|
||||
@@ -21,9 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "ppc_mac.h"
|
||||
#include "console.h"
|
||||
#include "vl.h"
|
||||
|
||||
/* ADB commands */
|
||||
#define ADB_BUSRESET 0x00
|
||||
@@ -98,9 +96,9 @@ int adb_poll(ADBBusState *s, uint8_t *obuf)
|
||||
return olen;
|
||||
}
|
||||
|
||||
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
|
||||
ADBDeviceRequest *devreq,
|
||||
ADBDeviceReset *devreset,
|
||||
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
|
||||
ADBDeviceRequest *devreq,
|
||||
ADBDeviceReset *devreset,
|
||||
void *opaque)
|
||||
{
|
||||
ADBDevice *d;
|
||||
@@ -301,31 +299,31 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
|
||||
if (s->last_buttons_state == s->buttons_state &&
|
||||
s->dx == 0 && s->dy == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
dx = s->dx;
|
||||
if (dx < -63)
|
||||
dx = -63;
|
||||
else if (dx > 63)
|
||||
dx = 63;
|
||||
|
||||
|
||||
dy = s->dy;
|
||||
if (dy < -63)
|
||||
dy = -63;
|
||||
else if (dy > 63)
|
||||
dy = 63;
|
||||
|
||||
|
||||
s->dx -= dx;
|
||||
s->dy -= dy;
|
||||
s->last_buttons_state = s->buttons_state;
|
||||
|
||||
|
||||
dx &= 0x7f;
|
||||
dy &= 0x7f;
|
||||
|
||||
|
||||
if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
|
||||
dy |= 0x80;
|
||||
if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
|
||||
dx |= 0x80;
|
||||
|
||||
|
||||
obuf[0] = dy;
|
||||
obuf[1] = dx;
|
||||
return 2;
|
||||
@@ -336,7 +334,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
|
||||
{
|
||||
MouseState *s = d->opaque;
|
||||
int cmd, reg, olen;
|
||||
|
||||
|
||||
if ((buf[0] & 0x0f) == ADB_FLUSH) {
|
||||
/* flush mouse fifo */
|
||||
s->buttons_state = s->last_buttons_state;
|
||||
@@ -408,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 ADB Mouse");
|
||||
qemu_add_mouse_event_handler(adb_mouse_event, d, 0);
|
||||
}
|
||||
|
||||
18
hw/adlib.c
18
hw/adlib.c
@@ -21,21 +21,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "hw.h"
|
||||
#include "audiodev.h"
|
||||
#include "audio/audio.h"
|
||||
#include "isa.h"
|
||||
|
||||
//#define DEBUG
|
||||
#include "vl.h"
|
||||
|
||||
#define ADLIB_KILL_TIMERS 1
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "qemu-timer.h"
|
||||
#endif
|
||||
|
||||
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
|
||||
#ifdef DEBUG
|
||||
#define ldebug(...) dolog (__VA_ARGS__)
|
||||
@@ -277,7 +267,7 @@ static void Adlib_fini (AdlibState *s)
|
||||
AUD_remove_card (&s->card);
|
||||
}
|
||||
|
||||
int Adlib_init (AudioState *audio, qemu_irq *pic)
|
||||
int Adlib_init (AudioState *audio)
|
||||
{
|
||||
AdlibState *s = &glob_adlib;
|
||||
audsettings_t as;
|
||||
@@ -311,7 +301,6 @@ int Adlib_init (AudioState *audio, qemu_irq *pic)
|
||||
as.freq = conf.freq;
|
||||
as.nchannels = SHIFT;
|
||||
as.fmt = AUD_FMT_S16;
|
||||
as.endianness = AUDIO_HOST_ENDIANNESS;
|
||||
|
||||
AUD_register_card (audio, "adlib", &s->card);
|
||||
|
||||
@@ -321,7 +310,8 @@ int Adlib_init (AudioState *audio, qemu_irq *pic)
|
||||
"adlib",
|
||||
s,
|
||||
adlib_callback,
|
||||
&as
|
||||
&as,
|
||||
0 /* XXX: little endian? */
|
||||
);
|
||||
if (!s->voice) {
|
||||
Adlib_fini (s);
|
||||
|
||||
169
hw/ads7846.c
169
hw/ads7846.c
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* TI ADS7846 / TSC2046 chip emulation.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GNU GPL v2.
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "devices.h"
|
||||
#include "console.h"
|
||||
|
||||
struct ads7846_state_s {
|
||||
qemu_irq interrupt;
|
||||
|
||||
int input[8];
|
||||
int pressure;
|
||||
int noise;
|
||||
|
||||
int cycle;
|
||||
int output;
|
||||
};
|
||||
|
||||
/* Control-byte bitfields */
|
||||
#define CB_PD0 (1 << 0)
|
||||
#define CB_PD1 (1 << 1)
|
||||
#define CB_SER (1 << 2)
|
||||
#define CB_MODE (1 << 3)
|
||||
#define CB_A0 (1 << 4)
|
||||
#define CB_A1 (1 << 5)
|
||||
#define CB_A2 (1 << 6)
|
||||
#define CB_START (1 << 7)
|
||||
|
||||
#define X_AXIS_DMAX 3470
|
||||
#define X_AXIS_MIN 290
|
||||
#define Y_AXIS_DMAX 3450
|
||||
#define Y_AXIS_MIN 200
|
||||
|
||||
#define ADS_VBAT 2000
|
||||
#define ADS_VAUX 2000
|
||||
#define ADS_TEMP0 2000
|
||||
#define ADS_TEMP1 3000
|
||||
#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
|
||||
#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
|
||||
#define ADS_Z1POS(x, y) 600
|
||||
#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
|
||||
|
||||
static void ads7846_int_update(struct ads7846_state_s *s)
|
||||
{
|
||||
if (s->interrupt)
|
||||
qemu_set_irq(s->interrupt, s->pressure == 0);
|
||||
}
|
||||
|
||||
uint32_t ads7846_read(void *opaque)
|
||||
{
|
||||
struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
|
||||
|
||||
return s->output;
|
||||
}
|
||||
|
||||
void ads7846_write(void *opaque, uint32_t value)
|
||||
{
|
||||
struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
|
||||
|
||||
switch (s->cycle ++) {
|
||||
case 0:
|
||||
if (!(value & CB_START)) {
|
||||
s->cycle = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
s->output = s->input[(value >> 4) & 7];
|
||||
|
||||
/* Imitate the ADC noise, some drivers expect this. */
|
||||
s->noise = (s->noise + 3) & 7;
|
||||
switch ((value >> 4) & 7) {
|
||||
case 1: s->output += s->noise ^ 2; break;
|
||||
case 3: s->output += s->noise ^ 0; break;
|
||||
case 4: s->output += s->noise ^ 7; break;
|
||||
case 5: s->output += s->noise ^ 5; break;
|
||||
}
|
||||
|
||||
if (value & CB_MODE)
|
||||
s->output >>= 4; /* 8 bits instead of 12 */
|
||||
|
||||
break;
|
||||
case 1:
|
||||
s->cycle = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ads7846_ts_event(void *opaque,
|
||||
int x, int y, int z, int buttons_state)
|
||||
{
|
||||
struct ads7846_state_s *s = opaque;
|
||||
|
||||
if (buttons_state) {
|
||||
x = 0x7fff - x;
|
||||
s->input[1] = ADS_XPOS(x, y);
|
||||
s->input[3] = ADS_Z1POS(x, y);
|
||||
s->input[4] = ADS_Z2POS(x, y);
|
||||
s->input[5] = ADS_YPOS(x, y);
|
||||
}
|
||||
|
||||
if (s->pressure == !buttons_state) {
|
||||
s->pressure = !!buttons_state;
|
||||
|
||||
ads7846_int_update(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void ads7846_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i ++)
|
||||
qemu_put_be32(f, s->input[i]);
|
||||
qemu_put_be32(f, s->noise);
|
||||
qemu_put_be32(f, s->cycle);
|
||||
qemu_put_be32(f, s->output);
|
||||
}
|
||||
|
||||
static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i ++)
|
||||
s->input[i] = qemu_get_be32(f);
|
||||
s->noise = qemu_get_be32(f);
|
||||
s->cycle = qemu_get_be32(f);
|
||||
s->output = qemu_get_be32(f);
|
||||
|
||||
s->pressure = 0;
|
||||
ads7846_int_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ads7846_iid = 0;
|
||||
|
||||
struct ads7846_state_s *ads7846_init(qemu_irq penirq)
|
||||
{
|
||||
struct ads7846_state_s *s;
|
||||
s = (struct ads7846_state_s *)
|
||||
qemu_mallocz(sizeof(struct ads7846_state_s));
|
||||
memset(s, 0, sizeof(struct ads7846_state_s));
|
||||
|
||||
s->interrupt = penirq;
|
||||
|
||||
s->input[0] = ADS_TEMP0; /* TEMP0 */
|
||||
s->input[2] = ADS_VBAT; /* VBAT */
|
||||
s->input[6] = ADS_VAUX; /* VAUX */
|
||||
s->input[7] = ADS_TEMP1; /* TEMP1 */
|
||||
|
||||
/* We want absolute coordinates */
|
||||
qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
|
||||
"QEMU ADS7846-driven Touchscreen");
|
||||
|
||||
ads7846_int_update(s);
|
||||
|
||||
register_savevm("ads7846", ads7846_iid ++, 0,
|
||||
ads7846_save, ads7846_load, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
1101
hw/alpha_palcode.c
1101
hw/alpha_palcode.c
File diff suppressed because it is too large
Load Diff
94
hw/an5206.c
94
hw/an5206.c
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Arnewsh 5206 ColdFire system emulation.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* This code is licenced under the GPL
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "mcf.h"
|
||||
#include "sysemu.h"
|
||||
#include "boards.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x10000
|
||||
#define AN5206_MBAR_ADDR 0x10000000
|
||||
#define AN5206_RAMBAR_ADDR 0x20000000
|
||||
|
||||
/* Stub functions for hardware that doesn't exist. */
|
||||
void pic_info(void)
|
||||
{
|
||||
}
|
||||
|
||||
void irq_info(void)
|
||||
{
|
||||
}
|
||||
|
||||
void DMA_run (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Board init. */
|
||||
|
||||
static void an5206_init(int ram_size, int vga_ram_size,
|
||||
const char *boot_device, DisplayState *ds,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model)
|
||||
{
|
||||
CPUState *env;
|
||||
int kernel_size;
|
||||
uint64_t elf_entry;
|
||||
target_ulong entry;
|
||||
|
||||
if (!cpu_model)
|
||||
cpu_model = "m5206";
|
||||
env = cpu_init(cpu_model);
|
||||
if (!env) {
|
||||
cpu_abort(env, "Unable to find m68k CPU definition\n");
|
||||
}
|
||||
|
||||
/* Initialize CPU registers. */
|
||||
env->vbr = 0;
|
||||
/* TODO: allow changing MBAR and RAMBAR. */
|
||||
env->mbar = AN5206_MBAR_ADDR | 1;
|
||||
env->rambar0 = AN5206_RAMBAR_ADDR | 1;
|
||||
|
||||
/* DRAM at address zero */
|
||||
cpu_register_physical_memory(0, ram_size,
|
||||
qemu_ram_alloc(ram_size) | IO_MEM_RAM);
|
||||
|
||||
/* Internal SRAM. */
|
||||
cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
|
||||
qemu_ram_alloc(512) | IO_MEM_RAM);
|
||||
|
||||
mcf5206_init(AN5206_MBAR_ADDR, env);
|
||||
|
||||
/* Load kernel. */
|
||||
if (!kernel_filename) {
|
||||
fprintf(stderr, "Kernel image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uboot(kernel_filename, &entry, NULL);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
entry = KERNEL_LOAD_ADDR;
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
env->pc = entry;
|
||||
}
|
||||
|
||||
QEMUMachine an5206_machine = {
|
||||
"an5206",
|
||||
"Arnewsh 5206",
|
||||
an5206_init,
|
||||
};
|
||||
260
hw/apb_pci.c
260
hw/apb_pci.c
@@ -1,260 +0,0 @@
|
||||
/*
|
||||
* QEMU Ultrasparc APB PCI host
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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 "hw.h"
|
||||
#include "pci.h"
|
||||
typedef target_phys_addr_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
typedef PCIHostState APBState;
|
||||
|
||||
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
APBState *s = opaque;
|
||||
int i;
|
||||
|
||||
for (i = 11; i < 32; i++) {
|
||||
if ((val & (1 << i)) != 0)
|
||||
break;
|
||||
}
|
||||
s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_config_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
APBState *s = opaque;
|
||||
uint32_t val;
|
||||
int devfn;
|
||||
|
||||
devfn = (s->config_reg >> 8) & 0xFF;
|
||||
val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
|
||||
&pci_apb_config_writel,
|
||||
&pci_apb_config_writel,
|
||||
&pci_apb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_config_read[] = {
|
||||
&pci_apb_config_readl,
|
||||
&pci_apb_config_readl,
|
||||
&pci_apb_config_readl,
|
||||
};
|
||||
|
||||
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
//PCIBus *s = opaque;
|
||||
|
||||
switch (addr & 0x3f) {
|
||||
case 0x00: // Control/Status
|
||||
case 0x10: // AFSR
|
||||
case 0x18: // AFAR
|
||||
case 0x20: // Diagnostic
|
||||
case 0x28: // Target address space
|
||||
// XXX
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t apb_config_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
//PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
switch (addr & 0x3f) {
|
||||
case 0x00: // Control/Status
|
||||
case 0x10: // AFSR
|
||||
case 0x18: // AFAR
|
||||
case 0x20: // Diagnostic
|
||||
case 0x28: // Target address space
|
||||
// XXX
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *apb_config_write[] = {
|
||||
&apb_config_writel,
|
||||
&apb_config_writel,
|
||||
&apb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *apb_config_read[] = {
|
||||
&apb_config_readl,
|
||||
&apb_config_readl,
|
||||
&apb_config_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_write[] = {
|
||||
&pci_host_data_writeb,
|
||||
&pci_host_data_writew,
|
||||
&pci_host_data_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_read[] = {
|
||||
&pci_host_data_readb,
|
||||
&pci_host_data_readw,
|
||||
&pci_host_data_readl,
|
||||
};
|
||||
|
||||
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outb(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outw(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outl(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inb(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inw(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inl(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
|
||||
&pci_apb_iowriteb,
|
||||
&pci_apb_iowritew,
|
||||
&pci_apb_iowritel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_ioread[] = {
|
||||
&pci_apb_ioreadb,
|
||||
&pci_apb_ioreadw,
|
||||
&pci_apb_ioreadl,
|
||||
};
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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(qemu_irq *pic, int irq_num, int level)
|
||||
{
|
||||
/* PCI IRQ map onto the first 32 INO. */
|
||||
qemu_set_irq(pic[irq_num], level);
|
||||
}
|
||||
|
||||
PCIBus *pci_apb_init(target_phys_addr_t special_base,
|
||||
target_phys_addr_t mem_base,
|
||||
qemu_irq *pic)
|
||||
{
|
||||
APBState *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
|
||||
PCIBus *secondary;
|
||||
|
||||
s = qemu_mallocz(sizeof(APBState));
|
||||
/* 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);
|
||||
apb_config = cpu_register_io_memory(0, apb_config_read,
|
||||
apb_config_write, s);
|
||||
pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
|
||||
pci_apb_write, s);
|
||||
pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
|
||||
pci_apb_iowrite, s);
|
||||
|
||||
cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
|
||||
cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
|
||||
cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
|
||||
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),
|
||||
0, NULL, NULL);
|
||||
d->config[0x00] = 0x8e; // vendor_id : Sun
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x00; // device_id
|
||||
d->config[0x03] = 0xa0;
|
||||
d->config[0x04] = 0x06; // command = bus master, pci mem
|
||||
d->config[0x05] = 0x00;
|
||||
d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
|
||||
d->config[0x07] = 0x03; // status = medium devsel
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x09] = 0x00; // programming i/f
|
||||
d->config[0x0A] = 0x00; // class_sub = pci host
|
||||
d->config[0x0B] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0D] = 0x10; // latency_timer
|
||||
d->config[0x0E] = 0x00; // header_type
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
110
hw/apic.c
110
hw/apic.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* APIC support
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@@ -17,9 +17,7 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "vl.h"
|
||||
|
||||
//#define DEBUG_APIC
|
||||
//#define DEBUG_IOAPIC
|
||||
@@ -184,7 +182,7 @@ static inline void reset_bit(uint32_t *tab, int index)
|
||||
}\
|
||||
}
|
||||
|
||||
static void apic_bus_deliver(const uint32_t *deliver_bitmask,
|
||||
static void apic_bus_deliver(const uint32_t *deliver_bitmask,
|
||||
uint8_t delivery_mode,
|
||||
uint8_t vector_num, uint8_t polarity,
|
||||
uint8_t trigger_mode)
|
||||
@@ -221,10 +219,10 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
|
||||
|
||||
case APIC_DM_INIT:
|
||||
/* normal INIT IPI sent to processors */
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
apic_init_ipi(apic_iter) );
|
||||
return;
|
||||
|
||||
|
||||
case APIC_DM_EXTINT:
|
||||
/* handled in I/O APIC code */
|
||||
break;
|
||||
@@ -233,7 +231,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
|
||||
return;
|
||||
}
|
||||
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
apic_set_irq(apic_iter, vector_num, trigger_mode) );
|
||||
}
|
||||
|
||||
@@ -241,9 +239,9 @@ void cpu_set_apic_base(CPUState *env, uint64_t val)
|
||||
{
|
||||
APICState *s = env->apic_state;
|
||||
#ifdef DEBUG_APIC
|
||||
printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
|
||||
printf("cpu_set_apic_base: %016llx\n", val);
|
||||
#endif
|
||||
s->apicbase = (val & 0xfffff000) |
|
||||
s->apicbase = (val & 0xfffff000) |
|
||||
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
|
||||
/* if disabled, cannot be enabled again */
|
||||
if (!(val & MSR_IA32_APICBASE_ENABLE)) {
|
||||
@@ -257,7 +255,7 @@ uint64_t cpu_get_apic_base(CPUState *env)
|
||||
{
|
||||
APICState *s = env->apic_state;
|
||||
#ifdef DEBUG_APIC
|
||||
printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
|
||||
printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
|
||||
#endif
|
||||
return s->apicbase;
|
||||
}
|
||||
@@ -384,6 +382,8 @@ 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,8 +391,7 @@ 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));
|
||||
for(i = 0; i < APIC_LVT_NB; i++)
|
||||
s->lvt[i] = 1 << 16; /* mask LVT */
|
||||
memset(s->lvt, 0, sizeof(s->lvt));
|
||||
s->esr = 0;
|
||||
memset(s->icr, 0, sizeof(s->icr));
|
||||
s->divide_conf = 0;
|
||||
@@ -409,7 +408,7 @@ static void apic_startup(APICState *s, int vector_num)
|
||||
if (!(env->hflags & HF_HALTED_MASK))
|
||||
return;
|
||||
env->eip = 0;
|
||||
cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
|
||||
cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
|
||||
0xffff, 0);
|
||||
env->hflags &= ~HF_HALTED_MASK;
|
||||
}
|
||||
@@ -445,7 +444,7 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
|
||||
int trig_mode = (s->icr[0] >> 15) & 1;
|
||||
int level = (s->icr[0] >> 14) & 1;
|
||||
if (level == 0 && trig_mode == 1) {
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
apic_iter->arb_id = apic_iter->id );
|
||||
return;
|
||||
}
|
||||
@@ -453,7 +452,7 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
|
||||
break;
|
||||
|
||||
case APIC_DM_SIPI:
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
apic_startup(apic_iter, vector_num) );
|
||||
return;
|
||||
}
|
||||
@@ -473,43 +472,24 @@ int apic_get_interrupt(CPUState *env)
|
||||
return -1;
|
||||
if (!(s->spurious_vec & APIC_SV_ENABLE))
|
||||
return -1;
|
||||
|
||||
|
||||
/* XXX: spurious IRQ handling */
|
||||
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;
|
||||
}
|
||||
|
||||
int apic_accept_pic_intr(CPUState *env)
|
||||
{
|
||||
APICState *s = env->apic_state;
|
||||
uint32_t lvt0;
|
||||
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
lvt0 = s->lvt[APIC_LVT_LINT0];
|
||||
|
||||
if (s->id == 0 &&
|
||||
((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
|
||||
((lvt0 & APIC_LVT_MASKED) == 0 &&
|
||||
((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t apic_get_current_count(APICState *s)
|
||||
{
|
||||
int64_t d;
|
||||
uint32_t val;
|
||||
d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
|
||||
d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
|
||||
s->count_shift;
|
||||
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
|
||||
/* periodic */
|
||||
@@ -526,9 +506,9 @@ static uint32_t apic_get_current_count(APICState *s)
|
||||
static void apic_timer_update(APICState *s, int64_t current_time)
|
||||
{
|
||||
int64_t next_time, d;
|
||||
|
||||
|
||||
if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
|
||||
d = (current_time - s->initial_count_load_time) >>
|
||||
d = (current_time - s->initial_count_load_time) >>
|
||||
s->count_shift;
|
||||
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
|
||||
d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
|
||||
@@ -761,12 +741,10 @@ static void apic_save(QEMUFile *f, void *opaque)
|
||||
qemu_put_be32s(f, &s->icr[0]);
|
||||
qemu_put_be32s(f, &s->icr[1]);
|
||||
qemu_put_be32s(f, &s->divide_conf);
|
||||
qemu_put_be32(f, s->count_shift);
|
||||
qemu_put_be32s(f, &s->count_shift);
|
||||
qemu_put_be32s(f, &s->initial_count);
|
||||
qemu_put_be64(f, s->initial_count_load_time);
|
||||
qemu_put_be64(f, s->next_time);
|
||||
|
||||
qemu_put_timer(f, s->timer);
|
||||
qemu_put_be64s(f, &s->initial_count_load_time);
|
||||
qemu_put_be64s(f, &s->next_time);
|
||||
}
|
||||
|
||||
static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
@@ -774,7 +752,7 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
APICState *s = opaque;
|
||||
int i;
|
||||
|
||||
if (version_id > 2)
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* XXX: what if the base changes? (registered memory regions) */
|
||||
@@ -797,13 +775,10 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
qemu_get_be32s(f, &s->icr[0]);
|
||||
qemu_get_be32s(f, &s->icr[1]);
|
||||
qemu_get_be32s(f, &s->divide_conf);
|
||||
s->count_shift=qemu_get_be32(f);
|
||||
qemu_get_be32s(f, &s->count_shift);
|
||||
qemu_get_be32s(f, &s->initial_count);
|
||||
s->initial_count_load_time=qemu_get_be64(f);
|
||||
s->next_time=qemu_get_be64(f);
|
||||
|
||||
if (version_id >= 2)
|
||||
qemu_get_timer(f, s->timer);
|
||||
qemu_get_be64s(f, &s->initial_count_load_time);
|
||||
qemu_get_be64s(f, &s->next_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -811,13 +786,6 @@ static void apic_reset(void *opaque)
|
||||
{
|
||||
APICState *s = opaque;
|
||||
apic_init_ipi(s);
|
||||
|
||||
/*
|
||||
* LINT0 delivery mode is set to ExtInt at initialization time
|
||||
* typically by BIOS, so PIC interrupt can be delivered to the
|
||||
* processor when local APIC is enabled.
|
||||
*/
|
||||
s->lvt[APIC_LVT_LINT0] = 0x700;
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *apic_mem_read[3] = {
|
||||
@@ -844,32 +812,24 @@ int apic_init(CPUState *env)
|
||||
env->apic_state = s;
|
||||
apic_init_ipi(s);
|
||||
s->id = last_apic_id++;
|
||||
env->cpuid_apic_id = s->id;
|
||||
s->cpu_env = env;
|
||||
s->apicbase = 0xfee00000 |
|
||||
s->apicbase = 0xfee00000 |
|
||||
(s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
|
||||
|
||||
/*
|
||||
* LINT0 delivery mode is set to ExtInt at initialization time
|
||||
* typically by BIOS, so PIC interrupt can be delivered to the
|
||||
* processor when local APIC is enabled.
|
||||
*/
|
||||
s->lvt[APIC_LVT_LINT0] = 0x700;
|
||||
|
||||
/* XXX: mapping more APICs at the same memory location */
|
||||
if (apic_io_memory == 0) {
|
||||
/* NOTE: the APIC is directly connected to the CPU - it is not
|
||||
on the global memory bus. */
|
||||
apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
|
||||
apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
|
||||
apic_mem_write, NULL);
|
||||
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
|
||||
apic_io_memory);
|
||||
}
|
||||
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
|
||||
|
||||
register_savevm("apic", s->id, 2, apic_save, apic_load, s);
|
||||
register_savevm("apic", 0, 1, apic_save, apic_load, s);
|
||||
qemu_register_reset(apic_reset, s);
|
||||
|
||||
|
||||
local_apics[s->id] = s;
|
||||
return 0;
|
||||
}
|
||||
@@ -903,9 +863,9 @@ static void ioapic_service(IOAPICState *s)
|
||||
vector = pic_read_irq(isa_pic);
|
||||
else
|
||||
vector = entry & 0xff;
|
||||
|
||||
|
||||
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
|
||||
apic_bus_deliver(deliver_bitmask, delivery_mode,
|
||||
apic_bus_deliver(deliver_bitmask, delivery_mode,
|
||||
vector, polarity, trig_mode);
|
||||
}
|
||||
}
|
||||
@@ -1071,12 +1031,12 @@ IOAPICState *ioapic_init(void)
|
||||
ioapic_reset(s);
|
||||
s->id = last_apic_id++;
|
||||
|
||||
io_memory = cpu_register_io_memory(0, ioapic_mem_read,
|
||||
io_memory = cpu_register_io_memory(0, ioapic_mem_read,
|
||||
ioapic_mem_write, s);
|
||||
cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
|
||||
|
||||
register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
|
||||
qemu_register_reset(ioapic_reset, s);
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Misc ARM declarations
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ARM_MISC_H
|
||||
#define ARM_MISC_H 1
|
||||
|
||||
/* The CPU is also modeled as an interrupt controller. */
|
||||
#define ARM_PIC_CPU_IRQ 0
|
||||
#define ARM_PIC_CPU_FIQ 1
|
||||
qemu_irq *arm_pic_init_cpu(CPUState *env);
|
||||
|
||||
/* armv7m.c */
|
||||
qemu_irq *armv7m_init(int flash_size, int sram_size,
|
||||
const char *kernel_filename, const char *cpu_model);
|
||||
|
||||
/* arm_boot.c */
|
||||
|
||||
void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
int board_id, target_phys_addr_t loader_start);
|
||||
|
||||
/* armv7m_nvic.c */
|
||||
int system_clock_scale;
|
||||
qemu_irq *armv7m_nvic_init(CPUState *env);
|
||||
|
||||
/* stellaris_enent.c */
|
||||
void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq);
|
||||
|
||||
#endif /* !ARM_MISC_H */
|
||||
|
||||
192
hw/arm_boot.c
192
hw/arm_boot.c
@@ -1,15 +1,13 @@
|
||||
/*
|
||||
/*
|
||||
* ARM kernel loader.
|
||||
*
|
||||
* Copyright (c) 2006-2007 CodeSourcery.
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "arm-misc.h"
|
||||
#include "sysemu.h"
|
||||
#include "vl.h"
|
||||
|
||||
#define KERNEL_ARGS_ADDR 0x100
|
||||
#define KERNEL_LOAD_ADDR 0x00010000
|
||||
@@ -26,38 +24,8 @@ static uint32_t bootloader[] = {
|
||||
0 /* Kernel entry point. Set by integratorcp_init. */
|
||||
};
|
||||
|
||||
/* Entry point for secondary CPUs. Enable interrupt controller and
|
||||
Issue WFI until start address is written to system controller. */
|
||||
static uint32_t smpboot[] = {
|
||||
0xe3a00201, /* mov r0, #0x10000000 */
|
||||
0xe3800601, /* orr r0, r0, #0x001000000 */
|
||||
0xe3a01001, /* mov r1, #1 */
|
||||
0xe5801100, /* str r1, [r0, #0x100] */
|
||||
0xe3a00201, /* mov r0, #0x10000000 */
|
||||
0xe3800030, /* orr r0, #0x30 */
|
||||
0xe320f003, /* wfi */
|
||||
0xe5901000, /* ldr r1, [r0] */
|
||||
0xe3110003, /* tst r1, #3 */
|
||||
0x1afffffb, /* bne <wfi> */
|
||||
0xe12fff11 /* bx r1 */
|
||||
};
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
CPUState *env = opaque;
|
||||
|
||||
cpu_reset(env);
|
||||
if (env->kernel_filename)
|
||||
arm_load_kernel(env, env->ram_size, env->kernel_filename,
|
||||
env->kernel_cmdline, env->initrd_filename,
|
||||
env->board_id, env->loader_start);
|
||||
|
||||
/* TODO: Reset secondary CPUs. */
|
||||
}
|
||||
|
||||
static void set_kernel_args(uint32_t ram_size, int initrd_size,
|
||||
const char *kernel_cmdline,
|
||||
target_phys_addr_t loader_start)
|
||||
const char *kernel_cmdline)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
||||
@@ -72,12 +40,12 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size,
|
||||
stl_raw(p++, 4);
|
||||
stl_raw(p++, 0x54410002);
|
||||
stl_raw(p++, ram_size);
|
||||
stl_raw(p++, loader_start);
|
||||
stl_raw(p++, 0);
|
||||
if (initrd_size) {
|
||||
/* ATAG_INITRD2 */
|
||||
stl_raw(p++, 4);
|
||||
stl_raw(p++, 0x54420005);
|
||||
stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
|
||||
stl_raw(p++, INITRD_LOAD_ADDR);
|
||||
stl_raw(p++, initrd_size);
|
||||
}
|
||||
if (kernel_cmdline && *kernel_cmdline) {
|
||||
@@ -96,148 +64,42 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size,
|
||||
stl_raw(p++, 0);
|
||||
}
|
||||
|
||||
static void set_kernel_args_old(uint32_t ram_size, int initrd_size,
|
||||
const char *kernel_cmdline,
|
||||
target_phys_addr_t loader_start)
|
||||
{
|
||||
uint32_t *p;
|
||||
unsigned char *s;
|
||||
|
||||
/* see linux/include/asm-arm/setup.h */
|
||||
p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
|
||||
/* page_size */
|
||||
stl_raw(p++, 4096);
|
||||
/* nr_pages */
|
||||
stl_raw(p++, ram_size / 4096);
|
||||
/* ramdisk_size */
|
||||
stl_raw(p++, 0);
|
||||
#define FLAG_READONLY 1
|
||||
#define FLAG_RDLOAD 4
|
||||
#define FLAG_RDPROMPT 8
|
||||
/* flags */
|
||||
stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
|
||||
/* rootdev */
|
||||
stl_raw(p++, (31 << 8) | 0); /* /dev/mtdblock0 */
|
||||
/* video_num_cols */
|
||||
stl_raw(p++, 0);
|
||||
/* video_num_rows */
|
||||
stl_raw(p++, 0);
|
||||
/* video_x */
|
||||
stl_raw(p++, 0);
|
||||
/* video_y */
|
||||
stl_raw(p++, 0);
|
||||
/* memc_control_reg */
|
||||
stl_raw(p++, 0);
|
||||
/* unsigned char sounddefault */
|
||||
/* unsigned char adfsdrives */
|
||||
/* unsigned char bytes_per_char_h */
|
||||
/* unsigned char bytes_per_char_v */
|
||||
stl_raw(p++, 0);
|
||||
/* pages_in_bank[4] */
|
||||
stl_raw(p++, 0);
|
||||
stl_raw(p++, 0);
|
||||
stl_raw(p++, 0);
|
||||
stl_raw(p++, 0);
|
||||
/* pages_in_vram */
|
||||
stl_raw(p++, 0);
|
||||
/* initrd_start */
|
||||
if (initrd_size)
|
||||
stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
|
||||
else
|
||||
stl_raw(p++, 0);
|
||||
/* initrd_size */
|
||||
stl_raw(p++, initrd_size);
|
||||
/* rd_start */
|
||||
stl_raw(p++, 0);
|
||||
/* system_rev */
|
||||
stl_raw(p++, 0);
|
||||
/* system_serial_low */
|
||||
stl_raw(p++, 0);
|
||||
/* system_serial_high */
|
||||
stl_raw(p++, 0);
|
||||
/* mem_fclk_21285 */
|
||||
stl_raw(p++, 0);
|
||||
/* zero unused fields */
|
||||
memset(p, 0, 256 + 1024 -
|
||||
(p - ((uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR))));
|
||||
s = phys_ram_base + KERNEL_ARGS_ADDR + 256 + 1024;
|
||||
if (kernel_cmdline)
|
||||
strcpy (s, kernel_cmdline);
|
||||
else
|
||||
stb_raw(s, 0);
|
||||
}
|
||||
|
||||
void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
|
||||
void arm_load_kernel(int ram_size, const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
int board_id, target_phys_addr_t loader_start)
|
||||
int board_id)
|
||||
{
|
||||
int kernel_size;
|
||||
int initrd_size;
|
||||
int n;
|
||||
int is_linux = 0;
|
||||
uint64_t elf_entry;
|
||||
target_ulong entry;
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!kernel_filename) {
|
||||
fprintf(stderr, "Kernel image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!env->kernel_filename) {
|
||||
env->ram_size = ram_size;
|
||||
env->kernel_filename = kernel_filename;
|
||||
env->kernel_cmdline = kernel_cmdline;
|
||||
env->initrd_filename = initrd_filename;
|
||||
env->board_id = board_id;
|
||||
env->loader_start = loader_start;
|
||||
qemu_register_reset(main_cpu_reset, env);
|
||||
}
|
||||
/* Assume that raw images are linux kernels, and ELF images are not. */
|
||||
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uboot(kernel_filename, &entry, &is_linux);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
entry = loader_start + KERNEL_LOAD_ADDR;
|
||||
is_linux = 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 (!is_linux) {
|
||||
/* Jump to the entry point. */
|
||||
env->regs[15] = entry & 0xfffffffe;
|
||||
env->thumb = entry & 1;
|
||||
} else {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
bootloader[1] |= board_id & 0xff;
|
||||
bootloader[2] |= (board_id >> 8) & 0xff;
|
||||
bootloader[5] = loader_start + KERNEL_ARGS_ADDR;
|
||||
bootloader[6] = entry;
|
||||
for (n = 0; n < sizeof(bootloader) / 4; n++)
|
||||
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
|
||||
for (n = 0; n < sizeof(smpboot) / 4; n++)
|
||||
stl_raw(phys_ram_base + ram_size + (n * 4), smpboot[n]);
|
||||
if (old_param)
|
||||
set_kernel_args_old(ram_size, initrd_size,
|
||||
kernel_cmdline, loader_start);
|
||||
else
|
||||
set_kernel_args(ram_size, initrd_size,
|
||||
kernel_cmdline, loader_start);
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user