Compare commits

..

1 Commits

Author SHA1 Message Date
(no author)
ea4b3c0748 This commit was manufactured by cvs2svn to create tag
'release_0_6_0'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_6_0@1006 c046a42c-6fe2-441c-8c8c-71466251a162
2004-07-10 18:18:20 +00:00
289 changed files with 15137 additions and 82481 deletions

View File

@@ -1,23 +1,15 @@
arm-user
armeb-user
config-host.*
dyngen
i386
i386-softmmu
i386-user
ppc-softmmu
ppc64-softmmu
ppc-user
qemu-doc.html
qemu-mkcow
qemu-tech.html
qemu.1
qemu.pod
qemu-img.1
qemu-img.pod
sparc-user
qemu-img
sparc-softmmu
x86_64-softmmu
sparc64-user
sparc64-softmmu
mips-softmmu
vmdk2raw

View File

@@ -1,73 +1,3 @@
version 0.7.1:
- read-only Virtual FAT support (Johannes Schindelin)
- Windows 2000 install disk full hack (original idea from Vladimir
N. Oleynik)
- VMDK disk image creation (Filip Navara)
- SPARC64 progress (Blue Swirl)
- initial MIPS support (Jocelyn mayer)
- MIPS improvements (Ralf Baechle)
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
version 0.7.0:
- better BIOS translation and HDD geometry auto-detection
- user mode networking bug fix
- undocumented FPU ops support
- Cirrus VGA: support for 1280x1024x[8,15,16] modes
- 'pidfile' option
- .dmg disk image format support (Johannes Schindelin)
- keymaps support (initial patch by Johannes Schindelin)
- big endian ARM support (Lennert Buytenhek)
- added generic 64 bit target support
- x86_64 target support
- initial APIC support
- MMX/SSE/SSE2/PNI support
- PC parallel port support (Mark Jonckheere)
- initial SPARC64 support (Blue Swirl)
- SPARC target boots Linux (Blue Swirl)
- armv5te user mode support (Paul Brook)
- ARM VFP support (Paul Brook)
- ARM "Angel" semihosting syscalls (Paul Brook)
- user mode gdb stub support (Paul Brook)
- Samba 3 support
- initial Cocoa support (Pierre d'Herbemont)
- generic FPU emulation code
- Virtual PC read-only disk image support (Alex Beregszaszi)
version 0.6.1:
- Mac OS X port (Pierre d'Herbemont)
- Virtual console support
- Better monitor line edition
- 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)
- Support for up to 4 serial ports
- TFTP server support (Magnus Damm)
- Port redirection support in user mode networking
- Support for not executable data sections
- Compressed loop disk image support (Johannes Schindelin)
- Level triggered IRQ fix (aka NE2000 PCI performance fix) (Steve
Wormley)
- Fixed Fedora Core 2 problems (now you can run qemu without any
LD_ASSUME_KERNEL tricks on FC2)
- DHCP fix for Windows (accept DHCPREQUEST alone)
- SPARC system emulation (Blue Swirl)
- Automatic Samba configuration for host file access from Windows.
- '-loadvm' and '-full-screen' options
- ne2000 savevm support (Johannes Schindelin)
- Ctrl-Alt is now the default grab key. Ctrl-Alt-[0-9] switches to
the virtual consoles.
- BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus, Volker Ruppert)
- Floppy fixes for NT4 and NT5 (Mike Nordell)
- NT4 IDE fixes (Ben Pfaf, Mike Nordell)
- SDL Audio support and SB16 fixes (malc)
- ENTER instruction bug fix (initial patch by Stefan Kisdaroczi)
- VGA font change fix
- VGA read-only CRTC register fix
version 0.6.0:
- minimalist FPU exception support (NetBSD FPU probe fix)

12
LICENSE
View File

@@ -1,12 +0,0 @@
The following points clarify the QEMU licenses:
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) The Linux user mode QEMU emulator is released under the GNU General
Public License.
3) QEMU is a trademark of Fabrice Bellard.
Fabrice Bellard.

View File

@@ -1,32 +1,32 @@
-include config-host.mak
include config-host.mak
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
CFLAGS=-Wall -O2 -g
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
ifdef CONFIG_WIN32
CFLAGS+=-fpack-struct
endif
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TOOLS=qemu-img$(EXESUF)
DEFINES+=-D_GNU_SOURCE
ifndef CONFIG_WIN32
TOOLS=qemu-mkcow vmdk2raw
endif
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
ifdef CONFIG_WIN32
$(MAKE) -C kqemu -f Makefile.winnt
else
$(MAKE) -C kqemu
endif
endif
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
qemu-mkcow: qemu-mkcow.c
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
vmdk2raw: vmdk2raw.c
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
dyngen$(EXESUF): dyngen.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
@@ -34,14 +34,11 @@ dyngen$(EXESUF): dyngen.c
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 *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.pod
$(MAKE) -C tests clean
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
$(MAKE) -C kqemu clean
endif
distclean: clean
rm -f config-host.mak config-host.h
@@ -49,33 +46,25 @@ distclean: clean
rm -rf $$d || exit 1 ; \
done
KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
install: all
mkdir -p "$(bindir)"
ifndef CONFIG_WIN32
install -m 755 -s $(TOOLS) "$(bindir)"
endif
mkdir -p "$(datadir)"
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
pc-bios/vgabios-cirrus.bin \
pc-bios/ppc_rom.bin pc-bios/video.x \
pc-bios/proll.elf \
pc-bios/ppc_rom.bin \
pc-bios/linux_boot.bin "$(datadir)"
mkdir -p "$(docdir)"
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
ifndef CONFIG_WIN32
mkdir -p "$(mandir)/man1"
install qemu.1 qemu-img.1 "$(mandir)/man1"
mkdir -p "$(datadir)/keymaps"
install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(datadir)/keymaps"
install qemu.1 qemu-mkcow.1 "$(mandir)/man1"
endif
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifdef CONFIG_KQEMU
cd kqemu ; ./install.sh
endif
# various test targets
test speed test2: all
@@ -92,10 +81,6 @@ qemu.1: qemu-doc.texi
./texi2pod.pl $< qemu.pod
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
qemu-img.1: qemu-img.texi
./texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
@@ -108,26 +93,21 @@ tar:
# generate a binary distribution
tarbin:
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
$(bindir)/qemu \
$(bindir)/qemu $(bindir)/qemu-fast \
$(bindir)/qemu-system-ppc \
$(bindir)/qemu-system-sparc \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-i386 \
$(bindir)/qemu-arm \
$(bindir)/qemu-sparc \
$(bindir)/qemu-ppc \
$(bindir)/qemu-img \
$(bindir)/qemu-mkcow $(bindir)/vmdk2raw \
$(datadir)/bios.bin \
$(datadir)/vgabios.bin \
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/proll.elf \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-mkcow.1 )
ifneq ($(wildcard .depend),)
include .depend

View File

@@ -1,38 +1,19 @@
include config.mak
TARGET_BASE_ARCH:=$(TARGET_ARCH)
ifeq ($(TARGET_ARCH), x86_64)
TARGET_BASE_ARCH:=i386
endif
ifeq ($(TARGET_ARCH), ppc64)
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:$(SRC_PATH)/audio
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
ifdef CONFIG_USER_ONLY
VPATH+=:$(SRC_PATH)/linux-user
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
#CFLAGS+=-Werror
LDFLAGS=-g
LIBS=
HELPER_CFLAGS=$(CFLAGS)
DYNGEN=../dyngen$(EXESUF)
# user emulator name
ifeq ($(TARGET_ARCH),arm)
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
QEMU_USER=qemu-armeb
else
QEMU_USER=qemu-arm
endif
else
QEMU_USER=qemu-$(TARGET_ARCH)
endif
QEMU_USER=qemu-$(TARGET_ARCH)
# system emulator name
ifdef CONFIG_SOFTMMU
ifeq ($(TARGET_ARCH), i386)
@@ -47,10 +28,41 @@ endif
ifdef CONFIG_USER_ONLY
PROGS=$(QEMU_USER)
else
ifeq ($(TARGET_ARCH), i386)
ifeq ($(ARCH), i386)
PROGS+=$(QEMU_SYSTEM)
ifndef CONFIG_SOFTMMU
CONFIG_STATIC=y
endif
else
# the system emulator using soft mmu is portable
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH != i386
endif # TARGET_ARCH = i386
ifeq ($(TARGET_ARCH), ppc)
ifeq ($(ARCH), ppc)
PROGS+=$(QEMU_SYSTEM)
endif
ifeq ($(ARCH), i386)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = i386
ifeq ($(ARCH), amd64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = amd64
endif # TARGET_ARCH = ppc
endif # !CONFIG_USER_ONLY
ifdef CONFIG_STATIC
@@ -61,7 +73,7 @@ ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0 -fno-gcse
OP_CFLAGS+= -falign-functions=0
else
OP_CFLAGS+= -malign-functions=0
endif
@@ -82,9 +94,9 @@ LDFLAGS+=-Wl,-shared
endif
endif
ifeq ($(ARCH),x86_64)
ifeq ($(ARCH),amd64)
OP_CFLAGS=$(CFLAGS) -falign-functions=0
LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld
endif
ifeq ($(ARCH),ppc)
@@ -123,13 +135,11 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
endif
ifeq ($(ARCH),ia64)
CFLAGS += -mno-sdata
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifeq ($(ARCH),arm)
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
endif
@@ -145,18 +155,14 @@ endif
ifeq ($(CONFIG_DARWIN),yes)
OP_CFLAGS+= -mdynamic-no-pic
LIBS+=-lmx
endif
#########################################################
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
DEFINES+=-D_GNU_SOURCE
LIBS+=-lm
ifndef CONFIG_USER_ONLY
LIBS+=-lz
endif
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
LIBS+=-lwinmm
endif
# profiling code
@@ -170,22 +176,16 @@ ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
ifeq ($(TARGET_ARCH), arm)
OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
OBJS+=nwfpe/softfloat.o 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
nwfpe/double_cpdo.o nwfpe/extended_cpdo.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
ifdef CONFIG_SOFTFLOAT
LIBOBJS+=fpu/softfloat.o
else
LIBOBJS+=fpu/softfloat-native.o
endif
DEFINES+=-I$(SRC_PATH)/fpu
LIBOBJS=exec.o translate-all.o cpu-exec.o\
translate.o op.o
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=helper.o helper2.o
@@ -194,32 +194,16 @@ LIBOBJS+=translate-copy.o
endif
endif
ifeq ($(TARGET_ARCH), x86_64)
LIBOBJS+=helper.o helper2.o
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
ifeq ($(TARGET_ARCH), ppc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_ARCH), mips)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), arm)
LIBOBJS+= op_helper.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
USE_I386_DIS=y
endif
ifeq ($(findstring x86_64, $(TARGET_ARCH) $(ARCH)),x86_64)
ifeq ($(findstring amd64, $(TARGET_ARCH) $(ARCH)),amd64)
USE_I386_DIS=y
endif
ifdef USE_I386_DIS
@@ -228,13 +212,10 @@ endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
LIBOBJS+=mips-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
@@ -244,9 +225,6 @@ endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
ifdef CONFIG_GDBSTUB
OBJS+=gdbstub.o
endif
all: $(PROGS)
@@ -259,54 +237,18 @@ ifeq ($(ARCH),alpha)
endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
VL_OBJS=vl.o osdep.o block.o monitor.o pci.o
SOUND_HW = sb16.o
AUDIODRV = audio.o noaudio.o wavaudio.o
ifdef CONFIG_SDL
AUDIODRV += sdlaudio.o
endif
ifdef CONFIG_OSS
AUDIODRV += ossaudio.o
endif
pc.o: DEFINES := -DUSE_SB16 $(DEFINES)
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
ifdef CONFIG_FMOD
AUDIODRV += fmodaudio.o
audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
LIBS += $(CONFIG_FMOD_LIB)
endif
ifeq ($(TARGET_BASE_ARCH), i386)
ifeq ($(TARGET_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
VL_OBJS+= cirrus_vga.o
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
ifeq ($(TARGET_ARCH), ppc)
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
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
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o
#VL_OBJS+= #ide.o pckbd.o i8254.o fdc.o m48t59.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
VL_OBJS+= magic-load.o
else
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
endif
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
@@ -314,15 +256,11 @@ endif
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
endif
ifdef CONFIG_COCOA
VL_OBJS+=cocoa.o
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
endif
ifdef CONFIG_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
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o
VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
endif
@@ -339,25 +277,11 @@ ifndef CONFIG_WIN32
VL_LIBS=-lutil
endif
endif
ifdef TARGET_GPROF
vl.o: CFLAGS+=-p
VL_LDFLAGS+=-p
endif
ifeq ($(ARCH),ia64)
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_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 $@ $<
sdlaudio.o: sdlaudio.c
sdl.o: sdl.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
depend: $(SRCS)
@@ -371,9 +295,7 @@ libqemu.a: $(LIBOBJS)
translate.o: translate.c gen-op.h opc.h cpu.h
translate-all.o: translate-all.c opc.h cpu.h
translate-op.o: translate-all.c op.h opc.h cpu.h
translate-all.o: translate-all.c op.h opc.h cpu.h
op.h: op.o $(DYNGEN)
$(DYNGEN) -o $@ $<
@@ -390,32 +312,23 @@ op.o: op.c
helper.o: helper.c
$(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
ifeq ($(TARGET_ARCH), i386)
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h
endif
ifeq ($(TARGET_ARCH), arm)
op.o: op.c op_template.h
endif
ifeq ($(TARGET_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
ifeq ($(TARGET_ARCH), sparc)
op.o: op.c op_template.h
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
ifeq ($(TARGET_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
mixeng.o: mixeng.c mixeng.h mixeng_template.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
@@ -423,7 +336,7 @@ mixeng.o: mixeng.c mixeng.h mixeng_template.h
$(CC) $(DEFINES) -c -o $@ $<
clean:
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o
install: all
ifneq ($(PROGS),)

58
README
View File

@@ -1,3 +1,61 @@
The QEMU x86 emulator
---------------------
INSTALLATION
------------
Type
./configure
make
to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various
supported target CPUs).
Type
make install
to install QEMU in /usr/local
Tested tool versions
--------------------
In order to compile QEMU succesfully, it is very important that you
have the right tools. The most important one is gcc. I cannot guaranty
that QEMU works if you do not use a tested gcc version. Look at
'configure' and 'Makefile' if you want to make a different gcc
version work.
host gcc binutils glibc linux distribution
----------------------------------------------------------------------
x86 2.95.2 2.13.2 2.1.3 2.4.18
3.2 2.13.2 2.1.3 2.4.18
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
3.2
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
for gcc version >= 3.3.
[2] Linux >= 2.4.20 is necessary for precise exception support
(untested).
[3] 2.4.9-ac10-rmk2-np1-cerf2
[4] gcc 2.95.x generates invalid code when using too many register
variables. You must use gcc 3.x on PowerPC.
Documentation
-------------
Read the documentation in qemu-doc.html.
Fabrice Bellard.

27
TODO
View File

@@ -1,22 +1,14 @@
short term:
----------
- 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
- handle fast timers + add explicit clocks
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- add sysenter/sysexit and fxsr for L4 pistachio 686
- basic VGA optimizations
- disable SMC handling for ARM/SPARC/PPC (not finished)
- see undefined flags for BTx insn
- user/kernel PUSHL/POPL in helper.c
@@ -30,23 +22,17 @@ short term:
- fix arm fpu rounding (at least for float->integer conversions)
- SMP support
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- SPR_ENCODE() not useful
- enable shift optimizations ?
lower priority:
--------------
- more friendly BIOS (logo)
- int15 ah=86: use better timing
- HDD geometry in CMOS (not used except for very old DOS programs)
- suppress shift_mem ops
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
- sysenter/sysexit emulation
- optimize FPU operations (evaluate x87 stack pointer statically)
- add IPC syscalls
- use -msoft-float on ARM
- use kernel traps for unaligned accesses on ARM ?
- handle rare page fault cases (in particular if page fault in helpers or
- handle rare page fault cases (in particular if page fault in heplers or
in syscall emulation code).
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
@@ -55,3 +41,4 @@ lower priority:
cases of self modifying code.
- use gcc as a backend to generate better code (easy to do by using
op-i386.c operations as local inline functions).
- add SSE2/MMX operations

View File

@@ -1 +1 @@
0.7.1
0.6.0

View File

@@ -151,7 +151,7 @@ struct external_lineno {
#define E_FILNMLEN 14 /* # characters in a file name */
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
struct __attribute__((packed)) external_syment
struct external_syment
{
union {
char e_name[E_SYMNMLEN];

1317
aes.c

File diff suppressed because it is too large Load Diff

26
aes.h
View File

@@ -1,26 +0,0 @@
#ifndef QEMU_AES_H
#define QEMU_AES_H
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
struct aes_key_st {
uint32_t rd_key[4 *(AES_MAXNR + 1)];
int rounds;
};
typedef struct aes_key_st AES_KEY;
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
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);
#endif

View File

View File

@@ -1556,11 +1556,6 @@ print_insn_arm (pc, info)
}
is_thumb = force_thumb;
if (pc & 1)
{
is_thumb = 1;
pc &= ~(bfd_vma) 1;
}
#if 0
if (!is_thumb && info->symbols != NULL)

View File

@@ -1,911 +0,0 @@
/*
* QEMU Audio subsystem
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include "vl.h"
#define USE_WAV_AUDIO
#include "audio/audio_int.h"
#define dolog(...) AUD_log ("audio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_AUDIO_DRV "QEMU_AUDIO_DRV"
#define QC_VOICES "QEMU_VOICES"
#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
#define QC_FIXED_FREQ "QEMU_FIXED_FREQ"
static HWVoice *hw_voices;
AudioState audio_state = {
1, /* use fixed settings */
44100, /* fixed frequency */
2, /* fixed channels */
AUD_FMT_S16, /* fixed format */
1, /* number of hw voices */
-1 /* voice size */
};
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
/* http://www.multi-platforms.com/Tips/PopCount.htm */
uint32_t popcount (uint32_t u)
{
u = ((u&0x55555555) + ((u>>1)&0x55555555));
u = ((u&0x33333333) + ((u>>2)&0x33333333));
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
u = ( u&0x0000ffff) + (u>>16);
return u;
}
inline uint32_t lsbindex (uint32_t u)
{
return popcount ((u&-u)-1);
}
int audio_get_conf_int (const char *key, int defval)
{
int val = defval;
char *strval;
strval = getenv (key);
if (strval) {
val = atoi (strval);
}
return val;
}
const char *audio_get_conf_str (const char *key, const char *defval)
{
const char *val = getenv (key);
if (!val)
return defval;
else
return val;
}
void AUD_log (const char *cap, const char *fmt, ...)
{
va_list ap;
fprintf (stderr, "%s: ", cap);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
/*
* Soft Voice
*/
void pcm_sw_free_resources (SWVoice *sw)
{
if (sw->buf) qemu_free (sw->buf);
if (sw->rate) st_rate_stop (sw->rate);
sw->buf = NULL;
sw->rate = NULL;
}
int pcm_sw_alloc_resources (SWVoice *sw)
{
sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
if (!sw->buf)
return -1;
sw->rate = st_rate_start (sw->freq, sw->hw->freq);
if (!sw->rate) {
qemu_free (sw->buf);
sw->buf = NULL;
return -1;
}
return 0;
}
void pcm_sw_fini (SWVoice *sw)
{
pcm_sw_free_resources (sw);
}
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt)
{
int bits = 8, sign = 0;
switch (fmt) {
case AUD_FMT_S8:
sign = 1;
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
sign = 1;
case AUD_FMT_U16:
bits = 16;
break;
}
sw->hw = hw;
sw->freq = freq;
sw->fmt = fmt;
sw->nchannels = nchannels;
sw->shift = (nchannels == 2) + (bits == 16);
sw->align = (1 << sw->shift) - 1;
sw->left = 0;
sw->pos = 0;
sw->wpos = 0;
sw->live = 0;
sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
sw->bytes_per_second = sw->freq << sw->shift;
sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
pcm_sw_free_resources (sw);
return pcm_sw_alloc_resources (sw);
}
/* Hard voice */
void pcm_hw_free_resources (HWVoice *hw)
{
if (hw->mix_buf)
qemu_free (hw->mix_buf);
hw->mix_buf = NULL;
}
int pcm_hw_alloc_resources (HWVoice *hw)
{
hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
if (!hw->mix_buf)
return -1;
return 0;
}
void pcm_hw_fini (HWVoice *hw)
{
if (hw->active) {
ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
pcm_hw_free_resources (hw);
hw->pcm_ops->fini (hw);
memset (hw, 0, audio_state.drv->voice_size);
}
}
void pcm_hw_gc (HWVoice *hw)
{
if (hw->nb_voices)
return;
pcm_hw_fini (hw);
}
int pcm_hw_get_live (HWVoice *hw)
{
int i, alive = 0, live = hw->samples;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
live = audio_MIN (hw->pvoice[i]->live, live);
alive += 1;
}
}
if (alive)
return live;
else
return -1;
}
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
{
int i, alive = 0, live = hw->samples;
*nb_active = 0;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
if (hw->pvoice[i]->live < live) {
*nb_active = hw->pvoice[i]->active != 0;
live = hw->pvoice[i]->live;
}
alive += 1;
}
}
if (alive)
return live;
else
return -1;
}
void pcm_hw_dec_live (HWVoice *hw, int decr)
{
int i;
for (i = 0; i < hw->nb_voices; i++) {
if (hw->pvoice[i]->live) {
hw->pvoice[i]->live -= decr;
}
}
}
void pcm_hw_clear (HWVoice *hw, void *buf, int len)
{
if (!len)
return;
switch (hw->fmt) {
case AUD_FMT_S16:
case AUD_FMT_S8:
memset (buf, len << hw->shift, 0x00);
break;
case AUD_FMT_U8:
memset (buf, len << hw->shift, 0x80);
break;
case AUD_FMT_U16:
{
unsigned int i;
uint16_t *p = buf;
int shift = hw->nchannels - 1;
for (i = 0; i < len << shift; i++) {
p[i] = INT16_MAX;
}
}
break;
}
}
int pcm_hw_write (SWVoice *sw, void *buf, int size)
{
int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
int ret = 0, pos = 0;
if (!sw)
return size;
hwsamples = sw->hw->samples;
samples = size >> sw->shift;
if (!sw->live) {
sw->wpos = sw->hw->rpos;
}
wpos = sw->wpos;
live = sw->live;
dead = hwsamples - live;
swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
swlim = audio_MIN (swlim, samples);
ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
size, live, dead, swlim, wpos);
if (swlim)
sw->conv (sw->buf, buf, swlim);
while (swlim) {
dead = hwsamples - live;
left = hwsamples - wpos;
blck = audio_MIN (dead, left);
if (!blck) {
/* dolog ("swlim=%d\n", swlim); */
break;
}
isamp = swlim;
osamp = blck;
st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
ret += isamp;
swlim -= isamp;
pos += isamp;
live += osamp;
wpos = (wpos + osamp) % hwsamples;
}
sw->wpos = wpos;
sw->live = live;
return ret << sw->shift;
}
int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int sign = 0, bits = 8;
pcm_hw_fini (hw);
ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
memset (hw, 0, audio_state.drv->voice_size);
return -1;
}
switch (hw->fmt) {
case AUD_FMT_S8:
sign = 1;
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
sign = 1;
case AUD_FMT_U16:
bits = 16;
break;
}
hw->nb_voices = 0;
hw->active = 1;
hw->shift = (hw->nchannels == 2) + (bits == 16);
hw->bytes_per_second = hw->freq << hw->shift;
hw->align = (1 << hw->shift) - 1;
hw->samples = hw->bufsize >> hw->shift;
hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
if (pcm_hw_alloc_resources (hw)) {
pcm_hw_fini (hw);
return -1;
}
return 0;
}
static int dist (void *hw)
{
if (hw) {
return (((uint8_t *) hw - (uint8_t *) hw_voices)
/ audio_state.drv->voice_size) + 1;
}
else {
return 0;
}
}
#define ADVANCE(hw) \
((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices)
HWVoice *pcm_hw_find_any (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_active (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (hw->active)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (hw->active && hw->enabled)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
{
int i = dist (hw);
for (; i < audio_state.nb_hw_voices; i++) {
hw = ADVANCE (hw);
if (!hw->active)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt)
{
while ((hw = pcm_hw_find_any_active (hw))) {
if (hw->freq == freq &&
hw->nchannels == nchannels &&
hw->fmt == fmt)
return hw;
}
return NULL;
}
HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
{
HWVoice *hw;
if (audio_state.fixed_format) {
freq = audio_state.fixed_freq;
nchannels = audio_state.fixed_channels;
fmt = audio_state.fixed_fmt;
}
hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
if (hw)
return hw;
hw = pcm_hw_find_any_passive (NULL);
if (hw) {
hw->pcm_ops = audio_state.drv->pcm_ops;
if (!hw->pcm_ops)
return NULL;
if (pcm_hw_init (hw, freq, nchannels, fmt)) {
pcm_hw_gc (hw);
return NULL;
}
else
return hw;
}
return pcm_hw_find_any (NULL);
}
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
{
SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
if (!pvoice)
return -1;
memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
qemu_free (hw->pvoice);
hw->pvoice = pvoice;
hw->pvoice[hw->nb_voices++] = sw;
return 0;
}
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
{
int i, j;
if (hw->nb_voices > 1) {
SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
if (!pvoice) {
dolog ("Can not maintain consistent state (not enough memory)\n");
return -1;
}
for (i = 0, j = 0; i < hw->nb_voices; i++) {
if (j >= hw->nb_voices - 1) {
dolog ("Can not maintain consistent state "
"(invariant violated)\n");
return -1;
}
if (hw->pvoice[i] != sw)
pvoice[j++] = hw->pvoice[i];
}
qemu_free (hw->pvoice);
hw->pvoice = pvoice;
hw->nb_voices -= 1;
}
else {
qemu_free (hw->pvoice);
hw->pvoice = NULL;
hw->nb_voices = 0;
}
return 0;
}
SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
{
SWVoice *sw;
HWVoice *hw;
sw = qemu_mallocz (sizeof (*sw));
if (!sw)
goto err1;
hw = pcm_hw_add (freq, nchannels, fmt);
if (!hw)
goto err2;
if (pcm_hw_add_sw (hw, sw))
goto err3;
if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
goto err4;
return sw;
err4:
pcm_hw_del_sw (hw, sw);
err3:
pcm_hw_gc (hw);
err2:
qemu_free (sw);
err1:
return NULL;
}
SWVoice *AUD_open (SWVoice *sw, const char *name,
int freq, int nchannels, audfmt_e fmt)
{
if (!audio_state.drv) {
return NULL;
}
if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
return sw;
}
if (sw) {
ldebug ("Different format %s %d %d %d\n",
name,
sw->freq == freq,
sw->nchannels == nchannels,
sw->fmt == fmt);
}
if (nchannels != 1 && nchannels != 2) {
dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
return NULL;
}
if (!audio_state.fixed_format && sw) {
pcm_sw_fini (sw);
pcm_hw_del_sw (sw->hw, sw);
pcm_hw_gc (sw->hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
sw = NULL;
}
if (sw) {
HWVoice *hw = sw->hw;
if (!hw) {
dolog ("Internal logic error voice %s has no hardware store\n",
name);
return sw;
}
if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
pcm_sw_fini (sw);
pcm_hw_del_sw (hw, sw);
pcm_hw_gc (hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
return NULL;
}
}
else {
sw = pcm_create_voice_pair (freq, nchannels, fmt);
if (!sw) {
dolog ("Failed to create voice %s\n", name);
return NULL;
}
}
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
sw->name = qemu_strdup (name);
return sw;
}
void AUD_close (SWVoice *sw)
{
if (!sw)
return;
pcm_sw_fini (sw);
pcm_hw_del_sw (sw->hw, sw);
pcm_hw_gc (sw->hw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
qemu_free (sw);
}
int AUD_write (SWVoice *sw, void *buf, int size)
{
int bytes;
if (!sw->hw->enabled)
dolog ("Writing to disabled voice %s\n", sw->name);
bytes = sw->hw->pcm_ops->write (sw, buf, size);
return bytes;
}
void AUD_run (void)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any_active_enabled (hw))) {
int i;
if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
hw->enabled = 0;
hw->pcm_ops->ctl (hw, VOICE_DISABLE);
for (i = 0; i < hw->nb_voices; i++) {
hw->pvoice[i]->live = 0;
/* hw->pvoice[i]->old_ticks = 0; */
}
continue;
}
hw->pcm_ops->run (hw);
assert (hw->rpos < hw->samples);
for (i = 0; i < hw->nb_voices; i++) {
SWVoice *sw = hw->pvoice[i];
if (!sw->active && !sw->live && sw->old_ticks) {
int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
if (delta > audio_state.ticks_threshold) {
ldebug ("resetting old_ticks for %s\n", sw->name);
sw->old_ticks = 0;
}
}
}
}
}
int AUD_get_free (SWVoice *sw)
{
int free;
if (!sw)
return 4096;
free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
/ INT_MAX;
free &= ~sw->hw->align;
if (!free) return 0;
return free;
}
int AUD_get_buffer_size (SWVoice *sw)
{
return sw->hw->bufsize;
}
void AUD_adjust (SWVoice *sw, int bytes)
{
if (!sw)
return;
sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
}
void AUD_reset (SWVoice *sw)
{
sw->active = 0;
sw->old_ticks = 0;
}
int AUD_calc_elapsed (SWVoice *sw)
{
int64_t now, delta, bytes;
int dead, swlim;
if (!sw)
return 0;
now = qemu_get_clock (vm_clock);
delta = now - sw->old_ticks;
bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
if (delta < 0) {
dolog ("whoops delta(<0)=%lld\n", delta);
return 0;
}
dead = sw->hw->samples - sw->live;
swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
if (bytes > swlim) {
return swlim;
}
else {
return bytes;
}
}
void AUD_enable (SWVoice *sw, int on)
{
int i;
HWVoice *hw;
if (!sw)
return;
hw = sw->hw;
if (on) {
if (!sw->live)
sw->wpos = sw->hw->rpos;
if (!sw->old_ticks) {
sw->old_ticks = qemu_get_clock (vm_clock);
}
}
if (sw->active != on) {
if (on) {
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
for (i = 0; i < hw->nb_voices; i++) {
ldebug ("resetting voice\n");
sw = hw->pvoice[i];
sw->old_ticks = qemu_get_clock (vm_clock);
}
hw->pcm_ops->ctl (hw, VOICE_ENABLE);
}
}
else {
if (hw->enabled && !hw->pending_disable) {
int nb_active = 0;
for (i = 0; i < hw->nb_voices; i++) {
nb_active += hw->pvoice[i]->active != 0;
}
if (nb_active == 1) {
hw->pending_disable = 1;
}
}
}
sw->active = on;
}
}
static struct audio_output_driver *drvtab[] = {
#ifdef CONFIG_OSS
&oss_output_driver,
#endif
#ifdef CONFIG_FMOD
&fmod_output_driver,
#endif
#ifdef CONFIG_SDL
&sdl_output_driver,
#endif
&no_output_driver,
#ifdef USE_WAV_AUDIO
&wav_output_driver,
#endif
};
static int voice_init (struct audio_output_driver *drv)
{
audio_state.opaque = drv->init ();
if (audio_state.opaque) {
if (audio_state.nb_hw_voices > drv->max_voices) {
dolog ("`%s' does not support %d multiple hardware channels\n"
"Resetting to %d\n",
drv->name, audio_state.nb_hw_voices, drv->max_voices);
audio_state.nb_hw_voices = drv->max_voices;
}
hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
if (hw_voices) {
audio_state.drv = drv;
return 1;
}
else {
dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
audio_state.nb_hw_voices, drv->name, drv->voice_size);
drv->fini (audio_state.opaque);
return 0;
}
}
else {
dolog ("Could not init `%s' audio\n", drv->name);
return 0;
}
}
static void audio_vm_stop_handler (void *opaque, int reason)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any (hw))) {
if (!hw->pcm_ops)
continue;
hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
}
}
static void audio_atexit (void)
{
HWVoice *hw = NULL;
while ((hw = pcm_hw_find_any (hw))) {
if (!hw->pcm_ops)
continue;
hw->pcm_ops->ctl (hw, VOICE_DISABLE);
hw->pcm_ops->fini (hw);
}
audio_state.drv->fini (audio_state.opaque);
}
static void audio_save (QEMUFile *f, void *opaque)
{
}
static int audio_load (QEMUFile *f, void *opaque, int version_id)
{
if (version_id != 1)
return -EINVAL;
return 0;
}
void AUD_init (void)
{
int i;
int done = 0;
const char *drvname;
audio_state.fixed_format =
!!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
audio_state.fixed_freq =
audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
audio_state.nb_hw_voices =
audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
if (audio_state.nb_hw_voices <= 0) {
dolog ("Bogus number of voices %d, resetting to 1\n",
audio_state.nb_hw_voices);
}
drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
if (drvname) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drvname, drvtab[i]->name)) {
done = voice_init (drvtab[i]);
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown audio driver `%s'\n", drvname);
}
}
qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
atexit (audio_atexit);
if (!done) {
for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (drvtab[i]->can_be_default)
done = voice_init (drvtab[i]);
}
}
audio_state.ticks_threshold = ticks_per_sec / 50;
audio_state.freq_threshold = 100;
register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
if (!done) {
dolog ("Can not initialize audio subsystem\n");
voice_init (&no_output_driver);
}
}

View File

@@ -1,65 +0,0 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "mixeng.h"
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
typedef struct SWVoice SWVoice;
SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
int nchannels, audfmt_e fmt);
void AUD_init (void);
void AUD_log (const char *cap, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));;
void AUD_close (SWVoice *sw);
int AUD_write (SWVoice *sw, void *pcm_buf, int size);
void AUD_adjust (SWVoice *sw, int leftover);
void AUD_reset (SWVoice *sw);
int AUD_get_free (SWVoice *sw);
int AUD_get_buffer_size (SWVoice *sw);
void AUD_run (void);
void AUD_enable (SWVoice *sw, int on);
int AUD_calc_elapsed (SWVoice *sw);
static inline void *advance (void *p, int incr)
{
uint8_t *d = p;
return (d + incr);
}
uint32_t popcount (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
#define audio_MIN(a, b) ((a)>(b)?(b):(a))
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
#endif /* audio.h */

View File

@@ -1,163 +0,0 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_AUDIO_INT_H
#define QEMU_AUDIO_INT_H
#include "vl.h"
struct pcm_ops;
typedef struct HWVoice {
int active;
int enabled;
int pending_disable;
int valid;
int freq;
f_sample *clip;
audfmt_e fmt;
int nchannels;
int align;
int shift;
int rpos;
int bufsize;
int bytes_per_second;
st_sample_t *mix_buf;
int samples;
int64_t old_ticks;
int nb_voices;
struct SWVoice **pvoice;
struct pcm_ops *pcm_ops;
} HWVoice;
extern struct pcm_ops no_pcm_ops;
extern struct audio_output_driver no_output_driver;
extern struct pcm_ops oss_pcm_ops;
extern struct audio_output_driver oss_output_driver;
extern struct pcm_ops sdl_pcm_ops;
extern struct audio_output_driver sdl_output_driver;
extern struct pcm_ops wav_pcm_ops;
extern struct audio_output_driver wav_output_driver;
extern struct pcm_ops fmod_pcm_ops;
extern struct audio_output_driver fmod_output_driver;
struct audio_output_driver {
const char *name;
void *(*init) (void);
void (*fini) (void *);
struct pcm_ops *pcm_ops;
int can_be_default;
int max_voices;
int voice_size;
};
typedef struct AudioState {
int fixed_format;
int fixed_freq;
int fixed_channels;
int fixed_fmt;
int nb_hw_voices;
int64_t ticks_threshold;
int freq_threshold;
void *opaque;
struct audio_output_driver *drv;
} AudioState;
extern AudioState audio_state;
struct SWVoice {
int freq;
audfmt_e fmt;
int nchannels;
int shift;
int align;
t_sample *conv;
int left;
int pos;
int bytes_per_second;
int64_t ratio;
st_sample_t *buf;
void *rate;
int wpos;
int live;
int active;
int64_t old_ticks;
HWVoice *hw;
char *name;
};
struct pcm_ops {
int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
void (*fini) (HWVoice *hw);
void (*run) (HWVoice *hw);
int (*write) (SWVoice *sw, void *buf, int size);
int (*ctl) (HWVoice *hw, int cmd, ...);
};
void pcm_sw_free_resources (SWVoice *sw);
int pcm_sw_alloc_resources (SWVoice *sw);
void pcm_sw_fini (SWVoice *sw);
int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
void pcm_hw_clear (HWVoice *hw, void *buf, int len);
HWVoice * pcm_hw_find_any (HWVoice *hw);
HWVoice * pcm_hw_find_any_active (HWVoice *hw);
HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
int nchannels, audfmt_e fmt);
HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
void pcm_hw_free_resources (HWVoice *hw);
int pcm_hw_alloc_resources (HWVoice *hw);
void pcm_hw_fini (HWVoice *hw);
void pcm_hw_gc (HWVoice *hw);
int pcm_hw_get_live (HWVoice *hw);
int pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
void pcm_hw_dec_live (HWVoice *hw, int decr);
int pcm_hw_write (SWVoice *sw, void *buf, int len);
int audio_get_conf_int (const char *key, int defval);
const char *audio_get_conf_str (const char *key, const char *defval);
struct audio_output_driver;
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
#endif /* audio_int.h */

View File

@@ -1,469 +0,0 @@
/*
* QEMU FMOD audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <fmod.h>
#include <fmod_errors.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct FMODVoice {
HWVoice hw;
unsigned int old_pos;
FSOUND_SAMPLE *fmod_sample;
int channel;
} FMODVoice;
#define dolog(...) AUD_log ("fmod", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_FMOD_DRV "QEMU_FMOD_DRV"
#define QC_FMOD_FREQ "QEMU_FMOD_FREQ"
#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES"
#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS"
#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE"
#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD"
static struct {
int nb_samples;
int freq;
int nb_channels;
int bufsize;
int threshold;
} conf = {
2048,
44100,
1,
0,
128
};
#define errstr() FMOD_ErrorString (FSOUND_GetError ())
static int fmod_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static void fmod_clear_sample (FMODVoice *fmd)
{
HWVoice *hw = &fmd->hw;
int status;
void *p1 = 0, *p2 = 0;
unsigned int len1 = 0, len2 = 0;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
0,
hw->samples << hw->shift,
&p1,
&p2,
&len1,
&len2
);
if (!status) {
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return;
}
if ((len1 & hw->align) || (len2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
len1, len2);
goto fail;
}
if (len1 + len2 != hw->samples << hw->shift) {
dolog ("Locking sample returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->shift);
goto fail;
}
pcm_hw_clear (hw, p1, hw->samples);
fail:
status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
if (!status) {
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
}
}
static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src,
int src_size, int src_pos, int dst_len)
{
int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
st_sample_t *src1 = src + src_pos, *src2 = 0;
if (src_pos + dst_len > src_size) {
src_len1 = src_size - src_pos;
src2 = src;
src_len2 = dst_len - src_len1;
pos = src_len2;
}
if (src_len1) {
hw->clip (dst, src1, src_len1);
memset (src1, 0, src_len1 * sizeof (st_sample_t));
advance (dst, src_len1);
}
if (src_len2) {
hw->clip (dst, src2, src_len2);
memset (src2, 0, src_len2 * sizeof (st_sample_t));
}
return pos;
}
static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
unsigned int blen1, unsigned int blen2)
{
int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
if (!status) {
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
void **p1, void **p2,
unsigned int *blen1, unsigned int *blen2)
{
HWVoice *hw = &fmd->hw;
int status;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
pos << hw->shift,
len << hw->shift,
p1,
p2,
blen1,
blen2
);
if (!status) {
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return -1;
}
if ((*blen1 & hw->align) || (*blen2 & hw->align)) {
dolog ("Locking sample returned unaligned length %d, %d\n",
*blen1, *blen2);
fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2);
return -1;
}
return 0;
}
static void fmod_hw_run (HWVoice *hw)
{
FMODVoice *fmd = (FMODVoice *) hw;
int rpos, live, decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
int nb_active;
live = pcm_hw_get_live2 (hw, &nb_active);
if (live <= 0) {
return;
}
if (!hw->pending_disable
&& nb_active
&& conf.threshold
&& live <= conf.threshold) {
ldebug ("live=%d nb_active=%d\n", live, nb_active);
return;
}
decr = live;
#if 1
if (fmd->channel >= 0) {
int pos2 = (fmd->old_pos + decr) % hw->samples;
int pos = FSOUND_GetCurrentPosition (fmd->channel);
if (fmd->old_pos < pos && pos2 >= pos) {
decr = pos - fmd->old_pos - (pos2 == pos) - 1;
}
else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) {
decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1;
}
/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */
/* pos, pos2, fmd->old_pos, live, decr); */
}
#endif
if (decr <= 0) {
return;
}
if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
return;
}
len1 = blen1 >> hw->shift;
len2 = blen2 >> hw->shift;
ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
decr = len1 + len2;
rpos = hw->rpos;
if (len1) {
rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
}
if (len2) {
rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
}
fmod_unlock_sample (fmd, p1, p2, blen1, blen2);
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos % hw->samples;
fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
}
static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
{
int mode = FSOUND_LOOP_NORMAL;
switch (fmt) {
case AUD_FMT_S8:
mode |= FSOUND_SIGNED | FSOUND_8BITS;
break;
case AUD_FMT_U8:
mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
break;
case AUD_FMT_S16:
mode |= FSOUND_SIGNED | FSOUND_16BITS;
break;
case AUD_FMT_U16:
mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
break;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
return mode;
}
static void fmod_hw_fini (HWVoice *hw)
{
FMODVoice *fmd = (FMODVoice *) hw;
if (fmd->fmod_sample) {
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
if (fmd->channel >= 0) {
FSOUND_StopSound (fmd->channel);
}
}
}
static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int bits16, mode, channel;
FMODVoice *fmd = (FMODVoice *) hw;
mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ());
return -1;
}
channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
if (channel < 0) {
dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
FSOUND_Sample_Free (fmd->fmod_sample);
return -1;
}
fmd->channel = channel;
hw->freq = freq;
hw->fmt = fmt;
hw->nchannels = nchannels;
bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16;
hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16;
return 0;
}
static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
{
int status;
FMODVoice *fmd = (FMODVoice *) hw;
switch (cmd) {
case VOICE_ENABLE:
fmod_clear_sample (fmd);
status = FSOUND_SetPaused (fmd->channel, 0);
if (!status) {
dolog ("Failed to resume channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
case VOICE_DISABLE:
status = FSOUND_SetPaused (fmd->channel, 1);
if (!status) {
dolog ("Failed to pause channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
}
return 0;
}
static struct {
const char *name;
int type;
} drvtab[] = {
{"none", FSOUND_OUTPUT_NOSOUND},
#ifdef _WIN32
{"winmm", FSOUND_OUTPUT_WINMM},
{"dsound", FSOUND_OUTPUT_DSOUND},
{"a3d", FSOUND_OUTPUT_A3D},
{"asio", FSOUND_OUTPUT_ASIO},
#endif
#ifdef __linux__
{"oss", FSOUND_OUTPUT_OSS},
{"alsa", FSOUND_OUTPUT_ALSA},
{"esd", FSOUND_OUTPUT_ESD},
#endif
#ifdef __APPLE__
{"mac", FSOUND_OUTPUT_MAC},
#endif
#if 0
{"xbox", FSOUND_OUTPUT_XBOX},
{"ps2", FSOUND_OUTPUT_PS2},
{"gcube", FSOUND_OUTPUT_GC},
#endif
{"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
};
static void *fmod_audio_init (void)
{
int i;
double ver;
int status;
int output_type = -1;
const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
ver = FSOUND_GetVersion ();
if (ver < FMOD_VERSION) {
dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
return NULL;
}
if (drv) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
if (!strcmp (drv, drvtab[i].name)) {
output_type = drvtab[i].type;
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown FMOD output driver `%s'\n", drv);
}
}
if (output_type != -1) {
status = FSOUND_SetOutput (output_type);
if (!status) {
dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n",
output_type, errstr ());
return NULL;
}
}
conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq);
conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples);
conf.nb_channels =
audio_get_conf_int (QC_FMOD_CHANNELS,
(audio_state.nb_hw_voices > 1
? audio_state.nb_hw_voices
: conf.nb_channels));
conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize);
conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold);
if (conf.bufsize) {
status = FSOUND_SetBufferSize (conf.bufsize);
if (!status) {
dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
conf.bufsize, errstr ());
}
}
status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
if (!status) {
dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
return NULL;
}
return &conf;
}
static void fmod_audio_fini (void *opaque)
{
FSOUND_Close ();
}
struct pcm_ops fmod_pcm_ops = {
fmod_hw_init,
fmod_hw_fini,
fmod_hw_run,
fmod_hw_write,
fmod_hw_ctl
};
struct audio_output_driver fmod_output_driver = {
"fmod",
fmod_audio_init,
fmod_audio_fini,
&fmod_pcm_ops,
1,
INT_MAX,
sizeof (FMODVoice)
};

View File

@@ -1,255 +0,0 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004 Vassili Karpov (malc)
* Copyright (c) 1998 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_FP
#include "audio/mixeng.h"
#define IN_T int8_t
#define IN_MIN CHAR_MIN
#define IN_MAX CHAR_MAX
#define SIGNED
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T uint8_t
#define IN_MIN 0
#define IN_MAX UCHAR_MAX
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T int16_t
#define IN_MIN SHRT_MIN
#define IN_MAX SHRT_MAX
#define SIGNED
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#define IN_T uint16_t
#define IN_MIN 0
#define IN_MAX USHRT_MAX
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
t_sample *mixeng_conv[2][2][2] = {
{
{
conv_uint8_t_to_mono,
conv_uint16_t_to_mono
},
{
conv_int8_t_to_mono,
conv_int16_t_to_mono
}
},
{
{
conv_uint8_t_to_stereo,
conv_uint16_t_to_stereo
},
{
conv_int8_t_to_stereo,
conv_int16_t_to_stereo
}
}
};
f_sample *mixeng_clip[2][2][2] = {
{
{
clip_uint8_t_from_mono,
clip_uint16_t_from_mono
},
{
clip_int8_t_from_mono,
clip_int16_t_from_mono
}
},
{
{
clip_uint8_t_from_stereo,
clip_uint16_t_from_stereo
},
{
clip_int8_t_from_stereo,
clip_int16_t_from_stereo
}
}
};
/*
* August 21, 1998
* Copyright 1998 Fabrice Bellard.
*
* [Rewrote completly the code of Lance Norskog And Sundry
* Contributors with a more efficient algorithm.]
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* Sound Tools rate change effect file.
*/
/*
* Linear Interpolation.
*
* The use of fractional increment allows us to use no buffer. It
* avoid the problems at the end of the buffer we had with the old
* method which stored a possibly big buffer of size
* lcm(in_rate,out_rate).
*
* Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
* the input & output frequencies are equal, a delay of one sample is
* introduced. Limited to processing 32-bit count worth of samples.
*
* 1 << FRAC_BITS evaluating to zero in several places. Changed with
* an (unsigned long) cast to make it safe. MarkMLl 2/1/99
*/
/* Private data */
typedef struct ratestuff {
uint64_t opos;
uint64_t opos_inc;
uint32_t ipos; /* position in the input stream (integer) */
st_sample_t ilast; /* last sample in the input stream */
} *rate_t;
/*
* Prepare processing.
*/
void *st_rate_start (int inrate, int outrate)
{
rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
if (!rate) {
exit (EXIT_FAILURE);
}
if (inrate == outrate) {
// exit (EXIT_FAILURE);
}
if (inrate >= 65535 || outrate >= 65535) {
// exit (EXIT_FAILURE);
}
rate->opos = 0;
/* increment */
rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
rate->ipos = 0;
rate->ilast.l = 0;
rate->ilast.r = 0;
return rate;
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp)
{
rate_t rate = (rate_t) opaque;
st_sample_t *istart, *iend;
st_sample_t *ostart, *oend;
st_sample_t ilast, icur, out;
int64_t t;
ilast = rate->ilast;
istart = ibuf;
iend = ibuf + *isamp;
ostart = obuf;
oend = obuf + *osamp;
if (rate->opos_inc == 1ULL << 32) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
obuf[i].l += ibuf[i].r;
obuf[i].r += ibuf[i].r;
}
*isamp = n;
*osamp = n;
return;
}
while (obuf < oend) {
/* Safety catch to make sure we have input samples. */
if (ibuf >= iend)
break;
/* read as many input samples so that ipos > opos */
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
/* See if we finished the input buffer yet */
if (ibuf >= iend) goto the_end;
}
icur = *ibuf;
/* interpolate */
t = rate->opos & 0xffffffff;
out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
/* output sample & increment position */
#if 0
*obuf++ = out;
#else
obuf->l += out.l;
obuf->r += out.r;
obuf += 1;
#endif
rate->opos += rate->opos_inc;
}
the_end:
*isamp = ibuf - istart;
*osamp = obuf - ostart;
rate->ilast = ilast;
}
void st_rate_stop (void *opaque)
{
qemu_free (opaque);
}

View File

@@ -1,39 +0,0 @@
/*
* QEMU Mixing engine header
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_MIXENG_H
#define QEMU_MIXENG_H
typedef void (t_sample) (void *dst, const void *src, int samples);
typedef void (f_sample) (void *dst, const void *src, int samples);
typedef struct { int64_t l; int64_t r; } st_sample_t;
extern t_sample *mixeng_conv[2][2][2];
extern f_sample *mixeng_clip[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,
int *isamp, int *osamp);
void st_rate_stop (void *opaque);
#endif /* mixeng.h */

View File

@@ -1,111 +0,0 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Tusen tack till Mike Nordell
* dec++'ified by Dscho
*/
#ifdef SIGNED
#define HALFT IN_MAX
#define HALF IN_MAX
#else
#define HALFT ((IN_MAX)>>1)
#define HALF HALFT
#endif
static int64_t inline glue(conv_,IN_T) (IN_T v)
{
#ifdef SIGNED
return (INT_MAX*(int64_t)v)/HALF;
#else
return (INT_MAX*((int64_t)v-HALFT))/HALF;
#endif
}
static IN_T inline glue(clip_,IN_T) (int64_t v)
{
if (v >= INT_MAX)
return IN_MAX;
else if (v < -INT_MAX)
return IN_MIN;
#ifdef SIGNED
return (IN_T) (v*HALF/INT_MAX);
#else
return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
#endif
}
static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
int samples)
{
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
while (samples--) {
out->l = glue(conv_,IN_T) (*in++);
out->r = glue(conv_,IN_T) (*in++);
out += 1;
}
}
static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
while (samples--) {
out->l = glue(conv_,IN_T) (in[0]);
out->r = out->l;
out += 1;
in += 1;
}
}
static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
int samples)
{
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue(clip_,IN_T) (in->l);
*out++ = glue(clip_,IN_T) (in->r);
in += 1;
}
}
static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue(clip_,IN_T) (in->l + in->r);
in += 1;
}
}
#undef HALF
#undef HALFT

View File

@@ -1,128 +0,0 @@
/*
* QEMU NULL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "audio/audio_int.h"
typedef struct NoVoice {
HWVoice hw;
int64_t old_ticks;
} NoVoice;
#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static void no_hw_run (HWVoice *hw)
{
NoVoice *no = (NoVoice *) hw;
int rpos, live, decr, samples;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
no->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int no_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
hw->freq = freq;
hw->nchannels = nchannels;
hw->fmt = fmt;
hw->bufsize = 4096;
return 0;
}
static void no_hw_fini (HWVoice *hw)
{
(void) hw;
}
static int no_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *no_audio_init (void)
{
return &no_audio_init;
}
static void no_audio_fini (void *opaque)
{
}
struct pcm_ops no_pcm_ops = {
no_hw_init,
no_hw_fini,
no_hw_run,
no_hw_write,
no_hw_ctl
};
struct audio_output_driver no_output_driver = {
"none",
no_audio_init,
no_audio_fini,
&no_pcm_ops,
1,
1,
sizeof (NoVoice)
};

View File

@@ -1,475 +0,0 @@
/*
* QEMU OSS audio output driver
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <assert.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct OSSVoice {
HWVoice hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int mmapped;
int old_optr;
} OSSVoice;
#define dolog(...) AUD_log ("oss", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
#define QC_OSS_MMAP "QEMU_OSS_MMAP"
#define QC_OSS_DEV "QEMU_OSS_DEV"
#define errstr() strerror (errno)
static struct {
int try_mmap;
int nfrags;
int fragsize;
const char *dspname;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.dspname = "/dev/dsp"
};
struct oss_params {
int freq;
audfmt_e fmt;
int nchannels;
int nfrags;
int fragsize;
};
static int oss_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
static int AUD_to_ossfmt (audfmt_e fmt)
{
switch (fmt) {
case AUD_FMT_S8: return AFMT_S8;
case AUD_FMT_U8: return AFMT_U8;
case AUD_FMT_S16: return AFMT_S16_LE;
case AUD_FMT_U16: return AFMT_U16_LE;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int oss_to_audfmt (int fmt)
{
switch (fmt) {
case AFMT_S8: return AUD_FMT_S8;
case AFMT_U8: return AUD_FMT_U8;
case AFMT_S16_LE: return AUD_FMT_S16;
case AFMT_U16_LE: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
"Aborting\n",
fmt);
exit (EXIT_FAILURE);
}
}
#ifdef DEBUG_PCM
static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
{
dolog ("parameter | requested value | obtained value\n");
dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels);
dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize);
}
#endif
static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
{
int fd;
int mmmmssss;
audio_buf_info abinfo;
int fmt, freq, nchannels;
const char *dspname = conf.dspname;
fd = open (dspname, O_WRONLY | O_NONBLOCK);
if (-1 == fd) {
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
"Reason:%s\n",
dspname,
errstr ());
return -1;
}
freq = req->freq;
nchannels = req->nchannels;
fmt = req->fmt;
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set sample size\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set number of channels\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set frequency\n"
"Reason: %s\n",
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set non-blocking mode\n"
"Reason: %s\n",
errstr ());
goto err;
}
mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
dolog ("Could not initialize audio hardware\n"
"Failed to set buffer length (%d, %d)\n"
"Reason:%s\n",
conf.nfrags, conf.fragsize,
errstr ());
goto err;
}
if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
dolog ("Could not initialize audio hardware\n"
"Failed to get buffer length\n"
"Reason:%s\n",
errstr ());
goto err;
}
obt->fmt = fmt;
obt->nchannels = nchannels;
obt->freq = freq;
obt->nfrags = abinfo.fragstotal;
obt->fragsize = abinfo.fragsize;
*pfd = fd;
if ((req->fmt != obt->fmt) ||
(req->nchannels != obt->nchannels) ||
(req->freq != obt->freq) ||
(req->fragsize != obt->fragsize) ||
(req->nfrags != obt->nfrags)) {
#ifdef DEBUG_PCM
dolog ("Audio parameters mismatch\n");
oss_dump_pcm_info (req, obt);
#endif
}
#ifdef DEBUG_PCM
oss_dump_pcm_info (req, obt);
#endif
return 0;
err:
close (fd);
return -1;
}
static void oss_hw_run (HWVoice *hw)
{
OSSVoice *oss = (OSSVoice *) hw;
int err, rpos, live, decr;
int samples;
uint8_t *dst;
st_sample_t *src;
struct audio_buf_info abinfo;
struct count_info cntinfo;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
if (oss->mmapped) {
int bytes;
err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
if (err < 0) {
dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
return;
}
if (cntinfo.ptr == oss->old_optr) {
if (abs (hw->samples - live) < 64)
dolog ("overrun\n");
return;
}
if (cntinfo.ptr > oss->old_optr) {
bytes = cntinfo.ptr - oss->old_optr;
}
else {
bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
}
decr = audio_MIN (bytes >> hw->shift, live);
}
else {
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
if (err < 0) {
dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
return;
}
decr = audio_MIN (abinfo.bytes >> hw->shift, live);
if (decr <= 0)
return;
}
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (oss->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
if (!oss->mmapped) {
int written;
written = write (oss->fd, dst, convert_samples << hw->shift);
/* XXX: follow errno recommendations ? */
if (written == -1) {
dolog ("Failed to write audio\nReason: %s\n", errstr ());
continue;
}
if (written != convert_samples << hw->shift) {
int wsamples = written >> hw->shift;
int wbytes = wsamples << hw->shift;
if (wbytes != written) {
dolog ("Unaligned write %d, %d\n", wbytes, written);
}
memset (src, 0, wbytes);
decr -= samples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
if (oss->mmapped) {
oss->old_optr = cntinfo.ptr;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static void oss_hw_fini (HWVoice *hw)
{
int err;
OSSVoice *oss = (OSSVoice *) hw;
ldebug ("oss_hw_fini\n");
err = close (oss->fd);
if (err) {
dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
}
oss->fd = -1;
if (oss->pcm_buf) {
if (oss->mmapped) {
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
dolog ("Failed to unmap OSS buffer\nReason: %s\n",
errstr ());
}
}
else {
qemu_free (oss->pcm_buf);
}
oss->pcm_buf = NULL;
}
}
static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
OSSVoice *oss = (OSSVoice *) hw;
struct oss_params req, obt;
assert (!oss->fd);
req.fmt = AUD_to_ossfmt (fmt);
req.freq = freq;
req.nchannels = nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (&req, &obt, &oss->fd))
return -1;
hw->freq = obt.freq;
hw->fmt = oss_to_audfmt (obt.fmt);
hw->nchannels = obt.nchannels;
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
hw->bufsize = obt.nfrags * obt.fragsize;
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
MAP_SHARED, oss->fd, 0);
if (oss->pcm_buf == MAP_FAILED) {
dolog ("Failed to mmap OSS device\nReason: %s\n",
errstr ());
} else {
int err;
int trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
}
else {
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
}
else {
oss->mmapped = 1;
}
}
if (!oss->mmapped) {
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
dolog ("Failed to unmap OSS device\nReason: %s\n",
errstr ());
}
}
}
}
if (!oss->mmapped) {
oss->pcm_buf = qemu_mallocz (hw->bufsize);
if (!oss->pcm_buf) {
close (oss->fd);
oss->fd = -1;
return -1;
}
}
return 0;
}
static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
{
int trig;
OSSVoice *oss = (OSSVoice *) hw;
if (!oss->mmapped)
return 0;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
return -1;
}
break;
case VOICE_DISABLE:
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
return -1;
}
break;
}
return 0;
}
static void *oss_audio_init (void)
{
conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
return &conf;
}
static void oss_audio_fini (void *opaque)
{
}
struct pcm_ops oss_pcm_ops = {
oss_hw_init,
oss_hw_fini,
oss_hw_run,
oss_hw_write,
oss_hw_ctl
};
struct audio_output_driver oss_output_driver = {
"oss",
oss_audio_init,
oss_audio_fini,
&oss_pcm_ops,
1,
INT_MAX,
sizeof (OSSVoice)
};

View File

@@ -1,332 +0,0 @@
/*
* QEMU SDL audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <SDL.h>
#include <SDL_thread.h>
#include "vl.h"
#include "audio/audio_int.h"
typedef struct SDLVoice {
HWVoice hw;
} SDLVoice;
#define dolog(...) AUD_log ("sdl", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
#define errstr() SDL_GetError ()
static struct {
int nb_samples;
} conf = {
1024
};
struct SDLAudioState {
int exit;
SDL_mutex *mutex;
SDL_sem *sem;
int initialized;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
static void sdl_hw_run (HWVoice *hw)
{
(void) hw;
}
static int sdl_lock (SDLAudioState *s)
{
if (SDL_LockMutex (s->mutex)) {
dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock (SDLAudioState *s)
{
if (SDL_UnlockMutex (s->mutex)) {
dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_post (SDLAudioState *s)
{
if (SDL_SemPost (s->sem)) {
dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_wait (SDLAudioState *s)
{
if (SDL_SemWait (s->sem)) {
dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock_and_post (SDLAudioState *s)
{
if (sdl_unlock (s))
return -1;
return sdl_post (s);
}
static int sdl_hw_write (SWVoice *sw, void *buf, int len)
{
int ret;
SDLAudioState *s = &glob_sdl;
sdl_lock (s);
ret = pcm_hw_write (sw, buf, len);
sdl_unlock_and_post (s);
return ret;
}
static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
{
*shift = 0;
switch (fmt) {
case AUD_FMT_S8: return AUDIO_S8;
case AUD_FMT_U8: return AUDIO_U8;
case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
default:
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_to_audfmt (int fmt)
{
switch (fmt) {
case AUDIO_S8: return AUD_FMT_S8;
case AUDIO_U8: return AUD_FMT_U8;
case AUDIO_S16LSB: return AUD_FMT_S16;
case AUDIO_U16LSB: return AUD_FMT_U16;
default:
dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
"Aborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
{
int status;
status = SDL_OpenAudio (req, obt);
if (status) {
dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
}
return status;
}
static void sdl_close (SDLAudioState *s)
{
if (s->initialized) {
sdl_lock (s);
s->exit = 1;
sdl_unlock_and_post (s);
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
}
}
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
SDLVoice *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoice *hw = &sdl->hw;
int samples = len >> hw->shift;
if (s->exit) {
return;
}
while (samples) {
int to_mix, live, decr;
/* dolog ("in callback samples=%d\n", samples); */
sdl_wait (s);
if (s->exit) {
return;
}
sdl_lock (s);
live = pcm_hw_get_live (hw);
if (live <= 0)
goto again;
/* dolog ("in callback live=%d\n", live); */
to_mix = audio_MIN (samples, live);
decr = to_mix;
while (to_mix) {
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
st_sample_t *src = hw->mix_buf + hw->rpos;
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
memset (src, 0, chunk * sizeof (st_sample_t));
hw->rpos = (hw->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->shift;
}
samples -= decr;
pcm_hw_dec_live (hw, decr);
again:
sdl_unlock (s);
}
/* dolog ("done len=%d\n", len); */
}
static void sdl_hw_fini (HWVoice *hw)
{
ldebug ("sdl_hw_fini %d fixed=%d\n",
glob_sdl.initialized, audio_state.fixed_format);
sdl_close (&glob_sdl);
}
static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
SDLVoice *sdl = (SDLVoice *) hw;
SDLAudioState *s = &glob_sdl;
SDL_AudioSpec req, obt;
int shift;
ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
s->initialized, freq, audio_state.fixed_format);
if (nchannels != 2) {
dolog ("Bogus channel count %d\n", nchannels);
return -1;
}
req.freq = freq;
req.format = AUD_to_sdlfmt (fmt, &shift);
req.channels = nchannels;
req.samples = conf.nb_samples;
shift <<= nchannels == 2;
req.callback = sdl_callback;
req.userdata = sdl;
if (sdl_open (&req, &obt))
return -1;
hw->freq = obt.freq;
hw->fmt = sdl_to_audfmt (obt.format);
hw->nchannels = obt.channels;
hw->bufsize = obt.samples << shift;
s->initialized = 1;
s->exit = 0;
SDL_PauseAudio (0);
return 0;
}
static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
switch (cmd) {
case VOICE_ENABLE:
SDL_PauseAudio (0);
break;
case VOICE_DISABLE:
SDL_PauseAudio (1);
break;
}
return 0;
}
static void *sdl_audio_init (void)
{
SDLAudioState *s = &glob_sdl;
conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
errstr ());
return NULL;
}
s->mutex = SDL_CreateMutex ();
if (!s->mutex) {
dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
s->sem = SDL_CreateSemaphore (0);
if (!s->sem) {
dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
return s;
}
static void sdl_audio_fini (void *opaque)
{
SDLAudioState *s = opaque;
sdl_close (s);
SDL_DestroySemaphore (s->sem);
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
}
struct pcm_ops sdl_pcm_ops = {
sdl_hw_init,
sdl_hw_fini,
sdl_hw_run,
sdl_hw_write,
sdl_hw_ctl
};
struct audio_output_driver sdl_output_driver = {
"sdl",
sdl_audio_init,
sdl_audio_fini,
&sdl_pcm_ops,
1,
1,
sizeof (SDLVoice)
};

View File

@@ -1,217 +0,0 @@
/*
* QEMU WAV audio output driver
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "audio/audio_int.h"
typedef struct WAVVoice {
HWVoice hw;
QEMUFile *f;
int64_t old_ticks;
void *pcm_buf;
int total_samples;
} WAVVoice;
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static struct {
const char *wav_path;
} conf = {
.wav_path = "qemu.wav"
};
static void wav_hw_run (HWVoice *hw)
{
WAVVoice *wav = (WAVVoice *) hw;
int rpos, live, decr, samples;
uint8_t *dst;
st_sample_t *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - wav->old_ticks;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
wav->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
dst = advance (wav->pcm_buf, rpos << hw->shift);
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
memset (src, 0, convert_samples * sizeof (st_sample_t));
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
wav->total_samples += convert_samples;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int wav_hw_write (SWVoice *sw, void *buf, int len)
{
return pcm_hw_write (sw, buf, len);
}
/* 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 int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
WAVVoice *wav = (WAVVoice *) hw;
int bits16 = 0, stereo = audio_state.fixed_channels == 2;
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
};
switch (audio_state.fixed_fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
bits16 = 1;
break;
}
hdr[34] = bits16 ? 0x10 : 0x08;
hw->freq = 44100;
hw->nchannels = stereo ? 2 : 1;
hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
hw->bufsize = 4096;
wav->pcm_buf = qemu_mallocz (hw->bufsize);
if (!wav->pcm_buf)
return -1;
le_store (hdr + 22, hw->nchannels, 2);
le_store (hdr + 24, hw->freq, 4);
le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
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));
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
return -1;
}
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
return 0;
}
static void wav_hw_fini (HWVoice *hw)
{
WAVVoice *wav = (WAVVoice *) hw;
int stereo = hw->nchannels == 2;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t rifflen = (wav->total_samples << stereo) + 36;
uint32_t datalen = wav->total_samples << stereo;
if (!wav->f || !hw->active)
return;
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
wav->f = NULL;
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
}
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static void *wav_audio_init (void)
{
return &conf;
}
static void wav_audio_fini (void *opaque)
{
ldebug ("wav_fini");
}
struct pcm_ops wav_pcm_ops = {
wav_hw_init,
wav_hw_fini,
wav_hw_run,
wav_hw_write,
wav_hw_ctl
};
struct audio_output_driver wav_output_driver = {
"wav",
wav_audio_init,
wav_audio_fini,
&wav_pcm_ops,
1,
1,
sizeof (WAVVoice)
};

View File

@@ -1,224 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
/**************************************************************/
#define HEADER_MAGIC "Bochs Virtual HD Image"
#define HEADER_VERSION 0x00010000
#define HEADER_SIZE 512
#define REDOLOG_TYPE "Redolog"
#define GROWING_TYPE "Growing"
// not allocated: 0xffffffff
// 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
uint64_t disk; // disk size
char padding[HEADER_SIZE - 64 - 8 - 20];
} 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;
} 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))
return 100;
return 0;
}
static int bochs_open(BlockDriverState *bs, const char *filename)
{
BDRVBochsState *s = bs->opaque;
int fd, i;
struct bochs_header bochs;
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, &bochs, sizeof(bochs)) != sizeof(bochs)) {
goto fail;
}
if (strcmp(bochs.magic, HEADER_MAGIC) ||
strcmp(bochs.type, REDOLOG_TYPE) ||
strcmp(bochs.subtype, GROWING_TYPE) ||
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
goto fail;
}
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
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]);
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
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;
fail:
close(fd);
return -1;
}
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVBochsState *s = bs->opaque;
int64_t offset = sector_num * 512;
int64_t extent_index, extent_offset, bitmap_offset, block_offset;
char bitmap_entry;
// 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",
// sector_num, extent_index, extent_offset);
return -1; // not allocated
}
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",
// sector_num);
return -1; // not allocated
}
lseek(s->fd, block_offset, SEEK_SET);
return 0;
}
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVBochsState *s = bs->opaque;
int ret;
while (nb_sectors > 0) {
if (!seek_to_sector(bs, sector_num))
{
ret = read(s->fd, buf, 512);
if (ret != 512)
return -1;
}
else
memset(buf, 0, 512);
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static void bochs_close(BlockDriverState *bs)
{
BDRVBochsState *s = bs->opaque;
qemu_free(s->catalog_bitmap);
close(s->fd);
}
BlockDriver bdrv_bochs = {
"bochs",
sizeof(BDRVBochsState),
bochs_probe,
bochs_open,
bochs_read,
NULL,
bochs_close,
};

View File

@@ -1,169 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#include <zlib.h>
typedef struct BDRVCloopState {
int fd;
uint32_t block_size;
uint32_t n_blocks;
uint64_t* offsets;
uint32_t sectors_per_block;
uint32_t current_block;
char* compressed_block;
char* uncompressed_block;
z_stream zstream;
} BDRVCloopState;
static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const char* magic_version_2_0="#!/bin/sh\n"
"#V2.0 Format\n"
"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
int length=strlen(magic_version_2_0);
if(length>buf_size)
length=buf_size;
if(!memcmp(magic_version_2_0,buf,length))
return 2;
return 0;
}
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 | O_LARGEFILE);
if (s->fd < 0)
return -1;
bs->read_only = 1;
/* read header */
if(lseek(s->fd,128,SEEK_SET)<0) {
cloop_close:
close(s->fd);
return -1;
}
if(read(s->fd,&s->block_size,4)<4)
goto cloop_close;
s->block_size=be32_to_cpu(s->block_size);
if(read(s->fd,&s->n_blocks,4)<4)
goto cloop_close;
s->n_blocks=be32_to_cpu(s->n_blocks);
/* read offsets */
offsets_size=s->n_blocks*sizeof(uint64_t);
if(!(s->offsets=(uint64_t*)malloc(offsets_size)))
goto cloop_close;
if(read(s->fd,s->offsets,offsets_size)<offsets_size)
goto cloop_close;
for(i=0;i<s->n_blocks;i++) {
s->offsets[i]=be64_to_cpu(s->offsets[i]);
if(i>0) {
uint32_t size=s->offsets[i]-s->offsets[i-1];
if(size>max_compressed_block_size)
max_compressed_block_size=size;
}
}
/* initialize zlib engine */
if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1)))
goto cloop_close;
if(!(s->uncompressed_block=(char*)malloc(s->block_size)))
goto 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;
}
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)
return -1;
s->zstream.next_in = s->compressed_block;
s->zstream.avail_in = bytes;
s->zstream.next_out = s->uncompressed_block;
s->zstream.avail_out = s->block_size;
ret = inflateReset(&s->zstream);
if(ret != Z_OK)
return -1;
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,
uint8_t *buf, int nb_sectors)
{
BDRVCloopState *s = bs->opaque;
int i;
for(i=0;i<nb_sectors;i++) {
uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
block_num=(sector_num+i)/s->sectors_per_block;
if(cloop_read_block(s, block_num) != 0)
return -1;
memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
}
return 0;
}
static void cloop_close(BlockDriverState *bs)
{
BDRVCloopState *s = bs->opaque;
close(s->fd);
if(s->n_blocks>0)
free(s->offsets);
free(s->compressed_block);
free(s->uncompressed_block);
inflateEnd(&s->zstream);
}
BlockDriver bdrv_cloop = {
"cloop",
sizeof(BDRVCloopState),
cloop_probe,
cloop_open,
cloop_read,
NULL,
cloop_close,
};

View File

@@ -1,264 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _WIN32
#include "vl.h"
#include "block_int.h"
#include <sys/mman.h>
/**************************************************************/
/* COW block driver using file system holes */
/* user mode linux compatible COW file */
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 2
struct cow_header_v2 {
uint32_t magic;
uint32_t version;
char backing_file[1024];
int32_t mtime;
uint64_t size;
uint32_t sectorsize;
};
typedef struct BDRVCowState {
int fd;
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
int cow_bitmap_size;
int64_t cow_sectors_offset;
} BDRVCowState;
static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct cow_header_v2 *cow_header = (const void *)buf;
if (buf_size >= sizeof(struct cow_header_v2) &&
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
be32_to_cpu(cow_header->version) == COW_VERSION)
return 100;
else
return 0;
}
static int cow_open(BlockDriverState *bs, const char *filename)
{
BDRVCowState *s = bs->opaque;
int fd;
struct cow_header_v2 cow_header;
int64_t size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
/* see if it is a cow image */
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
goto fail;
}
if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
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),
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,
PROT_READ | PROT_WRITE,
MAP_SHARED, s->fd, 0);
if (s->cow_bitmap_addr == MAP_FAILED)
goto fail;
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
return 0;
fail:
close(fd);
return -1;
}
static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
{
bitmap[bitnum / 8] |= (1 << (bitnum%8));
}
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
{
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
}
/* Return true if first block has been changed (ie. current version is
* in COW file). Set the number of continuous blocks for which that
* is true. */
static inline int is_changed(uint8_t *bitmap,
int64_t sector_num, int nb_sectors,
int *num_same)
{
int changed;
if (!bitmap || nb_sectors == 0) {
*num_same = nb_sectors;
return 0;
}
changed = is_bit_set(bitmap, sector_num);
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
break;
}
return changed;
}
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,
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)
return -1;
} else {
memset(buf, 0, n * 512);
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
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)
return -1;
for (i = 0; i < nb_sectors; i++)
cow_set_bit(s->cow_bitmap, sector_num + i);
return 0;
}
static void cow_close(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
close(s->fd);
}
static int cow_create(const char *filename, int64_t image_sectors,
const char *image_filename, int flags)
{
int fd, cow_fd;
struct cow_header_v2 cow_header;
struct stat st;
if (flags)
return -ENOTSUP;
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (cow_fd < 0)
return -1;
memset(&cow_header, 0, sizeof(cow_header));
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
return -1;
}
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
write(cow_fd, &cow_header, sizeof(cow_header));
/* resize to include at least all the bitmap */
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
close(cow_fd);
return 0;
}
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
cow_probe,
cow_open,
cow_read,
cow_write,
cow_close,
cow_create,
cow_is_allocated,
};
#endif

View File

@@ -1,297 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#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,
* sectors[i] is the sector beginning at offsets[i],
* sectorcounts[i] is the number of sectors in that chunk,
* the sectors array is ordered
* 0<=i<n_chunks */
uint32_t n_chunks;
uint32_t* types;
uint64_t* offsets;
uint64_t* lengths;
uint64_t* sectors;
uint64_t* sectorcounts;
uint32_t current_chunk;
char* compressed_chunk;
char* uncompressed_chunk;
z_stream zstream;
} BDRVDMGState;
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
{
int len=strlen(filename);
if(len>4 && !strcmp(filename+len-4,".dmg"))
return 2;
return 0;
}
static off_t read_off(int fd)
{
uint64_t buffer;
if(read(fd,&buffer,8)<8)
return 0;
return be64_to_cpu(buffer);
}
static off_t read_uint32(int fd)
{
uint32_t buffer;
if(read(fd,&buffer,4)<4)
return 0;
return be32_to_cpu(buffer);
}
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 | O_LARGEFILE);
if (s->fd < 0)
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);
}
info_begin=read_off(s->fd);
if(info_begin==0)
goto dmg_close;
if(lseek(s->fd,info_begin,SEEK_SET)<0)
goto dmg_close;
if(read_uint32(s->fd)!=0x100)
goto dmg_close;
if((count = read_uint32(s->fd))==0)
goto dmg_close;
info_end = info_begin+count;
if(lseek(s->fd,0xf8,SEEK_CUR)<0)
goto dmg_close;
/* read offsets */
last_in_offset = last_out_offset = 0;
while(lseek(s->fd,0,SEEK_CUR)<info_end) {
uint32_t type;
count = read_uint32(s->fd);
if(count==0)
goto dmg_close;
type = read_uint32(s->fd);
if(type!=0x6d697368 || count<244)
lseek(s->fd,count-4,SEEK_CUR);
else {
int new_size, chunk_count;
if(lseek(s->fd,200,SEEK_CUR)<0)
goto dmg_close;
chunk_count = (count-204)/40;
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
s->types = realloc(s->types, new_size/2);
s->offsets = realloc(s->offsets, new_size);
s->lengths = realloc(s->lengths, new_size);
s->sectors = realloc(s->sectors, new_size);
s->sectorcounts = realloc(s->sectorcounts, new_size);
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
s->types[i] = read_uint32(s->fd);
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
if(s->types[i]==0xffffffff) {
last_in_offset = s->offsets[i-1]+s->lengths[i-1];
last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
}
chunk_count--;
i--;
if(lseek(s->fd,36,SEEK_CUR)<0)
goto dmg_close;
continue;
}
read_uint32(s->fd);
s->sectors[i] = last_out_offset+read_off(s->fd);
s->sectorcounts[i] = read_off(s->fd);
s->offsets[i] = last_in_offset+read_off(s->fd);
s->lengths[i] = read_off(s->fd);
if(s->lengths[i]>max_compressed_size)
max_compressed_size = s->lengths[i];
if(s->sectorcounts[i]>max_sectors_per_chunk)
max_sectors_per_chunk = s->sectorcounts[i];
}
s->n_chunks+=chunk_count;
}
}
/* initialize zlib engine */
if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1)))
goto dmg_close;
if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk)))
goto dmg_close;
if(inflateInit(&s->zstream) != Z_OK)
goto dmg_close;
s->current_chunk = s->n_chunks;
return 0;
}
static inline int is_sector_in_chunk(BDRVDMGState* s,
uint32_t chunk_num,int sector_num)
{
if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
return 0;
else
return -1;
}
static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
{
/* binary search */
uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
while(chunk1!=chunk2) {
chunk3 = (chunk1+chunk2)/2;
if(s->sectors[chunk3]>sector_num)
chunk2 = chunk3;
else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
return chunk3;
else
chunk1 = chunk3;
}
return s->n_chunks; /* error */
}
static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
{
if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
int ret;
uint32_t chunk = search_chunk(s,sector_num);
if(chunk>=s->n_chunks)
return -1;
s->current_chunk = s->n_chunks;
switch(s->types[chunk]) {
case 0x80000005: { /* zlib compressed */
int i;
ret = lseek(s->fd, s->offsets[chunk], SEEK_SET);
if(ret<0)
return -1;
/* we need to buffer, because only the chunk as whole can be
* inflated. */
i=0;
do {
ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
if(ret<0 && errno==EINTR)
ret=0;
i+=ret;
} while(ret>=0 && ret+i<s->lengths[chunk]);
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;
s->zstream.avail_out = 512*s->sectorcounts[chunk];
ret = inflateReset(&s->zstream);
if(ret != Z_OK)
return -1;
ret = inflate(&s->zstream, Z_FINISH);
if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
return -1;
break; }
case 1: /* copy */
ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
if (ret != s->lengths[chunk])
return -1;
break;
case 2: /* zero */
memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
break;
}
s->current_chunk = chunk;
}
return 0;
}
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVDMGState *s = bs->opaque;
int i;
for(i=0;i<nb_sectors;i++) {
uint32_t sector_offset_in_chunk;
if(dmg_read_chunk(s, sector_num+i) != 0)
return -1;
sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
}
return 0;
}
static void dmg_close(BlockDriverState *bs)
{
BDRVDMGState *s = bs->opaque;
close(s->fd);
if(s->n_chunks>0) {
free(s->types);
free(s->offsets);
free(s->lengths);
free(s->sectors);
free(s->sectorcounts);
}
free(s->compressed_chunk);
free(s->uncompressed_chunk);
inflateEnd(&s->zstream);
}
BlockDriver bdrv_dmg = {
"dmg",
sizeof(BDRVDMGState),
dmg_probe,
dmg_open,
dmg_read,
NULL,
dmg_close,
};

View File

@@ -1,688 +0,0 @@
/*
* Block driver for the QCOW 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#include <zlib.h>
#include "aes.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
#define QCOW_VERSION 1
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
#define QCOW_OFLAG_COMPRESSED (1LL << 63)
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
uint64_t backing_file_offset;
uint32_t backing_file_size;
uint32_t mtime;
uint64_t size; /* in bytes */
uint8_t cluster_bits;
uint8_t l2_bits;
uint32_t crypt_method;
uint64_t l1_table_offset;
} QCowHeader;
#define L2_CACHE_SIZE 16
typedef struct BDRVQcowState {
int fd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
int l2_bits;
int l2_size;
int l1_size;
uint64_t cluster_offset_mask;
uint64_t l1_table_offset;
uint64_t *l1_table;
uint64_t *l2_cache;
uint64_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
} BDRVQcowState;
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)
return 100;
else
return 0;
}
static int qcow_open(BlockDriverState *bs, const char *filename)
{
BDRVQcowState *s = bs->opaque;
int fd, len, i, shift;
QCowHeader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
be64_to_cpus(&header.backing_file_offset);
be32_to_cpus(&header.backing_file_size);
be32_to_cpus(&header.mtime);
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)
goto fail;
if (header.crypt_method > QCOW_CRYPT_AES)
goto fail;
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header)
bs->encrypted = 1;
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
s->cluster_sectors = 1 << (s->cluster_bits - 9);
s->l2_bits = header.l2_bits;
s->l2_size = 1 << s->l2_bits;
bs->total_sectors = header.size / 512;
s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1;
/* read the level 1 table */
shift = s->cluster_bits + s->l2_bits;
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
s->l1_table_offset = header.l1_table_offset;
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
if (!s->l1_table)
goto fail;
lseek(fd, s->l1_table_offset, SEEK_SET);
if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
s->l1_size * sizeof(uint64_t))
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
/* alloc L2 cache */
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
if (!s->l2_cache)
goto fail;
s->cluster_cache = qemu_malloc(s->cluster_size);
if (!s->cluster_cache)
goto fail;
s->cluster_data = qemu_malloc(s->cluster_size);
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;
lseek(fd, header.backing_file_offset, SEEK_SET);
if (read(fd, bs->backing_file, len) != len)
goto fail;
bs->backing_file[len] = '\0';
}
return 0;
fail:
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(fd);
return -1;
}
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)
len = 16;
/* XXX: we could compress the chars to 7 bits to increase
entropy */
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
return -1;
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
return -1;
#if 0
/* test */
{
uint8_t in[16];
uint8_t out[16];
uint8_t tmp[16];
for(i=0;i<16;i++)
in[i] = i;
AES_encrypt(in, tmp, &s->aes_encrypt_key);
AES_decrypt(tmp, out, &s->aes_decrypt_key);
for(i = 0; i < 16; i++)
printf(" %02x", tmp[i]);
printf("\n");
for(i = 0; i < 16; i++)
printf(" %02x", out[i]);
printf("\n");
}
#endif
return 0;
}
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
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,
ivec.b, enc);
sector_num++;
in_buf += 512;
out_buf += 512;
}
}
/* 'allocate' is:
*
* 0 to not allocate.
*
* 1 to allocate a normal cluster (for sector indexes 'n_start' to
* 'n_end')
*
* 2 to allocate a compressed cluster of size
* 'compressed_size'. 'compressed_size' must be > 0 and <
* cluster_size
*
* return 0 if not allocated.
*/
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate,
int compressed_size,
int n_start, int n_end)
{
BDRVQcowState *s = bs->opaque;
int min_index, i, j, l1_index, l2_index;
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;
if (!l2_offset) {
if (!allocate)
return 0;
/* allocate a new l2 entry */
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);
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;
}
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i << s->l2_bits);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
lseek(s->fd, l2_offset, SEEK_SET);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
} else {
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
}
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
if (!cluster_offset ||
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
if (!allocate)
return 0;
/* allocate a new cluster */
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
(n_end - n_start) < s->cluster_sectors) {
/* if the cluster is already compressed, we must
decompress it in the case it is not completely
overwritten */
if (decompress_cluster(s, cluster_offset) < 0)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
/* write the cluster content */
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
s->cluster_size)
return -1;
} else {
cluster_offset = lseek(s->fd, 0, SEEK_END);
if (allocate == 1) {
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
ftruncate(s->fd, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (s->crypt_method &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0xaa, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
if (write(s->fd, s->cluster_data, 512) != 512)
return -1;
}
}
}
} else {
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;
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,
int nb_sectors, int *pnum)
{
BDRVQcowState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
*pnum = n;
return (cluster_offset != 0);
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
const uint8_t *buf, int buf_size)
{
z_stream strm1, *strm = &strm1;
int ret, out_len;
memset(strm, 0, sizeof(*strm));
strm->next_in = (uint8_t *)buf;
strm->avail_in = buf_size;
strm->next_out = out_buf;
strm->avail_out = out_buf_size;
ret = inflateInit2(strm, -12);
if (ret != Z_OK)
return -1;
ret = inflate(strm, Z_FINISH);
out_len = strm->next_out - out_buf;
if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
out_len != out_buf_size) {
inflateEnd(strm);
return -1;
}
inflateEnd(strm);
return 0;
}
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
{
int ret, csize;
uint64_t coffset;
coffset = cluster_offset & s->cluster_offset_mask;
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
lseek(s->fd, coffset, SEEK_SET);
ret = read(s->fd, s->cluster_data, csize);
if (ret != csize)
return -1;
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data, csize) < 0) {
return -1;
}
s->cluster_cache_offset = coffset;
}
return 0;
}
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);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
if (decompress_cluster(s, cluster_offset) < 0)
return -1;
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
if (s->crypt_method) {
encrypt_sectors(s, sector_num, buf, buf, n, 0,
&s->aes_decrypt_key);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
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,
index_in_cluster + n);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
if (s->crypt_method) {
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
&s->aes_encrypt_key);
ret = write(s->fd, s->cluster_data, n * 512);
} else {
ret = write(s->fd, buf, n * 512);
}
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
s->cluster_cache_offset = -1; /* disable compressed cache */
return 0;
}
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(s->fd);
}
static int qcow_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, header_size, backing_filename_len, l1_size, i, shift;
QCowHeader header;
char backing_filename[1024];
uint64_t tmp;
struct stat st;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
header.version = cpu_to_be32(QCOW_VERSION);
header.size = cpu_to_be64(total_size * 512);
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
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.mtime = cpu_to_be32(st.st_mtime);
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;
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
unmodifyed sectors */
header.l2_bits = 12; /* 32 KB L2 tables */
} else {
header.cluster_bits = 12; /* 4 KB clusters */
header.l2_bits = 9; /* 4 KB L2 tables */
}
header_size = (header_size + 7) & ~7;
shift = header.cluster_bits + header.l2_bits;
l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
header.l1_table_offset = cpu_to_be64(header_size);
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_filename, backing_filename_len);
}
lseek(fd, header_size, SEEK_SET);
tmp = 0;
for(i = 0;i < l1_size; i++) {
write(fd, &tmp, sizeof(tmp));
}
close(fd);
return 0;
}
int qcow_get_cluster_size(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
if (bs->drv != &bdrv_qcow)
return -1;
return s->cluster_size;
}
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf)
{
BDRVQcowState *s = bs->opaque;
z_stream strm;
int ret, out_len;
uint8_t *out_buf;
uint64_t cluster_offset;
if (bs->drv != &bdrv_qcow)
return -1;
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
if (!out_buf)
return -1;
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
qemu_free(out_buf);
return -1;
}
strm.avail_in = s->cluster_size;
strm.next_in = (uint8_t *)buf;
strm.avail_out = s->cluster_size;
strm.next_out = out_buf;
ret = deflate(&strm, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
qemu_free(out_buf);
deflateEnd(&strm);
return -1;
}
out_len = strm.next_out - out_buf;
deflateEnd(&strm);
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* 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,
out_len, 0, 0);
cluster_offset &= s->cluster_offset_mask;
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, out_buf, out_len) != out_len) {
qemu_free(out_buf);
return -1;
}
}
qemu_free(out_buf);
return 0;
}
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
qcow_probe,
qcow_open,
qcow_read,
qcow_write,
qcow_close,
qcow_create,
qcow_is_allocated,
qcow_set_key,
};

View File

@@ -1,439 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
typedef struct {
uint32_t version;
uint32_t flags;
uint32_t disk_sectors;
uint32_t granularity;
uint32_t l1dir_offset;
uint32_t l1dir_size;
uint32_t file_sectors;
uint32_t cylinders;
uint32_t heads;
uint32_t sectors_per_track;
} VMDK3Header;
typedef struct {
uint32_t version;
uint32_t flags;
int64_t capacity;
int64_t granularity;
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
int64_t rgd_offset;
int64_t gd_offset;
int64_t grain_offset;
char filler[1];
char check_bytes[4];
} __attribute__((packed)) VMDK4Header;
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
int fd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
uint32_t *l1_backup_table;
unsigned int l1_size;
uint32_t l1_entry_sectors;
unsigned int l2_size;
uint32_t *l2_cache;
uint32_t l2_cache_offsets[L2_CACHE_SIZE];
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
} BDRVVmdkState;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
if (buf_size < 4)
return 0;
magic = be32_to_cpu(*(uint32_t *)buf);
if (magic == VMDK3_MAGIC ||
magic == VMDK4_MAGIC)
return 100;
else
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename)
{
BDRVVmdkState *s = bs->opaque;
int fd, i;
uint32_t magic;
int l1_size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
bs->read_only = 1;
}
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
if (read(fd, &header, sizeof(header)) !=
sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
s->l1_size = 1 << 6;
bs->total_sectors = le32_to_cpu(header.disk_sectors);
s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
s->l1_backup_table_offset = 0;
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le32_to_cpu(header.capacity);
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
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_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;
} else {
goto fail;
}
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (!s->l1_table)
goto fail;
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
}
if (s->l1_backup_table_offset) {
s->l1_backup_table = qemu_malloc(l1_size);
if (!s->l1_backup_table)
goto fail;
if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_backup_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_backup_table[i]);
}
}
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
if (!s->l2_cache)
goto fail;
s->fd = fd;
return 0;
fail:
qemu_free(s->l1_backup_table);
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(fd);
return -1;
}
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;
uint64_t cluster_offset;
l1_index = (offset >> 9) / s->l1_entry_sectors;
if (l1_index >= s->l1_size)
return 0;
l2_offset = s->l1_table[l1_index];
if (!l2_offset)
return 0;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (l2_offset == s->l2_cache_offsets[i]) {
/* increment the hit count */
if (++s->l2_cache_counts[i] == 0xffffffff) {
for(j = 0; j < L2_CACHE_SIZE; j++) {
s->l2_cache_counts[j] >>= 1;
}
}
l2_table = s->l2_cache + (i * s->l2_size);
goto found;
}
}
/* not found: load a new entry in the least used one */
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
if (s->l2_cache_counts[i] < min_count) {
min_count = s->l2_cache_counts[i];
min_index = i;
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
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;
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;
/* 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,
int nb_sectors, int *pnum)
{
BDRVVmdkState *s = bs->opaque;
int index_in_cluster, n;
uint64_t cluster_offset;
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;
*pnum = n;
return (cluster_offset != 0);
}
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
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);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = write(s->fd, buf, n * 512);
if (ret != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
static int vmdk_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, i;
VMDK4Header header;
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
char *desc_template =
"# Disk DescriptorFile\n"
"version=1\n"
"CID=%x\n"
"parentCID=ffffffff\n"
"createType=\"monolithicSparse\"\n"
"\n"
"# Extent description\n"
"RW %lu SPARSE \"%s\"\n"
"\n"
"# The Disk Data Base \n"
"#DDB\n"
"\n"
"ddb.virtualHWVersion = \"3\"\n"
"ddb.geometry.cylinders = \"%lu\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"ide\"\n";
char desc[1024];
const char *real_filename, *temp_str;
/* XXX: add support for backing file */
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
header.version = cpu_to_le32(1);
header.flags = cpu_to_le32(3); /* ?? */
header.capacity = cpu_to_le64(total_size);
header.granularity = cpu_to_le64(128);
header.num_gtes_per_gte = cpu_to_le32(512);
grains = (total_size + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
header.desc_offset = 1;
header.desc_size = 20;
header.rgd_offset = header.desc_offset + header.desc_size;
header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
header.grain_offset =
((header.gd_offset + gd_size + (gt_size * gt_count) +
header.granularity - 1) / header.granularity) *
header.granularity;
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
header.gd_offset = cpu_to_le64(header.gd_offset);
header.grain_offset = cpu_to_le64(header.grain_offset);
header.check_bytes[0] = 0xa;
header.check_bytes[1] = 0x20;
header.check_bytes[2] = 0xd;
header.check_bytes[3] = 0xa;
/* write all the data */
write(fd, &magic, sizeof(magic));
write(fd, &header, sizeof(header));
ftruncate(fd, header.grain_offset << 9);
/* write grain directory */
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
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;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* compose the descriptor */
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(desc, desc_template, time(NULL), (unsigned long)total_size,
real_filename, total_size / (63 * 16));
/* write the descriptor */
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
write(fd, desc, strlen(desc));
close(fd);
return 0;
}
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(s->fd);
}
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
vmdk_probe,
vmdk_open,
vmdk_read,
vmdk_write,
vmdk_close,
vmdk_create,
vmdk_is_allocated,
};

View File

@@ -1,242 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
/**************************************************************/
#define HEADER_SIZE 512
//#define CACHE
// always big-endian
struct vpc_subheader {
char magic[8]; // "conectix" / "cxsparse"
union {
struct {
uint32_t unk1[2];
uint32_t unk2; // always zero?
uint32_t subheader_offset;
uint32_t unk3; // some size?
char creator[4]; // "vpc "
uint16_t major;
uint16_t minor;
char guest[4]; // "Wi2k"
uint32_t unk4[7];
uint8_t vnet_id[16]; // virtual network id, purpose unknown
// next 16 longs are used, but dunno the purpose
// next 6 longs unknown, following 7 long maybe a serial
char padding[HEADER_SIZE - 84];
} main;
struct {
uint32_t unk1[2]; // all bits set
uint32_t unk2; // always zero?
uint32_t pagetable_offset;
uint32_t unk3;
uint32_t pagetable_entries; // 32bit/entry
uint32_t pageentry_size; // 512*8*512
uint32_t nb_sectors;
char padding[HEADER_SIZE - 40];
} sparse;
char padding[HEADER_SIZE - 8];
} type;
};
typedef struct BDRVVPCState {
int fd;
int pagetable_entries;
uint32_t *pagetable;
uint32_t pageentry_size;
#ifdef CACHE
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(buf, "conectix", 8))
return 100;
return 0;
}
static int vpc_open(BlockDriverState *bs, const char *filename)
{
BDRVVPCState *s = bs->opaque;
int fd, i;
struct vpc_subheader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
bs->read_only = 1; // no write support yet
s->fd = fd;
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
goto fail;
if (strncmp(header.magic, "conectix", 8))
goto fail;
lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
goto fail;
if (strncmp(header.magic, "cxsparse", 8))
goto fail;
bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
s->pagetable = qemu_malloc(s->pagetable_entries * 4);
if (!s->pagetable)
goto fail;
if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
s->pagetable_entries * 4)
goto fail;
for (i = 0; i < s->pagetable_entries; i++)
be32_to_cpus(&s->pagetable[i]);
s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
#ifdef CACHE
s->pageentry_u8 = qemu_malloc(512);
if (!s->pageentry_u8)
goto fail;
s->pageentry_u32 = s->pageentry_u8;
s->pageentry_u16 = s->pageentry_u8;
s->last_pagetable = -1;
#endif
return 0;
fail:
close(fd);
return -1;
}
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVVPCState *s = bs->opaque;
uint64_t offset = sector_num * 512;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index;
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: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
// disabled by reason
#if 0
#ifdef CACHE
if (bitmap_offset != s->last_bitmap)
{
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);
for (i = 0; i < 128; i++)
be32_to_cpus(&s->pageentry_u32[i]);
}
if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
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)
return -1; // not allocated
#endif
#endif
lseek(s->fd, block_offset, SEEK_SET);
return 0;
}
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVPCState *s = bs->opaque;
int ret;
while (nb_sectors > 0) {
if (!seek_to_sector(bs, sector_num))
{
ret = read(s->fd, buf, 512);
if (ret != 512)
return -1;
}
else
memset(buf, 0, 512);
nb_sectors--;
sector_num++;
buf += 512;
}
return 0;
}
static void vpc_close(BlockDriverState *bs)
{
BDRVVPCState *s = bs->opaque;
qemu_free(s->pagetable);
#ifdef CACHE
qemu_free(s->pageentry_u8);
#endif
close(s->fd);
}
BlockDriver bdrv_vpc = {
"vpc",
sizeof(BDRVVPCState),
vpc_probe,
vpc_open,
vpc_read,
NULL,
vpc_close,
};

File diff suppressed because it is too large Load Diff

681
block.c
View File

@@ -22,24 +22,43 @@
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
#ifdef _BSD
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/disk.h>
#ifndef _WIN32
#include <sys/mman.h>
#endif
static BlockDriverState *bdrv_first;
static BlockDriver *first_drv;
#include "cow.h"
void bdrv_register(BlockDriver *bdrv)
{
bdrv->next = first_drv;
first_drv = bdrv;
}
struct BlockDriverState {
int fd; /* if -1, only COW mappings */
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 */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
int cow_bitmap_size;
int cow_fd;
int64_t cow_sectors_offset;
int boot_sector_enabled;
uint8_t boot_sector_data[512];
char filename[1024];
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs;
int type;
char device_name[32];
BlockDriverState *next;
};
static BlockDriverState *bdrv_first;
/* create a new block device (by default it is empty) */
BlockDriverState *bdrv_new(const char *device_name)
@@ -50,176 +69,126 @@ BlockDriverState *bdrv_new(const char *device_name)
if(!bs)
return NULL;
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
if (device_name[0] != '\0') {
/* insert at the end */
pbs = &bdrv_first;
while (*pbs != NULL)
pbs = &(*pbs)->next;
*pbs = bs;
}
/* insert at the end */
pbs = &bdrv_first;
while (*pbs != NULL)
pbs = &(*pbs)->next;
*pbs = bs;
return bs;
}
BlockDriver *bdrv_find_format(const char *format_name)
{
BlockDriver *drv1;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
if (!strcmp(drv1->format_name, format_name))
return drv1;
}
return NULL;
}
int bdrv_create(BlockDriver *drv,
const char *filename, int64_t size_in_sectors,
const char *backing_file, int flags)
{
if (!drv->bdrv_create)
return -ENOTSUP;
return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
}
#ifdef _WIN32
static void get_tmp_filename(char *filename, int size)
{
/* XXX: find a better function */
tmpnam(filename);
}
#else
static void get_tmp_filename(char *filename, int size)
{
int fd;
/* XXX: race condition possible */
pstrcpy(filename, size, "/tmp/vl.XXXXXX");
fd = mkstemp(filename);
close(fd);
}
#endif
/* XXX: force raw format if block or character device ? It would
simplify the BSD case */
static BlockDriver *find_image_format(const char *filename)
{
int fd, ret, score, score_max;
BlockDriver *drv1, *drv;
uint8_t *buf;
size_t bufsize = 1024;
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0) {
buf = NULL;
ret = 0;
} else {
#ifdef DIOCGSECTORSIZE
{
unsigned int sectorsize = 512;
if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
sectorsize > bufsize)
bufsize = sectorsize;
}
#endif
buf = qemu_malloc(bufsize);
if (!buf)
return NULL;
ret = read(fd, buf, bufsize);
if (ret < 0) {
close(fd);
qemu_free(buf);
return NULL;
}
close(fd);
}
drv = NULL;
score_max = 0;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
score = drv1->bdrv_probe(buf, ret, filename);
if (score > score_max) {
score_max = score;
drv = drv1;
}
}
qemu_free(buf);
return drv;
}
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
{
return bdrv_open2(bs, filename, snapshot, NULL);
}
int fd;
int64_t size;
struct cow_header_v2 cow_header;
#ifndef _WIN32
char template[] = "/tmp/vl.XXXXXX";
int cow_fd;
struct stat st;
#endif
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
BlockDriver *drv)
{
int ret;
char tmp_filename[1024];
bs->read_only = 0;
bs->is_temporary = 0;
bs->encrypted = 0;
if (snapshot) {
BlockDriverState *bs1;
int64_t total_size;
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
/* if there is a backing file, use it */
bs1 = bdrv_new("");
if (!bs1) {
return -1;
}
if (bdrv_open(bs1, filename, 0) < 0) {
bdrv_delete(bs1);
return -1;
}
total_size = bs1->total_sectors;
bdrv_delete(bs1);
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
/* XXX: use cow for linux as it is more efficient ? */
if (bdrv_create(&bdrv_qcow, tmp_filename,
total_size, filename, 0) < 0) {
return -1;
}
filename = tmp_filename;
bs->is_temporary = 1;
}
bs->fd = -1;
bs->cow_fd = -1;
bs->cow_bitmap = NULL;
pstrcpy(bs->filename, sizeof(bs->filename), filename);
if (!drv) {
drv = find_image_format(filename);
if (!drv)
return -1;
/* open standard HD image */
#ifdef _WIN32
fd = open(filename, O_RDWR | O_BINARY);
#else
fd = open(filename, O_RDWR | O_LARGEFILE);
#endif
if (fd < 0) {
/* read only image on disk */
#ifdef _WIN32
fd = open(filename, O_RDONLY | O_BINARY);
#else
fd = open(filename, O_RDONLY | O_LARGEFILE);
#endif
if (fd < 0) {
perror(filename);
goto fail;
}
if (!snapshot)
bs->read_only = 1;
}
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
if (bs->opaque == NULL && drv->instance_size > 0)
return -1;
ret = drv->bdrv_open(bs, filename);
if (ret < 0) {
qemu_free(bs->opaque);
return -1;
bs->fd = fd;
/* see if it is a cow image */
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
fprintf(stderr, "%s: could not read header\n", filename);
goto fail;
}
#ifndef _WIN32
if (bs->is_temporary) {
unlink(filename);
}
#endif
if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
/* if there is a backing file, use it */
bs->backing_hd = bdrv_new("");
if (!bs->backing_hd) {
fail:
bdrv_close(bs);
return -1;
if (be32_to_cpu(cow_header.magic) == COW_MAGIC &&
be32_to_cpu(cow_header.version) == COW_VERSION) {
/* cow image found */
size = cow_header.size;
#ifndef WORDS_BIGENDIAN
size = bswap64(size);
#endif
bs->total_sectors = size / 512;
bs->cow_fd = fd;
bs->fd = -1;
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != 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;
}
if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
/* mmap the bitmap */
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
bs->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, bs->cow_fd, 0);
if (bs->cow_bitmap_addr == MAP_FAILED)
goto fail;
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
snapshot = 0;
} else
#endif
{
/* standard raw image */
size = lseek64(fd, 0, SEEK_END);
bs->total_sectors = size / 512;
bs->fd = fd;
}
#ifndef _WIN32
if (snapshot) {
/* create a temporary COW file */
cow_fd = mkstemp64(template);
if (cow_fd < 0)
goto fail;
bs->cow_fd = cow_fd;
unlink(template);
/* just need to allocate bitmap */
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
bs->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (bs->cow_bitmap_addr == MAP_FAILED)
goto fail;
bs->cow_bitmap = bs->cow_bitmap_addr;
bs->cow_sectors_offset = 0;
}
#endif
bs->inserted = 1;
/* call the change callback */
@@ -227,22 +196,23 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
bs->change_cb(bs->change_opaque);
return 0;
fail:
bdrv_close(bs);
return -1;
}
void bdrv_close(BlockDriverState *bs)
{
if (bs->inserted) {
if (bs->backing_hd)
bdrv_delete(bs->backing_hd);
bs->drv->bdrv_close(bs);
qemu_free(bs->opaque);
#ifdef _WIN32
if (bs->is_temporary) {
unlink(bs->filename);
}
#ifndef _WIN32
/* we unmap the mapping so that it is written to the COW file */
if (bs->cow_bitmap_addr)
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
#endif
bs->opaque = NULL;
bs->drv = NULL;
if (bs->cow_fd >= 0)
close(bs->cow_fd);
if (bs->fd >= 0)
close(bs->fd);
bs->inserted = 0;
/* call the change callback */
@@ -253,45 +223,85 @@ void bdrv_close(BlockDriverState *bs)
void bdrv_delete(BlockDriverState *bs)
{
/* XXX: remove the driver list */
bdrv_close(bs);
qemu_free(bs);
}
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
{
bitmap[bitnum / 8] |= (1 << (bitnum%8));
}
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
{
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
}
/* Return true if first block has been changed (ie. current version is
* in COW file). Set the number of continuous blocks for which that
* is true. */
static int is_changed(uint8_t *bitmap,
int64_t sector_num, int nb_sectors,
int *num_same)
{
int changed;
if (!bitmap || nb_sectors == 0) {
*num_same = nb_sectors;
return 0;
}
changed = is_bit_set(bitmap, sector_num);
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
break;
}
return changed;
}
/* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs)
{
int64_t i;
int n, j;
unsigned char sector[512];
uint8_t *cow_bitmap;
if (!bs->inserted)
return -ENOENT;
return -1;
if (!bs->cow_bitmap) {
fprintf(stderr, "Already committed to %s\n", bs->filename);
return 0;
}
if (bs->read_only) {
return -EACCES;
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
return -1;
}
if (!bs->backing_hd) {
return -ENOTSUP;
}
for (i = 0; i < bs->total_sectors;) {
if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
if (bdrv_read(bs, i, sector, 1) != 0) {
return -EIO;
}
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
return -EIO;
}
i++;
cow_bitmap = bs->cow_bitmap;
for (i = 0; i < bs->total_sectors; i++) {
if (is_bit_set(cow_bitmap, i)) {
unsigned char sector[512];
if (bdrv_read(bs, i, sector, 1) != 0) {
fprintf(stderr, "Error reading sector %lli: aborting commit\n",
(long long)i);
return -1;
}
} else {
i += n;
}
/* Make bdrv_write write to real file for a moment. */
bs->cow_bitmap = NULL;
if (bdrv_write(bs, i, sector, 1) != 0) {
fprintf(stderr, "Error writing sector %lli: aborting commit\n",
(long long)i);
bs->cow_bitmap = cow_bitmap;
return -1;
}
bs->cow_bitmap = cow_bitmap;
}
}
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
return 0;
}
@@ -299,34 +309,37 @@ int bdrv_commit(BlockDriverState *bs)
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int ret, n;
BlockDriver *drv = bs->drv;
int ret, n, fd;
int64_t offset;
if (!bs->inserted)
return -1;
while (nb_sectors > 0) {
if (sector_num == 0 && bs->boot_sector_enabled) {
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
fd = bs->cow_fd;
offset = bs->cow_sectors_offset;
} else if (sector_num == 0 && bs->boot_sector_enabled) {
memcpy(buf, bs->boot_sector_data, 512);
n = 1;
} else if (bs->backing_hd) {
if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
ret = drv->bdrv_read(bs, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
}
goto next;
} else {
ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
if (ret < 0)
return -1;
/* no need to loop */
break;
fd = bs->fd;
offset = 0;
}
if (fd < 0) {
/* no file, just return empty sectors */
memset(buf, 0, n * 512);
} else {
offset += sector_num * 512;
lseek64(fd, offset, SEEK_SET);
ret = read(fd, buf, n * 512);
if (ret != n * 512) {
return -1;
}
}
next:
nb_sectors -= n;
sector_num += n;
buf += n * 512;
@@ -338,11 +351,37 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
int ret, fd, i;
int64_t offset, retl;
if (!bs->inserted)
return -1;
if (bs->read_only)
return -1;
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
if (bs->cow_bitmap) {
fd = bs->cow_fd;
offset = bs->cow_sectors_offset;
} else {
fd = bs->fd;
offset = 0;
}
offset += sector_num * 512;
retl = lseek64(fd, offset, SEEK_SET);
if (retl == -1) {
return -1;
}
ret = write(fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512) {
return -1;
}
if (bs->cow_bitmap) {
for (i = 0; i < nb_sectors; i++)
set_bit(bs->cow_bitmap, sector_num + i);
}
return 0;
}
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
@@ -375,11 +414,6 @@ void bdrv_set_type_hint(BlockDriverState *bs, int type)
type == BDRV_TYPE_FLOPPY));
}
void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
{
bs->translation = translation;
}
void bdrv_get_geometry_hint(BlockDriverState *bs,
int *pcyls, int *pheads, int *psecs)
{
@@ -393,11 +427,6 @@ int bdrv_get_type_hint(BlockDriverState *bs)
return bs->type;
}
int bdrv_get_translation_hint(BlockDriverState *bs)
{
return bs->translation;
}
int bdrv_is_removable(BlockDriverState *bs)
{
return bs->removable;
@@ -430,47 +459,6 @@ void bdrv_set_change_cb(BlockDriverState *bs,
bs->change_opaque = opaque;
}
int bdrv_is_encrypted(BlockDriverState *bs)
{
if (bs->backing_hd && bs->backing_hd->encrypted)
return 1;
return bs->encrypted;
}
int bdrv_set_key(BlockDriverState *bs, const char *key)
{
int ret;
if (bs->backing_hd && bs->backing_hd->encrypted) {
ret = bdrv_set_key(bs->backing_hd, key);
if (ret < 0)
return ret;
if (!bs->encrypted)
return 0;
}
if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
return -1;
return bs->drv->bdrv_set_key(bs, key);
}
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
{
if (!bs->inserted || !bs->drv) {
buf[0] = '\0';
} else {
pstrcpy(buf, buf_size, bs->drv->format_name);
}
}
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque)
{
BlockDriver *drv;
for (drv = first_drv; drv != NULL; drv = drv->next) {
it(opaque, drv->format_name);
}
}
BlockDriverState *bdrv_find(const char *name)
{
BlockDriverState *bs;
@@ -482,20 +470,6 @@ BlockDriverState *bdrv_find(const char *name)
return NULL;
}
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
{
BlockDriverState *bs;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
it(opaque, bs->device_name);
}
}
const char *bdrv_get_device_name(BlockDriverState *bs)
{
return bs->device_name;
}
void bdrv_info(void)
{
BlockDriverState *bs;
@@ -520,141 +494,10 @@ void bdrv_info(void)
}
if (bs->inserted) {
term_printf(" file=%s", bs->filename);
if (bs->backing_file[0] != '\0')
term_printf(" backing_file=%s", bs->backing_file);
term_printf(" ro=%d", bs->read_only);
term_printf(" drv=%s", bs->drv->format_name);
if (bs->encrypted)
term_printf(" encrypted");
} else {
term_printf(" [not inserted]");
}
term_printf("\n");
}
}
/**************************************************************/
/* RAW block driver */
typedef struct BDRVRawState {
int fd;
} BDRVRawState;
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
{
return 1; /* maybe */
}
static int raw_open(BlockDriverState *bs, const char *filename)
{
BDRVRawState *s = bs->opaque;
int fd;
int64_t size;
#ifdef _BSD
struct stat sb;
#endif
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;
}
#ifdef _BSD
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
#endif
size = lseek(fd, 0LL, SEEK_END);
} else
#endif
{
size = lseek(fd, 0, SEEK_END);
}
#ifdef _WIN32
/* On Windows hosts it can happen that we're unable to get file size
for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
if (size == -1)
size = LONG_LONG_MAX;
#endif
bs->total_sectors = size / 512;
s->fd = fd;
return 0;
}
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
return 0;
}
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512)
return -1;
return 0;
}
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
close(s->fd);
}
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 | O_LARGEFILE,
0644);
if (fd < 0)
return -EIO;
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
BlockDriver bdrv_raw = {
"raw",
sizeof(BDRVRawState),
raw_probe,
raw_open,
raw_read,
raw_write,
raw_close,
raw_create,
};
void bdrv_init(void)
{
bdrv_register(&bdrv_raw);
#ifndef _WIN32
bdrv_register(&bdrv_cow);
#endif
bdrv_register(&bdrv_qcow);
bdrv_register(&bdrv_vmdk);
bdrv_register(&bdrv_cloop);
bdrv_register(&bdrv_dmg);
bdrv_register(&bdrv_bochs);
bdrv_register(&bdrv_vpc);
bdrv_register(&bdrv_vvfat);
}

View File

@@ -1,77 +0,0 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_INT_H
#define BLOCK_INT_H
struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
struct BlockDriver *next;
};
struct BlockDriverState {
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 */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;
BlockDriver *drv;
void *opaque;
int boot_sector_enabled;
uint8_t boot_sector_data[512];
char filename[1024];
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
int is_temporary;
BlockDriverState *backing_hd;
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
int type;
char device_name[32];
BlockDriverState *next;
};
#endif /* BLOCK_INT_H */

126
bswap.h
View File

@@ -73,130 +73,4 @@ static inline void bswap64s(uint64_t *s)
*s = bswap64(*s);
}
#if defined(WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
#define le_bswap(v, size) bswap ## size(v)
#define be_bswaps(v, size)
#define le_bswaps(p, size) *p = bswap ## size(*p);
#else
#define le_bswap(v, size) (v)
#define be_bswap(v, size) bswap ## size(v)
#define le_bswaps(v, size)
#define be_bswaps(p, size) *p = bswap ## size(*p);
#endif
#define CPU_CONVERT(endian, size, type)\
static inline type endian ## size ## _to_cpu(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline type cpu_to_ ## endian ## size(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline void endian ## size ## _to_cpus(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline void cpu_to_ ## endian ## size ## s(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline type endian ## size ## _to_cpup(const type *p)\
{\
return endian ## size ## _to_cpu(*p);\
}\
\
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
{\
*p = cpu_to_ ## endian ## size(v);\
}
CPU_CONVERT(be, 16, uint16_t)
CPU_CONVERT(be, 32, uint32_t)
CPU_CONVERT(be, 64, uint64_t)
CPU_CONVERT(le, 16, uint16_t)
CPU_CONVERT(le, 32, uint32_t)
CPU_CONVERT(le, 64, uint64_t)
/* unaligned versions (optimized for frequent unaligned accesses)*/
#if defined(__i386__) || defined(__powerpc__)
#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
#define le16_to_cpupu(p) le16_to_cpup(p)
#define le32_to_cpupu(p) le32_to_cpup(p)
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
#else
static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
}
static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
p1[2] = v >> 16;
p1[3] = v >> 24;
}
static inline uint16_t le16_to_cpupu(const uint16_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8);
}
static inline uint32_t le32_to_cpupu(const uint32_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
}
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 8;
p1[1] = v;
}
static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 24;
p1[1] = v >> 16;
p1[2] = v >> 8;
p1[3] = v;
}
#endif
#ifdef WORDS_BIGENDIAN
#define cpu_to_32wu cpu_to_be32wu
#else
#define cpu_to_32wu cpu_to_le32wu
#endif
#undef le_bswap
#undef be_bswap
#undef le_bswaps
#undef be_bswaps
#endif /* BSWAP_H */

614
cocoa.m
View File

@@ -1,614 +0,0 @@
/*
* 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
* 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.
*/
/*
Todo : x miniaturize window
x center the window
- save window position
- handle keyboard event
- handle mouse event
- non 32 bpp support
- full screen
- mouse focus
x simple graphical prompt to demo
- better graphical prompt
*/
#import <Cocoa/Cocoa.h>
#include "vl.h"
NSWindow *window = NULL;
NSQuickDrawView *qd_view = NULL;
int gArgc;
char **gArgv;
DisplayState current_ds;
/* main defined in qemu/vl.c */
int qemu_main(int argc, char **argv);
/* To deal with miniaturization */
@interface QemuWindow : NSWindow
{ }
@end
/*
------------------------------------------------------
Qemu Video Driver
------------------------------------------------------
*/
/*
------------------------------------------------------
cocoa_update
------------------------------------------------------
*/
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
{
//printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
/* Use QDFlushPortBuffer() to flush content to display */
RgnHandle dirty = NewRgn ();
RgnHandle temp = NewRgn ();
SetEmptyRgn (dirty);
/* Build the region of dirty rectangles */
MacSetRectRgn (temp, x, y,
x + w, y + h);
MacUnionRgn (dirty, temp, dirty);
/* Flush the dirty region */
QDFlushPortBuffer ( [ qd_view qdPort ], dirty );
DisposeRgn (dirty);
DisposeRgn (temp);
}
/*
------------------------------------------------------
cocoa_resize
------------------------------------------------------
*/
static void cocoa_resize(DisplayState *ds, int w, int h)
{
const int device_bpp = 32;
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)
{
[window close];
[window release];
}
window = [ [ QemuWindow alloc ] initWithContentRect:contentRect
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
backing:NSBackingStoreBuffered defer:NO];
if(!window)
{
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 -
[ 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;
ds->linesize = screen_pitch;
ds->depth = device_bpp;
ds->width = w;
ds->height = h;
current_ds = *ds;
}
/*
------------------------------------------------------
keymap conversion
------------------------------------------------------
*/
static int keymap[] =
{
30, //'a' 0x0
31, //'s'
32, //'d'
33, //'f'
35, //'h'
34, //'g'
44, //'z'
45, //'x'
46, //'c'
47, //'v'
0, // 0 0x0a
48, //'b'
16, //'q'
17, //'w'
18, //'e'
19, //'r'
21, //'y' 0x10
20, //'t'
2, //'1'
3, //'2'
4, //'3'
5, //'4'
7, //'6'
6, //'5'
0, //'='
10, //'9'
8, //'7' 0x1A
0, //'-'
9, //'8'
11, //'0'
27, //']'
24, //'o'
22, //'u' 0x20
26, //'['
23, //'i'
25, //'p'
28, //'\n'
38, //'l'
36, //'j'
40, //'"'
37, //'k'
39, //';'
15, //'\t' 0x30
0, //' '
0, //'`'
14, //'<backspace>'
0, //'' 0x34
0, //'<esc>'
0, //'<esc>'
/* Not completed to finish see http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
};
static int cocoa_keycode_to_qemu(int keycode)
{
if(sizeof(keymap) <= keycode)
{
printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
return 0;
}
return keymap[keycode];
}
/*
------------------------------------------------------
cocoa_refresh
------------------------------------------------------
*/
static void cocoa_refresh(DisplayState *ds)
{
//printf("cocoa_refresh \n");
NSDate *distantPast;
NSEvent *event;
NSAutoreleasePool *pool;
int grab = 1;
pool = [ [ NSAutoreleasePool alloc ] init ];
distantPast = [ NSDate distantPast ];
if (is_active_console(vga_console))
vga_update_display();
do {
event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
inMode: NSDefaultRunLoopMode dequeue:YES ];
if (event != nil) {
switch ([event type]) {
case NSKeyDown:
if(grab)
{
int keycode = cocoa_keycode_to_qemu([event keyCode]);
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode & 0x7f);
}
break;
case NSKeyUp:
if(grab)
{
int keycode = cocoa_keycode_to_qemu([event keyCode]);
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode | 0x80);
}
break;
case NSScrollWheel:
case NSLeftMouseDown:
case NSLeftMouseUp:
case NSOtherMouseDown:
case NSRightMouseDown:
case NSOtherMouseUp:
case NSRightMouseUp:
case NSMouseMoved:
case NSOtherMouseDragged:
case NSRightMouseDragged:
case NSLeftMouseDragged:
default: [NSApp sendEvent:event];
}
}
} while(event != nil);
}
/*
------------------------------------------------------
cocoa_cleanup
------------------------------------------------------
*/
static void cocoa_cleanup(void)
{
}
/*
------------------------------------------------------
cocoa_display_init
------------------------------------------------------
*/
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);
}
/*
------------------------------------------------------
Interface with Cocoa
------------------------------------------------------
*/
/*
------------------------------------------------------
QemuWindow
Some trick from SDL to use miniwindow
------------------------------------------------------
*/
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;
}
}
}
@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
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 ];
}
@end
/*
------------------------------------------------------
QemuCocoaGUIController
NSApp's delegate - indeed main object
------------------------------------------------------
*/
@interface QemuCocoaGUIController : NSObject
{
}
- (void)applicationDidFinishLaunching: (NSNotification *) note;
- (void)applicationWillTerminate:(NSNotification *)aNotification;
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
@end
@implementation QemuCocoaGUIController
/* Called when the internal event loop has just started running */
- (void)applicationDidFinishLaunching: (NSNotification *) note
{
/* Display an open dialog box if no argument were passed or
if qemu was launched from the finder ( the Finder passes "-psn" ) */
if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
{
NSOpenPanel *op = [[NSOpenPanel alloc] init];
cocoa_resize(&current_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];
}
else
{
/* or Launch Qemu, with the global args */
[self startEmulationWithArgc:gArgc argv:gArgv];
}
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
printf("Application will terminate\n");
qemu_system_shutdown_request();
/* In order to avoid a crash */
exit(0);
}
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
if(returnCode == NSCancelButton)
{
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];
}
}
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
{
int status;
/* Launch Qemu */
printf("starting qemu...\n");
status = qemu_main (argc, argv);
exit(status);
}
@end
/*
------------------------------------------------------
Application Creation
------------------------------------------------------
*/
/* Dock Connection */
typedef struct CPSProcessSerNum
{
UInt32 lo;
UInt32 hi;
} CPSProcessSerNum;
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
/* Menu Creation */
static void setApplicationMenu(void)
{
/* warning: this code is very odd */
NSMenu *appleMenu;
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:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
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];
[[NSApp mainMenu] addItem:menuItem];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
/* Finally give up our references to the objects */
[appleMenu release];
[menuItem release];
}
/* Create a window menu */
static void setupWindowMenu(void)
{
NSMenu *windowMenu;
NSMenuItem *windowMenuItem;
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 (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();
setupWindowMenu();
/* 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];
}
/* Real main of qemu-cocoa */
int main(int argc, char **argv)
{
gArgc = argc;
gArgv = argv;
CustomApplicationMain (argc, argv);
return 0;
}

284
configure vendored
View File

@@ -27,15 +27,12 @@ ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
target_list=""
target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu"
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="i386"
;;
armv*b)
cpu="armv4b"
;;
armv*l)
armv4l)
cpu="armv4l"
;;
alpha)
@@ -63,7 +60,7 @@ case "$cpu" in
cpu="m68k"
;;
x86_64|amd64)
cpu="x86_64"
cpu="amd64"
;;
*)
cpu="unknown"
@@ -75,59 +72,34 @@ mingw32="no"
EXESUF=""
gdbstub="yes"
slirp="yes"
adlib="no"
oss="no"
fmod="no"
fmod_lib=""
fmod_inc=""
linux="no"
kqemu="no"
kernel_path=""
cocoa="no"
check_gfx="yes"
# OS specific
targetos=`uname -s`
case $targetos in
CYGWIN*)
mingw32="yes"
CFLAGS="-O2 -mno-cygwin"
;;
MINGW32*)
mingw32="yes"
;;
FreeBSD)
bsd="yes"
oss="yes"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
;;
NetBSD)
bsd="yes"
oss="yes"
;;
OpenBSD)
bsd="yes"
oss="yes"
;;
Darwin)
bsd="yes"
darwin="yes"
;;
*)
oss="yes"
linux="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
;;
*) ;;
esac
if [ "$bsd" = "yes" ] ; then
if [ ! "$darwin" = "yes" ] ; then
make="gmake"
fi
target_list="i386-softmmu ppc-softmmu"
fi
# find source path
@@ -153,14 +125,14 @@ for opt do
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
;;
--extra-libs=*) extralibs=${opt#--extra-libs=}
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-list=*) target_list=${opt#--target-list=}
@@ -171,26 +143,10 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
--enable-fmod) fmod="yes"
;;
--fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
;;
--fmod-inc=*) fmod_inc=${opt#--fmod-inc=}
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
;;
--disable-slirp) slirp="no"
;;
--enable-adlib) adlib="yes"
;;
--disable-kqemu) kqemu="no"
;;
--kernel-path=*) kernel_path=${opt#--kernel-path=}
;;
--enable-cocoa) cocoa="yes" ; sdl="no"
;;
--disable-gfx-check) check_gfx="no"
;;
esac
done
@@ -204,24 +160,10 @@ ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test "$mingw32" = "yes" ; then
linux="no"
target_list="i386-softmmu ppc-softmmu"
EXESUF=".exe"
gdbstub="no"
oss="no"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
fi
if test -z "$target_list" ; then
# these targets are portable
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
# the following are Linux specific
if [ "$linux" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list"
fi
else
target_list=$(echo "$target_list" | sed -e 's/,/ /g')
slirp="no"
fi
if test -z "$cross_prefix" ; then
@@ -245,18 +187,12 @@ fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then
bigendian="yes"
fi
fi
# host long bits test
hostlongbits="32"
if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" = "alpha"; then
hostlongbits="64"
fi
# check gcc options support
cat > $TMPC <<EOF
int main(void) {
@@ -333,22 +269,13 @@ echo " --interp-prefix=PREFIX where to find shared libraries, etc."
echo " use %M for cpu name [$interp_prefix]"
echo " --target-list=LIST set target list [$target_list]"
echo ""
echo "kqemu kernel acceleration support:"
echo " --disable-kqemu disable kqemu build"
echo " --kernel-path=PATH set the kernel path (configure probes it)"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --host-cc=CC use C compiler CC [$cc] for dyngen etc."
echo " --make=MAKE use specified make [$make]"
echo " --static enable static build [$static]"
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
echo " --enable-adlib enable Adlib emulation"
echo " --enable-fmod enable FMOD audio output driver"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@@ -372,48 +299,6 @@ docdir="$prefix/share/doc/qemu"
bindir="$prefix/bin"
fi
# kqemu support
if test $kqemu = "yes" ; then
# test if the source code is installed
if test '!' -f "kqemu/Makefile" ; then
kqemu="no"
fi
fi
# Linux specific kqemu configuration
if test $kqemu = "yes" -a $linux = "yes" ; then
# find the kernel path
if test -z "$kernel_path" ; then
kernel_version=`uname -r`
kernel_path="/lib/modules/$kernel_version/build"
if test '!' -d "$kernel_path/include" ; then
kernel_path="/usr/src/linux"
if test '!' -d "$kernel_path/include" ; then
echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module"
kqemu="no"
fi
fi
fi
if test $kqemu = "yes" ; then
# test that the kernel config is present
if test '!' -f "$kernel_path/Makefile" ; then
echo "No Makefile file present in $kernel_path - kqemu cannot be built"
kqemu="no"
fi
# find build system (2.6 or legacy)
kbuild26="yes"
if grep -q "PATCHLEVEL = 4" $kernel_path/Makefile ; then
kbuild26="no"
fi
fi # kqemu
fi # kqemu and linux
echo "Install prefix $prefix"
echo "BIOS directory $datadir"
echo "binary directory $bindir"
@@ -423,46 +308,22 @@ echo "ELF interp prefix $interp_prefix"
fi
echo "Source path $source_path"
echo "C compiler $cc"
echo "Host C compiler $host_cc"
echo "make $make"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "gprof enabled $gprof"
echo "static build $static"
if test "$darwin" = "yes" ; then
echo "Cocoa support $cocoa"
fi
echo "SDL support $sdl"
if test "$sdl" != "no" ; then
echo "SDL static link $sdl_static"
fi
echo "SDL static link $sdl_static"
echo "mingw32 support $mingw32"
echo "Adlib support $adlib"
echo -n "FMOD support $fmod"
if test $fmod = "yes"; then
echo -n " (lib='$fmod_lib' include='$fmod_inc')"
fi
echo ""
echo "kqemu support $kqemu"
if test $kqemu = "yes" -a $linux = "yes" ; then
echo ""
echo "KQEMU Linux module configuration:"
echo "kernel sources $kernel_path"
echo -n "kbuild type "
if test $kbuild26 = "yes"; then
echo "2.6"
else
echo "2.4"
fi
fi
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support"
fi
if test "$sdl_static" = "no"; then
echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
fi
#if test "$sdl_static" = "no"; then
# echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
#fi
config_mak="config-host.mak"
config_h="config-host.h"
@@ -492,12 +353,9 @@ echo "EXESUF=$EXESUF" >> $config_mak
if test "$cpu" = "i386" ; then
echo "ARCH=i386" >> $config_mak
echo "#define HOST_I386 1" >> $config_h
elif test "$cpu" = "x86_64" ; then
echo "ARCH=x86_64" >> $config_mak
echo "#define HOST_X86_64 1" >> $config_h
elif test "$cpu" = "armv4b" ; then
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
elif test "$cpu" = "amd64" ; then
echo "ARCH=amd64" >> $config_mak
echo "#define HOST_AMD64 1" >> $config_h
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
@@ -533,7 +391,6 @@ if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define WORDS_BIGENDIAN 1" >> $config_h
fi
echo "#define HOST_LONG_BITS $hostlongbits" >> $config_h
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> $config_mak
echo "#define CONFIG_WIN32 1" >> $config_h
@@ -560,20 +417,6 @@ if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=yes" >> $config_mak
echo "#define CONFIG_SLIRP 1" >> $config_h
fi
if test "$adlib" = "yes" ; then
echo "CONFIG_ADLIB=yes" >> $config_mak
echo "#define CONFIG_ADLIB 1" >> $config_h
fi
if test "$oss" = "yes" ; then
echo "CONFIG_OSS=yes" >> $config_mak
echo "#define CONFIG_OSS 1" >> $config_h
fi
if test "$fmod" = "yes" ; then
echo "CONFIG_FMOD=yes" >> $config_mak
echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
echo "#define CONFIG_FMOD 1" >> $config_h
fi
echo -n "VERSION=" >>$config_mak
head $source_path/VERSION >>$config_mak
echo "" >>$config_mak
@@ -581,21 +424,16 @@ echo -n "#define QEMU_VERSION \"" >> $config_h
head $source_path/VERSION >> $config_h
echo "\"" >> $config_h
if test $kqemu = "yes" ; then
echo "CONFIG_KQEMU=yes" >> $config_mak
if test $linux = "yes" ; then
echo "KERNEL_PATH=$kernel_path" >> $config_mak
if test $kbuild26 = "yes" ; then
echo "CONFIG_KBUILD26=yes" >> $config_mak
fi
fi
fi
echo "SRC_PATH=$source_path" >> $config_mak
echo "TARGET_DIRS=$target_list" >> $config_mak
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "#define O_LARGEFILE 0" >> $config_h
echo "#define lseek64 lseek" >> $config_h
echo "#define mkstemp64 mkstemp" >> $config_h
echo "#define ftruncate64 ftruncate" >> $config_h
echo "#define off64_t off_t" >> $config_h
echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
echo "#define _BSD 1" >> $config_h
fi
@@ -607,12 +445,8 @@ config_mak=$target_dir/config.mak
config_h=$target_dir/config.h
target_cpu=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
[ "$target_cpu" = "armeb" ] && target_bigendian=yes
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
[ "$target_cpu" = "sparc64" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
@@ -622,19 +456,10 @@ if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
echo "To build QEMU with graphical output configure with --disable-gfx-check"
echo "Note that this will disable all output from the virtual graphics card."
exit 1;
fi
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
mkdir -p $target_dir
mkdir -p $target_dir/fpu
if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
if test "$target" = "arm-user" ; then
mkdir -p $target_dir/nwfpe
fi
if test "$target_user_only" = "no" ; then
@@ -657,10 +482,7 @@ if test "$target_cpu" = "i386" ; then
echo "TARGET_ARCH=i386" >> $config_mak
echo "#define TARGET_ARCH \"i386\"" >> $config_h
echo "#define TARGET_I386 1" >> $config_h
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "i386" ; then
echo "#define USE_KQEMU 1" >> $config_h
fi
elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
elif test "$target_cpu" = "arm" ; then
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
@@ -668,32 +490,10 @@ elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
elif test "$target_cpu" = "sparc64" ; then
echo "TARGET_ARCH=sparc64" >> $config_mak
echo "#define TARGET_ARCH \"sparc64\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
echo "#define TARGET_SPARC64 1" >> $config_h
elif test "$target_cpu" = "ppc" ; then
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
elif test "$target_cpu" = "ppc64" ; then
echo "TARGET_ARCH=ppc64" >> $config_mak
echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPC64 1" >> $config_h
elif test "$target_cpu" = "x86_64" ; then
echo "TARGET_ARCH=x86_64" >> $config_mak
echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
echo "#define TARGET_I386 1" >> $config_h
echo "#define TARGET_X86_64 1" >> $config_h
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then
echo "#define USE_KQEMU 1" >> $config_h
fi
elif test "$target_cpu" = "mips" ; then
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1
@@ -711,37 +511,27 @@ if test "$target_user_only" = "yes" ; then
echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
fi
# sdl defines
if test "$target_user_only" = "no"; then
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
sdl1=$sdl_static
else
sdl1=$sdl
fi
if test "$sdl1" = "yes" ; then
echo "#define CONFIG_SDL 1" >> $config_h
echo "CONFIG_SDL=yes" >> $config_mak
if test "$target_softmmu" = "no" -o "$static" = "yes"; then
if test "$sdl_static" = "yes" ; then
echo "#define CONFIG_SDL 1" >> $config_h
echo "CONFIG_SDL=yes" >> $config_mak
echo "SDL_LIBS=$sdl_static_libs" >> $config_mak
else
fi
else
if test "$sdl" = "yes" ; then
echo "#define CONFIG_SDL 1" >> $config_h
echo "CONFIG_SDL=yes" >> $config_mak
echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak
fi
echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
if [ "${aa}" = "yes" ] ; then
echo -n " `aalib-config --cflags`" >> $config_mak ;
fi
echo "" >> $config_mak
fi
fi
if test "$cocoa" = "yes" ; then
echo "#define CONFIG_COCOA 1" >> $config_h
echo "CONFIG_COCOA=yes" >> $config_mak
echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
if [ "${aa}" = "yes" ] ; then
echo -n " `aalib-config --cflags`" >> $config_mak ;
fi
echo "" >> $config_mak
fi
done # for target in $targets

731
console.c
View File

@@ -1,731 +0,0 @@
/*
* 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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#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 TextCell {
uint8_t ch;
uint8_t bgcol:4;
uint8_t fgcol:4;
} TextCell;
#define MAX_ESC_PARAMS 3
enum TTYState {
TTY_STATE_NORM,
TTY_STATE_ESC,
TTY_STATE_CSI,
};
struct TextConsole {
int text_console; /* true if text console */
DisplayState *ds;
int g_width, g_height;
int width;
int height;
int total_height;
int backscroll_height;
int fgcol;
int bgcol;
int x, y;
int y_displayed;
int y_base;
TextCell *cells;
enum TTYState state;
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
/* kbd read handler */
IOReadHandler *fd_read;
void *fd_opaque;
};
static TextConsole *active_console;
static TextConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
/* convert a RGBA color to a color index usable in graphic primitives */
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
{
unsigned int r, g, b, color;
switch(ds->depth) {
#if 0
case 8:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = (rgb_to_index[r] * 6 * 6) +
(rgb_to_index[g] * 6) +
(rgb_to_index[b]);
break;
#endif
case 15:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
break;
case 16:
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
break;
case 32:
default:
color = rgba;
break;
}
return color;
}
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 +
ds->linesize * posy + bpp * posx;
for (y = 0; y < height; y++) {
d = d1;
switch(bpp) {
case 1:
for (x = 0; x < width; x++) {
*((uint8_t *)d) = color;
d++;
}
break;
case 2:
for (x = 0; x < width; x++) {
*((uint16_t *)d) = color;
d += 2;
}
break;
case 4:
for (x = 0; x < width; x++) {
*((uint32_t *)d) = color;
d += 4;
}
break;
}
d1 += ds->linesize;
}
}
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
{
const uint8_t *s;
uint8_t *d;
int wb, y, bpp;
bpp = (ds->depth + 7) >> 3;
wb = w * bpp;
if (yd <= ys) {
s = ds->data +
ds->linesize * ys + bpp * xs;
d = ds->data +
ds->linesize * yd + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d += ds->linesize;
s += ds->linesize;
}
} else {
s = ds->data +
ds->linesize * (ys + h - 1) + bpp * xs;
d = ds->data +
ds->linesize * (yd + h - 1) + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
d -= ds->linesize;
s -= ds->linesize;
}
}
}
/***********************************************************/
/* basic char display */
#define FONT_HEIGHT 16
#define FONT_WIDTH 8
#include "vgafont.h"
#define cbswap_32(__x) \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
#ifdef WORDS_BIGENDIAN
#define PAT(x) x
#else
#define PAT(x) cbswap_32(x)
#endif
static const uint32_t dmask16[16] = {
PAT(0x00000000),
PAT(0x000000ff),
PAT(0x0000ff00),
PAT(0x0000ffff),
PAT(0x00ff0000),
PAT(0x00ff00ff),
PAT(0x00ffff00),
PAT(0x00ffffff),
PAT(0xff000000),
PAT(0xff0000ff),
PAT(0xff00ff00),
PAT(0xff00ffff),
PAT(0xffff0000),
PAT(0xffff00ff),
PAT(0xffffff00),
PAT(0xffffffff),
};
static const uint32_t dmask4[4] = {
PAT(0x00000000),
PAT(0x0000ffff),
PAT(0xffff0000),
PAT(0xffffffff),
};
static uint32_t color_table[8];
static const uint32_t color_table_rgb[8] = {
RGB(0x00, 0x00, 0x00),
RGB(0xff, 0x00, 0x00),
RGB(0x00, 0xff, 0x00),
RGB(0xff, 0xff, 0x00),
RGB(0x00, 0x00, 0xff),
RGB(0xff, 0x00, 0xff),
RGB(0x00, 0xff, 0xff),
RGB(0xff, 0xff, 0xff),
};
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
{
switch(ds->depth) {
case 8:
col |= col << 8;
col |= col << 16;
break;
case 15:
case 16:
col |= col << 16;
break;
default:
break;
}
return col;
}
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
unsigned int fgcol, unsigned int bgcol)
{
uint8_t *d;
const uint8_t *font_ptr;
unsigned int font_data, linesize, xorcol, bpp;
int i;
bpp = (ds->depth + 7) >> 3;
d = ds->data +
ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
linesize = ds->linesize;
font_ptr = vgafont16 + FONT_HEIGHT * ch;
xorcol = bgcol ^ fgcol;
switch(ds->depth) {
case 8:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 16:
case 15:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
d += linesize;
}
break;
case 32:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
d += linesize;
}
break;
}
}
static void text_console_resize(TextConsole *s)
{
TextCell *cells, *c, *c1;
int w1, x, y, last_width;
last_width = s->width;
s->width = s->g_width / FONT_WIDTH;
s->height = s->g_height / FONT_HEIGHT;
w1 = last_width;
if (s->width < w1)
w1 = s->width;
cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
for(y = 0; y < s->total_height; y++) {
c = &cells[y * s->width];
if (w1 > 0) {
c1 = &s->cells[y * last_width];
for(x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
for(x = w1; x < s->width; x++) {
c->ch = ' ';
c->fgcol = 7;
c->bgcol = 0;
c++;
}
}
free(s->cells);
s->cells = cells;
}
static void update_xy(TextConsole *s, int x, int y)
{
TextCell *c;
int y1, y2;
if (s == active_console) {
y1 = (s->y_base + y) % s->total_height;
y2 = y1 - s->y_displayed;
if (y2 < 0)
y2 += s->total_height;
if (y2 < s->height) {
c = &s->cells[y1 * s->width + x];
vga_putcharxy(s->ds, x, y2, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
static void console_show_cursor(TextConsole *s, int show)
{
TextCell *c;
int y, y1;
if (s == active_console) {
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 + s->x];
if (show) {
vga_putcharxy(s->ds, s->x, y, c->ch,
color_table[0], color_table[7]);
} else {
vga_putcharxy(s->ds, s->x, y, c->ch,
color_table[c->fgcol], color_table[c->bgcol]);
}
dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
}
static void console_refresh(TextConsole *s)
{
TextCell *c;
int x, y, y1;
if (s != active_console)
return;
vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
color_table[0]);
y1 = s->y_displayed;
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,
color_table[c->fgcol], color_table[c->bgcol]);
c++;
}
if (++y1 == s->total_height)
y1 = 0;
}
dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
console_show_cursor(s, 1);
}
static void console_scroll(int ydelta)
{
TextConsole *s;
int i, y1;
s = active_console;
if (!s || !s->text_console)
return;
if (ydelta > 0) {
for(i = 0; i < ydelta; i++) {
if (s->y_displayed == s->y_base)
break;
if (++s->y_displayed == s->total_height)
s->y_displayed = 0;
}
} else {
ydelta = -ydelta;
i = s->backscroll_height;
if (i > s->total_height - s->height)
i = s->total_height - s->height;
y1 = s->y_base - i;
if (y1 < 0)
y1 += s->total_height;
for(i = 0; i < ydelta; i++) {
if (s->y_displayed == y1)
break;
if (--s->y_displayed < 0)
s->y_displayed = s->total_height - 1;
}
}
console_refresh(s);
}
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;
if (s->y_displayed == s->y_base) {
if (++s->y_displayed == s->total_height)
s->y_displayed = 0;
}
if (++s->y_base == s->total_height)
s->y_base = 0;
if (s->backscroll_height < s->total_height)
s->backscroll_height++;
y1 = (s->y_base + s->height - 1) % s->total_height;
c = &s->cells[y1 * s->width];
for(x = 0; x < s->width; x++) {
c->ch = ' ';
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
}
if (s == active_console && s->y_displayed == s->y_base) {
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,
color_table[s->bgcol]);
dpy_update(s->ds, 0, 0,
s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
}
}
}
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
int y1, i, x;
switch(s->state) {
case TTY_STATE_NORM:
switch(ch) {
case '\r':
s->x = 0;
break;
case '\n':
console_put_lf(s);
break;
case 27:
s->state = TTY_STATE_ESC;
break;
default:
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ch;
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
update_xy(s, s->x, s->y);
s->x++;
if (s->x >= s->width)
console_put_lf(s);
break;
}
break;
case TTY_STATE_ESC:
if (ch == '[') {
for(i=0;i<MAX_ESC_PARAMS;i++)
s->esc_params[i] = 0;
s->nb_esc_params = 0;
s->state = TTY_STATE_CSI;
} else {
s->state = TTY_STATE_NORM;
}
break;
case TTY_STATE_CSI:
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] * 10 + ch - '0';
}
} else {
s->nb_esc_params++;
if (ch == ';')
break;
s->state = TTY_STATE_NORM;
switch(ch) {
case 'D':
if (s->x > 0)
s->x--;
break;
case 'C':
if (s->x < (s->width - 1))
s->x++;
break;
case 'K':
/* clear to eol */
y1 = (s->y_base + s->y) % s->total_height;
for(x = s->x; x < s->width; x++) {
c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
update_xy(s, x, s->y);
}
break;
default:
break;
}
break;
}
}
}
void console_select(unsigned int index)
{
TextConsole *s;
if (index >= MAX_CONSOLES)
return;
s = consoles[index];
if (s) {
active_console = s;
if (s->text_console) {
if (s->g_width != s->ds->width ||
s->g_height != s->ds->height) {
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
}
console_refresh(s);
}
}
}
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
{
TextConsole *s = chr->opaque;
int i;
console_show_cursor(s, 0);
for(i = 0; i < len; i++) {
console_putchar(s, buf[i]);
}
console_show_cursor(s, 1);
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;
int i;
if (event == CHR_EVENT_FOCUS) {
for(i = 0; i < nb_consoles; i++) {
if (consoles[i] == s) {
console_select(i);
break;
}
}
}
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
TextConsole *s;
uint8_t buf[16], *q;
int c;
s = active_console;
if (!s || !s->text_console)
return;
switch(keysym) {
case QEMU_KEY_CTRL_UP:
console_scroll(-1);
break;
case QEMU_KEY_CTRL_DOWN:
console_scroll(1);
break;
case QEMU_KEY_CTRL_PAGEUP:
console_scroll(-10);
break;
case QEMU_KEY_CTRL_PAGEDOWN:
console_scroll(10);
break;
default:
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;
}
s->fd_read(s->fd_opaque, buf, q - buf);
}
break;
}
}
TextConsole *graphic_console_init(DisplayState *ds)
{
TextConsole *s;
if (nb_consoles >= MAX_CONSOLES)
return NULL;
s = qemu_mallocz(sizeof(TextConsole));
if (!s) {
return NULL;
}
if (!active_console)
active_console = s;
s->ds = ds;
consoles[nb_consoles++] = s;
return s;
}
int is_active_console(TextConsole *s)
{
return s == active_console;
}
CharDriverState *text_console_init(DisplayState *ds)
{
CharDriverState *chr;
TextConsole *s;
int i;
static int color_inited;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = graphic_console_init(ds);
if (!s) {
free(chr);
return NULL;
}
s->text_console = 1;
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;
if (!color_inited) {
color_inited = 1;
for(i = 0; i < 8; i++) {
color_table[i] = col_expand(s->ds,
vga_get_color(s->ds, color_table_rgb[i]));
}
}
s->y_displayed = 0;
s->y_base = 0;
s->total_height = DEFAULT_BACKSCROLL;
s->x = 0;
s->y = 0;
s->fgcol = 7;
s->bgcol = 0;
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
return chr;
}

13
cow.h Normal file
View File

@@ -0,0 +1,13 @@
/* user mode linux compatible COW file */
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 2
struct cow_header_v2 {
uint32_t magic;
uint32_t version;
char backing_file[1024];
int32_t mtime;
uint64_t size;
uint32_t sectorsize;
};

198
cpu-all.h
View File

@@ -109,27 +109,23 @@ static inline void tswap64s(uint64_t *s)
#if TARGET_LONG_SIZE == 4
#define tswapl(s) tswap32(s)
#define tswapls(s) tswap32s((uint32_t *)(s))
#define bswaptls(s) bswap32s(s)
#else
#define tswapl(s) tswap64(s)
#define tswapls(s) tswap64s((uint64_t *)(s))
#define bswaptls(s) bswap64s(s)
#endif
/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
endian ! */
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
typedef union {
float64 d;
#if defined(WORDS_BIGENDIAN) \
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
double d;
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
struct {
uint32_t upper;
uint32_t lower;
uint32_t upper;
} l;
#else
struct {
uint32_t lower;
uint32_t upper;
uint32_t lower;
} l;
#endif
uint64_t ll;
@@ -170,17 +166,17 @@ typedef union {
* user : user mode access using soft MMU
* kernel : kernel mode access using soft MMU
*/
static inline int ldub_p(void *ptr)
static inline int ldub_raw(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb_p(void *ptr)
static inline int ldsb_raw(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb_p(void *ptr, int v)
static inline void stb_raw(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
@@ -191,7 +187,7 @@ static inline void stb_p(void *ptr, int v)
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
/* conservative code for little endian unaligned accesses */
static inline int lduw_p(void *ptr)
static inline int lduw_raw(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -203,7 +199,7 @@ static inline int lduw_p(void *ptr)
#endif
}
static inline int ldsw_p(void *ptr)
static inline int ldsw_raw(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -215,7 +211,7 @@ static inline int ldsw_p(void *ptr)
#endif
}
static inline int ldl_p(void *ptr)
static inline int ldl_raw(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -227,16 +223,16 @@ static inline int ldl_p(void *ptr)
#endif
}
static inline uint64_t ldq_p(void *ptr)
static inline uint64_t ldq_raw(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl_p(p);
v2 = ldl_p(p + 4);
v1 = ldl_raw(p);
v2 = ldl_raw(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw_p(void *ptr, int v)
static inline void stw_raw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
@@ -247,7 +243,7 @@ static inline void stw_p(void *ptr, int v)
#endif
}
static inline void stl_p(void *ptr, int v)
static inline void stl_raw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
@@ -260,54 +256,54 @@ static inline void stl_p(void *ptr, int v)
#endif
}
static inline void stq_p(void *ptr, uint64_t v)
static inline void stq_raw(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl_p(p, (uint32_t)v);
stl_p(p + 4, v >> 32);
stl_raw(p, (uint32_t)v);
stl_raw(p + 4, v >> 32);
}
/* float access */
static inline float32 ldfl_p(void *ptr)
static inline float ldfl_raw(void *ptr)
{
union {
float32 f;
float f;
uint32_t i;
} u;
u.i = ldl_p(ptr);
u.i = ldl_raw(ptr);
return u.f;
}
static inline void stfl_p(void *ptr, float32 v)
static inline void stfl_raw(void *ptr, float v)
{
union {
float32 f;
float f;
uint32_t i;
} u;
u.f = v;
stl_p(ptr, u.i);
stl_raw(ptr, u.i);
}
static inline float64 ldfq_p(void *ptr)
static inline double ldfq_raw(void *ptr)
{
CPU_DoubleU u;
u.l.lower = ldl_p(ptr);
u.l.upper = ldl_p(ptr + 4);
u.l.lower = ldl_raw(ptr);
u.l.upper = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq_p(void *ptr, float64 v)
static inline void stfq_raw(void *ptr, double v)
{
CPU_DoubleU u;
u.d = v;
stl_p(ptr, u.l.lower);
stl_p(ptr + 4, u.l.upper);
stl_raw(ptr, u.l.lower);
stl_raw(ptr + 4, u.l.upper);
}
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
static inline int lduw_p(void *ptr)
static inline int lduw_raw(void *ptr)
{
#if defined(__i386__)
int val;
@@ -322,7 +318,7 @@ static inline int lduw_p(void *ptr)
#endif
}
static inline int ldsw_p(void *ptr)
static inline int ldsw_raw(void *ptr)
{
#if defined(__i386__)
int val;
@@ -337,7 +333,7 @@ static inline int ldsw_p(void *ptr)
#endif
}
static inline int ldl_p(void *ptr)
static inline int ldl_raw(void *ptr)
{
#if defined(__i386__) || defined(__x86_64__)
int val;
@@ -352,15 +348,15 @@ static inline int ldl_p(void *ptr)
#endif
}
static inline uint64_t ldq_p(void *ptr)
static inline uint64_t ldq_raw(void *ptr)
{
uint32_t a,b;
a = ldl_p(ptr);
b = ldl_p(ptr+4);
a = ldl_raw(ptr);
b = ldl_raw(ptr+4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_p(void *ptr, int v)
static inline void stw_raw(void *ptr, int v)
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
@@ -374,7 +370,7 @@ static inline void stw_p(void *ptr, int v)
#endif
}
static inline void stl_p(void *ptr, int v)
static inline void stl_raw(void *ptr, int v)
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
@@ -390,130 +386,112 @@ static inline void stl_p(void *ptr, int v)
#endif
}
static inline void stq_p(void *ptr, uint64_t v)
static inline void stq_raw(void *ptr, uint64_t v)
{
stl_p(ptr, v >> 32);
stl_p(ptr + 4, v);
stl_raw(ptr, v >> 32);
stl_raw(ptr + 4, v);
}
/* float access */
static inline float32 ldfl_p(void *ptr)
static inline float ldfl_raw(void *ptr)
{
union {
float32 f;
float f;
uint32_t i;
} u;
u.i = ldl_p(ptr);
u.i = ldl_raw(ptr);
return u.f;
}
static inline void stfl_p(void *ptr, float32 v)
static inline void stfl_raw(void *ptr, float v)
{
union {
float32 f;
float f;
uint32_t i;
} u;
u.f = v;
stl_p(ptr, u.i);
stl_raw(ptr, u.i);
}
static inline float64 ldfq_p(void *ptr)
static inline double ldfq_raw(void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_p(ptr);
u.l.lower = ldl_p(ptr + 4);
u.l.upper = ldl_raw(ptr);
u.l.lower = ldl_raw(ptr + 4);
return u.d;
}
static inline void stfq_p(void *ptr, float64 v)
static inline void stfq_raw(void *ptr, double v)
{
CPU_DoubleU u;
u.d = v;
stl_p(ptr, u.l.upper);
stl_p(ptr + 4, u.l.lower);
stl_raw(ptr, u.l.upper);
stl_raw(ptr + 4, u.l.lower);
}
#else
static inline int lduw_p(void *ptr)
static inline int lduw_raw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_p(void *ptr)
static inline int ldsw_raw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_p(void *ptr)
static inline int ldl_raw(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_p(void *ptr)
static inline uint64_t ldq_raw(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_p(void *ptr, int v)
static inline void stw_raw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_p(void *ptr, int v)
static inline void stl_raw(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_p(void *ptr, uint64_t v)
static inline void stq_raw(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_p(void *ptr)
static inline float ldfl_raw(void *ptr)
{
return *(float32 *)ptr;
return *(float *)ptr;
}
static inline float64 ldfq_p(void *ptr)
static inline double ldfq_raw(void *ptr)
{
return *(float64 *)ptr;
return *(double *)ptr;
}
static inline void stfl_p(void *ptr, float32 v)
static inline void stfl_raw(void *ptr, float v)
{
*(float32 *)ptr = v;
*(float *)ptr = v;
}
static inline void stfq_p(void *ptr, float64 v)
static inline void stfq_raw(void *ptr, double v)
{
*(float64 *)ptr = v;
*(double *)ptr = v;
}
#endif
/* MMU memory access macros */
/* NOTE: we use double casts if pointers and target_ulong have
different sizes */
#define ldub_raw(p) ldub_p((uint8_t *)(long)(p))
#define ldsb_raw(p) ldsb_p((uint8_t *)(long)(p))
#define lduw_raw(p) lduw_p((uint8_t *)(long)(p))
#define ldsw_raw(p) ldsw_p((uint8_t *)(long)(p))
#define ldl_raw(p) ldl_p((uint8_t *)(long)(p))
#define ldq_raw(p) ldq_p((uint8_t *)(long)(p))
#define ldfl_raw(p) ldfl_p((uint8_t *)(long)(p))
#define ldfq_raw(p) ldfq_p((uint8_t *)(long)(p))
#define stb_raw(p, v) stb_p((uint8_t *)(long)(p), v)
#define stw_raw(p, v) stw_p((uint8_t *)(long)(p), v)
#define stl_raw(p, v) stl_p((uint8_t *)(long)(p), v)
#define stq_raw(p, v) stq_p((uint8_t *)(long)(p), v)
#define stfl_raw(p, v) stfl_p((uint8_t *)(long)(p), v)
#define stfq_raw(p, v) stfq_p((uint8_t *)(long)(p), v)
#if defined(CONFIG_USER_ONLY)
/* if user mode, no other memory access functions */
@@ -592,6 +570,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_signal_handler cpu_x86_signal_handler
#define cpu_dump_state cpu_x86_dump_state
#elif defined(TARGET_ARM)
@@ -600,6 +579,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_exec cpu_arm_exec
#define cpu_gen_code cpu_arm_gen_code
#define cpu_signal_handler cpu_arm_signal_handler
#define cpu_dump_state cpu_arm_dump_state
#elif defined(TARGET_SPARC)
@@ -608,6 +588,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_exec cpu_sparc_exec
#define cpu_gen_code cpu_sparc_gen_code
#define cpu_signal_handler cpu_sparc_signal_handler
#define cpu_dump_state cpu_sparc_dump_state
#elif defined(TARGET_PPC)
@@ -616,13 +597,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#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
#define cpu_dump_state cpu_ppc_dump_state
#else
@@ -632,10 +607,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#endif /* SINGLE_CPU_DEFINES */
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *cpu_single_env;
extern int code_copy_enabled;
@@ -721,8 +692,6 @@ int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
void *opaque);
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
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);
@@ -736,36 +705,21 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr,
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
uint32_t ldl_phys(target_phys_addr_t addr);
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
void stl_phys(target_phys_addr_t addr, uint32_t val);
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write);
#define VGA_DIRTY_FLAG 0x01
/* read dirty bit (return 0 or 1) */
static inline int cpu_physical_memory_is_dirty(target_ulong addr)
{
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
}
static inline int cpu_physical_memory_get_dirty(target_ulong addr,
int dirty_flags)
{
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
return phys_ram_dirty[addr >> TARGET_PAGE_BITS];
}
static inline void cpu_physical_memory_set_dirty(target_ulong addr)
{
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 1;
}
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
int dirty_flags);
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end);
#endif /* CPU_ALL_H */

View File

@@ -29,6 +29,12 @@
#error TARGET_LONG_BITS must be defined before including this header
#endif
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32
#endif
#ifndef TARGET_PHYS_ADDR_BITS
#if TARGET_LONG_BITS >= HOST_LONG_BITS
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
@@ -43,11 +49,9 @@
#if TARGET_LONG_SIZE == 4
typedef int32_t target_long;
typedef uint32_t target_ulong;
#define TARGET_FMT_lx "%08x"
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#define TARGET_FMT_lx "%016llx"
#else
#error TARGET_LONG_SIZE undefined
#endif
@@ -68,9 +72,9 @@ typedef uint64_t target_phys_addr_t;
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
#define MAX_BREAKPOINTS 32

View File

@@ -1,7 +1,7 @@
/*
* i386 emulator main execution loop
*
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -47,9 +47,6 @@ void cpu_loop_exit(void)
longjmp(env->jmp_env, 1);
}
#endif
#ifndef TARGET_SPARC
#define reg_T2
#endif
/* exit the current TB from a signal handler. The host registers are
restored in a state compatible with the CPU emulator
@@ -77,12 +74,8 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
int cpu_exec(CPUState *env1)
{
int saved_T0, saved_T1;
#if defined(reg_T2)
int saved_T2;
#endif
int saved_T0, saved_T1, saved_T2;
CPUState *saved_env;
#if defined(TARGET_I386)
#ifdef reg_EAX
int saved_EAX;
#endif
@@ -107,29 +100,21 @@ int cpu_exec(CPUState *env1)
#ifdef reg_EDI
int saved_EDI;
#endif
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
uint32_t *saved_regwptr;
#endif
#endif
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
target_ulong cs_base, pc;
uint8_t *tc_ptr;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
/* first we save global registers */
saved_env = env;
env = env1;
saved_T0 = T0;
saved_T1 = T1;
#if defined(reg_T2)
saved_T2 = T2;
#endif
saved_env = env;
env = env1;
#ifdef __sparc__
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
@@ -138,30 +123,37 @@ int cpu_exec(CPUState *env1)
#if defined(TARGET_I386)
#ifdef reg_EAX
saved_EAX = EAX;
EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
saved_ECX = ECX;
ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
saved_EDX = EDX;
EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
saved_EBX = EBX;
EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
saved_ESP = ESP;
ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
saved_EBP = EBP;
EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
saved_ESI = ESI;
ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
saved_EDI = EDI;
EDI = env->regs[R_EDI];
#endif
env_to_regs();
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
@@ -174,15 +166,10 @@ int cpu_exec(CPUState *env1)
env->CF = (psr >> 29) & 1;
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
env->VF = (psr << 3) & 0x80000000;
env->QF = (psr >> 27) & 1;
env->cpsr = psr & ~CACHED_CPSR_BITS;
env->cpsr = psr & ~0xf0000000;
}
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
saved_regwptr = REGWPTR;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#else
#error unsupported target CPU
#endif
@@ -221,40 +208,10 @@ int cpu_exec(CPUState *env1)
env->exception_next_eip, 0);
#elif defined(TARGET_PPC)
do_interrupt(env);
#elif defined(TARGET_MIPS)
do_interrupt(env);
#elif defined(TARGET_SPARC)
do_interrupt(env->exception_index);
#endif
}
env->exception_index = -1;
}
#ifdef USE_KQEMU
if (kqemu_is_ok(env) && env->interrupt_request == 0) {
int ret;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
ret = kqemu_cpu_exec(env);
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
if (ret == 1) {
/* exception */
longjmp(env->jmp_env, 1);
} else if (ret == 2) {
/* softmmu execution needed */
} else {
if (env->interrupt_request != 0) {
/* hardware interrupt will be executed just after */
} else {
/* otherwise, we restart */
longjmp(env->jmp_env, 1);
}
}
}
#endif
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
@@ -304,36 +261,6 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
}
#elif defined(TARGET_MIPS)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->CP0_Status & (1 << CP0St_IE)) &&
(env->CP0_Cause & 0x0000FF00) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM)) {
/* Raise it */
env->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
#elif defined(TARGET_SPARC)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->psret != 0)) {
int pil = env->interrupt_index & 15;
int type = env->interrupt_index & 0xf0;
if (((type == TT_EXTINT) &&
(pil == 15 || pil > env->psrpil)) ||
type != TT_EXTINT) {
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
do_interrupt(env->interrupt_index);
env->interrupt_index = 0;
}
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
//do_interrupt(0, 0, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
#endif
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
@@ -352,48 +279,28 @@ int cpu_exec(CPUState *env1)
}
}
#ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_EXEC)) {
if (loglevel & CPU_LOG_EXEC) {
#if defined(TARGET_I386)
/* restore flags in standard format */
#ifdef reg_EAX
env->regs[R_EAX] = EAX;
#endif
#ifdef reg_EBX
env->regs[R_EBX] = EBX;
#endif
#ifdef reg_ECX
env->regs[R_ECX] = ECX;
#endif
#ifdef reg_EDX
env->regs[R_EDX] = EDX;
#endif
#ifdef reg_ESI
env->regs[R_ESI] = ESI;
#endif
#ifdef reg_EDI
env->regs[R_EDI] = EDI;
#endif
#ifdef reg_EBP
env->regs[R_EBP] = EBP;
#endif
#ifdef reg_ESP
env->regs[R_ESP] = ESP;
#endif
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
cpu_dump_state(env, logfile, fprintf, 0);
env->cpsr &= ~CACHED_CPSR_BITS;
cpu_arm_dump_state(env, logfile, 0);
env->cpsr &= ~0xf0000000;
#elif defined(TARGET_SPARC)
REGWPTR = env->regbase + (env->cwp * 16);
env->regwptr = REGWPTR;
cpu_dump_state(env, logfile, fprintf, 0);
cpu_sparc_dump_state (env, logfile, 0);
#elif defined(TARGET_PPC)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_MIPS)
cpu_dump_state(env, logfile, fprintf, 0);
cpu_ppc_dump_state(env, logfile, 0);
#else
#error unsupported target CPU
#endif
@@ -408,31 +315,21 @@ int cpu_exec(CPUState *env1)
cs_base = env->segs[R_CS].base;
pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
flags = env->thumb | (env->vfp.vec_len << 1)
| (env->vfp.vec_stride << 4);
flags = 0;
cs_base = 0;
pc = env->regs[15];
pc = (uint8_t *)env->regs[15];
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
#else
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
#endif
cs_base = env->npc;
pc = env->pc;
flags = 0;
cs_base = (uint8_t *)env->npc;
pc = (uint8_t *) env->pc;
#elif defined(TARGET_PPC)
flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
(msr_se << MSR_SE) | (msr_le << MSR_LE);
flags = 0;
cs_base = 0;
pc = env->nip;
#elif defined(TARGET_MIPS)
flags = env->hflags & MIPS_HFLAGS_TMASK;
cs_base = NULL;
pc = env->PC;
pc = (uint8_t *)env->nip;
#else
#error unsupported CPU
#endif
tb = tb_find(&ptb, pc, cs_base,
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
TranslationBlock **ptb1;
@@ -443,11 +340,9 @@ int cpu_exec(CPUState *env1)
spin_lock(&tb_lock);
tb_invalidated_flag = 0;
regs_to_env(); /* XXX: do it just before cpu_gen_code() */
/* find translated block using physical mappings */
phys_pc = get_phys_addr_code(env, pc);
phys_pc = get_phys_addr_code(env, (unsigned long)pc);
phys_page1 = phys_pc & TARGET_PAGE_MASK;
phys_page2 = -1;
h = tb_phys_hash_func(phys_pc);
@@ -456,13 +351,13 @@ int cpu_exec(CPUState *env1)
tb = *ptb1;
if (!tb)
goto not_found;
if (tb->pc == pc &&
if (tb->pc == (unsigned long)pc &&
tb->page_addr[0] == phys_page1 &&
tb->cs_base == cs_base &&
tb->cs_base == (unsigned long)cs_base &&
tb->flags == flags) {
/* check next page if needed */
if (tb->page_addr[1] != -1) {
virt_page2 = (pc & TARGET_PAGE_MASK) +
virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) +
TARGET_PAGE_SIZE;
phys_page2 = get_phys_addr_code(env, virt_page2);
if (tb->page_addr[1] == phys_page2)
@@ -475,27 +370,27 @@ int cpu_exec(CPUState *env1)
}
not_found:
/* if no translated code available, then translate it now */
tb = tb_alloc(pc);
tb = tb_alloc((unsigned long)pc);
if (!tb) {
/* flush must be done */
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc(pc);
tb = tb_alloc((unsigned long)pc);
/* don't forget to invalidate previous TB info */
ptb = &tb_hash[tb_hash_func(pc)];
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
T0 = 0;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = cs_base;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
phys_page2 = -1;
if ((pc & TARGET_PAGE_MASK) != virt_page2) {
if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
@@ -505,7 +400,7 @@ int cpu_exec(CPUState *env1)
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
ptb = &tb_hash[tb_hash_func(pc)];
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
while (*ptb != NULL)
ptb = &(*ptb)->hash_next;
T0 = 0;
@@ -517,25 +412,24 @@ int cpu_exec(CPUState *env1)
spin_unlock(&tb_lock);
}
#ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_EXEC)) {
fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
(long)tb->tc_ptr, tb->pc,
lookup_symbol(tb->pc));
if (loglevel & CPU_LOG_EXEC) {
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
(long)tb->tc_ptr, (long)tb->pc,
lookup_symbol((void *)tb->pc));
}
#endif
#ifdef __sparc__
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. */
{
if (T0 != 0
if (T0 != 0
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
&& (tb->cflags & CF_CODE_COPY) ==
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
#endif
) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
#if defined(USE_CODE_COPY)
/* propagates the FP use info */
((TranslationBlock *)(T0 & ~3))->cflags |=
@@ -543,7 +437,6 @@ int cpu_exec(CPUState *env1)
#endif
spin_unlock(&tb_lock);
}
}
tc_ptr = tb->tc_ptr;
env->current_tb = tb;
/* execute the generated code */
@@ -635,15 +528,6 @@ int cpu_exec(CPUState *env1)
);
}
}
#elif defined(__ia64)
struct fptr {
void *ip;
void *gp;
} fp;
fp.ip = tc_ptr;
fp.gp = code_gen_buffer + 2 * (1 << 20);
(*(void (*)(void)) &fp)();
#else
gen_func();
#endif
@@ -659,7 +543,6 @@ int cpu_exec(CPUState *env1)
#endif
}
} else {
env_to_regs();
}
} /* for(;;) */
@@ -700,13 +583,8 @@ int cpu_exec(CPUState *env1)
#endif
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
/* XXX: Save/restore host fpu exception state?. */
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
REGWPTR = saved_regwptr;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#else
#error unsupported target CPU
#endif
@@ -715,9 +593,7 @@ int cpu_exec(CPUState *env1)
#endif
T0 = saved_T0;
T1 = saved_T1;
#if defined(reg_T2)
T2 = saved_T2;
#endif
env = saved_env;
return ret;
}
@@ -746,7 +622,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
selector &= 0xffff;
cpu_x86_load_seg_cache(env, seg_reg, selector,
(selector << 4), 0xffff, 0);
(uint8_t *)(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector);
}
@@ -760,7 +636,7 @@ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
saved_env = env;
env = s;
helper_fsave((target_ulong)ptr, data32);
helper_fsave(ptr, data32);
env = saved_env;
}
@@ -772,7 +648,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
saved_env = env;
env = s;
helper_frstor((target_ulong)ptr, data32);
helper_frstor(ptr, data32);
env = saved_env;
}
@@ -842,72 +718,19 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* XXX: do more */
return 0;
}
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
return 0;
}
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
@@ -917,8 +740,10 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
TranslationBlock *tb;
int ret;
#if 1
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#endif
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
@@ -958,57 +783,6 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
/* never comes here */
return 1;
}
#elif defined (TARGET_MIPS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
do_raise_exception_err(env->exception_index, env->error_code);
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
#endif
@@ -1129,7 +903,7 @@ typedef struct ucontext SIGCONTEXT;
# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
#endif /* __APPLE__ */
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
@@ -1246,57 +1020,6 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
&uc->uc_sigmask, puc);
}
#elif defined(__ia64)
#ifndef __ISR_VALID
/* This ought to be in <bits/siginfo.h>... */
# define __ISR_VALID 1
# define si_flags _sifields._sigfault._si_pad0
#endif
int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
{
struct ucontext *uc = puc;
unsigned long ip;
int is_write = 0;
ip = uc->uc_mcontext.sc_ip;
switch (host_signum) {
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
case SIGTRAP:
if (info->si_code && (info->si_flags & __ISR_VALID))
/* ISR.W (write-access) is bit 33: */
is_write = (info->si_isr >> 33) & 1;
break;
default:
break;
}
return handle_cpu_signal(ip, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask, puc);
}
#elif defined(__s390__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
pc = uc->uc_mcontext.psw.addr;
/* XXX: compute is_write */
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask, puc);
}
#else
#error host CPU specific signal handler needed

View File

@@ -9,7 +9,6 @@
#ifndef DIS_ASM_H
#define DIS_ASM_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
@@ -21,8 +20,6 @@ typedef int64_t bfd_signed_vma;
typedef uint8_t bfd_byte;
#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
#define BFD64
enum bfd_flavour {
bfd_target_unknown_flavour,
bfd_target_aout_flavour,
@@ -126,24 +123,6 @@ enum bfd_architecture
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
#define bfd_mach_ppc 0
#define bfd_mach_ppc64 1
#define bfd_mach_ppc_403 403
#define bfd_mach_ppc_403gc 4030
#define bfd_mach_ppc_505 505
#define bfd_mach_ppc_601 601
#define bfd_mach_ppc_602 602
#define bfd_mach_ppc_603 603
#define bfd_mach_ppc_ec603e 6031
#define bfd_mach_ppc_604 604
#define bfd_mach_ppc_620 620
#define bfd_mach_ppc_630 630
#define bfd_mach_ppc_750 750
#define bfd_mach_ppc_860 860
#define bfd_mach_ppc_a35 35
#define bfd_mach_ppc_rs64ii 642
#define bfd_mach_ppc_rs64iii 643
#define bfd_mach_ppc_7400 7400
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
bfd_arch_d10v, /* Mitsubishi D10V */
@@ -422,8 +401,6 @@ extern int generic_symbol_at_address
bfd_vma bfd_getl32 (const bfd_byte *addr);
bfd_vma bfd_getb32 (const bfd_byte *addr);
bfd_vma bfd_getl16 (const bfd_byte *addr);
bfd_vma bfd_getb16 (const bfd_byte *addr);
typedef enum bfd_boolean {false, true} boolean;
#endif /* ! defined (DIS_ASM_H) */

259
disas.c
View File

@@ -9,7 +9,9 @@
#include "disas.h"
/* Filled in by elfload.c. Simplistic, but will do for now. */
struct syminfo *syminfos = NULL;
unsigned int disas_num_syms;
void *disas_symtab;
const char *disas_strtab;
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
@@ -28,20 +30,23 @@ buffer_read_memory (memaddr, myaddr, length, info)
return 0;
}
#if !defined(CONFIG_USER_ONLY)
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
static int
target_read_memory (bfd_vma memaddr,
bfd_byte *myaddr,
int length,
struct disassemble_info *info)
target_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
int i;
for(i = 0; i < length; i++) {
myaddr[i] = ldub_code(memaddr + i);
myaddr[i] = ldub_code((void *)((long)memaddr + i));
}
return 0;
}
#endif
/* Print an error message. We can assume that this is in response to
an error return from buffer_read_memory. */
@@ -108,156 +113,77 @@ bfd_vma bfd_getb32 (const bfd_byte *addr)
return (bfd_vma) v;
}
bfd_vma bfd_getl16 (const bfd_byte *addr)
/* Disassemble this for me please... (debugging). 'flags' is only used
for i386: non zero means 16 bit code */
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
return (bfd_vma) v;
}
bfd_vma bfd_getb16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
return (bfd_vma) v;
}
#ifdef TARGET_ARM
static int
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
{
return print_insn_arm(pc | 1, info);
}
#endif
/* Disassemble this for me please... (debugging). 'flags' has teh following
values:
i386 - nonzero means 16 bit code
arm - nonzero means thumb code
other targets - unused
*/
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
{
target_ulong pc;
uint8_t *pc;
int count;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
disasm_info.read_memory_func = target_read_memory;
disasm_info.buffer_vma = code;
disasm_info.buffer_length = size;
#ifdef TARGET_WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
if (flags == 2)
disasm_info.mach = bfd_mach_x86_64;
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)
if (flags)
print_insn = print_insn_thumb1;
else
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#ifdef TARGET_SPARC64
disasm_info.mach = bfd_mach_sparc_v9b;
#endif
#elif defined(TARGET_PPC)
if (cpu_single_env->msr[MSR_LE])
disasm_info.endian = BFD_ENDIAN_LITTLE;
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
#else
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
return;
#endif
for (pc = code; pc < code + size; pc += count) {
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
count = print_insn(pc, &disasm_info);
#if 0
{
int i;
uint8_t b;
fprintf(out, " {");
for(i = 0; i < count; i++) {
target_read_memory(pc + i, &b, 1, &disasm_info);
fprintf(out, " %02x", b);
}
fprintf(out, " }");
}
#endif
fprintf(out, "\n");
if (count < 0)
break;
#if !defined(CONFIG_USER_ONLY)
if (!is_host) {
disasm_info.read_memory_func = target_read_memory;
}
}
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
unsigned long pc;
int count;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
#endif
disasm_info.buffer = code;
disasm_info.buffer_vma = (unsigned long)code;
disasm_info.buffer_length = size;
if (is_host) {
#ifdef WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(__i386__)
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(__x86_64__)
disasm_info.mach = bfd_mach_x86_64;
print_insn = print_insn_i386;
disasm_info.mach = bfd_mach_x86_64;
print_insn = print_insn_i386;
#elif defined(__powerpc__)
print_insn = print_insn_ppc;
print_insn = print_insn_ppc;
#elif defined(__alpha__)
print_insn = print_insn_alpha;
print_insn = print_insn_alpha;
#elif defined(__sparc__)
print_insn = print_insn_sparc;
print_insn = print_insn_sparc;
#elif defined(__arm__)
print_insn = print_insn_arm;
#elif defined(__MIPSEB__)
print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
print_insn = print_insn_little_mips;
print_insn = print_insn_arm;
#else
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
(long) code);
return;
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
fprintf(out, "0x%08lx: ", pc);
} else {
#ifdef TARGET_WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
if (!flags)
disasm_info.mach = bfd_mach_i386_i386;
else
disasm_info.mach = bfd_mach_i386_i8086;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
print_insn = print_insn_ppc;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
}
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
fprintf(out, "0x%08lx: ", (long)pc);
#ifdef __arm__
/* since data are included in the code, it is better to
display code data too */
@@ -265,7 +191,7 @@ void disas(FILE *out, void *code, unsigned long size)
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
}
#endif
count = print_insn(pc, &disasm_info);
count = print_insn((unsigned long)pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
break;
@@ -273,36 +199,29 @@ void disas(FILE *out, void *code, unsigned long size)
}
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(target_ulong orig_addr)
const char *lookup_symbol(void *orig_addr)
{
unsigned int i;
/* Hack, because we know this is x86. */
Elf32_Sym *sym;
struct syminfo *s;
for (s = syminfos; s; s = s->next) {
sym = s->disas_symtab;
for (i = 0; i < s->disas_num_syms; i++) {
if (sym[i].st_shndx == SHN_UNDEF
|| sym[i].st_shndx >= SHN_LORESERVE)
continue;
Elf32_Sym *sym = disas_symtab;
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
continue;
for (i = 0; i < disas_num_syms; i++) {
if (sym[i].st_shndx == SHN_UNDEF
|| sym[i].st_shndx >= SHN_LORESERVE)
continue;
if (orig_addr >= sym[i].st_value
&& orig_addr < sym[i].st_value + sym[i].st_size)
return s->disas_strtab + sym[i].st_name;
}
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
continue;
if ((long)orig_addr >= sym[i].st_value
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
return disas_strtab + sym[i].st_name;
}
return "";
}
#if !defined(CONFIG_USER_ONLY)
void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);
static int monitor_disas_is_physical;
static int
@@ -320,22 +239,16 @@ monitor_read_memory (memaddr, myaddr, length, info)
return 0;
}
static int monitor_fprintf(FILE *stream, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
term_vprintf(fmt, ap);
va_end(ap);
return 0;
}
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
{
FILE *out;
int count, i;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
out = stdout;
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
monitor_disas_is_physical = is_physical;
disasm_info.read_memory_func = monitor_read_memory;
@@ -348,36 +261,26 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
if (flags == 2)
disasm_info.mach = bfd_mach_x86_64;
else if (flags == 1)
disasm_info.mach = bfd_mach_i386_i8086;
else
if (!flags)
disasm_info.mach = bfd_mach_i386_i386;
else
disasm_info.mach = bfd_mach_i386_i8086;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
#else
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
term_printf("0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
for(i = 0; i < nb_insn; i++) {
term_printf("0x" TARGET_FMT_lx ": ", pc);
fprintf(out, "0x%08lx: ", (unsigned long)pc);
count = print_insn(pc, &disasm_info);
term_printf("\n");
fprintf(out, "\n");
if (count < 0)
break;
pc += count;

15
disas.h
View File

@@ -2,19 +2,14 @@
#define _QEMU_DISAS_H
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size);
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(target_ulong orig_addr);
const char *lookup_symbol(void *orig_addr);
/* Filled in by elfload.c. Simplistic, but will do for now. */
extern struct syminfo {
unsigned int disas_num_syms;
void *disas_symtab;
const char *disas_strtab;
struct syminfo *next;
} *syminfos;
extern unsigned int disas_num_syms;
extern void *disas_symtab; /* FIXME: includes are a mess --RR */
extern const char *disas_strtab;
#endif /* _QEMU_DISAS_H */

View File

@@ -29,7 +29,7 @@ typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__) || defined(__ia64)
#if defined (__x86_64__)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
@@ -38,7 +38,7 @@ typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#if defined (__x86_64__) || defined(__ia64)
#if defined (__x86_64__)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
@@ -62,6 +62,17 @@ extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#undef NULL
#define NULL 0
#if defined(_BSD) && !defined(__APPLE__)
#include <ieeefp.h>
#define FE_TONEAREST FP_RN
#define FE_DOWNWARD FP_RM
#define FE_UPWARD FP_RP
#define FE_TOWARDZERO FP_RZ
#define fesetround(x) fpsetround(x)
#else
#include <fenv.h>
#endif
#ifdef __i386__
#define AREG0 "ebp"
@@ -74,8 +85,8 @@ extern int printf(const char *, ...);
#define AREG1 "rbx"
#define AREG2 "r12"
#define AREG3 "r13"
//#define AREG4 "r14"
//#define AREG5 "r15"
#define AREG4 "r14"
#define AREG5 "r15"
#endif
#ifdef __powerpc__
#define AREG0 "r27"
@@ -148,10 +159,10 @@ extern int printf(const char *, ...);
#define AREG4 "%d5"
#endif
#ifdef __ia64__
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
#endif
/* force GCC to generate only one epilog at the end of the function */
@@ -173,7 +184,7 @@ extern int printf(const char *, ...);
#define __hidden
#endif
#if defined(__alpha__)
#ifdef __alpha__
/* Suggested by Richard Henderson. This will result in code like
ldah $0,__op_param1($29) !gprelhigh
lda $0,__op_param1($0) !gprellow
@@ -186,47 +197,31 @@ extern int __op_param3 __hidden;
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
#else
#if defined(__APPLE__)
static int __op_param1, __op_param2, __op_param3;
#else
extern int __op_param1, __op_param2, __op_param3;
#endif
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#endif /* !defined(__alpha__) */
#endif
extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#if defined(_WIN32) || defined(__APPLE__)
#define ASM_NAME(x) "_" #x
#else
#define ASM_NAME(x) #x
#endif
#ifdef __i386__
#define EXIT_TB() asm volatile ("ret")
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __x86_64__
#define EXIT_TB() asm volatile ("ret")
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __powerpc__
#define EXIT_TB() asm volatile ("blr")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __s390__
#define EXIT_TB() asm volatile ("br %r14")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __alpha__
#define EXIT_TB() asm volatile ("ret")
#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)
#endif
#ifdef __sparc__
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
@@ -234,7 +229,6 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#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)
#endif
#ifdef __mc68000
#define EXIT_TB() asm volatile ("rts")

View File

@@ -1,9 +0,0 @@
static inline int gen_new_label(void)
{
return nb_gen_labels++;
}
static inline void gen_set_label(int n)
{
gen_labels[n] = gen_opc_ptr - gen_opc_buf;
}

346
dyngen.c
View File

@@ -54,7 +54,7 @@
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
#undef ELF_USES_RELOCA
#elif defined(HOST_X86_64)
#elif defined(HOST_AMD64)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_X86_64
@@ -635,8 +635,6 @@ static char *get_rel_sym_name(EXE_RELOC *rel)
name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
if (!strcmp(name, ".data"))
name = name_for_dotdata(rel);
if (name[0] == '.')
return NULL;
return name;
}
@@ -998,11 +996,11 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
switch(rel->r_type)
{
case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset & 0xffff);
break;
case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (other_half & 0xffff);
break;
case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (other_half & 0xffff);
break;
case PPC_RELOC_BR24:
sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
@@ -1148,11 +1146,13 @@ int load_object(const char *filename)
/* Now transform the symtab, to an extended version, with the sym size, and the C name */
for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
const char *name;
struct nlist *sym_follow, *sym_next = 0;
unsigned int j;
name = find_str_by_index(sym->n_un.n_strx);
memset(sym, 0, sizeof(*sym));
if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
if ( sym->n_type & N_STAB ) /* Debug symbols are skipped */
continue;
memcpy(sym, syment, sizeof(*syment));
@@ -1185,68 +1185,6 @@ int load_object(const char *filename)
#endif /* CONFIG_FORMAT_MACH */
void get_reloc_expr(char *name, int name_size, const char *sym_name)
{
const char *p;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, name_size, "param%s", p);
} else if (strstart(sym_name, "__op_gen_label", &p)) {
snprintf(name, name_size, "gen_labels[param%s]", p);
} else {
#ifdef HOST_SPARC
if (sym_name[0] == '.')
snprintf(name, sizeof(name),
"(long)(&__dot_%s)",
sym_name + 1);
else
#endif
snprintf(name, name_size, "(long)(&%s)", sym_name);
}
}
#ifdef HOST_IA64
#define PLT_ENTRY_SIZE 16 /* 1 bundle containing "brl" */
struct plt_entry {
struct plt_entry *next;
const char *name;
unsigned long addend;
} *plt_list;
static int
get_plt_index (const char *name, unsigned long addend)
{
struct plt_entry *plt, *prev= NULL;
int index = 0;
/* see if we already have an entry for this target: */
for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
if (strcmp(plt->name, name) == 0 && plt->addend == addend)
return index;
/* nope; create a new PLT entry: */
plt = malloc(sizeof(*plt));
if (!plt) {
perror("malloc");
exit(1);
}
memset(plt, 0, sizeof(*plt));
plt->name = strdup(name);
plt->addend = addend;
/* append to plt-list: */
if (prev)
prev->next = plt;
else
plt_list = plt;
return index;
}
#endif
#ifdef HOST_ARM
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
@@ -1306,7 +1244,11 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
if (rel->r_offset == (pc_offset + start_offset)) {
sym_name = get_rel_sym_name(rel);
/* the compiler leave some unnecessary references to the code */
get_reloc_expr(relname, sizeof(relname), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(relname, sizeof(relname), "param%s", p);
} else {
snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
if (type != R_ARM_ABS32)
error("%s: unsupported data relocation", name);
@@ -1365,7 +1307,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
p_start = text + offset;
p_end = p_start + size;
start_offset = offset;
#if defined(HOST_I386) || defined(HOST_X86_64)
#if defined(HOST_I386) || defined(HOST_AMD64)
#ifdef CONFIG_FORMAT_COFF
{
uint8_t *p;
@@ -1436,7 +1378,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
/* 08 00 84 00 */
if (get32((uint32_t *)p) != 0x00840008)
error("br.ret.sptk.many b0;; expected at the end of %s", name);
copy_size = p_end - p_start;
copy_size = p - p_start;
}
#elif defined(HOST_SPARC)
{
@@ -1540,8 +1482,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
sym_name = get_rel_sym_name(rel);
if(!sym_name)
continue;
if (strstart(sym_name, "__op_param", &p) ||
strstart(sym_name, "__op_gen_label", &p)) {
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
if (n > MAX_ARGS)
error("too many arguments in %s", name);
@@ -1573,11 +1514,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
fprintf(outfile, ";\n");
}
#if defined(HOST_IA64)
fprintf(outfile, " extern char %s;\n", name);
#else
fprintf(outfile, " extern void %s();\n", name);
#endif
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
host_ulong offset = get_rel_offset(rel);
@@ -1588,8 +1525,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
continue;
if (*sym_name &&
!strstart(sym_name, "__op_param", NULL) &&
!strstart(sym_name, "__op_jmp", NULL) &&
!strstart(sym_name, "__op_gen_label", NULL)) {
!strstart(sym_name, "__op_jmp", NULL)) {
#if defined(HOST_SPARC)
if (sym_name[0] == '.') {
fprintf(outfile,
@@ -1598,18 +1534,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
continue;
}
#endif
#if defined(__APPLE__)
#ifdef __APPLE__
/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
#elif defined(HOST_IA64)
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
/*
* PCREL21 br.call targets generally
* are out of range and need to go
* through an "import stub".
*/
fprintf(outfile, " extern char %s;\n",
sym_name);
#else
fprintf(outfile, "extern char %s;\n", sym_name);
#endif
@@ -1677,7 +1604,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
#endif
if (val >= start_offset && val <= start_offset + copy_size) {
if (val >= start_offset && val < start_offset + copy_size) {
n = strtol(p, NULL, 10);
fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
}
@@ -1700,8 +1628,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = get_rel_sym_name(rel);
if (!sym_name)
continue;
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
@@ -1714,7 +1640,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
continue;
}
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
addend = get32((uint32_t *)(text + rel->r_offset));
#ifdef CONFIG_FORMAT_ELF
type = ELF32_R_TYPE(rel->r_info);
@@ -1763,7 +1693,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
#elif defined(HOST_X86_64)
#elif defined(HOST_AMD64)
{
char name[256];
int type;
@@ -1772,7 +1702,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
@@ -1789,7 +1723,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported X86_64 relocation (%d)", type);
error("unsupported AMD64 relocation (%d)", type);
}
}
}
@@ -1816,7 +1750,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
continue;
}
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
@@ -1901,20 +1839,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
continue; /* dunno how to handle without final_sym_name */
}
get_reloc_expr(final_sym_name, sizeof(final_sym_name),
sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(final_sym_name, sizeof(final_sym_name), "param%s", p);
} else {
snprintf(final_sym_name, sizeof(final_sym_name), "(long)(&%s)", sym_name);
}
switch(type) {
case PPC_RELOC_BR24:
if (!strstart(sym_name,"__op_gen_label",&p)) {
fprintf(outfile, "{\n");
fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n",
fprintf(outfile, "{\n");
fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n",
slide, slide, name, sslide );
fprintf(outfile, "}\n");
} else {
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
slide, slide, final_sym_name, slide);
}
fprintf(outfile, "}\n");
break;
case PPC_RELOC_HI16:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
@@ -1945,7 +1882,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
@@ -2023,78 +1964,29 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_IA64)
{
unsigned long sym_idx;
long code_offset;
char name[256];
int type;
long addend;
int addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
sym_idx = ELF64_R_SYM(rel->r_info);
if (rel->r_offset < start_offset
|| rel->r_offset >= start_offset + copy_size)
continue;
sym_name = (strtab + symtab[sym_idx].st_name);
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
/* __op_jmp relocations are done at
runtime to do translated block
chaining: the offset of the instruction
needs to be stored */
fprintf(outfile, " jmp_offsets[%d] ="
"%ld + (gen_code_ptr - gen_code_buf);\n",
n, rel->r_offset - start_offset);
continue;
}
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
code_offset = rel->r_offset - start_offset;
switch(type) {
case R_IA64_IMM64:
fprintf(outfile,
" ia64_imm64(gen_code_ptr + %ld, "
"%s + %ld);\n",
code_offset, name, addend);
break;
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
fprintf(outfile, " IA64_LTOFF(gen_code_ptr + %ld,"
" %s + %ld, %d);\n",
code_offset, name, addend,
(type == R_IA64_LTOFF22X));
break;
case R_IA64_LDXMOV:
fprintf(outfile,
" ia64_ldxmov(gen_code_ptr + %ld,"
" %s + %ld);\n", code_offset, name, addend);
break;
case R_IA64_PCREL21B:
if (strstart(sym_name, "__op_gen_label", NULL)) {
fprintf(outfile,
" ia64_imm21b(gen_code_ptr + %ld,"
" (long) (%s + %ld -\n\t\t"
"((long) gen_code_ptr + %ld)) >> 4);\n",
code_offset, name, addend,
code_offset & ~0xfUL);
} else {
fprintf(outfile,
" IA64_PLT(gen_code_ptr + %ld, "
"%d);\t/* %s + %ld */\n",
code_offset,
get_plt_index(sym_name, addend),
sym_name, addend);
}
break;
default:
error("unsupported ia64 relocation (0x%x)",
type);
}
if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_IA64_LTOFF22:
error("must implemnt R_IA64_LTOFF22 relocation");
case R_IA64_PCREL21B:
error("must implemnt R_IA64_PCREL21B relocation");
default:
error("unsupported ia64 relocation (%d)", type);
}
}
}
fprintf(outfile, " ia64_nop_b(gen_code_ptr + %d);\n",
copy_size - 16 + 2);
}
#elif defined(HOST_SPARC)
{
@@ -2105,7 +1997,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
if (sym_name[0] == '.')
snprintf(name, sizeof(name),
"(long)(&__dot_%s)",
sym_name + 1);
else
snprintf(name, sizeof(name),
"(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
@@ -2160,7 +2062,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
@@ -2222,7 +2128,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
/* the compiler leave some unnecessary references to the code */
if (sym_name[0] == '\0')
continue;
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset));
switch(type) {
@@ -2251,7 +2161,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
rel->r_offset < start_offset + copy_size) {
sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
switch(type) {
@@ -2318,7 +2232,7 @@ int gen_file(FILE *outfile, int out_type)
}
} else if (out_type == OUT_GEN_OP) {
/* generate gen_xxx functions */
fprintf(outfile, "#include \"dyngen-op.h\"\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name;
name = get_sym_name(sym);
@@ -2336,7 +2250,7 @@ int gen_file(FILE *outfile, int out_type)
fprintf(outfile,
"int dyngen_code(uint8_t *gen_code_buf,\n"
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
" const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
"{\n"
" uint8_t *gen_code_ptr;\n"
" const uint16_t *opc_ptr;\n"
@@ -2348,63 +2262,6 @@ fprintf(outfile,
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
" uint32_t *arm_data_ptr = arm_data_table;\n");
#endif
#ifdef HOST_IA64
{
long addend, not_first = 0;
unsigned long sym_idx;
int index, max_index;
const char *sym_name;
EXE_RELOC *rel;
max_index = -1;
for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
sym_idx = ELF64_R_SYM(rel->r_info);
sym_name = (strtab + symtab[sym_idx].st_name);
if (strstart(sym_name, "__op_gen_label", NULL))
continue;
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
continue;
addend = rel->r_addend;
index = get_plt_index(sym_name, addend);
if (index <= max_index)
continue;
max_index = index;
fprintf(outfile, " extern void %s(void);\n", sym_name);
}
fprintf(outfile,
" struct ia64_fixup *plt_fixes = NULL, "
"*ltoff_fixes = NULL;\n"
" static long plt_target[] = {\n\t");
max_index = -1;
for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
sym_idx = ELF64_R_SYM(rel->r_info);
sym_name = (strtab + symtab[sym_idx].st_name);
if (strstart(sym_name, "__op_gen_label", NULL))
continue;
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
continue;
addend = rel->r_addend;
index = get_plt_index(sym_name, addend);
if (index <= max_index)
continue;
max_index = index;
if (not_first)
fprintf(outfile, ",\n\t");
not_first = 1;
if (addend)
fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
else
fprintf(outfile, "(long) &%s", sym_name);
}
fprintf(outfile, "\n };\n"
" unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
}
#endif
fprintf(outfile,
"\n"
@@ -2467,13 +2324,6 @@ fprintf(outfile,
" }\n"
" the_end:\n"
);
#ifdef HOST_IA64
fprintf(outfile,
" ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
"(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
"sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
"plt_target, plt_offset);\n");
#endif
/* generate some code patching */
#ifdef HOST_ARM

222
dyngen.h
View File

@@ -19,7 +19,6 @@
*/
int __op_param1, __op_param2, __op_param3;
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
@@ -43,11 +42,6 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
#ifdef __ia64__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
while (start < stop) {
asm volatile ("fc %0" :: "r"(start));
start += 32;
}
asm volatile (";;sync.i;;srlz.i;;");
}
#endif
@@ -210,217 +204,5 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
#endif /* __arm__ */
#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)
{
uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
# define insn_mask ((1UL << 41) - 1)
unsigned long shift;
b0 = b[0]; b1 = b[1];
shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
if (shift >= 64) {
m1 = mask << (shift - 64);
v1 = val << (shift - 64);
} else {
m0 = mask << shift; m1 = mask >> (64 - shift);
v0 = val << shift; v1 = val >> (64 - shift);
b[0] = (b0 & ~m0) | (v0 & m0);
}
b[1] = (b1 & ~m1) | (v1 & m1);
}
static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
{
ia64_patch(insn_addr,
0x011ffffe000UL,
( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
| ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
}
static inline void ia64_imm64 (void *insn, uint64_t val)
{
/* Ignore the slot number of the relocation; GCC and Intel
toolchains differed for some time on whether IMM64 relocs are
against slot 1 (Intel) or slot 2 (GCC). */
uint64_t insn_addr = (uint64_t) insn & ~3UL;
ia64_patch(insn_addr + 2,
0x01fffefe000UL,
( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
| ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */
| ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */
| ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */
| ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)
);
ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
}
static inline void ia64_imm60b (void *insn, uint64_t val)
{
/* Ignore the slot number of the relocation; GCC and Intel
toolchains differed for some time on whether IMM64 relocs are
against slot 1 (Intel) or slot 2 (GCC). */
uint64_t insn_addr = (uint64_t) insn & ~3UL;
if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
fprintf(stderr, "%s: value %ld out of IMM60 range\n",
__FUNCTION__, (int64_t) val);
ia64_patch_imm60(insn_addr + 2, val);
}
static inline void ia64_imm22 (void *insn, uint64_t val)
{
if (val + (1 << 21) >= (1 << 22))
fprintf(stderr, "%s: value %li out of IMM22 range\n",
__FUNCTION__, (int64_t)val);
ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
}
/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has
the effect of turning "addl rX=imm22,rY" into "addl
rX=imm22,r0". */
static inline void ia64_imm22_r0 (void *insn, uint64_t val)
{
if (val + (1 << 21) >= (1 << 22))
fprintf(stderr, "%s: value %li out of IMM22 range\n",
__FUNCTION__, (int64_t)val);
ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
}
static inline void ia64_imm21b (void *insn, uint64_t val)
{
if (val + (1 << 20) >= (1 << 21))
fprintf(stderr, "%s: value %li out of IMM21b range\n",
__FUNCTION__, (int64_t)val);
ia64_patch((uint64_t) insn, 0x11ffffe000UL,
( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
| ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */));
}
static inline void ia64_nop_b (void *insn)
{
ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
}
static inline void ia64_ldxmov(void *insn, uint64_t val)
{
if (val + (1 << 21) < (1 << 22))
ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
}
static inline int ia64_patch_ltoff(void *insn, uint64_t val,
int relaxable)
{
if (relaxable && (val + (1 << 21) < (1 << 22))) {
ia64_imm22_r0(insn, val);
return 0;
}
return 1;
}
struct ia64_fixup {
struct ia64_fixup *next;
void *addr; /* address that needs to be patched */
long value;
};
#define IA64_PLT(insn, plt_index) \
do { \
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
fixup->next = plt_fixes; \
plt_fixes = fixup; \
fixup->addr = (insn); \
fixup->value = (plt_index); \
plt_offset[(plt_index)] = 1; \
} while (0)
#define IA64_LTOFF(insn, val, relaxable) \
do { \
if (ia64_patch_ltoff(insn, val, relaxable)) { \
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
fixup->next = ltoff_fixes; \
ltoff_fixes = fixup; \
fixup->addr = (insn); \
fixup->value = (val); \
} \
} while (0)
static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
struct ia64_fixup *ltoff_fixes,
uint64_t gp,
struct ia64_fixup *plt_fixes,
int num_plts,
unsigned long *plt_target,
unsigned int *plt_offset)
{
static const uint8_t plt_bundle[] = {
0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
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, *vp;
struct ia64_fixup *fixup;
unsigned int offset = 0;
struct fdesc {
long ip;
long gp;
} *fdesc;
int i;
if (plt_fixes) {
plt_start = gen_code_ptr;
for (i = 0; i < num_plts; ++i) {
if (plt_offset[i]) {
plt_offset[i] = offset;
offset += sizeof(plt_bundle);
fdesc = (struct fdesc *) plt_target[i];
memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
ia64_imm60b(gen_code_ptr + 0x12,
(fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
gen_code_ptr += sizeof(plt_bundle);
}
}
for (fixup = plt_fixes; fixup; fixup = fixup->next)
ia64_imm21b(fixup->addr,
((long) plt_start + plt_offset[fixup->value]
- ((long) fixup->addr & ~0xf)) >> 4);
}
got_start = gen_code_ptr;
/* 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 = got_start; vp < gen_code_ptr; ++vp)
if (*(uint64_t *) vp == fixup->value)
break;
if (vp == gen_code_ptr) {
/* Nope, we need to put the value in the GOT: */
*(uint64_t *) vp = fixup->value;
gen_code_ptr += 8;
}
ia64_imm22(fixup->addr, (long) vp - gp);
}
*gen_code_pp = gen_code_ptr;
}
#endif

18
elf.h
View File

@@ -31,29 +31,11 @@ typedef int64_t Elf64_Sxword;
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_MIPS_REGINFO 0x70000000
#define PT_MIPS_OPTIONS 0x70000001
/* Flags in the e_flags field of the header */
/* MIPS architecture level. */
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
/* The ABI of a file. */
#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */
#define EF_MIPS_NOREORDER 0x00000001
#define EF_MIPS_PIC 0x00000002
#define EF_MIPS_CPIC 0x00000004
#define EF_MIPS_ABI2 0x00000020
#define EF_MIPS_OPTIONS_FIRST 0x00000080
#define EF_MIPS_32BITMODE 0x00000100
#define EF_MIPS_ABI 0x0000f000
#define EF_MIPS_ARCH 0xf0000000
/* These constants define the different elf file types */

View File

@@ -28,7 +28,7 @@
#define tostring(s) #s
#endif
#if __GNUC__ < 3
#if GCC_MAJOR < 3
#define __builtin_expect(x, n) (x)
#endif
@@ -55,13 +55,9 @@ struct TranslationBlock;
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
extern long gen_labels[OPC_BUF_SIZE];
extern int nb_gen_labels;
extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
extern target_ulong gen_opc_jump_pc[2];
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
@@ -126,12 +122,10 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
#if defined(__alpha__)
#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024)
#elif defined(__ia64)
#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */
#elif defined(__powerpc__)
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
#else
#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024)
#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024)
#endif
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
@@ -191,7 +185,7 @@ typedef struct TranslationBlock {
struct TranslationBlock *jmp_first;
} TranslationBlock;
static inline unsigned int tb_hash_func(target_ulong pc)
static inline unsigned int tb_hash_func(unsigned long pc)
{
return pc & (CODE_GEN_HASH_SIZE - 1);
}
@@ -201,7 +195,7 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc)
return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
}
TranslationBlock *tb_alloc(target_ulong pc);
TranslationBlock *tb_alloc(unsigned long pc);
void tb_flush(CPUState *env);
void tb_link(TranslationBlock *tb);
void tb_link_phys(TranslationBlock *tb,
@@ -315,15 +309,17 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#elif defined(__APPLE__)
#define ASM_DATA_SECTION ".data\n"
#define ASM_PREVIOUS_SECTION ".text\n"
#define ASM_NAME(x) "_" #x
#else
#define ASM_DATA_SECTION ".section \".data\"\n"
#define ASM_PREVIOUS_SECTION ".previous\n"
#define ASM_NAME(x) stringify(x)
#endif
#if defined(__powerpc__)
/* we patch the jump instruction directly */
#define GOTO_TB(opname, tbparam, n)\
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
asm volatile (ASM_DATA_SECTION\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
@@ -331,12 +327,20 @@ do {\
ASM_PREVIOUS_SECTION \
"b " ASM_NAME(__op_jmp) #n "\n"\
"1:\n");\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
EXIT_TB();\
} while (0)
#define JUMP_TB2(opname, tbparam, n)\
do {\
asm volatile ("b " ASM_NAME(__op_jmp) #n "\n");\
} while (0)
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
/* we patch the jump instruction directly */
#define GOTO_TB(opname, tbparam, n)\
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
asm volatile (".section .data\n"\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
@@ -344,32 +348,40 @@ do {\
ASM_PREVIOUS_SECTION \
"jmp " ASM_NAME(__op_jmp) #n "\n"\
"1:\n");\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
EXIT_TB();\
} while (0)
#define JUMP_TB2(opname, tbparam, n)\
do {\
asm volatile ("jmp " ASM_NAME(__op_jmp) #n "\n");\
} while (0)
#else
/* jump to next block operations (more portable code, does not need
cache flushing, but slower because of indirect jump) */
#define GOTO_TB(opname, tbparam, n)\
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
label ## n: ;\
dummy_label ## n: ;\
label ## n:\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
dummy_label ## n:\
EXIT_TB();\
} while (0)
/* second jump to same destination 'n' */
#define JUMP_TB2(opname, tbparam, n)\
do {\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\
} while (0)
#endif
/* XXX: will be suppressed */
#define JUMP_TB(opname, tbparam, n, eip)\
do {\
GOTO_TB(opname, tbparam, n);\
T0 = (long)(tbparam) + (n);\
EIP = (int32_t)eip;\
EXIT_TB();\
} while (0)
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];
@@ -395,26 +407,28 @@ static inline int testandset (int *p)
#ifdef __i386__
static inline int testandset (int *p)
{
long int readval = 0;
char ret;
long int readval;
__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
: "+m" (*p), "+a" (readval)
: "r" (1)
: "cc");
return readval;
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
: "=q" (ret), "=m" (*p), "=a" (readval)
: "r" (1), "m" (*p), "a" (0)
: "memory");
return ret;
}
#endif
#ifdef __x86_64__
static inline int testandset (int *p)
{
long int readval = 0;
char ret;
int readval;
__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
: "+m" (*p), "+a" (readval)
: "r" (1)
: "cc");
return readval;
__asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
: "=q" (ret), "=m" (*p), "=a" (readval)
: "r" (1), "m" (*p), "a" (0)
: "memory");
return ret;
}
#endif
@@ -485,16 +499,7 @@ static inline int testandset (int *p)
: "=r" (ret)
: "m" (p)
: "cc","memory");
return ret;
}
#endif
#ifdef __ia64
#include <ia64intrin.h>
static inline int testandset (int *p)
{
return __sync_lock_test_and_set (p, 1);
return ret == 0;
}
#endif
@@ -536,9 +541,10 @@ extern spinlock_t tb_lock;
extern int tb_invalidated_flag;
#if !defined(CONFIG_USER_ONLY)
#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \
!defined(CONFIG_USER_ONLY)
void tlb_fill(target_ulong addr, int is_write, int is_user,
void tlb_fill(unsigned long addr, int is_write, int is_user,
void *retaddr);
#define ACCESS_TYPE 3
@@ -554,9 +560,6 @@ void tlb_fill(target_ulong addr, int is_write, int is_user,
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#undef env
@@ -575,48 +578,26 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
/* XXX: i386 target specific */
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
int is_user, index, pd;
int is_user, index;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
#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);
#else
#error "Unimplemented !"
#endif
if (__builtin_expect(env->tlb_read[is_user][index].address !=
(addr & TARGET_PAGE_MASK), 0)) {
ldub_code(addr);
}
pd = env->tlb_read[is_user][index].address & ~TARGET_PAGE_MASK;
if (pd > IO_MEM_ROM) {
cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
#if defined (TARGET_PPC)
env->access_type = ACCESS_CODE;
ldub_code((void *)addr);
env->access_type = ACCESS_INT;
#else
ldub_code((void *)addr);
#endif
}
return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
}
#endif
#ifdef USE_KQEMU
int kqemu_init(CPUState *env);
int kqemu_cpu_exec(CPUState *env);
void kqemu_flush_page(CPUState *env, target_ulong addr);
void kqemu_flush(CPUState *env, int global);
static inline int kqemu_is_ok(CPUState *env)
{
return(env->kqemu_enabled &&
(env->hflags & HF_CPL_MASK) == 3 &&
(env->eflags & IOPL_MASK) != IOPL_MASK &&
(env->cr[0] & CR0_PE_MASK) &&
(env->eflags & IF_MASK) &&
!(env->eflags & VM_MASK) &&
(env->ldt.limit == 0 || env->ldt.limit == 0x27));
}
#endif

496
exec.c
View File

@@ -18,12 +18,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/mman.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
@@ -31,6 +25,9 @@
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#if !defined(CONFIG_SOFTMMU)
#include <sys/mman.h>
#endif
#include "cpu.h"
#include "exec-all.h"
@@ -51,15 +48,6 @@
#define MMAP_AREA_START 0x00000000
#define MMAP_AREA_END 0xa8000000
#if defined(TARGET_SPARC64)
#define TARGET_PHYS_ADDR_SPACE_BITS 41
#elif defined(TARGET_PPC64)
#define TARGET_PHYS_ADDR_SPACE_BITS 42
#else
/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#endif
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
@@ -67,7 +55,7 @@ int nb_tbs;
/* any access to the tbs or the page table must use this lock */
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
uint8_t *code_gen_ptr;
int phys_ram_size;
@@ -89,11 +77,9 @@ typedef struct PageDesc {
typedef struct PhysPageDesc {
/* offset in host memory of the page + io_index in the low 12 bits */
uint32_t phys_offset;
unsigned long phys_offset;
} PhysPageDesc;
/* Note: the VirtPage handling is absolete and will be suppressed
ASAP */
typedef struct VirtPageDesc {
/* physical address of code page. It is valid only if 'valid_tag'
matches 'virt_valid_tag' */
@@ -121,16 +107,10 @@ unsigned long qemu_host_page_mask;
/* XXX: for system emulation, it could just be an array */
static PageDesc *l1_map[L1_SIZE];
PhysPageDesc **l1_phys_map;
static PhysPageDesc *l1_phys_map[L1_SIZE];
#if !defined(CONFIG_USER_ONLY)
#if TARGET_LONG_BITS > 32
#define VIRT_L_BITS 9
#define VIRT_L_SIZE (1 << VIRT_L_BITS)
static void *l1_virt_map[VIRT_L_SIZE];
#else
static VirtPageDesc *l1_virt_map[L1_SIZE];
#endif
static unsigned int virt_valid_tag;
#endif
@@ -145,43 +125,15 @@ char *logfilename = "/tmp/qemu.log";
FILE *logfile;
int loglevel;
/* statistics */
static int tlb_flush_count;
static int tb_flush_count;
static int tb_phys_invalidate_count;
static void page_init(void)
{
/* NOTE: we can always suppose that qemu_host_page_size >=
TARGET_PAGE_SIZE */
#ifdef _WIN32
{
SYSTEM_INFO system_info;
DWORD old_protect;
GetSystemInfo(&system_info);
qemu_real_host_page_size = system_info.dwPageSize;
VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
PAGE_EXECUTE_READWRITE, &old_protect);
}
qemu_real_host_page_size = 4096;
#else
qemu_real_host_page_size = getpagesize();
{
unsigned long start, end;
start = (unsigned long)code_gen_buffer;
start &= ~(qemu_real_host_page_size - 1);
end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
end += qemu_real_host_page_size - 1;
end &= ~(qemu_real_host_page_size - 1);
mprotect((void *)start, end - start,
PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
if (qemu_host_page_size == 0)
qemu_host_page_size = qemu_real_host_page_size;
if (qemu_host_page_size < TARGET_PAGE_SIZE)
@@ -193,8 +145,6 @@ static void page_init(void)
#if !defined(CONFIG_USER_ONLY)
virt_valid_tag = 1;
#endif
l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
}
static inline PageDesc *page_find_alloc(unsigned int index)
@@ -222,156 +172,76 @@ static inline PageDesc *page_find(unsigned int index)
return p + (index & (L2_SIZE - 1));
}
static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
{
void **lp, **p;
PhysPageDesc **lp, *p;
p = (void **)l1_phys_map;
#if TARGET_PHYS_ADDR_SPACE_BITS > 32
#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
#endif
lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
lp = &l1_phys_map[index >> L2_BITS];
p = *lp;
if (!p) {
/* allocate if not found */
if (!alloc)
return NULL;
p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
memset(p, 0, sizeof(void *) * L1_SIZE);
*lp = p;
}
#endif
lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
p = *lp;
if (!p) {
/* allocate if not found */
if (!alloc)
return NULL;
p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
*lp = p;
}
return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1));
return p + (index & (L2_SIZE - 1));
}
static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
static inline PhysPageDesc *phys_page_find(unsigned int index)
{
return phys_page_find_alloc(index, 0);
PhysPageDesc *p;
p = l1_phys_map[index >> L2_BITS];
if (!p)
return 0;
return p + (index & (L2_SIZE - 1));
}
#if !defined(CONFIG_USER_ONLY)
static void tlb_protect_code(CPUState *env, target_ulong addr);
static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
{
#if TARGET_LONG_BITS > 32
void **p, **lp;
p = l1_virt_map;
lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
*lp = p;
}
return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
#else
VirtPageDesc *p, **lp;
VirtPageDesc **lp, *p;
lp = &l1_virt_map[index >> L2_BITS];
p = *lp;
if (!p) {
/* allocate if not found */
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
*lp = p;
}
return p + (index & (L2_SIZE - 1));
#endif
}
static inline VirtPageDesc *virt_page_find(target_ulong index)
static inline VirtPageDesc *virt_page_find(unsigned int index)
{
return virt_page_find_alloc(index, 0);
}
VirtPageDesc *p;
#if TARGET_LONG_BITS > 32
static void virt_page_flush_internal(void **p, int level)
{
int i;
if (level == 0) {
VirtPageDesc *q = (VirtPageDesc *)p;
for(i = 0; i < VIRT_L_SIZE; i++)
q[i].valid_tag = 0;
} else {
level--;
for(i = 0; i < VIRT_L_SIZE; i++) {
if (p[i])
virt_page_flush_internal(p[i], level);
}
}
p = l1_virt_map[index >> L2_BITS];
if (!p)
return 0;
return p + (index & (L2_SIZE - 1));
}
#endif
static void virt_page_flush(void)
{
int i, j;
VirtPageDesc *p;
virt_valid_tag++;
if (virt_valid_tag == 0) {
virt_valid_tag = 1;
#if TARGET_LONG_BITS > 32
virt_page_flush_internal(l1_virt_map, 5);
#else
{
int i, j;
VirtPageDesc *p;
for(i = 0; i < L1_SIZE; i++) {
p = l1_virt_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].valid_tag = 0;
}
for(i = 0; i < L1_SIZE; i++) {
p = l1_virt_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].valid_tag = 0;
}
}
#endif
}
}
#else
@@ -420,6 +290,7 @@ static void page_flush_tb(void)
/* XXX: tb_flush is currently not thread safe */
void tb_flush(CPUState *env)
{
int i;
#if defined(DEBUG_FLUSH)
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
code_gen_ptr - code_gen_buffer,
@@ -427,16 +298,17 @@ void tb_flush(CPUState *env)
nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
#endif
nb_tbs = 0;
memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL;
virt_page_flush();
memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++)
tb_phys_hash[i] = NULL;
page_flush_tb();
code_gen_ptr = code_gen_buffer;
/* XXX: flush processor icache at this point if cache flush is
expensive */
tb_flush_count++;
}
#ifdef DEBUG_TB_CHECK
@@ -631,7 +503,6 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad
}
tb_invalidate(tb);
tb_phys_invalidate_count++;
}
static inline void set_bits(uint8_t *tab, int start, int len)
@@ -703,13 +574,13 @@ static void tb_gen_code(CPUState *env,
target_ulong phys_pc, phys_page2, virt_page2;
int code_gen_size;
phys_pc = get_phys_addr_code(env, pc);
tb = tb_alloc(pc);
phys_pc = get_phys_addr_code(env, (unsigned long)pc);
tb = tb_alloc((unsigned long)pc);
if (!tb) {
/* flush must be done */
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc(pc);
tb = tb_alloc((unsigned long)pc);
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
@@ -720,9 +591,9 @@ static void tb_gen_code(CPUState *env,
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
phys_page2 = -1;
if ((pc & TARGET_PAGE_MASK) != virt_page2) {
if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
@@ -990,7 +861,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
/* Allocate a new translation block. Flush the translation buffer if
too many translation blocks or too much generated code. */
TranslationBlock *tb_alloc(target_ulong pc)
TranslationBlock *tb_alloc(unsigned long pc)
{
TranslationBlock *tb;
@@ -1038,7 +909,7 @@ void tb_link(TranslationBlock *tb)
/* save the code memory mappings (needed to invalidate the code) */
addr = tb->pc & TARGET_PAGE_MASK;
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
#ifdef DEBUG_TLB_CHECK
if (vp->valid_tag == virt_valid_tag &&
vp->phys_addr != tb->page_addr[0]) {
@@ -1056,7 +927,7 @@ void tb_link(TranslationBlock *tb)
if (tb->page_addr[1] != -1) {
addr += TARGET_PAGE_SIZE;
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
#ifdef DEBUG_TLB_CHECK
if (vp->valid_tag == virt_valid_tag &&
vp->phys_addr != tb->page_addr[1]) {
@@ -1169,7 +1040,6 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
tb_reset_jump_recursive2(tb, 1);
}
#if defined(TARGET_HAS_ICE)
static void breakpoint_invalidate(CPUState *env, target_ulong pc)
{
target_ulong phys_addr;
@@ -1177,13 +1047,12 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
phys_addr = cpu_get_phys_page_debug(env, pc);
tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
}
#endif
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
breakpoint is reached */
int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
{
#if defined(TARGET_HAS_ICE)
#if defined(TARGET_I386) || defined(TARGET_PPC)
int i;
for(i = 0; i < env->nb_breakpoints; i++) {
@@ -1205,7 +1074,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
/* remove a breakpoint */
int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
{
#if defined(TARGET_HAS_ICE)
#if defined(TARGET_I386) || defined(TARGET_PPC)
int i;
for(i = 0; i < env->nb_breakpoints; i++) {
if (env->breakpoints[i] == pc)
@@ -1213,9 +1082,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
}
return -1;
found:
memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
(env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
env->nb_breakpoints--;
if (i < env->nb_breakpoints)
env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
breakpoint_invalidate(env, pc);
return 0;
@@ -1228,7 +1097,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
CPU loop after each instruction */
void cpu_single_step(CPUState *env, int enabled)
{
#if defined(TARGET_HAS_ICE)
#if defined(TARGET_I386) || defined(TARGET_PPC)
if (env->singlestep_enabled != enabled) {
env->singlestep_enabled = enabled;
/* must flush all the translated code to avoid inconsistancies */
@@ -1308,10 +1177,8 @@ CPULogItem cpu_log_items[] = {
{ CPU_LOG_PCALL, "pcall",
"show protected mode far calls/returns/exceptions" },
#endif
#ifdef DEBUG_IOPORT
{ CPU_LOG_IOPORT, "ioport",
"show all i/o ports accesses" },
#endif
{ 0, NULL, NULL },
};
@@ -1335,17 +1202,11 @@ int cpu_str_to_log_mask(const char *str)
p1 = strchr(p, ',');
if (!p1)
p1 = p + strlen(p);
if(cmp1(p,p1-p,"all")) {
for(item = cpu_log_items; item->mask != 0; item++) {
mask |= item->mask;
}
} else {
for(item = cpu_log_items; item->mask != 0; item++) {
if (cmp1(p, p1 - p, item->name))
goto found;
}
return 0;
}
found:
mask |= item->mask;
if (*p1 != ',')
@@ -1364,9 +1225,7 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
#ifdef TARGET_I386
cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
#else
cpu_dump_state(env, stderr, fprintf, 0);
cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
#endif
va_end(ap);
abort();
@@ -1395,17 +1254,12 @@ void tlb_flush(CPUState *env, int flush_global)
}
virt_page_flush();
memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL;
#if !defined(CONFIG_SOFTMMU)
munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
#endif
#ifdef USE_KQEMU
if (env->kqemu_enabled) {
kqemu_flush(env, flush_global);
}
#endif
tlb_flush_count++;
}
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
@@ -1423,7 +1277,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
TranslationBlock *tb;
#if defined(DEBUG_TLB)
printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
printf("tlb_flush_page: 0x%08x\n", addr);
#endif
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
@@ -1462,11 +1316,6 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
if (addr < MMAP_AREA_END)
munmap((void *)addr, TARGET_PAGE_SIZE);
#endif
#ifdef USE_KQEMU
if (env->kqemu_enabled) {
kqemu_flush_page(env, addr);
}
#endif
}
static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
@@ -1531,13 +1380,11 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
}
}
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
int dirty_flags)
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
{
CPUState *env;
unsigned long length, start1;
int i, mask, len;
uint8_t *p;
int i;
start &= TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
@@ -1545,11 +1392,7 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
length = end - start;
if (length == 0)
return;
mask = ~dirty_flags;
p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
len = length >> TARGET_PAGE_BITS;
for(i = 0; i < len; i++)
p[i] &= mask;
memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
env = cpu_single_env;
/* we modify the TLB cache so that the dirty bit will be set again
@@ -1590,7 +1433,7 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
}
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
unsigned long start)
unsigned long start)
{
unsigned long addr;
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
@@ -1608,7 +1451,7 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
CPUState *env = cpu_single_env;
int i;
phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff;
phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
addr &= TARGET_PAGE_MASK;
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -1629,7 +1472,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
TranslationBlock *first_tb;
unsigned int index;
target_ulong address;
target_phys_addr_t addend;
unsigned long addend;
int ret;
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
@@ -1646,7 +1489,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
}
}
#if defined(DEBUG_TLB)
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
#endif
@@ -1665,7 +1508,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
}
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
addend -= vaddr;
if (prot & PAGE_READ) {
env->tlb_read[is_user][index].address = address;
@@ -1728,7 +1571,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
original mapping */
VirtPageDesc *vp;
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
vp->phys_addr = pd;
vp->prot = prot;
vp->valid_tag = virt_valid_tag;
@@ -1780,7 +1623,7 @@ int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
(unsigned long)addr, vp->prot);
/* set the dirty bit */
phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
/* flush the code inside */
tb_invalidate_phys_page(vp->phys_addr, pc, puc);
return 1;
@@ -1952,13 +1795,13 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset)
{
target_phys_addr_t addr, end_addr;
unsigned long addr, end_addr;
PhysPageDesc *p;
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + size;
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
p->phys_offset = phys_offset;
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
phys_offset += TARGET_PAGE_SIZE;
@@ -1997,8 +1840,8 @@ static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
#if !defined(CONFIG_USER_ONLY)
tb_invalidate_phys_page_fast(phys_addr, 1);
#endif
stb_p((uint8_t *)(long)addr, val);
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
stb_raw((uint8_t *)addr, val);
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
}
static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -2009,8 +1852,8 @@ static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
#if !defined(CONFIG_USER_ONLY)
tb_invalidate_phys_page_fast(phys_addr, 2);
#endif
stw_p((uint8_t *)(long)addr, val);
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
stw_raw((uint8_t *)addr, val);
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
}
static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -2021,8 +1864,8 @@ static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
#if !defined(CONFIG_USER_ONLY)
tb_invalidate_phys_page_fast(phys_addr, 4);
#endif
stl_p((uint8_t *)(long)addr, val);
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
stl_raw((uint8_t *)addr, val);
phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
}
static CPUReadMemoryFunc *code_mem_read[3] = {
@@ -2039,19 +1882,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = {
static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
stb_p((uint8_t *)(long)addr, val);
stb_raw((uint8_t *)addr, val);
tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
}
static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
stw_p((uint8_t *)(long)addr, val);
stw_raw((uint8_t *)addr, val);
tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
}
static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
stl_p((uint8_t *)(long)addr, val);
stl_raw((uint8_t *)addr, val);
tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
}
@@ -2070,7 +1913,7 @@ static void io_mem_init(void)
io_mem_nb = 5;
/* alloc dirty bits array */
phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
}
/* mem_read and mem_write are arrays of functions containing the
@@ -2103,16 +1946,6 @@ int cpu_register_io_memory(int io_index,
return io_index << IO_MEM_SHIFT;
}
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
{
return io_mem_write[io_index >> IO_MEM_SHIFT];
}
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
{
return io_mem_read[io_index >> IO_MEM_SHIFT];
}
/* physical memory access (slow version, mainly for debug) */
#if defined(CONFIG_USER_ONLY)
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
@@ -2143,21 +1976,6 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
addr += l;
}
}
/* never used */
uint32_t ldl_phys(target_phys_addr_t addr)
{
return 0;
}
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
{
}
void stl_phys(target_phys_addr_t addr, uint32_t val)
{
}
#else
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write)
@@ -2186,17 +2004,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
if (l >= 4 && ((addr & 3) == 0)) {
/* 32 bit read access */
val = ldl_p(buf);
val = ldl_raw(buf);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
l = 4;
} else if (l >= 2 && ((addr & 1) == 0)) {
/* 16 bit read access */
val = lduw_p(buf);
val = lduw_raw(buf);
io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
l = 2;
} else {
/* 8 bit access */
val = ldub_p(buf);
val = ldub_raw(buf);
io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
l = 1;
}
@@ -2209,7 +2027,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
/* invalidate code */
tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
/* set dirty bit */
phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1;
}
} else {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
@@ -2219,17 +2037,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
if (l >= 4 && ((addr & 3) == 0)) {
/* 32 bit read access */
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
stl_p(buf, val);
stl_raw(buf, val);
l = 4;
} else if (l >= 2 && ((addr & 1) == 0)) {
/* 16 bit read access */
val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
stw_p(buf, val);
stw_raw(buf, val);
l = 2;
} else {
/* 8 bit access */
val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
stb_p(buf, val);
stb_raw(buf, val);
l = 1;
}
} else {
@@ -2244,96 +2062,6 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
addr += l;
}
}
/* warning: addr must be aligned */
uint32_t ldl_phys(target_phys_addr_t addr)
{
int io_index;
uint8_t *ptr;
uint32_t val;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
(pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
} else {
/* RAM case */
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
val = ldl_p(ptr);
}
return val;
}
/* warning: addr must be aligned. The ram page is not masked as dirty
and the code inside is not invalidated. It is useful if the dirty
bits are used to track modified PTEs */
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
{
int io_index;
uint8_t *ptr;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) != 0) {
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
} else {
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
stl_p(ptr, val);
}
}
/* warning: addr must be aligned */
/* XXX: optimize code invalidation test */
void stl_phys(target_phys_addr_t addr, uint32_t val)
{
int io_index;
uint8_t *ptr;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) != 0) {
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* RAM case */
ptr = phys_ram_base + addr1;
stl_p(ptr, val);
/* invalidate code */
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
/* set dirty bit */
phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
}
}
#endif
/* virtual memory access for debug */
@@ -2361,59 +2089,11 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
return 0;
}
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
int i, target_code_size, max_target_code_size;
int direct_jmp_count, direct_jmp2_count, cross_page;
TranslationBlock *tb;
target_code_size = 0;
max_target_code_size = 0;
cross_page = 0;
direct_jmp_count = 0;
direct_jmp2_count = 0;
for(i = 0; i < nb_tbs; i++) {
tb = &tbs[i];
target_code_size += tb->size;
if (tb->size > max_target_code_size)
max_target_code_size = tb->size;
if (tb->page_addr[1] != -1)
cross_page++;
if (tb->tb_next_offset[0] != 0xffff) {
direct_jmp_count++;
if (tb->tb_next_offset[1] != 0xffff) {
direct_jmp2_count++;
}
}
}
/* XXX: avoid using doubles ? */
cpu_fprintf(f, "TB count %d\n", nb_tbs);
cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
nb_tbs ? target_code_size / nb_tbs : 0,
max_target_code_size);
cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
cross_page,
nb_tbs ? (cross_page * 100) / nb_tbs : 0);
cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
direct_jmp_count,
nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
direct_jmp2_count,
nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
}
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _cmmu
#define GETPC() NULL
#define env cpu_single_env
#define SOFTMMU_CODE_ACCESS
#define SHIFT 0
#include "softmmu_template.h"

View File

@@ -1,720 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 32, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
{
bits32 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 32 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 64, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
{
bits64 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 64 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
| _plus_ the number of bits given in `count'. The shifted result is at most
| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
| bits shifted off form a second 64-bit result as follows: The _last_ bit
| shifted off is the most-significant bit of the extra result, and the other
| 63 bits of the extra result are all zero if and only if _all_but_the_last_
| bits shifted off were all zero. This extra result is stored in the location
| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0' and `a1' are considered to form
| a fixed-point value with binary point between `a0' and `a1'. This fixed-
| point value is shifted right by the number of bits given in `count', and
| the integer part of the result is returned at the location pointed to by
| `z0Ptr'. The fractional part of the result may be slightly corrupted as
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
shift64ExtraRightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1 != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' can be arbitrarily large; in particular, if `count' is greater
| than 128, the result will be 0. The result is broken into two 64-bit pieces
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shift128Right(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. If any nonzero bits are shifted off, they
| are ``jammed'' into the least significant bit of the result by setting the
| least significant bit to 1. The value of `count' can be arbitrarily large;
| in particular, if `count' is greater than 128, the result will be either
| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
| nonzero. The result is broken into two 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shift128RightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else if ( count < 128 ) {
z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
| by 64 _plus_ the number of bits given in `count'. The shifted result is
| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
| off form a third 64-bit result as follows: The _last_ bit shifted off is
| the most-significant bit of the extra result, and the other 63 bits of the
| extra result are all zero if and only if _all_but_the_last_ bits shifted off
| were all zero. This extra result is stored in the location pointed to by
| `z2Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0', `a1', and `a2' are considered
| to form a fixed-point value with binary point between `a1' and `a2'. This
| fixed-point value is shifted right by the number of bits given in `count',
| and the integer part of the result is returned at the locations pointed to
| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
| corrupted as described above, and is returned at the location pointed to by
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
shift128ExtraRightJamming(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if ( count < 64 ) {
z2 = a1<<negCount;
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if ( count < 128 ) {
z2 = a0<<negCount;
z1 = a0>>( count & 63 );
}
else {
z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
z1 = 0;
}
}
z0 = 0;
}
z2 |= ( a2 != 0 );
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' must be less than 64. The result is broken into two 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shortShift128Left(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1<<count;
*z0Ptr =
( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
| by the number of bits given in `count'. Any bits shifted off are lost.
| The value of `count' must be less than 64. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shortShift192Left(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount;
z2 = a2<<count;
z1 = a1<<count;
z0 = a0<<count;
if ( 0 < count ) {
negCount = ( ( - count ) & 63 );
z1 |= a2>>negCount;
z0 |= a1>>negCount;
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
| any carry out is lost. The result is broken into two 64-bit pieces which
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
add128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + ( z1 < a1 );
}
/*----------------------------------------------------------------------------
| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
| modulo 2^192, so any carry out is lost. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
add192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 carry0, carry1;
z2 = a2 + b2;
carry1 = ( z2 < a2 );
z1 = a1 + b1;
carry0 = ( z1 < a1 );
z0 = a0 + b0;
z1 += carry1;
z0 += ( z1 < carry1 );
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
| 2^128, so any borrow out (carry out) is lost. The result is broken into two
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
| `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
sub128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - ( a1 < b1 );
}
/*----------------------------------------------------------------------------
| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
| result is broken into three 64-bit pieces which are stored at the locations
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
sub192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 borrow0, borrow1;
z2 = a2 - b2;
borrow1 = ( a2 < b2 );
z1 = a1 - b1;
borrow0 = ( a1 < b1 );
z0 = a0 - b0;
z0 -= ( z1 < borrow1 );
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
| into two 64-bit pieces which are stored at the locations pointed to by
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a>>32;
bLow = b;
bHigh = b>>32;
z1 = ( (bits64) aLow ) * bLow;
zMiddleA = ( (bits64) aLow ) * bHigh;
zMiddleB = ( (bits64) aHigh ) * bLow;
z0 = ( (bits64) aHigh ) * bHigh;
zMiddleA += zMiddleB;
z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += ( z1 < zMiddleA );
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
| `b' to obtain a 192-bit product. The product is broken into three 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
| `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
mul128By64To192(
bits64 a0,
bits64 a1,
bits64 b,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2, more1;
mul64To128( a1, b, &z1, &z2 );
mul64To128( a0, b, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
| product. The product is broken into four 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
mul128To256(
bits64 a0,
bits64 a1,
bits64 b0,
bits64 b1,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr,
bits64 *z3Ptr
)
{
bits64 z0, z1, z2, z3;
bits64 more1, more2;
mul64To128( a1, b1, &z2, &z3 );
mul64To128( a1, b0, &z1, &more2 );
add128( z1, more2, 0, z2, &z1, &z2 );
mul64To128( a0, b0, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
mul64To128( a0, b1, &more1, &more2 );
add128( more1, more2, 0, z2, &more1, &z2 );
add128( z0, z1, 0, more1, &z0, &z1 );
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the 64-bit integer quotient obtained by dividing
| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
| divisor `b' must be at least 2^63. If q is the exact quotient truncated
| toward zero, the approximation returned lies between q and q + 2 inclusive.
| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
| unsigned integer is returned.
*----------------------------------------------------------------------------*/
static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
b0 = b>>32;
z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
z -= LIT64( 0x100000000 );
b1 = b<<32;
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the square root of the 32-bit significand given
| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
| `aExp' (the least significant bit) is 1, the integer returned approximates
| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
| case, the approximation returned lies strictly within +/-2 of the exact
| value.
*----------------------------------------------------------------------------*/
static bits32 estimateSqrt32( int16 aExp, bits32 a )
{
static const bits16 sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const bits16 sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
int8 index;
bits32 z;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros32( bits32 a )
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if ( a < 0x10000 ) {
shiftCount += 16;
a <<= 16;
}
if ( a < 0x1000000 ) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros64( bits64 a )
{
int8 shiftCount;
shiftCount = 0;
if ( a < ( (bits64) 1 )<<32 ) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
| returns 0.
*----------------------------------------------------------------------------*/
INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
| not equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );
}

View File

@@ -1,348 +0,0 @@
/* Native implementation of soft float functions. Only a single status
context is supported */
#include "softfloat.h"
#include <math.h>
void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
#if defined(_BSD) && !defined(__APPLE__)
fpsetround(val);
#elif defined(__arm__)
/* nothing to do */
#else
fesetround(val);
#endif
}
#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM)
{
STATUS(floatx80_rounding_precision) = val;
}
#endif
#if defined(_BSD)
#define lrint(d) ((int32_t)rint(d))
#define llrint(d) ((int64_t)rint(d))
#endif
#if defined(__powerpc__)
/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
double qemu_rint(double x)
{
double y = 4503599627370496.0;
if (fabs(x) >= y)
return x;
if (x < 0)
y = -y;
y = (x + y) - y;
if (y == 0.0)
y = copysign(y, x);
return y;
}
#define rint qemu_rint
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32(int v STATUS_PARAM)
{
return (float32)v;
}
float64 int32_to_float64(int v STATUS_PARAM)
{
return (float64)v;
}
#ifdef FLOATX80
floatx80 int32_to_floatx80(int v STATUS_PARAM)
{
return (floatx80)v;
}
#endif
float32 int64_to_float32( int64_t v STATUS_PARAM)
{
return (float32)v;
}
float64 int64_to_float64( int64_t v STATUS_PARAM)
{
return (float64)v;
}
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
{
return (floatx80)v;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 a STATUS_PARAM)
{
return lrintf(a);
}
int float32_to_int32_round_to_zero( float32 a STATUS_PARAM)
{
return (int)a;
}
int64_t float32_to_int64( float32 a STATUS_PARAM)
{
return llrintf(a);
}
int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM)
{
return (int64_t)a;
}
float64 float32_to_float64( float32 a STATUS_PARAM)
{
return a;
}
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 a STATUS_PARAM)
{
return a;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 a STATUS_PARAM)
{
return rintf(a);
}
float32 float32_rem( float32 a, float32 b STATUS_PARAM)
{
return remainderf(a, b);
}
float32 float32_sqrt( float32 a STATUS_PARAM)
{
return sqrtf(a);
}
char float32_compare( float32 a, float32 b STATUS_PARAM )
{
if (a < b) {
return -1;
} else if (a == b) {
return 0;
} else if (a > b) {
return 1;
} else {
return 2;
}
}
char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
} else if (a == b) {
return 0;
} else if (isgreater(a, b)) {
return 1;
} else {
return 2;
}
}
char float32_is_signaling_nan( float32 a1)
{
float32u u;
uint32_t a;
u.f = a1;
a = u.i;
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 a STATUS_PARAM)
{
return lrint(a);
}
int float64_to_int32_round_to_zero( float64 a STATUS_PARAM)
{
return (int)a;
}
int64_t float64_to_int64( float64 a STATUS_PARAM)
{
return llrint(a);
}
int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM)
{
return (int64_t)a;
}
float32 float64_to_float32( float64 a STATUS_PARAM)
{
return a;
}
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 a STATUS_PARAM)
{
return a;
}
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 a STATUS_PARAM)
{
return a;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 a STATUS_PARAM )
{
#if defined(__arm__)
switch(STATUS(float_rounding_mode)) {
default:
case float_round_nearest_even:
asm("rndd %0, %1" : "=f" (a) : "f"(a));
break;
case float_round_down:
asm("rnddm %0, %1" : "=f" (a) : "f"(a));
break;
case float_round_up:
asm("rnddp %0, %1" : "=f" (a) : "f"(a));
break;
case float_round_to_zero:
asm("rnddz %0, %1" : "=f" (a) : "f"(a));
break;
}
#else
return rint(a);
#endif
}
float64 float64_rem( float64 a, float64 b STATUS_PARAM)
{
return remainder(a, b);
}
float64 float64_sqrt( float64 a STATUS_PARAM)
{
return sqrt(a);
}
char float64_compare( float64 a, float64 b STATUS_PARAM )
{
if (a < b) {
return -1;
} else if (a == b) {
return 0;
} else if (a > b) {
return 1;
} else {
return 2;
}
}
char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
} else if (a == b) {
return 0;
} else if (isgreater(a, b)) {
return 1;
} else {
return 2;
}
}
char float64_is_signaling_nan( float64 a1)
{
float64u u;
uint64_t a;
u.f = a1;
a = u.i;
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 a STATUS_PARAM)
{
return lrintl(a);
}
int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
{
return (int)a;
}
int64_t floatx80_to_int64( floatx80 a STATUS_PARAM)
{
return llrintl(a);
}
int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM)
{
return (int64_t)a;
}
float32 floatx80_to_float32( floatx80 a STATUS_PARAM)
{
return a;
}
float64 floatx80_to_float64( floatx80 a STATUS_PARAM)
{
return a;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
{
return rintl(a);
}
floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM)
{
return remainderl(a, b);
}
floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
{
return sqrtl(a);
}
char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
{
if (a < b) {
return -1;
} else if (a == b) {
return 0;
} else if (a > b) {
return 1;
} else {
return 2;
}
}
char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
} else if (a == b) {
return 0;
} else if (isgreater(a, b)) {
return 1;
} else {
return 2;
}
}
char floatx80_is_signaling_nan( floatx80 a1)
{
floatx80u u;
u.f = a1;
return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
}
#endif

View File

@@ -1,332 +0,0 @@
/* Native implementation of soft float functions */
#include <math.h>
#if defined(_BSD) && !defined(__APPLE__)
#include <ieeefp.h>
#else
#include <fenv.h>
#endif
typedef float float32;
typedef double float64;
#ifdef FLOATX80
typedef long double floatx80;
#endif
typedef union {
float32 f;
uint32_t i;
} float32u;
typedef union {
float64 f;
uint64_t i;
} float64u;
#ifdef FLOATX80
typedef union {
floatx80 f;
struct {
uint64_t low;
uint16_t high;
} i;
} floatx80u;
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
#if defined(_BSD) && !defined(__APPLE__)
enum {
float_round_nearest_even = FP_RN,
float_round_down = FE_RM,
float_round_up = FE_RP,
float_round_to_zero = FE_RZ
};
#elif defined(__arm__)
enum {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
#else
enum {
float_round_nearest_even = FE_TONEAREST,
float_round_down = FE_DOWNWARD,
float_round_up = FE_UPWARD,
float_round_to_zero = FE_TOWARDZERO
};
#endif
typedef struct float_status {
signed char float_rounding_mode;
#ifdef FLOATX80
signed char floatx80_rounding_precision;
#endif
} float_status;
void set_float_rounding_mode(int val STATUS_PARAM);
#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32( int STATUS_PARAM);
float64 int32_to_float64( int STATUS_PARAM);
#ifdef FLOATX80
floatx80 int32_to_floatx80( int STATUS_PARAM);
#endif
#ifdef FLOAT128
float128 int32_to_float128( int STATUS_PARAM);
#endif
float32 int64_to_float32( int64_t STATUS_PARAM);
float64 int64_to_float64( int64_t STATUS_PARAM);
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
#endif
#ifdef FLOAT128
float128 int64_to_float128( int64_t STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 STATUS_PARAM);
int float32_to_int32_round_to_zero( float32 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);
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 STATUS_PARAM);
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 STATUS_PARAM);
INLINE float32 float32_add( float32 a, float32 b STATUS_PARAM)
{
return a + b;
}
INLINE float32 float32_sub( float32 a, float32 b STATUS_PARAM)
{
return a - b;
}
INLINE float32 float32_mul( float32 a, float32 b STATUS_PARAM)
{
return a * b;
}
INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
{
return a / b;
}
float32 float32_rem( float32, float32 STATUS_PARAM);
float32 float32_sqrt( float32 STATUS_PARAM);
INLINE char float32_eq( float32 a, float32 b STATUS_PARAM)
{
return a == b;
}
INLINE char float32_le( float32 a, float32 b STATUS_PARAM)
{
return a <= b;
}
INLINE char float32_lt( float32 a, float32 b STATUS_PARAM)
{
return a < b;
}
INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM)
{
return isunordered(a, b);
}
char float32_compare( float32, float32 STATUS_PARAM );
char float32_compare_quiet( float32, float32 STATUS_PARAM );
char float32_is_signaling_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
return fabsf(a);
}
INLINE float32 float32_chs(float32 a)
{
return -a;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 STATUS_PARAM );
int float64_to_int32_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 );
float32 float64_to_float32( float64 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 STATUS_PARAM );
INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM)
{
return a + b;
}
INLINE float64 float64_sub( float64 a, float64 b STATUS_PARAM)
{
return a - b;
}
INLINE float64 float64_mul( float64 a, float64 b STATUS_PARAM)
{
return a * b;
}
INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
{
return a / b;
}
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
INLINE char float64_eq( float64 a, float64 b STATUS_PARAM)
{
return a == b;
}
INLINE char float64_le( float64 a, float64 b STATUS_PARAM)
{
return a <= b;
}
INLINE char float64_lt( float64 a, float64 b STATUS_PARAM)
{
return a < b;
}
INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM)
{
return isunordered(a, b);
}
char float64_compare( float64, float64 STATUS_PARAM );
char float64_compare_quiet( float64, float64 STATUS_PARAM );
char float64_is_signaling_nan( float64 );
INLINE float64 float64_abs(float64 a)
{
return fabs(a);
}
INLINE float64 float64_chs(float64 a)
{
return -a;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 STATUS_PARAM );
int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
int64_t floatx80_to_int64( floatx80 STATUS_PARAM);
int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM);
float32 floatx80_to_float32( floatx80 STATUS_PARAM );
float64 floatx80_to_float64( floatx80 STATUS_PARAM );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM );
INLINE floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM)
{
return a + b;
}
INLINE floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM)
{
return a - b;
}
INLINE floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM)
{
return a * b;
}
INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
{
return a / b;
}
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
{
return a == b;
}
INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b;
}
INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
{
return a < b;
}
INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
{
return isunordered(a, b);
}
char floatx80_compare( floatx80, floatx80 STATUS_PARAM );
char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_is_signaling_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
return fabsl(a);
}
INLINE floatx80 floatx80_chs(floatx80 a)
{
return -a;
}
#endif

View File

@@ -1,464 +0,0 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Underflow tininess-detection mode, statically initialized to default value.
| (The declaration in `softfloat.h' must match the `int8' type here.)
*----------------------------------------------------------------------------*/
int8 float_detect_tininess = float_tininess_after_rounding;
/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap
| to substitute a result value. If traps are not implemented, this routine
| should be simply `float_exception_flags |= flags;'.
*----------------------------------------------------------------------------*/
void float_raise( int8 flags STATUS_PARAM )
{
STATUS(float_exception_flags) |= flags;
}
/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
flag sign;
bits64 high, low;
} commonNaNT;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#define float32_default_nan 0xFFC00000
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
{
commonNaNT z;
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
z.sign = a>>31;
z.low = 0;
z.high = ( (bits64) a )<<41;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the single-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float32 commonNaNToFloat32( commonNaNT a )
{
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
bIsSignalingNaN = float32_is_signaling_nan( b );
a |= 0x00400000;
b |= 0x00400000;
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#define float64_default_nan LIT64( 0xFFF8000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_nan( float64 a )
{
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_signaling_nan( float64 a )
{
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
{
commonNaNT z;
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
z.sign = a>>63;
z.low = 0;
z.high = a<<12;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the double-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float64 commonNaNToFloat64( commonNaNT a )
{
return
( ( (bits64) a.sign )<<63 )
| LIT64( 0x7FF8000000000000 )
| ( a.high>>12 );
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
bIsSignalingNaN = float64_is_signaling_nan( b );
a |= LIT64( 0x0008000000000000 );
b |= LIT64( 0x0008000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
*----------------------------------------------------------------------------*/
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_signaling_nan( floatx80 a )
{
bits64 aLow;
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
| invalid exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
{
commonNaNT z;
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<<1;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the extended
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
static floatx80 commonNaNToFloatx80( commonNaNT a )
{
floatx80 z;
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
return z;
}
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
a.low |= LIT64( 0xC000000000000000 );
b.low |= LIT64( 0xC000000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( a.low < b.low ) return b;
if ( b.low < a.low ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
#define float128_default_nan_low LIT64( 0x0000000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_nan( float128 a )
{
return
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_signaling_nan( float128 a )
{
return
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM)
{
commonNaNT z;
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
z.sign = a.high>>63;
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the quadruple-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float128 commonNaNToFloat128( commonNaNT a )
{
float128 z;
shift128Right( a.high, a.low, 16, &z.high, &z.low );
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
return z;
}
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
bIsSignalingNaN = float128_is_signaling_nan( b );
a.high |= LIT64( 0x0000800000000000 );
b.high |= LIT64( 0x0000800000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,398 +0,0 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#ifndef SOFTFLOAT_H
#define SOFTFLOAT_H
#include <inttypes.h>
#include "config.h"
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines the most convenient type that holds
| integers of at least as many bits as specified. For example, `uint8' should
| be the most convenient type that can hold unsigned integers of as many as
| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
| to the same as `int'.
*----------------------------------------------------------------------------*/
typedef char flag;
typedef uint8_t uint8;
typedef int8_t int8;
typedef int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
typedef uint64_t uint64;
typedef int64_t int64;
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines a type that holds integers
| of _exactly_ the number of bits specified. For instance, for most
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
| `unsigned short int' and `signed short int' (or `short int'), respectively.
*----------------------------------------------------------------------------*/
typedef uint8_t bits8;
typedef int8_t sbits8;
typedef uint16_t bits16;
typedef int16_t sbits16;
typedef uint32_t bits32;
typedef int32_t sbits32;
typedef uint64_t bits64;
typedef int64_t sbits64;
#define LIT64( a ) a##LL
#define INLINE static inline
/*----------------------------------------------------------------------------
| The macro `FLOATX80' must be defined to enable the extended double-precision
| floating-point format `floatx80'. If this macro is not defined, the
| `floatx80' type will not be defined, and none of the functions that either
| input or output the `floatx80' type will be defined. The same applies to
| the `FLOAT128' macro and the quadruple-precision format `float128'.
*----------------------------------------------------------------------------*/
#ifdef CONFIG_SOFTFLOAT
/* bit exact soft float support */
#define FLOATX80
#define FLOAT128
#else
/* native float support */
#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD)
#define FLOATX80
#endif
#endif /* !CONFIG_SOFTFLOAT */
#define STATUS_PARAM , float_status *status
#define STATUS(field) status->field
#define STATUS_VAR , status
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point ordering relations
*----------------------------------------------------------------------------*/
enum {
float_relation_less = -1,
float_relation_equal = 0,
float_relation_greater = 1,
float_relation_unordered = 2
};
#ifdef CONFIG_SOFTFLOAT
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
typedef uint32_t float32;
typedef uint64_t float64;
#ifdef FLOATX80
typedef struct {
uint64_t low;
uint16_t high;
} floatx80;
#endif
#ifdef FLOAT128
typedef struct {
#ifdef WORDS_BIGENDIAN
uint64_t high, low;
#else
uint64_t low, high;
#endif
} float128;
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point underflow tininess-detection mode.
*----------------------------------------------------------------------------*/
enum {
float_tininess_after_rounding = 0,
float_tininess_before_rounding = 1
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
enum {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
enum {
float_flag_invalid = 1,
float_flag_divbyzero = 4,
float_flag_overflow = 8,
float_flag_underflow = 16,
float_flag_inexact = 32
};
typedef struct float_status {
signed char float_detect_tininess;
signed char float_rounding_mode;
signed char float_exception_flags;
#ifdef FLOATX80
signed char floatx80_rounding_precision;
#endif
} float_status;
void set_float_rounding_mode(int val STATUS_PARAM);
void set_float_exception_flags(int val STATUS_PARAM);
INLINE int get_float_exception_flags(float_status *status)
{
return STATUS(float_exception_flags);
}
#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
void float_raise( signed char STATUS_PARAM);
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32( int STATUS_PARAM );
float64 int32_to_float64( int STATUS_PARAM );
float32 uint32_to_float32( unsigned int STATUS_PARAM );
float64 uint32_to_float64( unsigned int STATUS_PARAM );
#ifdef FLOATX80
floatx80 int32_to_floatx80( int STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 int32_to_float128( int STATUS_PARAM );
#endif
float32 int64_to_float32( int64_t STATUS_PARAM );
float64 int64_to_float64( int64_t STATUS_PARAM );
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64_t STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 int64_to_float128( int64_t STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 STATUS_PARAM );
int float32_to_int32_round_to_zero( float32 STATUS_PARAM );
unsigned int float32_to_uint32( float32 STATUS_PARAM );
unsigned int float32_to_uint32_round_to_zero( float32 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 );
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 STATUS_PARAM );
float32 float32_add( float32, float32 STATUS_PARAM );
float32 float32_sub( float32, float32 STATUS_PARAM );
float32 float32_mul( float32, float32 STATUS_PARAM );
float32 float32_div( float32, float32 STATUS_PARAM );
float32 float32_rem( float32, float32 STATUS_PARAM );
float32 float32_sqrt( float32 STATUS_PARAM );
char float32_eq( float32, float32 STATUS_PARAM );
char float32_le( float32, float32 STATUS_PARAM );
char float32_lt( float32, float32 STATUS_PARAM );
char float32_eq_signaling( float32, float32 STATUS_PARAM );
char float32_le_quiet( float32, float32 STATUS_PARAM );
char float32_lt_quiet( float32, float32 STATUS_PARAM );
char float32_compare( float32, float32 STATUS_PARAM );
char float32_compare_quiet( float32, float32 STATUS_PARAM );
char float32_is_signaling_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
return a & 0x7fffffff;
}
INLINE float32 float32_chs(float32 a)
{
return a ^ 0x80000000;
}
/*----------------------------------------------------------------------------
| 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 );
float32 float64_to_float32( float64 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 STATUS_PARAM );
float64 float64_add( float64, float64 STATUS_PARAM );
float64 float64_sub( float64, float64 STATUS_PARAM );
float64 float64_mul( float64, float64 STATUS_PARAM );
float64 float64_div( float64, float64 STATUS_PARAM );
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
char float64_eq( float64, float64 STATUS_PARAM );
char float64_le( float64, float64 STATUS_PARAM );
char float64_lt( float64, float64 STATUS_PARAM );
char float64_eq_signaling( float64, float64 STATUS_PARAM );
char float64_le_quiet( float64, float64 STATUS_PARAM );
char float64_lt_quiet( float64, float64 STATUS_PARAM );
char float64_compare( float64, float64 STATUS_PARAM );
char float64_compare_quiet( float64, float64 STATUS_PARAM );
char float64_is_signaling_nan( float64 );
INLINE float64 float64_abs(float64 a)
{
return a & 0x7fffffffffffffffLL;
}
INLINE float64 float64_chs(float64 a)
{
return a ^ 0x8000000000000000LL;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 STATUS_PARAM );
int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
int64_t floatx80_to_int64( floatx80 STATUS_PARAM );
int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM );
float32 floatx80_to_float32( floatx80 STATUS_PARAM );
float64 floatx80_to_float64( floatx80 STATUS_PARAM );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM );
floatx80 floatx80_add( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sub( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
char floatx80_eq( floatx80, floatx80 STATUS_PARAM );
char floatx80_le( floatx80, floatx80 STATUS_PARAM );
char floatx80_lt( floatx80, floatx80 STATUS_PARAM );
char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_is_signaling_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
a.high &= 0x7fff;
return a;
}
INLINE floatx80 floatx80_chs(floatx80 a)
{
a.high ^= 0x8000;
return a;
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
int float128_to_int32( float128 STATUS_PARAM );
int float128_to_int32_round_to_zero( float128 STATUS_PARAM );
int64_t float128_to_int64( float128 STATUS_PARAM );
int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM );
float32 float128_to_float32( float128 STATUS_PARAM );
float64 float128_to_float64( float128 STATUS_PARAM );
#ifdef FLOATX80
floatx80 float128_to_floatx80( float128 STATUS_PARAM );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
*----------------------------------------------------------------------------*/
float128 float128_round_to_int( float128 STATUS_PARAM );
float128 float128_add( float128, float128 STATUS_PARAM );
float128 float128_sub( float128, float128 STATUS_PARAM );
float128 float128_mul( float128, float128 STATUS_PARAM );
float128 float128_div( float128, float128 STATUS_PARAM );
float128 float128_rem( float128, float128 STATUS_PARAM );
float128 float128_sqrt( float128 STATUS_PARAM );
char float128_eq( float128, float128 STATUS_PARAM );
char float128_le( float128, float128 STATUS_PARAM );
char float128_lt( float128, float128 STATUS_PARAM );
char float128_eq_signaling( float128, float128 STATUS_PARAM );
char float128_le_quiet( float128, float128 STATUS_PARAM );
char float128_lt_quiet( float128, float128 STATUS_PARAM );
char float128_is_signaling_nan( float128 );
INLINE float128 float128_abs(float128 a)
{
a.high &= 0x7fffffffffffffffLL;
return a;
}
INLINE float128 float128_chs(float128 a)
{
a.high ^= 0x8000000000000000LL;
return a;
}
#endif
#else /* CONFIG_SOFTFLOAT */
#include "softfloat-native.h"
#endif /* !CONFIG_SOFTFLOAT */
#endif /* !SOFTFLOAT_H */

388
gdbstub.c
View File

@@ -1,7 +1,7 @@
/*
* gdb server stub
*
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,18 +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
*/
#ifdef CONFIG_USER_ONLY
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "qemu.h"
#else
#include "vl.h"
#endif
#include <sys/socket.h>
#include <netinet/in.h>
@@ -43,25 +32,17 @@ enum RSState {
RS_CHKSUM1,
RS_CHKSUM2,
};
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
static int gdbserver_fd;
typedef struct GDBState {
enum RSState state; /* parsing state */
enum RSState state;
int fd;
char line_buf[4096];
int line_buf_index;
int line_csum;
#ifdef CONFIG_USER_ONLY
int running_state;
#endif
} GDBState;
#ifdef CONFIG_USER_ONLY
/* XXX: remove this hack. */
static GDBState gdbserver_state;
#endif
static int get_char(GDBState *s)
{
uint8_t ch;
@@ -176,40 +157,42 @@ static int put_packet(GDBState *s, char *buf)
#if defined(TARGET_I386)
static void to_le32(uint8_t *p, int v)
{
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
}
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf;
int i, fpus;
for(i = 0; i < 8; i++) {
registers[i] = env->regs[i];
to_le32(mem_buf + i * 4, env->regs[i]);
}
registers[8] = env->eip;
registers[9] = env->eflags;
registers[10] = env->segs[R_CS].selector;
registers[11] = env->segs[R_SS].selector;
registers[12] = env->segs[R_DS].selector;
registers[13] = env->segs[R_ES].selector;
registers[14] = env->segs[R_FS].selector;
registers[15] = env->segs[R_GS].selector;
to_le32(mem_buf + 8 * 4, env->eip);
to_le32(mem_buf + 9 * 4, env->eflags);
to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector);
to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector);
to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector);
to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector);
to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector);
to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector);
/* XXX: convert floats */
for(i = 0; i < 8; i++) {
memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10);
}
registers[36] = env->fpuc;
to_le32(mem_buf + 36 * 4, env->fpuc);
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
registers[37] = fpus;
registers[38] = 0; /* XXX: convert tags */
registers[39] = 0; /* fiseg */
registers[40] = 0; /* fioff */
registers[41] = 0; /* foseg */
registers[42] = 0; /* fooff */
registers[43] = 0; /* fop */
for(i = 0; i < 16; i++)
tswapls(&registers[i]);
for(i = 36; i < 44; i++)
tswapls(&registers[i]);
to_le32(mem_buf + 37 * 4, fpus);
to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */
to_le32(mem_buf + 39 * 4, 0); /* fiseg */
to_le32(mem_buf + 40 * 4, 0); /* fioff */
to_le32(mem_buf + 41 * 4, 0); /* foseg */
to_le32(mem_buf + 42 * 4, 0); /* fooff */
to_le32(mem_buf + 43 * 4, 0); /* fop */
return 44 * 4;
}
@@ -221,8 +204,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
for(i = 0; i < 8; i++) {
env->regs[i] = tswapl(registers[i]);
}
env->eip = tswapl(registers[8]);
env->eflags = tswapl(registers[9]);
env->eip = registers[8];
env->eflags = registers[9];
#if defined(CONFIG_USER_ONLY)
#define LOAD_SEG(index, sreg)\
if (tswapl(registers[index]) != env->segs[sreg].selector)\
@@ -237,6 +220,22 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
}
#elif defined (TARGET_PPC)
static void to_le32(uint32_t *buf, uint32_t v)
{
uint8_t *p = (uint8_t *)buf;
p[3] = v;
p[2] = v >> 8;
p[1] = v >> 16;
p[0] = v >> 24;
}
static uint32_t from_le32 (uint32_t *buf)
{
uint8_t *p = (uint8_t *)buf;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf, tmp;
@@ -244,24 +243,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
/* fill in gprs */
for(i = 0; i < 32; i++) {
registers[i] = tswapl(env->gpr[i]);
to_le32(&registers[i], env->gpr[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1));
to_le32(&registers[(i * 2) + 32], *((uint32_t *)&env->fpr[i]));
to_le32(&registers[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1));
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
registers[96] = tswapl(env->nip);
registers[97] = tswapl(do_load_msr(env));
to_le32(&registers[96], (uint32_t)env->nip/* - 4*/);
to_le32(&registers[97], _load_msr(env));
tmp = 0;
for (i = 0; i < 8; i++)
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr);
registers[101] = tswapl(do_load_xer(env));
registers[102] = 0;
to_le32(&registers[98], tmp);
to_le32(&registers[99], env->lr);
to_le32(&registers[100], env->ctr);
to_le32(&registers[101], _load_xer(env));
to_le32(&registers[102], 0);
return 103 * 4;
}
@@ -273,154 +272,25 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
/* fill in gprs */
for (i = 0; i < 32; i++) {
env->gpr[i] = tswapl(registers[i]);
env->gpr[i] = from_le32(&registers[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]);
*((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]);
*((uint32_t *)&env->fpr[i]) = from_le32(&registers[(i * 2) + 32]);
*((uint32_t *)&env->fpr[i] + 1) = from_le32(&registers[(i * 2) + 33]);
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
env->nip = tswapl(registers[96]);
do_store_msr(env, tswapl(registers[97]));
registers[98] = tswapl(registers[98]);
env->nip = from_le32(&registers[96]);
_store_msr(env, from_le32(&registers[97]));
registers[98] = from_le32(&registers[98]);
for (i = 0; i < 8; i++)
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]);
do_store_xer(env, tswapl(registers[101]));
}
#elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
target_ulong *registers = (target_ulong *)mem_buf;
int i;
/* fill in g0..g7 */
for(i = 0; i < 7; i++) {
registers[i] = tswapl(env->gregs[i]);
}
/* fill in register window */
for(i = 0; i < 24; i++) {
registers[i + 8] = tswapl(env->regwptr[i]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
}
#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
registers[64] = tswapl(env->y);
{
target_ulong tmp;
tmp = GET_PSR(env);
registers[65] = tswapl(tmp);
}
registers[66] = tswapl(env->wim);
registers[67] = tswapl(env->tbr);
registers[68] = tswapl(env->pc);
registers[69] = tswapl(env->npc);
registers[70] = tswapl(env->fsr);
registers[71] = 0; /* csr */
registers[72] = 0;
return 73 * sizeof(target_ulong);
#else
for (i = 0; i < 32; i += 2) {
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
}
registers[81] = tswapl(env->pc);
registers[82] = tswapl(env->npc);
registers[83] = tswapl(env->tstate[env->tl]);
registers[84] = tswapl(env->fsr);
registers[85] = tswapl(env->fprs);
registers[86] = tswapl(env->y);
return 87 * sizeof(target_ulong);
#endif
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
target_ulong *registers = (target_ulong *)mem_buf;
int i;
/* fill in g0..g7 */
for(i = 0; i < 7; i++) {
env->gregs[i] = tswapl(registers[i]);
}
/* fill in register window */
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i + 8]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
}
#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
env->y = tswapl(registers[64]);
PUT_PSR(env, tswapl(registers[65]));
env->wim = tswapl(registers[66]);
env->tbr = tswapl(registers[67]);
env->pc = tswapl(registers[68]);
env->npc = tswapl(registers[69]);
env->fsr = tswapl(registers[70]);
#else
for (i = 0; i < 32; i += 2) {
uint64_t tmp;
tmp = tswapl(registers[i/2 + 64]) << 32;
tmp |= tswapl(registers[i/2 + 64 + 1]);
*((uint64_t *)&env->fpr[i]) = tmp;
}
env->pc = tswapl(registers[81]);
env->npc = tswapl(registers[82]);
env->tstate[env->tl] = tswapl(registers[83]);
env->fsr = tswapl(registers[84]);
env->fprs = tswapl(registers[85]);
env->y = tswapl(registers[86]);
#endif
}
#elif defined (TARGET_ARM)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
int i;
uint8_t *ptr;
ptr = mem_buf;
/* 16 core integer registers (4 bytes each). */
for (i = 0; i < 16; i++)
{
*(uint32_t *)ptr = tswapl(env->regs[i]);
ptr += 4;
}
/* 8 FPA registers (12 bytes each), FPS (4 bytes).
Not yet implemented. */
memset (ptr, 0, 8 * 12 + 4);
ptr += 8 * 12 + 4;
/* CPSR (4 bytes). */
*(uint32_t *)ptr = tswapl (env->cpsr);
ptr += 4;
return ptr - mem_buf;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
int i;
uint8_t *ptr;
ptr = mem_buf;
/* Core integer registers. */
for (i = 0; i < 16; i++)
{
env->regs[i] = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
/* Ignore FPA regs and scr. */
ptr += 8 * 12 + 4;
env->cpsr = tswapl(*(uint32_t *)ptr);
env->lr = from_le32(&registers[99]);
env->ctr = from_le32(&registers[100]);
_store_xer(env, from_le32(&registers[101]));
}
#else
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
return 0;
@@ -432,8 +302,10 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
#endif
static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
/* port = 0 means default port */
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
CPUState *env = cpu_single_env;
const char *p;
int ch, reg_size, type;
char buf[4096];
@@ -448,7 +320,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
ch = *p++;
switch(ch) {
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
put_packet(s, buf);
break;
@@ -459,17 +330,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
env->eip = addr;
#elif defined (TARGET_PPC)
env->nip = addr;
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#endif
}
#ifdef CONFIG_USER_ONLY
s->running_state = 1;
#else
vm_start();
#endif
return RS_IDLE;
break;
case 's':
if (*p != '\0') {
addr = strtoul(p, (char **)&p, 16);
@@ -477,18 +341,11 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
env->eip = addr;
#elif defined (TARGET_PPC)
env->nip = addr;
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#endif
}
cpu_single_step(env, 1);
#ifdef CONFIG_USER_ONLY
s->running_state = 1;
#else
vm_start();
#endif
return RS_IDLE;
break;
case 'g':
reg_size = cpu_gdb_read_registers(env, mem_buf);
memtohex(buf, mem_buf, reg_size);
@@ -516,11 +373,11 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (*p == ':')
if (*p == ',')
p++;
hextomem(mem_buf, p, len);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
put_packet(s, "E14");
put_packet(s, "ENN");
else
put_packet(s, "OK");
break;
@@ -538,7 +395,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
put_packet(s, "OK");
} else {
breakpoint_error:
put_packet(s, "E22");
put_packet(s, "ENN");
}
break;
case 'z':
@@ -566,9 +423,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
return RS_IDLE;
}
extern void tb_flush(CPUState *env);
#ifndef CONFIG_USER_ONLY
static void gdb_vm_stopped(void *opaque, int reason)
{
GDBState *s = opaque;
@@ -578,30 +432,24 @@ static void gdb_vm_stopped(void *opaque, int reason)
/* disable single step if it was enable */
cpu_single_step(cpu_single_env, 0);
if (reason == EXCP_DEBUG) {
tb_flush(cpu_single_env);
if (reason == EXCP_DEBUG)
ret = SIGTRAP;
}
else
ret = 0;
snprintf(buf, sizeof(buf), "S%02x", ret);
put_packet(s, buf);
}
#endif
static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
static void gdb_read_byte(GDBState *s, int ch)
{
int i, csum;
char reply[1];
#ifndef CONFIG_USER_ONLY
if (vm_running) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
vm_stop(EXCP_INTERRUPT);
} else
#endif
{
} else {
switch(s->state) {
case RS_IDLE:
if (ch == '$') {
@@ -636,74 +484,13 @@ static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
} else {
reply[0] = '+';
put_buffer(s, reply, 1);
s->state = gdb_handle_packet(s, env, s->line_buf);
s->state = gdb_handle_packet(s, s->line_buf);
}
break;
}
}
}
#ifdef CONFIG_USER_ONLY
int
gdb_handlesig (CPUState *env, int sig)
{
GDBState *s;
char buf[256];
int n;
if (gdbserver_fd < 0)
return sig;
s = &gdbserver_state;
/* disable single step if it was enabled */
cpu_single_step(env, 0);
tb_flush(env);
if (sig != 0)
{
snprintf(buf, sizeof(buf), "S%02x", sig);
put_packet(s, buf);
}
sig = 0;
s->state = RS_IDLE;
s->running_state = 0;
while (s->running_state == 0) {
n = read (s->fd, buf, 256);
if (n > 0)
{
int i;
for (i = 0; i < n; i++)
gdb_read_byte (s, env, buf[i]);
}
else if (n == 0 || errno != EAGAIN)
{
/* XXX: Connection closed. Should probably wait for annother
connection before continuing. */
return sig;
}
}
return sig;
}
/* Tell the remote gdb that the process has exited. */
void gdb_exit(CPUState *env, int code)
{
GDBState *s;
char buf[4];
if (gdbserver_fd < 0)
return;
s = &gdbserver_state;
snprintf(buf, sizeof(buf), "W%02x", code);
put_packet(s, buf);
}
#else
static int gdb_can_read(void *opaque)
{
return 256;
@@ -721,12 +508,10 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size)
vm_start();
} else {
for(i = 0; i < size; i++)
gdb_read_byte(s, cpu_single_env, buf[i]);
gdb_read_byte(s, buf[i]);
}
}
#endif
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
{
GDBState *s;
@@ -749,21 +534,15 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
memset (s, 0, sizeof (GDBState));
#else
s = qemu_mallocz(sizeof(GDBState));
if (!s) {
close(fd);
return;
}
#endif
s->fd = fd;
fcntl(fd, F_SETFL, O_NONBLOCK);
#ifndef CONFIG_USER_ONLY
/* stop the VM */
vm_stop(EXCP_INTERRUPT);
@@ -771,7 +550,6 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
/* when the VM is stopped, the following callback is called */
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
#endif
}
static int gdbserver_open(int port)
@@ -802,9 +580,7 @@ static int gdbserver_open(int port)
perror("listen");
return -1;
}
#ifndef CONFIG_USER_ONLY
fcntl(fd, F_SETFL, O_NONBLOCK);
#endif
return fd;
}
@@ -814,10 +590,6 @@ int gdbserver_start(int port)
if (gdbserver_fd < 0)
return -1;
/* accept connections */
#ifdef CONFIG_USER_ONLY
gdb_accept (NULL, NULL, 0);
#else
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
#endif
return 0;
}

View File

@@ -1,12 +0,0 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
#define DEFAULT_GDBSTUB_PORT 1234
#ifdef CONFIG_USER_ONLY
int gdb_handlesig (CPUState *, int);
void gdb_exit(CPUState *, int);
#endif
int gdbserver_start(int);
#endif

114
hw/adb.c
View File

@@ -43,62 +43,53 @@
#define ADB_MODEM 5
#define ADB_MISC 7
/* error codes */
#define ADB_RET_NOTPRESENT (-2)
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
{
ADBDevice *d;
int devaddr, cmd, i;
cmd = buf[0] & 0xf;
if (cmd == ADB_BUSRESET) {
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devreset) {
d->devreset(d);
}
}
return 0;
}
devaddr = buf[0] >> 4;
if (buf[1] == ADB_BUSRESET) {
obuf[0] = 0x00;
obuf[1] = 0x00;
return 2;
}
if (cmd == ADB_FLUSH) {
obuf[0] = 0x00;
obuf[1] = 0x00;
return 2;
}
for(i = 0; i < s->nb_devices; i++) {
d = &s->devices[i];
if (d->devaddr == devaddr) {
return d->devreq(d, obuf, buf, len);
}
}
return ADB_RET_NOTPRESENT;
return 0;
}
/* XXX: move that to cuda ? */
int adb_poll(ADBBusState *s, uint8_t *obuf)
{
ADBDevice *d;
int olen, i;
uint8_t buf[1];
olen = 0;
for(i = 0; i < s->nb_devices; i++) {
if (s->poll_index >= s->nb_devices)
s->poll_index = 0;
d = &s->devices[s->poll_index];
buf[0] = ADB_READREG | (d->devaddr << 4);
olen = adb_request(s, obuf + 1, buf, 1);
/* if there is data, we poll again the same device */
if (olen > 0) {
obuf[0] = buf[0];
olen++;
break;
}
olen = d->devreq(d, obuf, NULL, 0);
s->poll_index++;
if (olen)
break;
}
return olen;
}
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
ADBDeviceRequest *devreq,
ADBDeviceReset *devreset,
void *opaque)
{
ADBDevice *d;
@@ -108,7 +99,6 @@ ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
d->bus = s;
d->devaddr = devaddr;
d->devreq = devreq;
d->devreset = devreset;
d->opaque = opaque;
return d;
}
@@ -176,10 +166,10 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
adb_keycode = pc_to_adb_keycode[keycode | 0x80];
else
adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
obuf[0] = adb_keycode | (keycode & 0x80);
/* NOTE: could put a second keycode if needed */
obuf[1] = 0xff;
olen = 2;
obuf[0] = (d->devaddr << 4) | 0x0c;
obuf[1] = adb_keycode | (keycode & 0x80);
obuf[2] = 0xff;
olen = 3;
ext_keycode = 0;
break;
}
@@ -190,13 +180,10 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
KBDState *s = d->opaque;
int cmd, reg, olen;
if ((buf[0] & 0x0f) == ADB_FLUSH) {
/* flush keyboard fifo */
s->wptr = s->rptr = s->count = 0;
return 0;
if (!buf) {
return adb_kbd_poll(d, obuf);
}
cmd = buf[0] & 0xc;
@@ -227,9 +214,6 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
break;
case ADB_READREG:
switch(reg) {
case 0:
olen = adb_kbd_poll(d, obuf);
break;
case 1:
break;
case 2:
@@ -248,25 +232,13 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
return olen;
}
static int adb_kbd_reset(ADBDevice *d)
{
KBDState *s = d->opaque;
d->handler = 1;
d->devaddr = ADB_KEYBOARD;
memset(s, 0, sizeof(KBDState));
return 0;
}
void adb_kbd_init(ADBBusState *bus)
{
ADBDevice *d;
KBDState *s;
s = qemu_mallocz(sizeof(KBDState));
d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
adb_kbd_reset, s);
adb_kbd_reset(d);
d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, s);
d->handler = 1;
qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
}
@@ -319,29 +291,24 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
dx &= 0x7f;
dy &= 0x7f;
if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
if (s->buttons_state & MOUSE_EVENT_LBUTTON)
dy |= 0x80;
if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
if (s->buttons_state & MOUSE_EVENT_RBUTTON)
dx |= 0x80;
obuf[0] = dy;
obuf[1] = dx;
return 2;
obuf[0] = (d->devaddr << 4) | 0x0c;
obuf[1] = dy;
obuf[2] = dx;
return 3;
}
static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
const uint8_t *buf, int len)
{
MouseState *s = d->opaque;
int cmd, reg, olen;
if ((buf[0] & 0x0f) == ADB_FLUSH) {
/* flush mouse fifo */
s->buttons_state = s->last_buttons_state;
s->dx = 0;
s->dy = 0;
s->dz = 0;
return 0;
if (!buf) {
return adb_mouse_poll(d, obuf);
}
cmd = buf[0] & 0xc;
@@ -370,9 +337,6 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
break;
case ADB_READREG:
switch(reg) {
case 0:
olen = adb_mouse_poll(d, obuf);
break;
case 1:
break;
case 3:
@@ -386,25 +350,13 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
return olen;
}
static int adb_mouse_reset(ADBDevice *d)
{
MouseState *s = d->opaque;
d->handler = 2;
d->devaddr = ADB_MOUSE;
memset(s, 0, sizeof(MouseState));
return 0;
}
void adb_mouse_init(ADBBusState *bus)
{
ADBDevice *d;
MouseState *s;
s = qemu_mallocz(sizeof(MouseState));
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
adb_mouse_reset, s);
adb_mouse_reset(d);
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, s);
d->handler = 2;
qemu_add_mouse_event_handler(adb_mouse_event, d);
}

View File

@@ -1,313 +0,0 @@
/*
* QEMU Adlib emulation
*
* Copyright (c) 2004 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
#ifdef USE_YMF262
#define HAS_YMF262 1
#include "ymf262.h"
void YMF262UpdateOneQEMU(int which, INT16 *dst, int length);
#define SHIFT 2
#else
#include "fmopl.h"
#define SHIFT 1
#endif
#ifdef _WIN32
#include <windows.h>
#define small_delay() Sleep (1)
#else
#define small_delay() usleep (1)
#endif
#define IO_READ_PROTO(name) \
uint32_t name (void *opaque, uint32_t nport)
#define IO_WRITE_PROTO(name) \
void name (void *opaque, uint32_t nport, uint32_t val)
static struct {
int port;
int freq;
} conf = {0x220, 44100};
typedef struct {
int enabled;
int active;
int cparam;
int64_t ticks;
int bufpos;
int16_t *mixbuf;
double interval;
QEMUTimer *ts, *opl_ts;
SWVoice *voice;
int left, pos, samples, bytes_per_second, old_free;
int refcount;
#ifndef USE_YMF262
FM_OPL *opl;
#endif
} AdlibState;
static AdlibState adlib;
static IO_WRITE_PROTO(adlib_write)
{
AdlibState *s = opaque;
int a = nport & 3;
int status;
s->ticks = qemu_get_clock (vm_clock);
s->active = 1;
AUD_enable (s->voice, 1);
#ifdef USE_YMF262
status = YMF262Write (0, a, val);
#else
status = OPLWrite (s->opl, a, val);
#endif
}
static IO_READ_PROTO(adlib_read)
{
AdlibState *s = opaque;
uint8_t data;
int a = nport & 3;
#ifdef USE_YMF262
(void) s;
data = YMF262Read (0, a);
#else
data = OPLRead (s->opl, a);
#endif
return data;
}
static void OPL_timer (void *opaque)
{
AdlibState *s = opaque;
#ifdef USE_YMF262
YMF262TimerOver (s->cparam >> 1, s->cparam & 1);
#else
OPLTimerOver (s->opl, s->cparam);
#endif
qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
}
static void YMF262TimerHandler (int c, double interval_Sec)
{
AdlibState *s = &adlib;
if (interval_Sec == 0.0) {
qemu_del_timer (s->opl_ts);
return;
}
s->cparam = c;
s->interval = ticks_per_sec * interval_Sec;
qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
small_delay ();
}
static int write_audio (AdlibState *s, int samples)
{
int net = 0;
int ss = samples;
while (samples) {
int nbytes = samples << SHIFT;
int wbytes = AUD_write (s->voice,
s->mixbuf + (s->pos << (SHIFT - 1)),
nbytes);
int wsampl = wbytes >> SHIFT;
samples -= wsampl;
s->pos = (s->pos + wsampl) % s->samples;
net += wsampl;
if (!wbytes)
break;
}
if (net > ss) {
dolog ("WARNING: net > ss\n");
}
return net;
}
static void timer (void *opaque)
{
AdlibState *s = opaque;
int elapsed, samples, net = 0;
if (s->refcount)
dolog ("refcount=%d\n", s->refcount);
s->refcount += 1;
if (!(s->active && s->enabled))
goto reset;
AUD_run ();
while (s->left) {
int written = write_audio (s, s->left);
net += written;
if (!written)
goto reset2;
s->left -= written;
}
s->pos = 0;
elapsed = AUD_calc_elapsed (s->voice);
if (!elapsed)
goto reset2;
/* elapsed = AUD_get_free (s->voice); */
samples = elapsed >> SHIFT;
if (!samples)
goto reset2;
samples = audio_MIN (samples, s->samples - s->pos);
if (s->left)
dolog ("left=%d samples=%d elapsed=%d free=%d\n",
s->left, samples, elapsed, AUD_get_free (s->voice));
if (!samples)
goto reset2;
#ifdef USE_YMF262
YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
#else
YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
#endif
while (samples) {
int written = write_audio (s, samples);
net += written;
if (!written)
break;
samples -= written;
}
if (!samples)
s->pos = 0;
s->left = samples;
reset2:
AUD_adjust (s->voice, net << SHIFT);
reset:
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024);
s->refcount -= 1;
}
static void Adlib_fini (AdlibState *s)
{
#ifdef USE_YMF262
YMF262Shutdown ();
#else
if (s->opl) {
OPLDestroy (s->opl);
s->opl = NULL;
}
#endif
if (s->opl_ts)
qemu_free_timer (s->opl_ts);
if (s->ts)
qemu_free_timer (s->ts);
#define maybe_free(p) if (p) qemu_free (p)
maybe_free (s->mixbuf);
#undef maybe_free
s->active = 0;
s->enabled = 0;
}
void Adlib_init (void)
{
AdlibState *s = &adlib;
memset (s, 0, sizeof (*s));
#ifdef USE_YMF262
if (YMF262Init (1, 14318180, conf.freq)) {
dolog ("YMF262Init %d failed\n", conf.freq);
return;
}
else {
YMF262SetTimerHandler (0, YMF262TimerHandler, 0);
s->enabled = 1;
}
#else
s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
if (!s->opl) {
dolog ("OPLCreate %d failed\n", conf.freq);
return;
}
else {
OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
s->enabled = 1;
}
#endif
s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s);
if (!s->opl_ts) {
dolog ("Can not get timer for adlib emulation\n");
Adlib_fini (s);
return;
}
s->ts = qemu_new_timer (vm_clock, timer, s);
if (!s->opl_ts) {
dolog ("Can not get timer for adlib emulation\n");
Adlib_fini (s);
return;
}
s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16);
if (!s->voice) {
Adlib_fini (s);
return;
}
s->bytes_per_second = conf.freq << SHIFT;
s->samples = AUD_get_buffer_size (s->voice) >> SHIFT;
s->mixbuf = qemu_mallocz (s->samples << SHIFT);
if (!s->mixbuf) {
dolog ("not enough memory for adlib mixing buffer (%d)\n",
s->samples << SHIFT);
Adlib_fini (s);
return;
}
register_ioport_read (0x388, 4, 1, adlib_read, s);
register_ioport_write (0x388, 4, 1, adlib_write, s);
register_ioport_read (conf.port, 4, 1, adlib_read, s);
register_ioport_write (conf.port, 4, 1, adlib_write, s);
register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
}

956
hw/apic.c
View File

@@ -1,956 +0,0 @@
/*
* APIC support
*
* Copyright (c) 2004-2005 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "vl.h"
//#define DEBUG_APIC
//#define DEBUG_IOAPIC
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
#define APIC_LVT_THERMAL 1
#define APIC_LVT_PERFORM 2
#define APIC_LVT_LINT0 3
#define APIC_LVT_LINT1 4
#define APIC_LVT_ERROR 5
#define APIC_LVT_NB 6
/* APIC delivery modes */
#define APIC_DM_FIXED 0
#define APIC_DM_LOWPRI 1
#define APIC_DM_SMI 2
#define APIC_DM_NMI 4
#define APIC_DM_INIT 5
#define APIC_DM_SIPI 6
#define APIC_DM_EXTINT 7
/* APIC destination mode */
#define APIC_DESTMODE_FLAT 0xf
#define APIC_DESTMODE_CLUSTER 1
#define APIC_TRIGGER_EDGE 0
#define APIC_TRIGGER_LEVEL 1
#define APIC_LVT_TIMER_PERIODIC (1<<17)
#define APIC_LVT_MASKED (1<<16)
#define APIC_LVT_LEVEL_TRIGGER (1<<15)
#define APIC_LVT_REMOTE_IRR (1<<14)
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
#define IOAPIC_NUM_PINS 0x18
#define ESR_ILLEGAL_ADDRESS (1 << 7)
#define APIC_SV_ENABLE (1 << 8)
typedef struct APICState {
CPUState *cpu_env;
uint32_t apicbase;
uint8_t id;
uint8_t arb_id;
uint8_t tpr;
uint32_t spurious_vec;
uint8_t log_dest;
uint8_t dest_mode;
uint32_t isr[8]; /* in service register */
uint32_t tmr[8]; /* trigger mode register */
uint32_t irr[8]; /* interrupt request register */
uint32_t lvt[APIC_LVT_NB];
uint32_t esr; /* error register */
uint32_t icr[2];
uint32_t divide_conf;
int count_shift;
uint32_t initial_count;
int64_t initial_count_load_time, next_time;
QEMUTimer *timer;
struct APICState *next_apic;
} APICState;
struct IOAPICState {
uint8_t id;
uint8_t ioregsel;
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
};
static int apic_io_memory;
static APICState *first_local_apic = NULL;
static int last_apic_id = 0;
static void apic_init_ipi(APICState *s);
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
static void apic_update_irq(APICState *s);
static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
uint8_t vector_num, uint8_t polarity,
uint8_t trigger_mode)
{
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
case APIC_DM_FIXED:
/* XXX: arbitration */
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
break;
case APIC_DM_INIT:
/* normal INIT IPI sent to processors */
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
apic_init_ipi(apic_iter);
}
return;
case APIC_DM_EXTINT:
/* handled in I/O APIC code */
break;
default:
return;
}
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id))
apic_set_irq(apic_iter, vector_num, trigger_mode);
}
}
void cpu_set_apic_base(CPUState *env, uint64_t val)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
printf("cpu_set_apic_base: %016llx\n", val);
#endif
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)) {
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
env->cpuid_features &= ~CPUID_APIC;
s->spurious_vec &= ~APIC_SV_ENABLE;
}
}
uint64_t cpu_get_apic_base(CPUState *env)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
#endif
return s->apicbase;
}
void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
{
APICState *s = env->apic_state;
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
}
uint8_t cpu_get_apic_tpr(CPUX86State *env)
{
APICState *s = env->apic_state;
return s->tpr >> 4;
}
static int fls_bit(int value)
{
unsigned int ret = 0;
#ifdef HOST_I386
__asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
return ret;
#else
if (value > 0xffff)
value >>= 16, ret = 16;
if (value > 0xff)
value >>= 8, ret += 8;
if (value > 0xf)
value >>= 4, ret += 4;
if (value > 0x3)
value >>= 2, ret += 2;
return ret + (value >> 1);
#endif
}
static inline void set_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
tab[i] |= mask;
}
static inline void reset_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
tab[i] &= ~mask;
}
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
int i;
for(i = 7; i >= 0; i--) {
if (tab[i] != 0) {
return i * 32 + fls_bit(tab[i]);
}
}
return -1;
}
static int apic_get_ppr(APICState *s)
{
int tpr, isrv, ppr;
tpr = (s->tpr >> 4);
isrv = get_highest_priority_int(s->isr);
if (isrv < 0)
isrv = 0;
isrv >>= 4;
if (tpr >= isrv)
ppr = s->tpr;
else
ppr = isrv << 4;
return ppr;
}
static int apic_get_arb_pri(APICState *s)
{
/* XXX: arbitration */
return 0;
}
/* signal the CPU if an irq is pending */
static void apic_update_irq(APICState *s)
{
int irrv, ppr;
if (!(s->spurious_vec & APIC_SV_ENABLE))
return;
irrv = get_highest_priority_int(s->irr);
if (irrv < 0)
return;
ppr = apic_get_ppr(s);
if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
return;
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
{
set_bit(s->irr, vector_num);
if (trigger_mode)
set_bit(s->tmr, vector_num);
else
reset_bit(s->tmr, vector_num);
apic_update_irq(s);
}
static void apic_eoi(APICState *s)
{
int isrv;
isrv = get_highest_priority_int(s->isr);
if (isrv < 0)
return;
reset_bit(s->isr, isrv);
/* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
set the remote IRR bit for level triggered interrupts. */
apic_update_irq(s);
}
static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
{
uint32_t mask = 0;
APICState *apic_iter;
if (dest_mode == 0) {
if (dest == 0xff)
mask = 0xff;
else
mask = 1 << dest;
} else {
/* XXX: cluster mode */
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (dest & apic_iter->log_dest)
mask |= (1 << apic_iter->id);
}
}
return mask;
}
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;
s->dest_mode = 0;
memset(s->isr, 0, sizeof(s->isr));
memset(s->tmr, 0, sizeof(s->tmr));
memset(s->irr, 0, sizeof(s->irr));
memset(s->lvt, 0, sizeof(s->lvt));
s->esr = 0;
memset(s->icr, 0, sizeof(s->icr));
s->divide_conf = 0;
s->count_shift = 0;
s->initial_count = 0;
s->initial_count_load_time = 0;
s->next_time = 0;
}
static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t polarity, uint8_t trigger_mode)
{
uint32_t deliver_bitmask = 0;
int dest_shorthand = (s->icr[0] >> 18) & 3;
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
/* XXX: serch for focus processor, arbitration */
dest = s->id;
case APIC_DM_INIT:
{
int trig_mode = (s->icr[0] >> 15) & 1;
int level = (s->icr[0] >> 14) & 1;
if (level == 0 && trig_mode == 1) {
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id)) {
apic_iter->arb_id = apic_iter->id;
}
}
return;
}
}
break;
case APIC_DM_SIPI:
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id)) {
/* XXX: SMP support */
/* apic_startup(apic_iter); */
}
}
return;
}
switch (dest_shorthand) {
case 0:
deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
break;
case 1:
deliver_bitmask = (1 << s->id);
break;
case 2:
deliver_bitmask = 0xffffffff;
break;
case 3:
deliver_bitmask = 0xffffffff & ~(1 << s->id);
break;
}
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
trigger_mode);
}
int apic_get_interrupt(CPUState *env)
{
APICState *s = env->apic_state;
int intno;
/* if the APIC is installed or enabled, we let the 8259 handle the
IRQs */
if (!s)
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;
set_bit(s->isr, intno);
apic_update_irq(s);
return intno;
}
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) >>
s->count_shift;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
/* periodic */
val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
} else {
if (d >= s->initial_count)
val = 0;
else
val = s->initial_count - d;
}
return val;
}
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) >>
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);
} else {
if (d >= s->initial_count)
goto no_timer;
d = (uint64_t)s->initial_count + 1;
}
next_time = s->initial_count_load_time + (d << s->count_shift);
qemu_mod_timer(s->timer, next_time);
s->next_time = next_time;
} else {
no_timer:
qemu_del_timer(s->timer);
}
}
static void apic_timer(void *opaque)
{
APICState *s = opaque;
if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
}
apic_timer_update(s, s->next_time);
}
static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
{
return 0;
}
static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
{
return 0;
}
static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
}
static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
}
static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
{
CPUState *env;
APICState *s;
uint32_t val;
int index;
env = cpu_single_env;
if (!env)
return 0;
s = env->apic_state;
index = (addr >> 4) & 0xff;
switch(index) {
case 0x02: /* id */
val = s->id << 24;
break;
case 0x03: /* version */
val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
break;
case 0x08:
val = s->tpr;
break;
case 0x09:
val = apic_get_arb_pri(s);
break;
case 0x0a:
/* ppr */
val = apic_get_ppr(s);
break;
case 0x0d:
val = s->log_dest << 24;
break;
case 0x0e:
val = s->dest_mode << 28;
break;
case 0x0f:
val = s->spurious_vec;
break;
case 0x10 ... 0x17:
val = s->isr[index & 7];
break;
case 0x18 ... 0x1f:
val = s->tmr[index & 7];
break;
case 0x20 ... 0x27:
val = s->irr[index & 7];
break;
case 0x28:
val = s->esr;
break;
case 0x32 ... 0x37:
val = s->lvt[index - 0x32];
break;
case 0x30:
case 0x31:
val = s->icr[index & 1];
break;
case 0x38:
val = s->initial_count;
break;
case 0x39:
val = apic_get_current_count(s);
break;
case 0x3e:
val = s->divide_conf;
break;
default:
s->esr |= ESR_ILLEGAL_ADDRESS;
val = 0;
break;
}
#ifdef DEBUG_APIC
printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
#endif
return val;
}
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
CPUState *env;
APICState *s;
int index;
env = cpu_single_env;
if (!env)
return;
s = env->apic_state;
#ifdef DEBUG_APIC
printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
#endif
index = (addr >> 4) & 0xff;
switch(index) {
case 0x02:
s->id = (val >> 24);
break;
case 0x08:
s->tpr = val;
apic_update_irq(s);
break;
case 0x0b: /* EOI */
apic_eoi(s);
break;
case 0x0d:
s->log_dest = val >> 24;
break;
case 0x0e:
s->dest_mode = val >> 28;
break;
case 0x0f:
s->spurious_vec = val & 0x1ff;
apic_update_irq(s);
break;
case 0x30:
s->icr[0] = val;
apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
(s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
(s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
break;
case 0x31:
s->icr[1] = val;
break;
case 0x32 ... 0x37:
{
int n = index - 0x32;
s->lvt[n] = val;
if (n == APIC_LVT_TIMER)
apic_timer_update(s, qemu_get_clock(vm_clock));
}
break;
case 0x38:
s->initial_count = val;
s->initial_count_load_time = qemu_get_clock(vm_clock);
apic_timer_update(s, s->initial_count_load_time);
break;
case 0x3e:
{
int v;
s->divide_conf = val & 0xb;
v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
s->count_shift = (v + 1) & 7;
}
break;
default:
s->esr |= ESR_ILLEGAL_ADDRESS;
break;
}
}
static void apic_save(QEMUFile *f, void *opaque)
{
APICState *s = opaque;
int i;
qemu_put_be32s(f, &s->apicbase);
qemu_put_8s(f, &s->id);
qemu_put_8s(f, &s->arb_id);
qemu_put_8s(f, &s->tpr);
qemu_put_be32s(f, &s->spurious_vec);
qemu_put_8s(f, &s->log_dest);
qemu_put_8s(f, &s->dest_mode);
for (i = 0; i < 8; i++) {
qemu_put_be32s(f, &s->isr[i]);
qemu_put_be32s(f, &s->tmr[i]);
qemu_put_be32s(f, &s->irr[i]);
}
for (i = 0; i < APIC_LVT_NB; i++) {
qemu_put_be32s(f, &s->lvt[i]);
}
qemu_put_be32s(f, &s->esr);
qemu_put_be32s(f, &s->icr[0]);
qemu_put_be32s(f, &s->icr[1]);
qemu_put_be32s(f, &s->divide_conf);
qemu_put_be32s(f, &s->count_shift);
qemu_put_be32s(f, &s->initial_count);
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)
{
APICState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
/* XXX: what if the base changes? (registered memory regions) */
qemu_get_be32s(f, &s->apicbase);
qemu_get_8s(f, &s->id);
qemu_get_8s(f, &s->arb_id);
qemu_get_8s(f, &s->tpr);
qemu_get_be32s(f, &s->spurious_vec);
qemu_get_8s(f, &s->log_dest);
qemu_get_8s(f, &s->dest_mode);
for (i = 0; i < 8; i++) {
qemu_get_be32s(f, &s->isr[i]);
qemu_get_be32s(f, &s->tmr[i]);
qemu_get_be32s(f, &s->irr[i]);
}
for (i = 0; i < APIC_LVT_NB; i++) {
qemu_get_be32s(f, &s->lvt[i]);
}
qemu_get_be32s(f, &s->esr);
qemu_get_be32s(f, &s->icr[0]);
qemu_get_be32s(f, &s->icr[1]);
qemu_get_be32s(f, &s->divide_conf);
qemu_get_be32s(f, &s->count_shift);
qemu_get_be32s(f, &s->initial_count);
qemu_get_be64s(f, &s->initial_count_load_time);
qemu_get_be64s(f, &s->next_time);
return 0;
}
static void apic_reset(void *opaque)
{
APICState *s = opaque;
apic_init_ipi(s);
}
static CPUReadMemoryFunc *apic_mem_read[3] = {
apic_mem_readb,
apic_mem_readw,
apic_mem_readl,
};
static CPUWriteMemoryFunc *apic_mem_write[3] = {
apic_mem_writeb,
apic_mem_writew,
apic_mem_writel,
};
int apic_init(CPUState *env)
{
APICState *s;
s = qemu_mallocz(sizeof(APICState));
if (!s)
return -1;
env->apic_state = s;
apic_init_ipi(s);
s->id = last_apic_id++;
s->cpu_env = env;
s->apicbase = 0xfee00000 |
(s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
/* 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_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", 0, 1, apic_save, apic_load, s);
qemu_register_reset(apic_reset, s);
s->next_apic = first_local_apic;
first_local_apic = s;
return 0;
}
static void ioapic_service(IOAPICState *s)
{
uint8_t i;
uint8_t trig_mode;
uint8_t vector;
uint8_t delivery_mode;
uint32_t mask;
uint64_t entry;
uint8_t dest;
uint8_t dest_mode;
uint8_t polarity;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
mask = 1 << i;
if (s->irr & mask) {
entry = s->ioredtbl[i];
if (!(entry & APIC_LVT_MASKED)) {
trig_mode = ((entry >> 15) & 1);
dest = entry >> 56;
dest_mode = (entry >> 11) & 1;
delivery_mode = (entry >> 8) & 7;
polarity = (entry >> 13) & 1;
if (trig_mode == APIC_TRIGGER_EDGE)
s->irr &= ~mask;
if (delivery_mode == APIC_DM_EXTINT)
vector = pic_read_irq(isa_pic);
else
vector = entry & 0xff;
apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
delivery_mode, vector, polarity, trig_mode);
}
}
}
}
void ioapic_set_irq(void *opaque, int vector, int level)
{
IOAPICState *s = opaque;
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
if ((entry >> 15) & 1) {
/* level triggered */
if (level) {
s->irr |= mask;
ioapic_service(s);
} else {
s->irr &= ~mask;
}
} else {
/* edge triggered */
if (level) {
s->irr |= mask;
ioapic_service(s);
}
}
}
}
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
{
IOAPICState *s = opaque;
int index;
uint32_t val = 0;
addr &= 0xff;
if (addr == 0x00) {
val = s->ioregsel;
} else if (addr == 0x10) {
switch (s->ioregsel) {
case 0x00:
val = s->id << 24;
break;
case 0x01:
val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
break;
case 0x02:
val = 0;
break;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1)
val = s->ioredtbl[index] >> 32;
else
val = s->ioredtbl[index] & 0xffffffff;
}
}
#ifdef DEBUG_IOAPIC
printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
#endif
}
return val;
}
static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOAPICState *s = opaque;
int index;
addr &= 0xff;
if (addr == 0x00) {
s->ioregsel = val;
return;
} else if (addr == 0x10) {
#ifdef DEBUG_IOAPIC
printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
#endif
switch (s->ioregsel) {
case 0x00:
s->id = (val >> 24) & 0xff;
return;
case 0x01:
case 0x02:
return;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
} else {
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
ioapic_service(s);
}
}
}
}
static void ioapic_save(QEMUFile *f, void *opaque)
{
IOAPICState *s = opaque;
int i;
qemu_put_8s(f, &s->id);
qemu_put_8s(f, &s->ioregsel);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
qemu_put_be64s(f, &s->ioredtbl[i]);
}
}
static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
{
IOAPICState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->id);
qemu_get_8s(f, &s->ioregsel);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
qemu_get_be64s(f, &s->ioredtbl[i]);
}
return 0;
}
static void ioapic_reset(void *opaque)
{
IOAPICState *s = opaque;
int i;
memset(s, 0, sizeof(*s));
for(i = 0; i < IOAPIC_NUM_PINS; i++)
s->ioredtbl[i] = 1 << 16; /* mask LVT */
}
static CPUReadMemoryFunc *ioapic_mem_read[3] = {
ioapic_mem_readl,
ioapic_mem_readl,
ioapic_mem_readl,
};
static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
ioapic_mem_writel,
ioapic_mem_writel,
ioapic_mem_writel,
};
IOAPICState *ioapic_init(void)
{
IOAPICState *s;
int io_memory;
s = qemu_mallocz(sizeof(IOAPICState));
if (!s)
return NULL;
ioapic_reset(s);
s->id = last_apic_id++;
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;
}

View File

@@ -31,7 +31,7 @@
/*
* TODO:
* - destination write mask support not complete (bits 5..7)
* - add support for WRITEMASK (GR2F)
* - optimize linear mappings
* - optimize bitblt functions
*/
@@ -259,6 +259,9 @@ typedef struct CirrusVGAState {
uint8_t *cirrus_srcptr;
uint8_t *cirrus_srcptr_end;
uint32_t cirrus_srccounter;
uint8_t *cirrus_dstptr;
uint8_t *cirrus_dstptr_end;
uint32_t cirrus_dstcounter;
/* hwcursor display state */
int last_hw_cursor_size;
int last_hw_cursor_x;
@@ -266,7 +269,6 @@ typedef struct CirrusVGAState {
int last_hw_cursor_y_start;
int last_hw_cursor_y_end;
int real_vram_size; /* XXX: suppress that */
CPUWriteMemoryFunc **cirrus_linear_write;
} CirrusVGAState;
typedef struct PCICirrusVGAState {
@@ -283,8 +285,7 @@ static uint8_t rop_to_index[256];
***************************************/
static void cirrus_bitblt_reset(CirrusVGAState *s);
static void cirrus_update_memory_access(CirrusVGAState *s);
static void cirrus_bitblt_reset(CirrusVGAState * s);
/***************************************
*
@@ -710,7 +711,9 @@ static void cirrus_bitblt_reset(CirrusVGAState * s)
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
s->cirrus_srccounter = 0;
cirrus_update_memory_access(s);
s->cirrus_dstptr = &s->cirrus_bltbuf[0];
s->cirrus_dstptr_end = &s->cirrus_bltbuf[0];
s->cirrus_dstcounter = 0;
}
static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
@@ -737,14 +740,12 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
else
s->cirrus_blt_srcpitch = ((w + 7) >> 3);
} else {
/* always align input size to 32 bits */
s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
s->cirrus_blt_srcpitch = s->cirrus_blt_width;
}
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
}
s->cirrus_srcptr = s->cirrus_bltbuf;
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
cirrus_update_memory_access(s);
return 1;
}
@@ -790,7 +791,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
blt_rop = s->gr[0x32];
#ifdef DEBUG_BITBLT
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spicth=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
blt_rop,
s->cirrus_blt_mode,
s->cirrus_blt_modeext,
@@ -800,7 +801,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
s->cirrus_blt_srcpitch,
s->cirrus_blt_dstaddr,
s->cirrus_blt_srcaddr,
s->gr[0x2f]);
s->sr[0x2f]);
#endif
switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
@@ -1042,10 +1043,10 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
else
offset <<= 12;
if (s->real_vram_size <= offset)
if (s->vram_size <= offset)
limit = 0;
else
limit = s->real_vram_size - offset;
limit = s->vram_size - offset;
if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
if (limit > 0x8000) {
@@ -1198,6 +1199,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
case 0x14: // Scratch Register 2
case 0x15: // Scratch Register 3
case 0x16: // Performance Tuning Register
case 0x17: // Configuration Readback and Extended Control
case 0x18: // Signature Generator Control
case 0x19: // Signature Generator Result
case 0x1a: // Signature Generator Result
@@ -1212,10 +1214,6 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
reg_index, reg_value);
#endif
break;
case 0x17: // Configuration Readback and Extended Control
s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7);
cirrus_update_memory_access(s);
break;
default:
#ifdef DEBUG_CIRRUS
printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
@@ -1350,19 +1348,13 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
return CIRRUS_HOOK_NOT_HANDLED;
case 0x05: // Standard VGA, Cirrus extended mode
s->gr[reg_index] = reg_value & 0x7f;
cirrus_update_memory_access(s);
break;
case 0x09: // bank offset #0
case 0x0A: // bank offset #1
s->gr[reg_index] = reg_value;
cirrus_update_bank_ptr(s, 0);
cirrus_update_bank_ptr(s, 1);
break;
case 0x0B:
s->gr[reg_index] = reg_value;
cirrus_update_bank_ptr(s, 0);
cirrus_update_bank_ptr(s, 1);
cirrus_update_memory_access(s);
break;
case 0x10: // BGCOLOR 0x0000ff00
case 0x11: // FGCOLOR 0x0000ff00
@@ -1780,12 +1772,11 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
dst = s->vram_ptr + offset;
for (x = 0; x < 8; x++) {
if (val & 0x80) {
*dst = s->cirrus_shadow_gr1;
*dst++ = s->cirrus_shadow_gr1;
} else if (mode == 5) {
*dst = s->cirrus_shadow_gr0;
*dst++ = s->cirrus_shadow_gr0;
}
val <<= 1;
dst++;
}
cpu_physical_memory_set_dirty(s->vram_offset + offset);
cpu_physical_memory_set_dirty(s->vram_offset + offset + 7);
@@ -1803,14 +1794,13 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
dst = s->vram_ptr + offset;
for (x = 0; x < 8; x++) {
if (val & 0x80) {
*dst = s->cirrus_shadow_gr1;
*(dst + 1) = s->gr[0x11];
*dst++ = s->cirrus_shadow_gr1;
*dst++ = s->gr[0x11];
} else if (mode == 5) {
*dst = s->cirrus_shadow_gr0;
*(dst + 1) = s->gr[0x10];
*dst++ = s->cirrus_shadow_gr0;
*dst++ = s->gr[0x10];
}
val <<= 1;
dst += 2;
}
cpu_physical_memory_set_dirty(s->vram_offset + offset);
cpu_physical_memory_set_dirty(s->vram_offset + offset + 15);
@@ -2314,36 +2304,6 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
cirrus_linear_writel,
};
static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
CirrusVGAState *s = (CirrusVGAState *) opaque;
addr &= s->cirrus_addr_mask;
*(s->vram_ptr + addr) = val;
cpu_physical_memory_set_dirty(s->vram_offset + addr);
}
static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
CirrusVGAState *s = (CirrusVGAState *) opaque;
addr &= s->cirrus_addr_mask;
cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val);
cpu_physical_memory_set_dirty(s->vram_offset + addr);
}
static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
CirrusVGAState *s = (CirrusVGAState *) opaque;
addr &= s->cirrus_addr_mask;
cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val);
cpu_physical_memory_set_dirty(s->vram_offset + addr);
}
/***************************************
*
* system to screen memory access
@@ -2445,37 +2405,6 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
cirrus_linear_bitblt_writel,
};
/* Compute the memory access functions */
static void cirrus_update_memory_access(CirrusVGAState *s)
{
unsigned mode;
if ((s->sr[0x17] & 0x44) == 0x44) {
goto generic_io;
} else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
goto generic_io;
} else {
if ((s->gr[0x0B] & 0x14) == 0x14) {
goto generic_io;
} else if (s->gr[0x0B] & 0x02) {
goto generic_io;
}
mode = s->gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
} else {
generic_io:
s->cirrus_linear_write[0] = cirrus_linear_writeb;
s->cirrus_linear_write[1] = cirrus_linear_writew;
s->cirrus_linear_write[2] = cirrus_linear_writel;
}
}
}
/* I/O ports */
static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
@@ -2692,7 +2621,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
#endif
/* handle CR0-7 protection */
if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
/* can always write bit 4 of CR7 */
if (s->cr_index == 7)
s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
@@ -3004,8 +2933,6 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
s->cirrus_linear_io_addr =
cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write,
s);
s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);
/* I/O handler for LFB */
s->cirrus_linear_bitblt_io_addr =
cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write,

View File

@@ -47,11 +47,6 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
int x, y, pattern_y, pattern_pitch, pattern_x;
unsigned int col;
const uint8_t *src1;
#if DEPTH == 24
int skipleft = s->gr[0x2f] & 0x1f;
#else
int skipleft = (s->gr[0x2f] & 0x07) * (DEPTH / 8);
#endif
#if DEPTH == 8
pattern_pitch = 8;
@@ -61,11 +56,11 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
pattern_pitch = 32;
#endif
pattern_y = s->cirrus_blt_srcaddr & 7;
pattern_x = 0;
for(y = 0; y < bltheight; y++) {
pattern_x = skipleft;
d = dst + skipleft;
d = dst;
src1 = src + pattern_y * pattern_pitch;
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
#if DEPTH == 8
col = src1[pattern_x];
pattern_x = (pattern_x + 1) & 7;
@@ -104,13 +99,7 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
unsigned int col;
unsigned bitmask;
unsigned index;
#if DEPTH == 24
int dstskipleft = s->gr[0x2f] & 0x1f;
int srcskipleft = dstskipleft / 3;
#else
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
#endif
int srcskipleft = 0;
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
bits_xor = 0xff;
@@ -123,8 +112,8 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
for(y = 0; y < bltheight; y++) {
bitmask = 0x80 >> srcskipleft;
bits = *src++ ^ bits_xor;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
if ((bitmask & 0xff) == 0) {
bitmask = 0x80;
bits = *src++ ^ bits_xor;
@@ -153,16 +142,15 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
unsigned bits;
unsigned int col;
unsigned bitmask;
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
int srcskipleft = 0;
colors[0] = s->cirrus_blt_bgcol;
colors[1] = s->cirrus_blt_fgcol;
for(y = 0; y < bltheight; y++) {
bitmask = 0x80 >> srcskipleft;
bits = *src++;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
if ((bitmask & 0xff) == 0) {
bitmask = 0x80;
bits = *src++;
@@ -187,13 +175,6 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
int x, y, bitpos, pattern_y;
unsigned int bits, bits_xor;
unsigned int col;
#if DEPTH == 24
int dstskipleft = s->gr[0x2f] & 0x1f;
int srcskipleft = dstskipleft / 3;
#else
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
#endif
if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
bits_xor = 0xff;
@@ -206,9 +187,9 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
for(y = 0; y < bltheight; y++) {
bits = src[pattern_y] ^ bits_xor;
bitpos = 7 - srcskipleft;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
bitpos = 7;
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
if ((bits >> bitpos) & 1) {
PUTPIXEL();
}
@@ -232,8 +213,6 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
int x, y, bitpos, pattern_y;
unsigned int bits;
unsigned int col;
int srcskipleft = s->gr[0x2f] & 0x07;
int dstskipleft = srcskipleft * (DEPTH / 8);
colors[0] = s->cirrus_blt_bgcol;
colors[1] = s->cirrus_blt_fgcol;
@@ -241,9 +220,9 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
for(y = 0; y < bltheight; y++) {
bits = src[pattern_y];
bitpos = 7 - srcskipleft;
d = dst + dstskipleft;
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
bitpos = 7;
d = dst;
for (x = 0; x < bltwidth; x += (DEPTH / 8)) {
col = colors[(bits >> bitpos) & 1];
PUTPIXEL();
d += (DEPTH / 8);

109
hw/cuda.c
View File

@@ -23,8 +23,6 @@
*/
#include "vl.h"
/* XXX: implement all timer modes */
//#define DEBUG_CUDA
//#define DEBUG_CUDA_PACKET
@@ -43,7 +41,6 @@
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
#define T1_INT 0x40 /* Timer 1 interrupt */
#define T2_INT 0x20 /* Timer 2 interrupt */
/* Bits in ACR */
#define T1MODE 0xc0 /* Timer 1 mode */
@@ -90,12 +87,8 @@
#define CUDA_TIMER_FREQ (4700000 / 6)
#define CUDA_ADB_POLL_FREQ 50
/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
#define RTC_OFFSET 2082844800
typedef struct CUDATimer {
int index;
uint16_t latch;
unsigned int latch;
uint16_t counter_value; /* counter value at load time */
int64_t load_time;
int64_t next_irq_time;
@@ -124,9 +117,8 @@ typedef struct CUDAState {
int data_in_index;
int data_out_index;
SetIRQFunc *set_irq;
int irq;
void *irq_opaque;
openpic_t *openpic;
uint8_t autopoll;
uint8_t data_in[128];
uint8_t data_out[16];
@@ -145,9 +137,9 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
static void cuda_update_irq(CUDAState *s)
{
if (s->ifr & s->ier & (SR_INT | T1_INT)) {
s->set_irq(s->irq_opaque, s->irq, 1);
openpic_set_irq(s->openpic, s->irq, 1);
} else {
s->set_irq(s->irq_opaque, s->irq, 0);
openpic_set_irq(s->openpic, s->irq, 0);
}
}
@@ -158,16 +150,10 @@ static unsigned int get_counter(CUDATimer *s)
d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
if (s->index == 0) {
/* the timer goes down from latch to -1 (period of latch + 2) */
if (d <= (s->counter_value + 1)) {
counter = (s->counter_value - d) & 0xffff;
} else {
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
counter = (s->latch - counter) & 0xffff;
}
if (d <= s->counter_value) {
counter = d;
} else {
counter = (s->counter_value - d) & 0xffff;
counter = s->latch - 1 - ((d - s->counter_value) % s->latch);
}
return counter;
}
@@ -185,33 +171,20 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
{
int64_t d, next_time;
unsigned int counter;
int64_t d, next_time, base;
/* current counter value */
d = muldiv64(current_time - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
/* the timer goes down from latch to -1 (period of latch + 2) */
if (d <= (s->counter_value + 1)) {
counter = (s->counter_value - d) & 0xffff;
if (d <= s->counter_value) {
next_time = s->counter_value + 1;
} else {
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
counter = (s->latch - counter) & 0xffff;
base = ((d - s->counter_value) / s->latch);
base = (base * s->latch) + s->counter_value;
next_time = base + s->latch;
}
/* Note: we consider the irq is raised on 0 */
if (counter == 0xffff) {
next_time = d + s->latch + 1;
} else if (counter == 0) {
next_time = d + s->latch + 2;
} else {
next_time = d + counter;
}
#if 0
#ifdef DEBUG_CUDA
printf("latch=%d counter=%lld delta_next=%lld\n",
s->latch, d, next_time - d);
#endif
#endif
next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
s->load_time;
@@ -269,18 +242,17 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
break;
case 5:
val = get_counter(&s->timers[0]) >> 8;
s->ifr &= ~T1_INT;
cuda_update_irq(s);
break;
case 6:
val = s->timers[0].latch & 0xff;
break;
case 7:
/* XXX: check this */
val = (s->timers[0].latch >> 8) & 0xff;
break;
case 8:
val = get_counter(&s->timers[1]) & 0xff;
s->ifr &= ~T2_INT;
break;
case 9:
val = get_counter(&s->timers[1]) >> 8;
@@ -298,11 +270,9 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
break;
case 13:
val = s->ifr;
if (s->ifr & s->ier)
val |= 0x80;
break;
case 14:
val = s->ier | 0x80;
val = s->ier;
break;
default:
case 15:
@@ -340,13 +310,12 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
s->dira = val;
break;
case 4:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
val = val | (get_counter(&s->timers[0]) & 0xff00);
set_counter(s, &s->timers[0], val);
break;
case 5:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
s->ifr &= ~T1_INT;
set_counter(s, &s->timers[0], s->timers[0].latch);
val = (val << 8) | (get_counter(&s->timers[0]) & 0xff);
set_counter(s, &s->timers[0], val);
break;
case 6:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
@@ -354,15 +323,15 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case 7:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
s->ifr &= ~T1_INT;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 8:
s->timers[1].latch = val;
val = val | (get_counter(&s->timers[1]) & 0xff00);
set_counter(s, &s->timers[1], val);
break;
case 9:
set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
val = (val << 8) | (get_counter(&s->timers[1]) & 0xff);
set_counter(s, &s->timers[1], val);
break;
case 10:
s->sr = val;
@@ -533,9 +502,8 @@ static void cuda_receive_packet(CUDAState *s,
cuda_send_packet_to_host(s, obuf, 2);
break;
case CUDA_GET_TIME:
case CUDA_SET_TIME:
/* XXX: add time support ? */
ti = time(NULL) + RTC_OFFSET;
ti = time(NULL);
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
obuf[2] = 0;
@@ -545,6 +513,7 @@ static void cuda_receive_packet(CUDAState *s,
obuf[6] = ti;
cuda_send_packet_to_host(s, obuf, 7);
break;
case CUDA_SET_TIME:
case CUDA_FILE_SERVER_FLAG:
case CUDA_SET_DEVICE_LIST:
case CUDA_SET_AUTO_RATE:
@@ -553,12 +522,6 @@ static void cuda_receive_packet(CUDAState *s,
obuf[1] = 0;
cuda_send_packet_to_host(s, obuf, 2);
break;
case CUDA_POWERDOWN:
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
cuda_send_packet_to_host(s, obuf, 2);
qemu_system_shutdown_request();
break;
default:
break;
}
@@ -570,7 +533,7 @@ static void cuda_receive_packet_from_host(CUDAState *s,
#ifdef DEBUG_CUDA_PACKET
{
int i;
printf("cuda_receive_packet_from_host:\n");
printf("cuda_receive_packet_to_host:\n");
for(i = 0; i < len; i++)
printf(" %02x", data[i]);
printf("\n");
@@ -582,14 +545,13 @@ static void cuda_receive_packet_from_host(CUDAState *s,
uint8_t obuf[ADB_MAX_OUT_LEN + 2];
int olen;
olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
if (olen > 0) {
if (olen != 0) {
obuf[0] = ADB_PACKET;
obuf[1] = 0x00;
} else {
/* error */
/* empty reply */
obuf[0] = ADB_PACKET;
obuf[1] = -olen;
olen = 0;
obuf[1] = 0x02;
}
cuda_send_packet_to_host(s, obuf, olen + 2);
}
@@ -630,24 +592,19 @@ static CPUReadMemoryFunc *cuda_read[] = {
&cuda_readl,
};
int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
int cuda_init(openpic_t *openpic, int irq)
{
CUDAState *s = &cuda_state;
int cuda_mem_index;
s->set_irq = set_irq;
s->irq_opaque = irq_opaque;
s->openpic = openpic;
s->irq = irq;
s->timers[0].index = 0;
s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
s->timers[0].latch = 0xffff;
s->timers[0].latch = 0x10000;
set_counter(s, &s->timers[0], 0xffff);
s->timers[1].index = 1;
s->timers[1].latch = 0;
// s->ier = T1_INT | SR_INT;
s->ier = 0;
s->timers[1].latch = 0x10000;
s->ier = T1_INT | SR_INT;
set_counter(s, &s->timers[1], 0xffff);
s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);

249
hw/dma.c
View File

@@ -1,8 +1,8 @@
/*
* QEMU DMA emulation
*
* Copyright (c) 2003-2004 Vassili Karpov (malc)
*
*
* Copyright (c) 2003 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -23,9 +23,9 @@
*/
#include "vl.h"
/* #define DEBUG_DMA */
//#define DEBUG_DMA
#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
#ifdef DEBUG_DMA
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
@@ -63,17 +63,17 @@ static struct dma_cont {
} dma_controllers[2];
enum {
CMD_MEMORY_TO_MEMORY = 0x01,
CMD_FIXED_ADDRESS = 0x02,
CMD_BLOCK_CONTROLLER = 0x04,
CMD_COMPRESSED_TIME = 0x08,
CMD_CYCLIC_PRIORITY = 0x10,
CMD_EXTENDED_WRITE = 0x20,
CMD_LOW_DREQ = 0x40,
CMD_LOW_DACK = 0x80,
CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
| CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
| CMD_LOW_DREQ | CMD_LOW_DACK
CMD_MEMORY_TO_MEMORY = 0x01,
CMD_FIXED_ADDRESS = 0x02,
CMD_BLOCK_CONTROLLER = 0x04,
CMD_COMPRESSED_TIME = 0x08,
CMD_CYCLIC_PRIORITY = 0x10,
CMD_EXTENDED_WRITE = 0x20,
CMD_LOW_DREQ = 0x40,
CMD_LOW_DACK = 0x80,
CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
| CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
| CMD_LOW_DREQ | CMD_LOW_DACK
};
@@ -86,7 +86,7 @@ static void write_page (void *opaque, uint32_t nport, uint32_t data)
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel %#x %#x\n", nport, data);
log ("invalid channel %#x %#x\n", nport, data);
return;
}
d->regs[ichan].page = data;
@@ -99,7 +99,7 @@ static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel %#x %#x\n", nport, data);
log ("invalid channel %#x %#x\n", nport, data);
return;
}
d->regs[ichan].pageh = data;
@@ -112,7 +112,7 @@ static uint32_t read_page (void *opaque, uint32_t nport)
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel read %#x\n", nport);
log ("invalid channel read %#x\n", nport);
return 0;
}
return d->regs[ichan].page;
@@ -125,7 +125,7 @@ static uint32_t read_pageh (void *opaque, uint32_t nport)
ichan = channels[nport & 7];
if (-1 == ichan) {
dolog ("invalid channel read %#x\n", nport);
log ("invalid channel read %#x\n", nport);
return 0;
}
return d->regs[ichan].pageh;
@@ -136,7 +136,7 @@ static inline void init_chan (struct dma_cont *d, int ichan)
struct dma_regs *r;
r = d->regs + ichan;
r->now[ADDR] = r->base[ADDR] << d->dshift;
r->now[ADDR] = r->base[0] << d->dshift;
r->now[COUNT] = 0;
}
@@ -152,7 +152,7 @@ static inline int getff (struct dma_cont *d)
static uint32_t read_chan (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int ichan, nreg, iport, ff, val, dir;
int ichan, nreg, iport, ff, val;
struct dma_regs *r;
iport = (nport >> d->dshift) & 0x0f;
@@ -160,14 +160,12 @@ static uint32_t read_chan (void *opaque, uint32_t nport)
nreg = iport & 1;
r = d->regs + ichan;
dir = ((r->mode >> 5) & 1) ? -1 : 1;
ff = getff (d);
if (nreg)
val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
else
val = r->now[ADDR] + r->now[COUNT] * dir;
val = r->now[ADDR] + r->now[COUNT];
ldebug ("read_chan %#x -> %d\n", iport, val);
return (val >> (d->dshift + (ff << 3))) & 0xff;
}
@@ -192,19 +190,19 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data)
static void write_cont (void *opaque, uint32_t nport, uint32_t data)
{
struct dma_cont *d = opaque;
int iport, ichan = 0;
int iport, ichan;
iport = (nport >> d->dshift) & 0x0f;
switch (iport) {
case 0x08: /* command */
case 8: /* command */
if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
dolog ("command %#x not supported\n", data);
log ("command %#x not supported\n", data);
return;
}
d->command = data;
break;
case 0x09:
case 9:
ichan = data & 3;
if (data & 4) {
d->status |= 1 << (ichan + 4);
@@ -215,59 +213,62 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data)
d->status &= ~(1 << ichan);
break;
case 0x0a: /* single mask */
case 0xa: /* single mask */
if (data & 4)
d->mask |= 1 << (data & 3);
else
d->mask &= ~(1 << (data & 3));
break;
case 0x0b: /* mode */
case 0xb: /* mode */
{
ichan = data & 3;
#ifdef DEBUG_DMA
{
int op, ai, dir, opmode;
op = (data >> 2) & 3;
ai = (data >> 4) & 1;
dir = (data >> 5) & 1;
opmode = (data >> 6) & 3;
int op;
int ai;
int dir;
int opmode;
linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
ichan, op, ai, dir, opmode);
}
op = (data >> 2) & 3;
ai = (data >> 4) & 1;
dir = (data >> 5) & 1;
opmode = (data >> 6) & 3;
linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
ichan, op, ai, dir, opmode);
#endif
d->regs[ichan].mode = data;
break;
}
case 0x0c: /* clear flip flop */
case 0xc: /* clear flip flop */
d->flip_flop = 0;
break;
case 0x0d: /* reset */
case 0xd: /* reset */
d->flip_flop = 0;
d->mask = ~0;
d->status = 0;
d->command = 0;
break;
case 0x0e: /* clear mask for all channels */
case 0xe: /* clear mask for all channels */
d->mask = 0;
break;
case 0x0f: /* write mask for all channels */
case 0xf: /* write mask for all channels */
d->mask = data;
break;
default:
dolog ("unknown iport %#x\n", iport);
log ("dma: unknown iport %#x\n", iport);
break;
}
#ifdef DEBUG_DMA
if (0xc != iport) {
linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
linfo ("nport %#06x, ichan % 2d, val %#06x\n",
nport, ichan, data);
}
#endif
@@ -277,22 +278,20 @@ static uint32_t read_cont (void *opaque, uint32_t nport)
{
struct dma_cont *d = opaque;
int iport, val;
iport = (nport >> d->dshift) & 0x0f;
switch (iport) {
case 0x08: /* status */
case 0x08: /* status */
val = d->status;
d->status &= 0xf0;
break;
case 0x0f: /* mask */
case 0x0f: /* mask */
val = d->mask;
break;
default:
val = 0;
break;
}
ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
return val;
}
@@ -323,27 +322,23 @@ void DMA_release_DREQ (int nchan)
static void channel_run (int ncont, int ichan)
{
struct dma_regs *r;
int n;
struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
#ifdef DEBUG_DMA
int dir, opmode;
dir = (r->mode >> 5) & 1;
opmode = (r->mode >> 6) & 3;
if (dir) {
dolog ("DMA in address decrement mode\n");
}
if (opmode != 1) {
dolog ("DMA not in single mode select %#x\n", opmode);
}
#endif
target_ulong addr;
/* int ai, dir; */
r = dma_controllers[ncont].regs + ichan;
n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
r->now[COUNT], (r->base[COUNT] + 1) << ncont);
/* ai = r->mode & 16; */
/* dir = r->mode & 32 ? -1 : 1; */
/* NOTE: pageh is only used by PPC PREP */
addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
n = r->transfer_handler (r->opaque, addr,
(r->base[COUNT] << ncont) + (1 << ncont));
r->now[COUNT] = n;
ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
ldebug ("dma_pos %d size %d\n",
n, (r->base[1] << ncont) + (1 << ncont));
}
void DMA_run (void)
@@ -366,7 +361,7 @@ void DMA_run (void)
}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
DMA_transfer_handler transfer_handler,
void *opaque)
{
struct dma_regs *r;
@@ -380,50 +375,6 @@ void DMA_register_channel (int nchan,
r->opaque = opaque;
}
int DMA_read_memory (int nchan, void *buf, int pos, int len)
{
struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
if (r->mode & 0x20) {
int i;
uint8_t *p = buf;
cpu_physical_memory_read (addr - pos - len, buf, len);
/* What about 16bit transfers? */
for (i = 0; i < len >> 1; i++) {
uint8_t b = p[len - i - 1];
p[i] = b;
}
}
else
cpu_physical_memory_read (addr + pos, buf, len);
return len;
}
int DMA_write_memory (int nchan, void *buf, int pos, int len)
{
struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
if (r->mode & 0x20) {
int i;
uint8_t *p = buf;
cpu_physical_memory_write (addr - pos - len, buf, len);
/* What about 16bit transfers? */
for (i = 0; i < len; i++) {
uint8_t b = p[len - i - 1];
p[i] = b;
}
}
else
cpu_physical_memory_write (addr + pos, buf, len);
return len;
}
/* request the emulator to transfer a new DMA memory block ASAP */
void DMA_schedule(int nchan)
{
@@ -437,7 +388,7 @@ static void dma_reset(void *opaque)
}
/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
static void dma_init2(struct dma_cont *d, int base, int dshift,
static void dma_init2(struct dma_cont *d, int base, int dshift,
int page_base, int pageh_base)
{
const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
@@ -449,87 +400,31 @@ static void dma_init2(struct dma_cont *d, int base, int dshift,
register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
}
for (i = 0; i < LENOFA (page_port_list); i++) {
register_ioport_write (page_base + page_port_list[i], 1, 1,
register_ioport_write (page_base + page_port_list[i], 1, 1,
write_page, d);
register_ioport_read (page_base + page_port_list[i], 1, 1,
register_ioport_read (page_base + page_port_list[i], 1, 1,
read_page, d);
if (pageh_base >= 0) {
register_ioport_write (pageh_base + page_port_list[i], 1, 1,
register_ioport_write (pageh_base + page_port_list[i], 1, 1,
write_pageh, d);
register_ioport_read (pageh_base + page_port_list[i], 1, 1,
register_ioport_read (pageh_base + page_port_list[i], 1, 1,
read_pageh, d);
}
}
for (i = 0; i < 8; i++) {
register_ioport_write (base + ((i + 8) << dshift), 1, 1,
register_ioport_write (base + ((i + 8) << dshift), 1, 1,
write_cont, d);
register_ioport_read (base + ((i + 8) << dshift), 1, 1,
register_ioport_read (base + ((i + 8) << dshift), 1, 1,
read_cont, d);
}
qemu_register_reset(dma_reset, d);
dma_reset(d);
}
static void dma_save (QEMUFile *f, void *opaque)
{
struct dma_cont *d = opaque;
int i;
/* qemu_put_8s (f, &d->status); */
qemu_put_8s (f, &d->command);
qemu_put_8s (f, &d->mask);
qemu_put_8s (f, &d->flip_flop);
qemu_put_be32s (f, &d->dshift);
for (i = 0; i < 4; ++i) {
struct dma_regs *r = &d->regs[i];
qemu_put_be32s (f, &r->now[0]);
qemu_put_be32s (f, &r->now[1]);
qemu_put_be16s (f, &r->base[0]);
qemu_put_be16s (f, &r->base[1]);
qemu_put_8s (f, &r->mode);
qemu_put_8s (f, &r->page);
qemu_put_8s (f, &r->pageh);
qemu_put_8s (f, &r->dack);
qemu_put_8s (f, &r->eop);
}
}
static int dma_load (QEMUFile *f, void *opaque, int version_id)
{
struct dma_cont *d = opaque;
int i;
if (version_id != 1)
return -EINVAL;
/* qemu_get_8s (f, &d->status); */
qemu_get_8s (f, &d->command);
qemu_get_8s (f, &d->mask);
qemu_get_8s (f, &d->flip_flop);
qemu_get_be32s (f, &d->dshift);
for (i = 0; i < 4; ++i) {
struct dma_regs *r = &d->regs[i];
qemu_get_be32s (f, &r->now[0]);
qemu_get_be32s (f, &r->now[1]);
qemu_get_be16s (f, &r->base[0]);
qemu_get_be16s (f, &r->base[1]);
qemu_get_8s (f, &r->mode);
qemu_get_8s (f, &r->page);
qemu_get_8s (f, &r->pageh);
qemu_get_8s (f, &r->dack);
qemu_get_8s (f, &r->eop);
}
return 0;
}
void DMA_init (int high_page_enable)
{
dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
high_page_enable ? 0x480 : -1);
dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
high_page_enable ? 0x488 : -1);
register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
}

View File

@@ -1,218 +0,0 @@
#ifdef BSWAP_NEEDED
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
bswap16s(&ehdr->e_machine); /* Architecture */
bswap32s(&ehdr->e_version); /* Object file version */
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
{
bswap32s(&phdr->p_type); /* Segment type */
bswapSZs(&phdr->p_offset); /* Segment file offset */
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
bswapSZs(&phdr->p_paddr); /* Segment physical address */
bswapSZs(&phdr->p_filesz); /* Segment size in file */
bswapSZs(&phdr->p_memsz); /* Segment size in memory */
bswap32s(&phdr->p_flags); /* Segment flags */
bswapSZs(&phdr->p_align); /* Segment alignment */
}
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
{
bswap32s(&shdr->sh_name);
bswap32s(&shdr->sh_type);
bswapSZs(&shdr->sh_flags);
bswapSZs(&shdr->sh_addr);
bswapSZs(&shdr->sh_offset);
bswapSZs(&shdr->sh_size);
bswap32s(&shdr->sh_link);
bswap32s(&shdr->sh_info);
bswapSZs(&shdr->sh_addralign);
bswapSZs(&shdr->sh_entsize);
}
static void glue(bswap_sym, SZ)(struct elf_sym *sym)
{
bswap32s(&sym->st_name);
bswapSZs(&sym->st_value);
bswapSZs(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#endif
static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type)
{
int i, retval;
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
if (retval < 0)
return -1;
for (i = 0; i < ehdr->e_phnum; i++) {
retval = read(fd, phdr, sizeof(*phdr));
if (retval < 0)
return -1;
glue(bswap_phdr, SZ)(phdr);
if (phdr->p_type == type)
return 0;
}
return -1;
}
static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
{
int i, retval;
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
if (retval < 0)
return NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
glue(bswap_shdr, SZ)(shdr);
if (shdr->sh_type == type)
return qemu_malloc(shdr->sh_size);
}
return NULL;
}
static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
if (retval < 0)
return NULL;
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
glue(bswap_shdr, SZ)(shdr);
if (shdr->sh_type == SHT_STRTAB)
return qemu_malloc(shdr->sh_size);;
return NULL;
}
static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry)
{
int retval;
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
if (retval < 0)
return -1;
return read(fd, dst, phdr->p_filesz);
}
static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst)
{
int retval;
retval = lseek(fd, s->sh_offset, SEEK_SET);
if (retval < 0)
return -1;
retval = read(fd, dst, s->sh_size);
if (retval < 0)
return -1;
return 0;
}
static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
{
void *dst;
dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type);
if (!dst)
goto error;
if (glue(read_section, SZ)(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
void *dst;
dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab);
if (!dst)
goto error;
if (glue(read_section, SZ)(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd)
{
struct elf_shdr symtab, strtab;
struct elf_sym *syms;
#if (SZ == 64)
struct elf32_sym *syms32;
#endif
struct syminfo *s;
int nsyms, i;
char *str;
/* Symbol table */
syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB);
if (!syms)
return;
nsyms = symtab.sh_size / sizeof(struct elf_sym);
#if (SZ == 64)
syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));
#endif
for (i = 0; i < nsyms; i++) {
glue(bswap_sym, SZ)(&syms[i]);
#if (SZ == 64)
syms32[i].st_name = syms[i].st_name;
syms32[i].st_info = syms[i].st_info;
syms32[i].st_other = syms[i].st_other;
syms32[i].st_shndx = syms[i].st_shndx;
syms32[i].st_value = syms[i].st_value & 0xffffffff;
syms32[i].st_size = syms[i].st_size & 0xffffffff;
#endif
}
/* String table */
str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab);
if (!str)
goto error_freesyms;
/* Commit */
s = qemu_mallocz(sizeof(*s));
#if (SZ == 64)
s->disas_symtab = syms32;
qemu_free(syms);
#else
s->disas_symtab = syms;
#endif
s->disas_num_syms = nsyms;
s->disas_strtab = str;
s->next = syminfos;
syminfos = s;
return;
error_freesyms:
#if (SZ == 64)
qemu_free(syms32);
#endif
qemu_free(syms);
return;
}

398
hw/esp.c
View File

@@ -1,398 +0,0 @@
/*
* QEMU ESP emulation
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug ESP card */
//#define DEBUG_ESP
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f
typedef struct ESPState {
BlockDriverState **bd;
uint8_t rregs[ESP_MAXREG];
uint8_t wregs[ESP_MAXREG];
int irq;
uint32_t espdmaregs[ESPDMA_REGS];
uint32_t ti_size;
int ti_dir;
uint8_t ti_buf[65536];
} ESPState;
#define STAT_DO 0x00
#define STAT_DI 0x01
#define STAT_CD 0x02
#define STAT_ST 0x03
#define STAT_MI 0x06
#define STAT_MO 0x07
#define STAT_TC 0x10
#define STAT_IN 0x80
#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
#define SEQ_0 0x0
#define SEQ_CD 0x4
static void handle_satn(ESPState *s)
{
uint8_t buf[32];
uint32_t dmaptr, dmalen;
unsigned int i;
int64_t nb_sectors;
int target;
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
cpu_physical_memory_read(dmaptr, buf, dmalen);
for (i = 0; i < dmalen; i++) {
DPRINTF("Command %2.2x\n", buf[i]);
}
s->ti_dir = 0;
s->ti_size = 0;
target = s->wregs[4] & 7;
if (target > 4 || !s->bd[target]) { // No such drive
s->rregs[4] = STAT_IN;
s->rregs[5] = INTR_DC;
s->rregs[6] = SEQ_0;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
return;
}
switch (buf[1]) {
case 0x0:
DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
break;
case 0x12:
DPRINTF("Inquiry (len %d)\n", buf[5]);
memset(s->ti_buf, 0, 36);
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
s->ti_buf[0] = 5;
memcpy(&s->ti_buf[16], "QEMU CDROM ", 16);
} else {
s->ti_buf[0] = 0;
memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16);
}
memcpy(&s->ti_buf[8], "QEMU ", 8);
s->ti_buf[2] = 1;
s->ti_buf[3] = 2;
s->ti_dir = 1;
s->ti_size = 36;
break;
case 0x1a:
DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
break;
case 0x25:
DPRINTF("Read Capacity (len %d)\n", buf[5]);
memset(s->ti_buf, 0, 8);
bdrv_get_geometry(s->bd[target], &nb_sectors);
s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
s->ti_buf[3] = nb_sectors & 0xff;
s->ti_buf[4] = 0;
s->ti_buf[5] = 0;
s->ti_buf[6] = 2;
s->ti_buf[7] = 0;
s->ti_dir = 1;
s->ti_size = 8;
break;
case 0x28:
{
int64_t offset, len;
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
len = (buf[8] << 8) | buf[9];
DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
bdrv_read(s->bd[target], offset, s->ti_buf, len);
s->ti_dir = 1;
s->ti_size = len * 512;
break;
}
case 0x2a:
{
int64_t offset, len;
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
len = (buf[8] << 8) | buf[9];
DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
bdrv_write(s->bd[target], offset, s->ti_buf, len);
s->ti_dir = 0;
s->ti_size = len * 512;
break;
}
default:
DPRINTF("Unknown command (%2.2x)\n", buf[1]);
break;
}
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
}
static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
{
uint32_t dmaptr, dmalen;
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
cpu_physical_memory_write(dmaptr, buf, len);
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
}
static const uint8_t okbuf[] = {0, 0};
static void handle_ti(ESPState *s)
{
uint32_t dmaptr, dmalen;
unsigned int i;
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
for (i = 0; i < s->ti_size; i++) {
dmaptr = iommu_translate(s->espdmaregs[1] + i);
if (s->ti_dir)
cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
else
cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
}
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS;
s->rregs[6] = 0;
s->espdmaregs[0] |= 1;
pic_set_irq(s->irq, 1);
}
static void esp_reset(void *opaque)
{
ESPState *s = opaque;
memset(s->rregs, 0, ESP_MAXREG);
s->rregs[0x0e] = 0x4; // Indicate fas100a
memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESP_MAXREG) >> 2;
switch (saddr) {
default:
break;
}
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
return s->rregs[saddr];
}
static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESP_MAXREG) >> 2;
DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
switch (saddr) {
case 3:
// Command
switch(val & 0x7f) {
case 0:
DPRINTF("NOP (%2.2x)\n", val);
break;
case 1:
DPRINTF("Flush FIFO (%2.2x)\n", val);
s->rregs[6] = 0;
s->rregs[5] = INTR_FC;
break;
case 2:
DPRINTF("Chip reset (%2.2x)\n", val);
esp_reset(s);
break;
case 3:
DPRINTF("Bus reset (%2.2x)\n", val);
break;
case 0x10:
handle_ti(s);
break;
case 0x11:
DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
dma_write(s, okbuf, 2);
break;
case 0x12:
DPRINTF("Message Accepted (%2.2x)\n", val);
dma_write(s, okbuf, 2);
s->rregs[5] = INTR_DC;
s->rregs[6] = 0;
break;
case 0x1a:
DPRINTF("Set ATN (%2.2x)\n", val);
break;
case 0x42:
handle_satn(s);
break;
case 0x43:
DPRINTF("Set ATN & stop (%2.2x)\n", val);
handle_satn(s);
break;
default:
DPRINTF("Unhandled command (%2.2x)\n", val);
break;
}
break;
case 4 ... 7:
case 9 ... 0xf:
break;
default:
break;
}
s->wregs[saddr] = val;
}
static CPUReadMemoryFunc *esp_mem_read[3] = {
esp_mem_readb,
esp_mem_readb,
esp_mem_readb,
};
static CPUWriteMemoryFunc *esp_mem_write[3] = {
esp_mem_writeb,
esp_mem_writeb,
esp_mem_writeb,
};
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]);
return s->espdmaregs[saddr];
}
static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val);
switch (saddr) {
case 0:
if (!(val & 0x10))
pic_set_irq(s->irq, 0);
break;
default:
break;
}
s->espdmaregs[saddr] = val;
}
static CPUReadMemoryFunc *espdma_mem_read[3] = {
espdma_mem_readl,
espdma_mem_readl,
espdma_mem_readl,
};
static CPUWriteMemoryFunc *espdma_mem_write[3] = {
espdma_mem_writel,
espdma_mem_writel,
espdma_mem_writel,
};
static void esp_save(QEMUFile *f, void *opaque)
{
ESPState *s = opaque;
unsigned int i;
qemu_put_buffer(f, s->rregs, ESP_MAXREG);
qemu_put_buffer(f, s->wregs, ESP_MAXREG);
qemu_put_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_put_be32s(f, &s->espdmaregs[i]);
}
static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
ESPState *s = opaque;
unsigned int i;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->rregs, ESP_MAXREG);
qemu_get_buffer(f, s->wregs, ESP_MAXREG);
qemu_get_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_get_be32s(f, &s->espdmaregs[i]);
return 0;
}
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
{
ESPState *s;
int esp_io_memory, espdma_io_memory;
s = qemu_mallocz(sizeof(ESPState));
if (!s)
return;
s->bd = bd;
s->irq = irq;
esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
esp_reset(s);
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
}

184
hw/fdc.c
View File

@@ -1,5 +1,5 @@
/*
* QEMU Floppy disk emulator (Intel 82078)
* QEMU Floppy disk emulator
*
* Copyright (c) 2003 Jocelyn Mayer
*
@@ -21,10 +21,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* The controller is used in Sun4m systems in a slightly different
* way. There are changes in DOR register and DMA is not available.
*/
#include "vl.h"
/********************************************************/
@@ -313,12 +309,11 @@ static void fd_reset (fdrive_t *drv)
}
/********************************************************/
/* Intel 82078 floppy disk controller emulation */
/* Intel 82078 floppy disk controler emulation */
static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
static int fdctrl_transfer_handler (void *opaque, int nchan,
int dma_pos, int dma_len);
static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size);
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
static void fdctrl_result_timer(void *opaque);
@@ -368,13 +363,13 @@ do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
struct fdctrl_t {
fdctrl_t *fdctrl;
/* Controller's identification */
/* Controler's identification */
uint8_t version;
/* HW */
int irq_lvl;
int dma_chann;
uint32_t io_base;
/* Controller state */
/* Controler state */
QEMUTimer *result_timer;
uint8_t state;
uint8_t dma_en;
@@ -387,7 +382,6 @@ struct fdctrl_t {
uint8_t data_state;
uint8_t data_dir;
uint8_t int_status;
uint8_t eot; /* last wanted sector */
/* States kept only to be returned back */
/* Timers state */
uint8_t timer0;
@@ -408,12 +402,6 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg)
uint32_t retval;
switch (reg & 0x07) {
#ifdef TARGET_SPARC
case 0x00:
// Identify to Linux as S82078B
retval = fdctrl_read_statusB(fdctrl);
break;
#endif
case 0x01:
retval = fdctrl_read_statusB(fdctrl);
break;
@@ -465,29 +453,6 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
}
}
static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
{
return fdctrl_read(opaque, reg);
}
static void fdctrl_write_mem (void *opaque,
target_phys_addr_t reg, uint32_t value)
{
fdctrl_write(opaque, reg, value);
}
static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
fdctrl_read_mem,
fdctrl_read_mem,
fdctrl_read_mem,
};
static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
fdctrl_write_mem,
fdctrl_write_mem,
fdctrl_write_mem,
};
static void fd_change_cb (void *opaque)
{
fdrive_t *drv = opaque;
@@ -506,17 +471,17 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
BlockDriverState **fds)
{
fdctrl_t *fdctrl;
int io_mem;
// int io_mem;
int i;
FLOPPY_DPRINTF("init controller\n");
FLOPPY_DPRINTF("init controler\n");
fdctrl = qemu_mallocz(sizeof(fdctrl_t));
if (!fdctrl)
return NULL;
fdctrl->result_timer = qemu_new_timer(vm_clock,
fdctrl_result_timer, fdctrl);
fdctrl->version = 0x90; /* Intel 82078 controller */
fdctrl->version = 0x90; /* Intel 82078 controler */
fdctrl->irq_lvl = irq_lvl;
fdctrl->dma_chann = dma_chann;
fdctrl->io_base = io_base;
@@ -537,8 +502,11 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
fdctrl_reset(fdctrl, 0);
fdctrl->state = FD_CTRL_ACTIVE;
if (mem_mapped) {
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
cpu_register_physical_memory(io_base, 0x08, io_mem);
FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
#if 0
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
cpu_register_physical_memory(base, 0x08, io_mem);
#endif
} else {
register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
@@ -568,14 +536,6 @@ static void fdctrl_reset_irq (fdctrl_t *fdctrl)
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
{
#ifdef TARGET_SPARC
// Sparc mutation
if (!fdctrl->dma_en) {
fdctrl->state &= ~FD_CTRL_BUSY;
fdctrl->int_status = status;
return;
}
#endif
if (~(fdctrl->state & FD_CTRL_INTR)) {
pic_set_irq(fdctrl->irq_lvl, 1);
fdctrl->state |= FD_CTRL_INTR;
@@ -584,14 +544,14 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
fdctrl->int_status = status;
}
/* Reset controller */
/* Reset controler */
static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
{
int i;
FLOPPY_DPRINTF("reset controller\n");
FLOPPY_DPRINTF("reset controler\n");
fdctrl_reset_irq(fdctrl);
/* Initialise controller */
/* Initialise controler */
fdctrl->cur_drv = 0;
/* FIFO state */
fdctrl->data_pos = 0;
@@ -653,7 +613,7 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
/* Reset mode */
if (fdctrl->state & FD_CTRL_RESET) {
if (!(value & 0x04)) {
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
return;
}
}
@@ -675,12 +635,12 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
/* Reset */
if (!(value & 0x04)) {
if (!(fdctrl->state & FD_CTRL_RESET)) {
FLOPPY_DPRINTF("controller enter RESET state\n");
FLOPPY_DPRINTF("controler enter RESET state\n");
fdctrl->state |= FD_CTRL_RESET;
}
} else {
if (fdctrl->state & FD_CTRL_RESET) {
FLOPPY_DPRINTF("controller out of RESET state\n");
FLOPPY_DPRINTF("controler out of RESET state\n");
fdctrl_reset(fdctrl, 1);
fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
}
@@ -706,7 +666,7 @@ static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
{
/* Reset mode */
if (fdctrl->state & FD_CTRL_RESET) {
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
return;
}
FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
@@ -743,7 +703,7 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
{
/* Reset mode */
if (fdctrl->state & FD_CTRL_RESET) {
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
return;
}
FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
@@ -802,7 +762,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl)
fdrive_t *cur_drv;
cur_drv = get_cur_drv(fdctrl);
fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
fdctrl->fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl->cur_drv;
fdctrl->fifo[1] = 0x00;
fdctrl->fifo[2] = 0x00;
fdctrl_set_fifo(fdctrl, 3, 1);
@@ -822,8 +782,8 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
cur_drv = get_cur_drv(fdctrl);
FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
status0, status1, status2,
status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
status0 | (cur_drv->head << 1) | fdctrl->cur_drv);
fdctrl->fifo[0] = status0 | (cur_drv->head << 1) | fdctrl->cur_drv;
fdctrl->fifo[1] = status1;
fdctrl->fifo[2] = status2;
fdctrl->fifo[3] = cur_drv->track;
@@ -850,7 +810,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
kt = fdctrl->fifo[2];
kh = fdctrl->fifo[3];
ks = fdctrl->fifo[4];
FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n",
fdctrl->cur_drv, kh, kt, ks,
_fd_sector(kh, kt, ks, cur_drv->last_sect));
did_seek = 0;
@@ -904,7 +864,6 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
tmp += cur_drv->last_sect;
fdctrl->data_len *= tmp;
}
fdctrl->eot = fdctrl->fifo[6];
if (fdctrl->dma_en) {
int dma_mode;
/* DMA transfer are enabled. Check if DMA channel is well programmed */
@@ -920,7 +879,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
(direction == FD_DIR_READ && dma_mode == 1)) {
/* No access is allowed until DMA transfer has completed */
fdctrl->state |= FD_CTRL_BUSY;
/* Now, we just have to wait for the DMA controller to
/* Now, we just have to wait for the DMA controler to
* recall us...
*/
DMA_hold_DREQ(fdctrl->dma_chann);
@@ -947,8 +906,7 @@ static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
}
/* handlers for DMA transfers */
static int fdctrl_transfer_handler (void *opaque, int nchan,
int dma_pos, int dma_len)
static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size)
{
fdctrl_t *fdctrl;
fdrive_t *cur_drv;
@@ -964,26 +922,26 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
fdctrl->data_dir == FD_DIR_SCANH)
status2 = 0x04;
if (dma_len > fdctrl->data_len)
dma_len = fdctrl->data_len;
if (cur_drv->bs == NULL) {
if (size > fdctrl->data_len)
size = fdctrl->data_len;
if (cur_drv->bs == NULL) {
if (fdctrl->data_dir == FD_DIR_WRITE)
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
else
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
len = 0;
goto transfer_error;
}
goto transfer_error;
}
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
len = dma_len - fdctrl->data_pos;
for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) {
len = size - fdctrl->data_pos;
if (len + rel_pos > FD_SECTOR_LEN)
len = FD_SECTOR_LEN - rel_pos;
FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
"(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
"(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos,
fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
fd_sector(cur_drv) * 512);
fd_sector(cur_drv) * 512, addr);
if (fdctrl->data_dir != FD_DIR_WRITE ||
len < FD_SECTOR_LEN || rel_pos != 0) {
/* READ & SCAN commands and realign to a sector for WRITE */
@@ -994,36 +952,31 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
/* Sure, image size is too small... */
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
}
}
}
switch (fdctrl->data_dir) {
case FD_DIR_READ:
/* READ commands */
DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
fdctrl->data_pos, len);
/* cpu_physical_memory_write(addr + fdctrl->data_pos, */
/* fdctrl->fifo + rel_pos, len); */
cpu_physical_memory_write(addr + fdctrl->data_pos,
fdctrl->fifo + rel_pos, len);
break;
case FD_DIR_WRITE:
/* WRITE commands */
DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
fdctrl->data_pos, len);
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
/* fdctrl->fifo + rel_pos, len); */
cpu_physical_memory_read(addr + fdctrl->data_pos,
fdctrl->fifo + rel_pos, len);
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
fdctrl->fifo, 1) < 0) {
FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
goto transfer_error;
}
}
break;
default:
/* SCAN commands */
{
uint8_t tmpbuf[FD_SECTOR_LEN];
int ret;
DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
/* tmpbuf, len); */
cpu_physical_memory_read(addr + fdctrl->data_pos,
tmpbuf, len);
ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
if (ret == 0) {
status2 = 0x08;
@@ -1041,34 +994,30 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
if (rel_pos == 0) {
/* Seek to next sector */
cur_drv->sect++;
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
cur_drv->head, cur_drv->track, cur_drv->sect,
fd_sector(cur_drv),
fdctrl->data_pos - len);
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an
error in fact */
if (cur_drv->sect >= cur_drv->last_sect ||
cur_drv->sect == fdctrl->eot) {
fdctrl->data_pos - size);
if (cur_drv->sect > cur_drv->last_sect) {
cur_drv->sect = 1;
if (FD_MULTI_TRACK(fdctrl->data_state)) {
if (cur_drv->head == 0 &&
(cur_drv->flags & FDISK_DBL_SIDES) != 0) {
cur_drv->head = 1;
} else {
cur_drv->head = 0;
cur_drv->head = 1;
} else {
cur_drv->head = 0;
cur_drv->track++;
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
break;
}
} else {
cur_drv->track++;
break;
}
} else {
cur_drv->track++;
break;
}
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
cur_drv->head, cur_drv->track,
cur_drv->sect, fd_sector(cur_drv));
} else {
cur_drv->sect++;
}
}
}
@@ -1084,7 +1033,7 @@ end_transfer:
status0 |= 0x20;
fdctrl->data_len -= len;
// if (fdctrl->data_len == 0)
fdctrl_stop_transfer(fdctrl, status0, status1, status2);
fdctrl_stop_transfer(fdctrl, status0, status1, status2);
transfer_error:
return len;
@@ -1117,7 +1066,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
retval = fdctrl->fifo[pos];
if (++fdctrl->data_pos == fdctrl->data_len) {
fdctrl->data_pos = 0;
/* Switch from transfer mode to status mode
/* Switch from transfert mode to status mode
* then from status mode to command mode
*/
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
@@ -1204,7 +1153,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
cur_drv = get_cur_drv(fdctrl);
/* Reset mode */
if (fdctrl->state & FD_CTRL_RESET) {
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
return;
}
fdctrl->state &= ~FD_CTRL_SLEEP;
@@ -1221,7 +1170,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
bdrv_write(cur_drv->bs, fd_sector(cur_drv),
fdctrl->fifo, FD_SECTOR_LEN);
}
/* Switch from transfer mode to status mode
/* Switch from transfert mode to status mode
* then from status mode to command mode
*/
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
@@ -1310,16 +1259,8 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
fdctrl->int_status);
/* No parameters cmd: returns status if no interrupt */
#if 0
fdctrl->fifo[0] =
fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
#else
/* XXX: int_status handling is broken for read/write
commands, so we do this hack. It should be suppressed
ASAP */
fdctrl->fifo[0] =
0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
#endif
fdctrl->fifo[1] = cur_drv->track;
fdctrl_set_fifo(fdctrl, 2, 0);
fdctrl_reset_irq(fdctrl);
@@ -1353,7 +1294,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
/* VERSION */
FLOPPY_DPRINTF("VERSION command\n");
/* No parameters cmd */
/* Controller's version */
/* Controler's version */
fdctrl->fifo[0] = fdctrl->version;
fdctrl_set_fifo(fdctrl, 1, 1);
return;
@@ -1569,9 +1510,7 @@ enqueue:
/* 1 Byte status back */
fdctrl->fifo[0] = (cur_drv->ro << 6) |
(cur_drv->track == 0 ? 0x10 : 0x00) |
(cur_drv->head << 2) |
fdctrl->cur_drv |
0x28;
fdctrl->cur_drv;
fdctrl_set_fifo(fdctrl, 1, 0);
break;
case 0x07:
@@ -1642,7 +1581,6 @@ enqueue:
/* READ_ID */
FLOPPY_DPRINTF("treat READ_ID command\n");
/* XXX: should set main status register to busy */
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
qemu_mod_timer(fdctrl->result_timer,
qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
break;

1390
hw/fmopl.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +0,0 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
/* --- select emulation chips --- */
#define BUILD_YM3812 (HAS_YM3812)
//#define BUILD_YM3526 (HAS_YM3526)
//#define BUILD_Y8950 (HAS_Y8950)
/* --- system optimize --- */
/* select bit size of output : 8 or 16 */
#define OPL_OUTPUT_BIT 16
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if (OPL_OUTPUT_BIT==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_OUTPUT_BIT==8)
typedef unsigned char OPLSAMPLE;
#endif
#if BUILD_Y8950
#include "ymdeltat.h"
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
#define OPL_TYPE_IO 0x08 /* I/O port */
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
INT32 TL; /* total level :TL << 8 */
INT32 TLL; /* adjusted now TL */
UINT8 KSR; /* key scale rate :(shift down bit) */
INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
INT32 SL; /* sustin level :SL_TALBE[SL] */
INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
UINT8 ksl; /* keyscale level :(shift down bits) */
UINT8 ksr; /* key scale rate :kcode>>KSR */
UINT32 mul; /* multiple :ML_TABLE[ML] */
UINT32 Cnt; /* frequency count : */
UINT32 Incr; /* frequency step : */
/* envelope generator state */
UINT8 eg_typ; /* envelope type flag */
UINT8 evm; /* envelope phase */
INT32 evc; /* envelope counter */
INT32 eve; /* envelope counter end point */
INT32 evs; /* envelope counter step */
INT32 evsa; /* envelope step for AR :AR[ksr] */
INT32 evsd; /* envelope step for DR :DR[ksr] */
INT32 evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
UINT8 ams; /* ams flag */
UINT8 vib; /* vibrate flag */
/* wave selector */
INT32 **wavetable;
}OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
UINT8 CON; /* connection type */
UINT8 FB; /* feed back :(shift down bit) */
INT32 *connect1; /* slot1 output pointer */
INT32 *connect2; /* slot2 output pointer */
INT32 op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
UINT32 block_fnum; /* block+fnum : */
UINT8 kcode; /* key code : KeyScaleCode */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
UINT8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
UINT8 address; /* address register */
UINT8 status; /* status flag */
UINT8 statusmask; /* status mask */
UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
UINT8 st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rythm sention */
UINT8 rythm; /* Rythm mode , key flag */
#if BUILD_Y8950
/* Delta-T ADPCM unit (Y8950) */
YM_DELTAT *deltat; /* DELTA-T ADPCM */
#endif
/* Keyboard / I/O interface unit (Y8950) */
UINT8 portDirection;
UINT8 portLatch;
OPL_PORTHANDLER_R porthandler_r;
OPL_PORTHANDLER_W porthandler_w;
int port_param;
OPL_PORTHANDLER_R keyboardhandler_r;
OPL_PORTHANDLER_W keyboardhandler_w;
int keyboard_param;
/* time tables */
INT32 AR_TABLE[75]; /* atttack rate tables */
INT32 DR_TABLE[75]; /* decay rate tables */
UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
/* LFO */
INT32 *ams_table;
INT32 *vib_table;
INT32 amsCnt;
INT32 amsIncr;
INT32 vibCnt;
INT32 vibIncr;
/* wave selector enable flag */
UINT8 wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
int UpdateParam; /* stream update parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
/* Y8950 port handlers */
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
#endif

View File

@@ -1,168 +0,0 @@
/*
* Heathrow PIC support (standard PowerMac PIC)
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG
typedef struct HeathrowPIC {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPIC;
struct HeathrowPICS {
HeathrowPIC pics[2];
};
static inline int check_irq(HeathrowPIC *pic)
{
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
}
/* update the CPU irq state */
static void heathrow_pic_update(HeathrowPICS *s)
{
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int n;
value = bswap32(value);
#ifdef DEBUG
printf("pic_writel: %08x: %08x\n",
addr, value);
#endif
n = ((addr & 0xfff) - 0x10) >> 4;
if (n >= 2)
return;
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x04:
pic->mask = value;
heathrow_pic_update(s);
break;
case 0x08:
/* do not reset level triggered IRQs */
value &= ~pic->level_triggered;
pic->events &= ~value;
heathrow_pic_update(s);
break;
default:
break;
}
}
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int n;
uint32_t value;
n = ((addr & 0xfff) - 0x10) >> 4;
if (n >= 2) {
value = 0;
} else {
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x0:
value = pic->events;
break;
case 0x4:
value = pic->mask;
break;
case 0xc:
value = pic->levels;
break;
default:
value = 0;
break;
}
}
#ifdef DEBUG
printf("pic_readl: %08x: %08x\n",
addr, value);
#endif
value = bswap32(value);
return value;
}
static CPUWriteMemoryFunc *pic_write[] = {
&pic_writel,
&pic_writel,
&pic_writel,
};
static CPUReadMemoryFunc *pic_read[] = {
&pic_readl,
&pic_readl,
&pic_readl,
};
void heathrow_pic_set_irq(void *opaque, int num, int level)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int irq_bit;
#if defined(DEBUG)
{
static int last_level[64];
if (last_level[num] != level) {
printf("set_irq: num=0x%02x level=%d\n", num, level);
last_level[num] = level;
}
}
#endif
pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f);
if (level) {
pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit;
} else {
pic->levels &= ~irq_bit;
}
heathrow_pic_update(s);
}
HeathrowPICS *heathrow_pic_init(int *pmem_index)
{
HeathrowPICS *s;
s = qemu_mallocz(sizeof(HeathrowPICS));
s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000;
*pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
return s;
}

View File

@@ -46,19 +46,10 @@ typedef struct PicState {
uint8_t init4; /* true if 4 byte init */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
PicState2 *pics_state;
} PicState;
struct PicState2 {
/* 0 is master pic, 1 is slave pic */
/* XXX: better separation between the two pics */
PicState pics[2];
IRQRequestFunc *irq_request;
void *irq_request_opaque;
/* IOAPIC callback support */
SetIRQFunc *alt_irq_func;
void *alt_irq_opaque;
};
/* 0 is master pic, 1 is slave pic */
static PicState pics[2];
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
static int irq_level[16];
@@ -119,7 +110,7 @@ static int pic_get_irq(PicState *s)
master, the IRQ coming from the slave is not taken into account
for the priority computation. */
mask = s->isr;
if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
if (s->special_fully_nested_mode && s == &pics[0])
mask &= ~(1 << 2);
cur_priority = get_priority(s, mask);
if (priority < cur_priority) {
@@ -132,34 +123,32 @@ static int pic_get_irq(PicState *s)
/* raise irq to CPU if necessary. must be called every time the active
irq may change */
/* XXX: should not export it, but it is needed for an APIC kludge */
void pic_update_irq(PicState2 *s)
static void pic_update_irq(void)
{
int irq2, irq;
/* first look at slave pic */
irq2 = pic_get_irq(&s->pics[1]);
irq2 = pic_get_irq(&pics[1]);
if (irq2 >= 0) {
/* if irq request by slave pic, signal master PIC */
pic_set_irq1(&s->pics[0], 2, 1);
pic_set_irq1(&s->pics[0], 2, 0);
pic_set_irq1(&pics[0], 2, 1);
pic_set_irq1(&pics[0], 2, 0);
}
/* look at requested irq */
irq = pic_get_irq(&s->pics[0]);
irq = pic_get_irq(&pics[0]);
if (irq >= 0) {
#if defined(DEBUG_PIC)
{
int i;
for(i = 0; i < 2; i++) {
printf("pic%d: imr=%x irr=%x padd=%d\n",
i, s->pics[i].imr, s->pics[i].irr,
s->pics[i].priority_add);
i, pics[i].imr, pics[i].irr, pics[i].priority_add);
}
}
printf("pic: cpu_interrupt\n");
#endif
s->irq_request(s->irq_request_opaque, 1);
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
@@ -167,10 +156,8 @@ void pic_update_irq(PicState2 *s)
int64_t irq_time[16];
#endif
void pic_set_irq_new(void *opaque, int irq, int level)
void pic_set_irq(int irq, int level)
{
PicState2 *s = opaque;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
#if defined(DEBUG_PIC)
@@ -188,17 +175,8 @@ void pic_set_irq_new(void *opaque, int irq, int level)
irq_time[irq] = qemu_get_clock(vm_clock);
}
#endif
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
/* used for IOAPIC irqs */
if (s->alt_irq_func)
s->alt_irq_func(s->alt_irq_opaque, irq, level);
pic_update_irq(s);
}
/* obsolete function */
void pic_set_irq(int irq, int level)
{
pic_set_irq_new(isa_pic, irq, level);
pic_set_irq1(&pics[irq >> 3], irq & 7, level);
pic_update_irq();
}
/* acknowledge interrupt 'irq' */
@@ -210,37 +188,37 @@ static inline void pic_intack(PicState *s, int irq)
} else {
s->isr |= (1 << irq);
}
/* We don't clear a level sensitive interrupt here */
if (!(s->elcr & (1 << irq)))
s->irr &= ~(1 << irq);
s->irr &= ~(1 << irq);
}
int pic_read_irq(PicState2 *s)
int cpu_get_pic_interrupt(CPUState *env)
{
int irq, irq2, intno;
irq = pic_get_irq(&s->pics[0]);
/* read the irq from the PIC */
irq = pic_get_irq(&pics[0]);
if (irq >= 0) {
pic_intack(&s->pics[0], irq);
pic_intack(&pics[0], irq);
if (irq == 2) {
irq2 = pic_get_irq(&s->pics[1]);
irq2 = pic_get_irq(&pics[1]);
if (irq2 >= 0) {
pic_intack(&s->pics[1], irq2);
pic_intack(&pics[1], irq2);
} else {
/* spurious IRQ on slave controller */
irq2 = 7;
}
intno = s->pics[1].irq_base + irq2;
intno = pics[1].irq_base + irq2;
irq = irq2 + 8;
} else {
intno = s->pics[0].irq_base + irq;
intno = pics[0].irq_base + irq;
}
} else {
/* spurious IRQ on host controller */
irq = 7;
intno = s->pics[0].irq_base + irq;
intno = pics[0].irq_base + irq;
}
pic_update_irq(s);
pic_update_irq();
#ifdef DEBUG_IRQ_LATENCY
printf("IRQ%d latency=%0.3fus\n",
@@ -256,22 +234,11 @@ int pic_read_irq(PicState2 *s)
static void pic_reset(void *opaque)
{
PicState *s = opaque;
int tmp;
s->last_irr = 0;
s->irr = 0;
s->imr = 0;
s->isr = 0;
s->priority_add = 0;
s->irq_base = 0;
s->read_reg_select = 0;
s->poll = 0;
s->special_mask = 0;
s->init_state = 0;
s->auto_eoi = 0;
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
s->elcr = 0;
tmp = s->elcr_mask;
memset(s, 0, sizeof(PicState));
s->elcr_mask = tmp;
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -288,7 +255,8 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* init */
pic_reset(s);
/* deassert a pending interrupt */
s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
s->init_state = 1;
s->init4 = val & 1;
if (val & 0x02)
@@ -317,23 +285,23 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->isr &= ~(1 << irq);
if (cmd == 5)
s->priority_add = (irq + 1) & 7;
pic_update_irq(s->pics_state);
pic_update_irq();
}
break;
case 3:
irq = val & 7;
s->isr &= ~(1 << irq);
pic_update_irq(s->pics_state);
pic_update_irq();
break;
case 6:
s->priority_add = (val + 1) & 7;
pic_update_irq(s->pics_state);
pic_update_irq();
break;
case 7:
irq = val & 7;
s->isr &= ~(1 << irq);
s->priority_add = (irq + 1) & 7;
pic_update_irq(s->pics_state);
pic_update_irq();
break;
default:
/* no operation */
@@ -345,7 +313,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case 0:
/* normal mode */
s->imr = val;
pic_update_irq(s->pics_state);
pic_update_irq();
break;
case 1:
s->irq_base = val & 0xf8;
@@ -374,16 +342,16 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
ret = pic_get_irq(s);
if (ret >= 0) {
if (addr1 >> 7) {
s->pics_state->pics[0].isr &= ~(1 << 2);
s->pics_state->pics[0].irr &= ~(1 << 2);
pics[0].isr &= ~(1 << 2);
pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
s->isr &= ~(1 << ret);
if (addr1 >> 7 || ret != 2)
pic_update_irq(s->pics_state);
pic_update_irq();
} else {
ret = 0x07;
pic_update_irq(s->pics_state);
pic_update_irq();
}
return ret;
@@ -417,16 +385,15 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
}
/* memory mapped interrupt status */
/* XXX: may be the same than pic_read_irq() */
uint32_t pic_intack_read(PicState2 *s)
uint32_t pic_intack_read(CPUState *env)
{
int ret;
ret = pic_poll_read(&s->pics[0], 0x00);
ret = pic_poll_read(&pics[0], 0x00);
if (ret == 2)
ret = pic_poll_read(&s->pics[1], 0x80) + 8;
ret = pic_poll_read(&pics[1], 0x80) + 8;
/* Prepare for ISR read */
s->pics[0].read_reg_select = 1;
pics[0].read_reg_select = 1;
return ret;
}
@@ -506,12 +473,9 @@ void pic_info(void)
{
int i;
PicState *s;
if (!isa_pic)
return;
for(i=0;i<2;i++) {
s = &isa_pic->pics[i];
s = &pics[i];
term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
i, s->irr, s->imr, s->isr, s->priority_add,
s->irq_base, s->read_reg_select, s->elcr,
@@ -536,26 +500,11 @@ void irq_info(void)
#endif
}
PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
void pic_init(void)
{
PicState2 *s;
s = qemu_mallocz(sizeof(PicState2));
if (!s)
return NULL;
pic_init1(0x20, 0x4d0, &s->pics[0]);
pic_init1(0xa0, 0x4d1, &s->pics[1]);
s->pics[0].elcr_mask = 0xf8;
s->pics[1].elcr_mask = 0xde;
s->irq_request = irq_request;
s->irq_request_opaque = irq_request_opaque;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
return s;
pic_init1(0x20, 0x4d0, &pics[0]);
pic_init1(0xa0, 0x4d1, &pics[1]);
pics[0].elcr_mask = 0xf8;
pics[1].elcr_mask = 0xde;
}
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
void *alt_irq_opaque)
{
s->alt_irq_func = alt_irq_func;
s->alt_irq_opaque = alt_irq_opaque;
}

364
hw/ide.c
View File

@@ -296,9 +296,8 @@ typedef struct IDEState {
int cylinders, heads, sectors;
int64_t nb_sectors;
int mult_sectors;
SetIRQFunc *set_irq;
void *irq_opaque;
int irq;
openpic_t *openpic;
PCIDevice *pci_dev;
struct BMDMAState *bmdma;
int drive_serial;
@@ -333,7 +332,6 @@ typedef struct IDEState {
uint8_t *data_ptr;
uint8_t *data_end;
uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
} IDEState;
#define BM_STATUS_DMAING 0x01
@@ -343,18 +341,6 @@ typedef struct IDEState {
#define BM_CMD_START 0x01
#define BM_CMD_READ 0x08
#define IDE_TYPE_PIIX3 0
#define IDE_TYPE_CMD646 1
/* CMD646 specific */
#define MRDMODE 0x71
#define MRDMODE_INTR_CH0 0x04
#define MRDMODE_INTR_CH1 0x08
#define MRDMODE_BLK_CH0 0x10
#define MRDMODE_BLK_CH1 0x20
#define UDIDETCR0 0x73
#define UDIDETCR1 0x7B
typedef int IDEDMAFunc(IDEState *s,
target_phys_addr_t phys_addr,
int transfer_size1);
@@ -363,8 +349,6 @@ typedef struct BMDMAState {
uint8_t cmd;
uint8_t status;
uint32_t addr;
struct PCIIDEState *pci_dev;
/* current transfer state */
IDEState *ide_if;
IDEDMAFunc *dma_cb;
@@ -374,7 +358,6 @@ typedef struct PCIIDEState {
PCIDevice dev;
IDEState ide_if[4];
BMDMAState bmdma[2];
int type; /* see IDE_TYPE_xxx */
} PCIIDEState;
static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb);
@@ -433,10 +416,10 @@ static void ide_identify(IDEState *s)
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
#endif
put_le16(p + 48, 1); /* dword I/O */
put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
put_le16(p + 51, 0x200); /* PIO transfer cycle */
put_le16(p + 52, 0x200); /* DMA transfer cycle */
put_le16(p + 53, 1 | 1 << 2); /* words 54-58,88 are valid */
put_le16(p + 53, 1); /* words 54-58 are valid */
put_le16(p + 54, s->cylinders);
put_le16(p + 55, s->heads);
put_le16(p + 56, s->sectors);
@@ -454,8 +437,6 @@ static void ide_identify(IDEState *s)
put_le16(p + 85, (1 << 14));
put_le16(p + 86, 0);
put_le16(p + 87, (1 << 14));
put_le16(p + 88, 0x1f | (1 << 13));
put_le16(p + 93, 1 | (1 << 14) | 0x2000 | 0x4000);
}
static void ide_atapi_identify(IDEState *s)
@@ -516,12 +497,16 @@ static inline void ide_abort_command(IDEState *s)
static inline void ide_set_irq(IDEState *s)
{
BMDMAState *bm = s->bmdma;
if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
if (bm) {
bm->status |= BM_STATUS_INT;
}
s->set_irq(s->irq_opaque, s->irq, 1);
#ifdef TARGET_PPC
if (s->openpic)
openpic_set_irq(s->openpic, s->irq, 1);
else
#endif
if (s->irq == 16)
pci_set_irq(s->pci_dev, 0, 1);
else
pic_set_irq(s->irq, 1);
}
}
@@ -655,12 +640,6 @@ static void ide_sector_read_dma(IDEState *s)
ide_dma_start(s, ide_read_dma_cb);
}
static void ide_sector_write_timer_cb(void *opaque)
{
IDEState *s = opaque;
ide_set_irq(s);
}
static void ide_sector_write(IDEState *s)
{
int64_t sector_num;
@@ -686,22 +665,7 @@ static void ide_sector_write(IDEState *s)
ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
}
ide_set_sector(s, sector_num + n);
#ifdef TARGET_I386
if (win2k_install_hack) {
/* It seems there is a bug in the Windows 2000 installer HDD
IDE driver which fills the disk with empty logs when the
IDE write IRQ comes too early. This hack tries to correct
that at the expense of slower write performances. Use this
option _only_ to install Windows 2000. You must disable it
for normal use. */
qemu_mod_timer(s->sector_write_timer,
qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
} else
#endif
{
ide_set_irq(s);
}
ide_set_irq(s);
}
static int ide_write_dma_cb(IDEState *s,
@@ -823,8 +787,7 @@ static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
case 2352:
/* sync bytes */
buf[0] = 0x00;
memset(buf + 1, 0xff, 10);
buf[11] = 0x00;
memset(buf + 1, 0xff, 11);
buf += 12;
/* MSF */
lba_to_msf(buf, lba);
@@ -952,9 +915,6 @@ static int ide_atapi_cmd_read_dma_cb(IDEState *s,
transfer_size = transfer_size1;
while (transfer_size > 0) {
#ifdef DEBUG_IDE_ATAPI
printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr);
#endif
if (s->packet_transfer_size <= 0)
break;
len = s->cd_sector_size - s->io_buffer_index;
@@ -1032,8 +992,9 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, 0);
q += 3;
*q++ = 0; /* minute */
*q++ = 2; /* second */
*q++ = 0; /* frame */
} else {
/* sector 0 */
cpu_to_ube32(q, 0);
@@ -1118,16 +1079,10 @@ static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf,
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
if (msf) {
*q++ = 0;
lba_to_msf(q, 0);
q += 3;
} else {
*q++ = 0;
*q++ = 0;
*q++ = 0;
*q++ = 0;
}
*q++ = 0;
*q++ = 0;
*q++ = 0;
*q++ = 0;
len = q - buf;
cpu_to_ube16(buf, len - 2);
@@ -1522,7 +1477,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case WIN_SPECIFY:
case WIN_RECAL:
s->error = 0;
s->status = READY_STAT | SEEK_STAT;
s->status = READY_STAT;
ide_set_irq(s);
break;
case WIN_SETMULT:
@@ -1605,19 +1560,13 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case 0x82: /* write cache disable */
case 0xaa: /* read look-ahead enable */
case 0x55: /* read look-ahead disable */
s->status = READY_STAT | SEEK_STAT;
s->status = READY_STAT;
ide_set_irq(s);
break;
default:
goto abort_cmd;
}
break;
case WIN_STANDBYNOW1:
case WIN_IDLEIMMEDIATE:
case WIN_FLUSH_CACHE:
s->status = READY_STAT;
ide_set_irq(s);
break;
/* ATAPI commands */
case WIN_PIDENTIFY:
if (s->is_cdrom) {
@@ -1629,11 +1578,6 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
}
ide_set_irq(s);
break;
case WIN_DIAGNOSE:
ide_set_signature(s);
s->status = 0x00; /* NOTE: READY is _not_ set */
s->error = 0x01;
break;
case WIN_SRST:
if (!s->is_cdrom)
goto abort_cmd;
@@ -1716,7 +1660,15 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
ret = 0;
else
ret = s->status;
s->set_irq(s->irq_opaque, s->irq, 0);
#ifdef TARGET_PPC
if (s->openpic)
openpic_set_irq(s->openpic, s->irq, 0);
else
#endif
if (s->irq == 16)
pci_set_irq(s->pci_dev, 0, 0);
else
pic_set_irq(s->irq, 0);
break;
}
#ifdef DEBUG_IDE
@@ -1832,16 +1784,6 @@ static uint32_t ide_data_readl(void *opaque, uint32_t addr)
return ret;
}
static void ide_dummy_transfer_stop(IDEState *s)
{
s->data_ptr = s->io_buffer;
s->data_end = s->io_buffer;
s->io_buffer[0] = 0xff;
s->io_buffer[1] = 0xff;
s->io_buffer[2] = 0xff;
s->io_buffer[3] = 0xff;
}
static void ide_reset(IDEState *s)
{
s->mult_sectors = MAX_MULT_SECTORS;
@@ -1849,10 +1791,6 @@ static void ide_reset(IDEState *s)
s->select = 0xa0;
s->status = READY_STAT;
ide_set_signature(s);
/* init the transfer handler so that 0xffff is returned on data
accesses */
s->end_transfer_func = ide_dummy_transfer_stop;
ide_dummy_transfer_stop(s);
}
struct partition {
@@ -1868,54 +1806,45 @@ struct partition {
uint32_t nr_sects; /* nr of sectors in partition */
} __attribute__((packed));
/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
static int guess_disk_lchs(IDEState *s,
int *pcylinders, int *pheads, int *psectors)
/* try to guess the IDE geometry from the MSDOS partition table */
static void ide_guess_geometry(IDEState *s)
{
uint8_t buf[512];
int ret, i, heads, sectors, cylinders;
int ret, i;
struct partition *p;
uint32_t nr_sects;
if (s->cylinders != 0)
return;
ret = bdrv_read(s->bs, 0, buf, 1);
if (ret < 0)
return -1;
return;
/* test msdos magic */
if (buf[510] != 0x55 || buf[511] != 0xaa)
return -1;
return;
for(i = 0; i < 4; i++) {
p = ((struct partition *)(buf + 0x1be)) + i;
nr_sects = le32_to_cpu(p->nr_sects);
if (nr_sects && p->end_head) {
/* We make the assumption that the partition terminates on
a cylinder boundary */
heads = p->end_head + 1;
sectors = p->end_sector & 63;
if (sectors == 0)
continue;
cylinders = s->nb_sectors / (heads * sectors);
if (cylinders < 1 || cylinders > 16383)
continue;
*pheads = heads;
*psectors = sectors;
*pcylinders = cylinders;
s->heads = p->end_head + 1;
s->sectors = p->end_sector & 63;
s->cylinders = s->nb_sectors / (s->heads * s->sectors);
#if 0
printf("guessed geometry: LCHS=%d %d %d\n",
cylinders, heads, sectors);
printf("guessed partition: CHS=%d %d %d\n",
s->cylinders, s->heads, s->sectors);
#endif
return 0;
}
}
return -1;
}
static void ide_init2(IDEState *ide_state,
BlockDriverState *hd0, BlockDriverState *hd1,
SetIRQFunc *set_irq, void *irq_opaque, int irq)
static void ide_init2(IDEState *ide_state, int irq,
BlockDriverState *hd0, BlockDriverState *hd1)
{
IDEState *s;
static int drive_serial = 1;
int i, cylinders, heads, secs, translation;
int i, cylinders, heads, secs;
int64_t nb_sectors;
for(i = 0; i < 2; i++) {
@@ -1934,27 +1863,9 @@ static void ide_init2(IDEState *ide_state,
s->heads = heads;
s->sectors = secs;
} else {
if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) {
if (heads > 16) {
/* if heads > 16, it means that a BIOS LBA
translation was active, so the default
hardware geometry is OK */
goto default_geometry;
} else {
s->cylinders = cylinders;
s->heads = heads;
s->sectors = secs;
/* disable any translation to be in sync with
the logical geometry */
translation = bdrv_get_translation_hint(s->bs);
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
bdrv_set_translation_hint(s->bs,
BIOS_ATA_TRANSLATION_NONE);
}
}
} else {
default_geometry:
/* if no geometry, use a standard physical disk geometry */
ide_guess_geometry(s);
if (s->cylinders == 0) {
/* if no geometry, use a LBA compatible one */
cylinders = nb_sectors / (16 * 63);
if (cylinders > 16383)
cylinders = 16383;
@@ -1964,7 +1875,6 @@ static void ide_init2(IDEState *ide_state,
s->heads = 16;
s->sectors = 63;
}
bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors);
}
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
s->is_cdrom = 1;
@@ -1972,11 +1882,7 @@ static void ide_init2(IDEState *ide_state,
}
}
s->drive_serial = drive_serial++;
s->set_irq = set_irq;
s->irq_opaque = irq_opaque;
s->irq = irq;
s->sector_write_timer = qemu_new_timer(vm_clock,
ide_sector_write_timer_cb, s);
ide_reset(s);
}
}
@@ -2009,15 +1915,13 @@ void isa_ide_init(int iobase, int iobase2, int irq,
if (!ide_state)
return;
ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
ide_init2(ide_state, irq, hd0, hd1);
ide_init_ioport(ide_state, iobase, iobase2);
}
/***********************************************************/
/* PCI IDE definitions */
static void cmd646_update_irq(PCIIDEState *d);
static void ide_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
@@ -2098,6 +2002,17 @@ static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb)
}
}
static uint32_t bmdma_cmd_readb(void *opaque, uint32_t addr)
{
BMDMAState *bm = opaque;
uint32_t val;
val = bm->cmd;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
return val;
}
static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
{
BMDMAState *bm = opaque;
@@ -2117,77 +2032,24 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
}
}
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
static uint32_t bmdma_status_readb(void *opaque, uint32_t addr)
{
BMDMAState *bm = opaque;
PCIIDEState *pci_dev;
uint32_t val;
switch(addr & 3) {
case 0:
val = bm->cmd;
break;
case 1:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
val = pci_dev->dev.config[MRDMODE];
} else {
val = 0xff;
}
break;
case 2:
val = bm->status;
break;
case 3:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
if (bm == &pci_dev->bmdma[0])
val = pci_dev->dev.config[UDIDETCR0];
else
val = pci_dev->dev.config[UDIDETCR1];
} else {
val = 0xff;
}
break;
default:
val = 0xff;
break;
}
val = bm->status;
#ifdef DEBUG_IDE
printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
printf("%s: 0x%08x\n", __func__, val);
#endif
return val;
}
static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
static void bmdma_status_writeb(void *opaque, uint32_t addr, uint32_t val)
{
BMDMAState *bm = opaque;
PCIIDEState *pci_dev;
#ifdef DEBUG_IDE
printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
printf("%s: 0x%08x\n", __func__, val);
#endif
switch(addr & 3) {
case 1:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
pci_dev->dev.config[MRDMODE] =
(pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
cmd646_update_irq(pci_dev);
}
break;
case 2:
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
break;
case 3:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
if (bm == &pci_dev->bmdma[0])
pci_dev->dev.config[UDIDETCR0] = val;
else
pci_dev->dev.config[UDIDETCR1] = val;
}
break;
}
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
}
static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
@@ -2220,12 +2082,12 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
BMDMAState *bm = &d->bmdma[i];
d->ide_if[2 * i].bmdma = bm;
d->ide_if[2 * i + 1].bmdma = bm;
bm->pci_dev = (PCIIDEState *)pci_dev;
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
register_ioport_read(addr, 1, 1, bmdma_cmd_readb, bm);
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
register_ioport_read(addr, 4, 1, bmdma_readb, bm);
register_ioport_write(addr + 2, 1, 1, bmdma_status_writeb, bm);
register_ioport_read(addr + 2, 1, 1, bmdma_status_readb, bm);
register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
@@ -2233,62 +2095,29 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
}
}
/* XXX: call it also when the MRDMODE is changed from the PCI config
registers */
static void cmd646_update_irq(PCIIDEState *d)
{
int pci_level;
pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
pci_set_irq((PCIDevice *)d, 0, pci_level);
}
/* the PCI irq level is the logical OR of the two channels */
static void cmd646_set_irq(void *opaque, int channel, int level)
{
PCIIDEState *d = opaque;
int irq_mask;
irq_mask = MRDMODE_INTR_CH0 << channel;
if (level)
d->dev.config[MRDMODE] |= irq_mask;
else
d->dev.config[MRDMODE] &= ~irq_mask;
cmd646_update_irq(d);
}
/* CMD646 PCI IDE controller */
void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
int secondary_ide_enabled)
/* hd_table must contain 4 block drivers */
void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table)
{
PCIIDEState *d;
uint8_t *pci_conf;
int i;
d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
sizeof(PCIIDEState),
d = (PCIIDEState *)pci_register_device(bus, "IDE", sizeof(PCIIDEState),
-1,
NULL, NULL);
d->type = IDE_TYPE_CMD646;
pci_conf = d->dev.config;
pci_conf[0x00] = 0x95; // CMD646
pci_conf[0x01] = 0x10;
pci_conf[0x02] = 0x46;
pci_conf[0x03] = 0x06;
pci_conf[0x08] = 0x07; // IDE controller revision
pci_conf[0x09] = 0x8f;
pci_conf[0x00] = 0x86; // Intel
pci_conf[0x01] = 0x80;
pci_conf[0x02] = 0x00; // fake
pci_conf[0x03] = 0x01; // fake
pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
pci_conf[0x0e] = 0x00; // header_type
if (secondary_ide_enabled) {
/* XXX: if not enabled, really disable the seconday IDE controller */
pci_conf[0x51] = 0x80; /* enable IDE1 */
}
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
pci_conf[0x2c] = 0x86; // subsys vendor
pci_conf[0x2d] = 0x80; // subsys vendor
pci_conf[0x2e] = 0x00; // fake
pci_conf[0x2f] = 0x01; // fake
pci_register_io_region((PCIDevice *)d, 0, 0x8,
PCI_ADDRESS_SPACE_IO, ide_map);
@@ -2302,13 +2131,11 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
PCI_ADDRESS_SPACE_IO, bmdma_map);
pci_conf[0x3d] = 0x01; // interrupt on pin 1
for(i = 0; i < 4; i++)
d->ide_if[i].pci_dev = (PCIDevice *)d;
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
cmd646_set_irq, d, 0);
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
cmd646_set_irq, d, 1);
ide_init2(&d->ide_if[0], 16, hd_table[0], hd_table[1]);
ide_init2(&d->ide_if[2], 16, hd_table[2], hd_table[3]);
}
/* hd_table must contain 4 block drivers */
@@ -2323,8 +2150,6 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
sizeof(PCIIDEState),
((PCIDevice *)piix3_state)->devfn + 1,
NULL, NULL);
d->type = IDE_TYPE_PIIX3;
pci_conf = d->dev.config;
pci_conf[0x00] = 0x86; // Intel
pci_conf[0x01] = 0x80;
@@ -2337,10 +2162,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
pci_register_io_region((PCIDevice *)d, 4, 0x10,
PCI_ADDRESS_SPACE_IO, bmdma_map);
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
pic_set_irq_new, isa_pic, 14);
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
pic_set_irq_new, isa_pic, 15);
ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]);
ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]);
ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
}
@@ -2458,14 +2281,15 @@ static CPUReadMemoryFunc *pmac_ide_read[] = {
/* PowerMac uses memory mapped registers, not I/O. Return the memory
I/O index to access the ide. */
int pmac_ide_init (BlockDriverState **hd_table,
SetIRQFunc *set_irq, void *irq_opaque, int irq)
openpic_t *openpic, int irq)
{
IDEState *ide_if;
int pmac_ide_memory;
ide_if = qemu_mallocz(sizeof(IDEState) * 2);
ide_init2(&ide_if[0], hd_table[0], hd_table[1],
set_irq, irq_opaque, irq);
ide_init2(&ide_if[0], irq, hd_table[0], hd_table[1]);
ide_if[0].openpic = openpic;
ide_if[1].openpic = openpic;
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
pmac_ide_write, &ide_if[0]);

View File

@@ -1,207 +0,0 @@
/*
* QEMU SPARC iommu emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug iommu */
//#define DEBUG_IOMMU
#ifdef DEBUG_IOMMU
#define DPRINTF(fmt, args...) \
do { printf("IOMMU: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#define IOMMU_NREGS (3*4096)
#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */
#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */
#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */
#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */
#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */
#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */
#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */
#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
/* The format of an iopte in the page tables */
#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */
#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
#define IOPTE_WRITE 0x00000004 /* Writeable */
#define IOPTE_VALID 0x00000002 /* IOPTE is valid */
#define IOPTE_WAZ 0x00000001 /* Write as zeros */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
typedef struct IOMMUState {
uint32_t addr;
uint32_t regs[IOMMU_NREGS];
uint32_t iostart;
} IOMMUState;
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
{
IOMMUState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
switch (saddr) {
default:
DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]);
return s->regs[saddr];
break;
}
return 0;
}
static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOMMUState *s = opaque;
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
DPRINTF("write reg[%d] = %x\n", saddr, val);
switch (saddr) {
case 0:
switch (val & IOMMU_CTRL_RNGE) {
case IOMMU_RNGE_16MB:
s->iostart = 0xff000000;
break;
case IOMMU_RNGE_32MB:
s->iostart = 0xfe000000;
break;
case IOMMU_RNGE_64MB:
s->iostart = 0xfc000000;
break;
case IOMMU_RNGE_128MB:
s->iostart = 0xf8000000;
break;
case IOMMU_RNGE_256MB:
s->iostart = 0xf0000000;
break;
case IOMMU_RNGE_512MB:
s->iostart = 0xe0000000;
break;
case IOMMU_RNGE_1GB:
s->iostart = 0xc0000000;
break;
default:
case IOMMU_RNGE_2GB:
s->iostart = 0x80000000;
break;
}
DPRINTF("iostart = %x\n", s->iostart);
/* Fall through */
default:
s->regs[saddr] = val;
break;
}
}
static CPUReadMemoryFunc *iommu_mem_read[3] = {
iommu_mem_readw,
iommu_mem_readw,
iommu_mem_readw,
};
static CPUWriteMemoryFunc *iommu_mem_write[3] = {
iommu_mem_writew,
iommu_mem_writew,
iommu_mem_writew,
};
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
{
IOMMUState *s = opaque;
uint32_t iopte, pa, tmppte;
iopte = s->regs[1] << 4;
addr &= ~s->iostart;
iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
cpu_physical_memory_read(iopte, (void *) &pa, 4);
bswap32s(&pa);
tmppte = pa;
pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
return pa;
}
static void iommu_save(QEMUFile *f, void *opaque)
{
IOMMUState *s = opaque;
int i;
qemu_put_be32s(f, &s->addr);
for (i = 0; i < IOMMU_NREGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_put_be32s(f, &s->iostart);
}
static int iommu_load(QEMUFile *f, void *opaque, int version_id)
{
IOMMUState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->addr);
for (i = 0; i < IOMMU_NREGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_get_be32s(f, &s->iostart);
return 0;
}
static void iommu_reset(void *opaque)
{
IOMMUState *s = opaque;
memset(s->regs, 0, IOMMU_NREGS * 4);
s->iostart = 0;
}
void *iommu_init(uint32_t addr)
{
IOMMUState *s;
int iommu_io_memory;
s = qemu_mallocz(sizeof(IOMMUState));
if (!s)
return NULL;
s->addr = addr;
iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
qemu_register_reset(iommu_reset, s);
return s;
}

View File

@@ -1,469 +0,0 @@
/*
* QEMU Lance emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug LANCE card */
//#define DEBUG_LANCE
#ifdef DEBUG_LANCE
#define DPRINTF(fmt, args...) \
do { printf("LANCE: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
#define LANCE_LOG_RX_BUFFERS 4
#endif
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
#define LE_CSR3 3
#define LE_NREGS (LE_CSR3 + 1)
#define LE_MAXREG LE_CSR3
#define LE_RDP 0
#define LE_RAP 1
#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
#define LE_C0_MERR 0x0800 /* ME: Memory error */
#define LE_C0_RINT 0x0400 /* Received interrupt */
#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
#define LE_C0_INTR 0x0080 /* Interrupt or error */
#define LE_C0_INEA 0x0040 /* Interrupt enable */
#define LE_C0_RXON 0x0020 /* Receiver on */
#define LE_C0_TXON 0x0010 /* Transmitter on */
#define LE_C0_TDMD 0x0008 /* Transmitter demand */
#define LE_C0_STOP 0x0004 /* Stop the card */
#define LE_C0_STRT 0x0002 /* Start the card */
#define LE_C0_INIT 0x0001 /* Init the card */
#define LE_C3_BSWP 0x4 /* SWAP */
#define LE_C3_ACON 0x2 /* ALE Control */
#define LE_C3_BCON 0x1 /* Byte control */
/* Receive message descriptor 1 */
#define LE_R1_OWN 0x80 /* Who owns the entry */
#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
#define LE_R1_FRA 0x20 /* FRA: Frame error */
#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
#define LE_R1_CRC 0x08 /* CRC error */
#define LE_R1_BUF 0x04 /* BUF: Buffer error */
#define LE_R1_SOP 0x02 /* Start of packet */
#define LE_R1_EOP 0x01 /* End of packet */
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T1_OWN 0x80 /* Lance owns the packet */
#define LE_T1_ERR 0x40 /* Error summary */
#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
#define LE_T1_EONE 0x08 /* Error: one retry needed */
#define LE_T1_EDEF 0x04 /* Error: deferred */
#define LE_T1_SOP 0x02 /* Start of packet */
#define LE_T1_EOP 0x01 /* End of packet */
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T3_BUF 0x8000 /* Buffer error */
#define LE_T3_UFL 0x4000 /* Error underflow */
#define LE_T3_LCOL 0x1000 /* Error late collision */
#define LE_T3_CLOS 0x0800 /* Error carrier loss */
#define LE_T3_RTY 0x0400 /* Error retry */
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
#define PKT_BUF_SZ 1544
#define RX_BUFF_SIZE PKT_BUF_SZ
#define TX_BUFF_SIZE PKT_BUF_SZ
struct lance_rx_desc {
unsigned short rmd0; /* low address of packet */
unsigned char rmd1_bits; /* descriptor bits */
unsigned char rmd1_hadr; /* high address of packet */
short length; /* This length is 2s complement (negative)!
* Buffer length
*/
unsigned short mblength; /* This is the actual number of bytes received */
};
struct lance_tx_desc {
unsigned short tmd0; /* low address of packet */
unsigned char tmd1_bits; /* descriptor bits */
unsigned char tmd1_hadr; /* high address of packet */
short length; /* Length is 2s complement (negative)! */
unsigned short misc;
};
/* The LANCE initialization block, described in databook. */
/* On the Sparc, this block should be on a DMA region */
struct lance_init_block {
unsigned short mode; /* Pre-set mode (reg. 15) */
unsigned char phys_addr[6]; /* Physical ethernet address */
unsigned filter[2]; /* Multicast filter. */
/* Receive and transmit ring base, along with extra bits. */
unsigned short rx_ptr; /* receive descriptor addr */
unsigned short rx_len; /* receive len and high addr */
unsigned short tx_ptr; /* transmit descriptor addr */
unsigned short tx_len; /* transmit len and high addr */
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
char pad[2]; /* align rx_buf for copy_and_sum(). */
char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
};
#define LEDMA_REGS 4
#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
typedef struct LANCEState {
NetDriverState *nd;
uint32_t leptr;
uint16_t addr;
uint16_t regs[LE_NREGS];
uint8_t phys[6]; /* mac address */
int irq;
unsigned int rxptr, txptr;
uint32_t ledmaregs[LEDMA_REGS];
} LANCEState;
static void lance_send(void *opaque);
static void lance_reset(void *opaque)
{
LANCEState *s = opaque;
memcpy(s->phys, s->nd->macaddr, 6);
s->rxptr = 0;
s->txptr = 0;
memset(s->regs, 0, LE_NREGS * 2);
s->regs[LE_CSR0] = LE_C0_STOP;
memset(s->ledmaregs, 0, LEDMA_REGS * 4);
}
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
return s->regs[s->addr];
case LE_RAP:
DPRINTF("read areg = %4.4x\n", s->addr);
return s->addr;
default:
DPRINTF("read unknown(%d)\n", saddr>>1);
break;
}
return 0;
}
static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
uint16_t reg;
saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
switch(s->addr) {
case LE_CSR0:
if (val & LE_C0_STOP) {
s->regs[LE_CSR0] = LE_C0_STOP;
break;
}
reg = s->regs[LE_CSR0];
// 1 = clear for some bits
reg &= ~(val & 0x7f00);
// generated bits
reg &= ~(LE_C0_ERR | LE_C0_INTR);
if (reg & 0x7100)
reg |= LE_C0_ERR;
if (reg & 0x7f00)
reg |= LE_C0_INTR;
// direct bit
reg &= ~LE_C0_INEA;
reg |= val & LE_C0_INEA;
// exclusive bits
if (val & LE_C0_INIT) {
reg |= LE_C0_IDON | LE_C0_INIT;
reg &= ~LE_C0_STOP;
}
else if (val & LE_C0_STRT) {
reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
reg &= ~LE_C0_STOP;
}
s->regs[LE_CSR0] = reg;
break;
case LE_CSR1:
s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
s->regs[s->addr] = val;
break;
case LE_CSR2:
s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
s->regs[s->addr] = val;
break;
case LE_CSR3:
s->regs[s->addr] = val;
break;
}
break;
case LE_RAP:
DPRINTF("write areg = %4.4x\n", val);
if (val < LE_NREGS)
s->addr = val;
break;
default:
DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val);
break;
}
lance_send(s);
}
static CPUReadMemoryFunc *lance_mem_read[3] = {
lance_mem_readw,
lance_mem_readw,
lance_mem_readw,
};
static CPUWriteMemoryFunc *lance_mem_write[3] = {
lance_mem_writew,
lance_mem_writew,
lance_mem_writew,
};
/* return the max buffer size if the LANCE can receive more data */
static int lance_can_receive(void *opaque)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
int i;
uint8_t temp8;
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return 0;
ib = (void *) iommu_translate(dmaptr);
for (i = 0; i < RX_RING_SIZE; i++) {
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_R1_OWN)) {
DPRINTF("can receive %d\n", RX_BUFF_SIZE);
return RX_BUFF_SIZE;
}
}
DPRINTF("cannot receive\n");
return 0;
}
#define MIN_BUF_SIZE 60
static void lance_receive(void *opaque, const uint8_t *buf, int size)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_rxptr;
uint16_t temp16;
uint8_t temp8;
DPRINTF("receive size %d\n", size);
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
old_rxptr = s->rxptr;
for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_R1_OWN)) {
s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
temp16 = size + 4;
bswap16s(&temp16);
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2);
cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
temp8 = LE_R1_POK;
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
if (s->regs[LE_CSR0] & LE_C0_INEA)
pic_set_irq(s->irq, 1);
DPRINTF("got packet, len %d\n", size);
return;
}
}
}
static void lance_send(void *opaque)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_txptr;
uint16_t temp16;
uint8_t temp8;
char pkt_buf[PKT_BUF_SZ];
DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
old_txptr = s->txptr;
for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2);
bswap16s(&temp16);
temp16 = (~temp16) + 1;
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
DPRINTF("sending packet, len %d\n", temp16);
qemu_send_packet(s->nd, pkt_buf, temp16);
temp8 = LE_T1_POK;
cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
}
}
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
pic_set_irq(s->irq, 1);
}
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = (addr & LEDMA_MAXADDR) >> 2;
return s->ledmaregs[saddr];
}
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = (addr & LEDMA_MAXADDR) >> 2;
s->ledmaregs[saddr] = val;
}
static CPUReadMemoryFunc *ledma_mem_read[3] = {
ledma_mem_readl,
ledma_mem_readl,
ledma_mem_readl,
};
static CPUWriteMemoryFunc *ledma_mem_write[3] = {
ledma_mem_writel,
ledma_mem_writel,
ledma_mem_writel,
};
static void lance_save(QEMUFile *f, void *opaque)
{
LANCEState *s = opaque;
int i;
qemu_put_be32s(f, &s->leptr);
qemu_put_be16s(f, &s->addr);
for (i = 0; i < LE_NREGS; i ++)
qemu_put_be16s(f, &s->regs[i]);
qemu_put_buffer(f, s->phys, 6);
qemu_put_be32s(f, &s->irq);
for (i = 0; i < LEDMA_REGS; i ++)
qemu_put_be32s(f, &s->ledmaregs[i]);
}
static int lance_load(QEMUFile *f, void *opaque, int version_id)
{
LANCEState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->leptr);
qemu_get_be16s(f, &s->addr);
for (i = 0; i < LE_NREGS; i ++)
qemu_get_be16s(f, &s->regs[i]);
qemu_get_buffer(f, s->phys, 6);
qemu_get_be32s(f, &s->irq);
for (i = 0; i < LEDMA_REGS; i ++)
qemu_get_be32s(f, &s->ledmaregs[i]);
return 0;
}
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
{
LANCEState *s;
int lance_io_memory, ledma_io_memory;
s = qemu_mallocz(sizeof(LANCEState));
if (!s)
return;
s->nd = nd;
s->irq = irq;
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
cpu_register_physical_memory(leaddr, 4, lance_io_memory);
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
lance_reset(s);
qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
qemu_register_reset(lance_reset, s);
}

View File

@@ -1,356 +0,0 @@
/*
* QEMU M48T08 NVRAM emulation for Sparc platform
*
* Copyright (c) 2003-2004 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.
*/
#include "vl.h"
#include "m48t08.h"
//#define DEBUG_NVRAM
#if defined(DEBUG_NVRAM)
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
#else
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
#define NVRAM_MAX_MEM 0x1ff0
#define NVRAM_MAXADDR 0x1fff
struct m48t08_t {
/* RTC management */
time_t time_offset;
time_t stop_time;
/* NVRAM storage */
uint8_t *buffer;
};
/* Fake timer functions */
/* Generic helpers for BCD */
static inline uint8_t toBCD (uint8_t value)
{
return (((value / 10) % 10) << 4) | (value % 10);
}
static inline uint8_t fromBCD (uint8_t BCD)
{
return ((BCD >> 4) * 10) + (BCD & 0x0F);
}
/* RTC management helpers */
static void get_time (m48t08_t *NVRAM, struct tm *tm)
{
time_t t;
t = time(NULL) + NVRAM->time_offset;
#ifdef _WIN32
memcpy(tm,localtime(&t),sizeof(*tm));
#else
localtime_r (&t, tm) ;
#endif
}
static void set_time (m48t08_t *NVRAM, struct tm *tm)
{
time_t now, new_time;
new_time = mktime(tm);
now = time(NULL);
NVRAM->time_offset = new_time - now;
}
/* Direct access to NVRAM */
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
{
struct tm tm;
int tmp;
addr &= NVRAM_MAXADDR;
switch (addr) {
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
break;
case 0x1FF9:
/* seconds (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_sec = tmp;
set_time(NVRAM, &tm);
}
if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
if (val & 0x80) {
NVRAM->stop_time = time(NULL);
} else {
NVRAM->time_offset += NVRAM->stop_time - time(NULL);
NVRAM->stop_time = 0;
}
}
NVRAM->buffer[0x1FF9] = val & 0x80;
break;
case 0x1FFA:
/* minutes (BCD) */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_time(NVRAM, &tm);
tm.tm_min = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFB:
/* hours (BCD) */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_time(NVRAM, &tm);
tm.tm_hour = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFC:
/* day of the week / century */
tmp = fromBCD(val & 0x07);
get_time(NVRAM, &tm);
tm.tm_wday = tmp;
set_time(NVRAM, &tm);
NVRAM->buffer[0x1FFC] = val & 0x40;
break;
case 0x1FFD:
/* date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
set_time(NVRAM, &tm);
}
break;
case 0x1FFE:
/* month */
tmp = fromBCD(val & 0x1F);
if (tmp >= 1 && tmp <= 12) {
get_time(NVRAM, &tm);
tm.tm_mon = tmp - 1;
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
NVRAM->buffer[addr] = val & 0xFF;
break;
}
}
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
{
struct tm tm;
uint8_t retval = 0xFF;
addr &= NVRAM_MAXADDR;
switch (addr) {
case 0x1FF8:
/* control */
goto do_read;
case 0x1FF9:
/* seconds (BCD) */
get_time(NVRAM, &tm);
retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
break;
case 0x1FFA:
/* minutes (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_min);
break;
case 0x1FFB:
/* hours (BCD) */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_hour);
break;
case 0x1FFC:
/* day of the week / century */
get_time(NVRAM, &tm);
retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
break;
case 0x1FFD:
/* date */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mday);
break;
case 0x1FFE:
/* month */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_mon + 1);
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
break;
default:
do_read:
retval = NVRAM->buffer[addr];
break;
}
return retval;
}
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
m48t08_write(NVRAM, addr, value);
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
m48t08_write(NVRAM, addr, value);
m48t08_write(NVRAM, addr + 1, value >> 8);
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
m48t08_write(NVRAM, addr, value);
m48t08_write(NVRAM, addr + 1, value >> 8);
m48t08_write(NVRAM, addr + 2, value >> 16);
m48t08_write(NVRAM, addr + 3, value >> 24);
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
retval = m48t08_read(NVRAM, addr);
return retval;
}
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
retval = m48t08_read(NVRAM, addr) << 8;
retval |= m48t08_read(NVRAM, addr + 1);
return retval;
}
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
{
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
retval = m48t08_read(NVRAM, addr) << 24;
retval |= m48t08_read(NVRAM, addr + 1) << 16;
retval |= m48t08_read(NVRAM, addr + 2) << 8;
retval |= m48t08_read(NVRAM, addr + 3);
return retval;
}
static CPUWriteMemoryFunc *nvram_write[] = {
&nvram_writeb,
&nvram_writew,
&nvram_writel,
};
static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readb,
&nvram_readw,
&nvram_readl,
};
static void nvram_save(QEMUFile *f, void *opaque)
{
m48t08_t *s = opaque;
qemu_put_be32s(f, (uint32_t *)&s->time_offset);
qemu_put_be32s(f, (uint32_t *)&s->stop_time);
qemu_put_buffer(f, s->buffer, 0x2000);
}
static int nvram_load(QEMUFile *f, void *opaque, int version_id)
{
m48t08_t *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, (uint32_t *)&s->time_offset);
qemu_get_be32s(f, (uint32_t *)&s->stop_time);
qemu_get_buffer(f, s->buffer, 0x2000);
return 0;
}
static void m48t08_reset(void *opaque)
{
m48t08_t *s = opaque;
s->time_offset = 0;
s->stop_time = 0;
}
/* Initialisation routine */
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
{
m48t08_t *s;
int mem_index;
s = qemu_mallocz(sizeof(m48t08_t));
if (!s)
return NULL;
s->buffer = qemu_mallocz(size);
if (!s->buffer) {
qemu_free(s);
return NULL;
}
if (mem_base != 0) {
mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
cpu_register_physical_memory(mem_base, 0x2000, mem_index);
}
register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
qemu_register_reset(m48t08_reset, s);
return s;
}
#if 0
struct idprom
{
unsigned char id_format; /* Format identifier (always 0x01) */
unsigned char id_machtype; /* Machine type */
unsigned char id_ethaddr[6]; /* Hardware ethernet address */
long id_date; /* Date of manufacture */
unsigned int id_sernum:24; /* Unique serial number */
unsigned char id_cksum; /* Checksum - xor of the data bytes */
unsigned char reserved[16];
};
#endif

View File

@@ -1,10 +0,0 @@
#if !defined (__M48T08_H__)
#define __M48T08_H__
typedef struct m48t08_t m48t08_t;
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val);
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr);
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size);
#endif /* !defined (__M48T08_H__) */

View File

@@ -1,201 +0,0 @@
#include "vl.h"
#include "disas.h"
#include "exec-all.h"
struct exec
{
uint32_t a_info; /* Use macros N_MAGIC, etc for access */
uint32_t a_text; /* length of text, in bytes */
uint32_t a_data; /* length of data, in bytes */
uint32_t a_bss; /* length of uninitialized data area, in bytes */
uint32_t a_syms; /* length of symbol table data in file, in bytes */
uint32_t a_entry; /* start address */
uint32_t a_trsize; /* length of relocation info for text, in bytes */
uint32_t a_drsize; /* length of relocation info for data, in bytes */
};
#ifdef BSWAP_NEEDED
static void bswap_ahdr(struct exec *e)
{
bswap32s(&e->a_info);
bswap32s(&e->a_text);
bswap32s(&e->a_data);
bswap32s(&e->a_bss);
bswap32s(&e->a_syms);
bswap32s(&e->a_entry);
bswap32s(&e->a_trsize);
bswap32s(&e->a_drsize);
}
#else
#define bswap_ahdr(x) do { } while (0)
#endif
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
#define OMAGIC 0407
#define NMAGIC 0410
#define ZMAGIC 0413
#define QMAGIC 0314
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
#define N_TXTOFF(x) \
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
#define N_DATADDR(x) \
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_SPARC
#include "elf.h"
#ifndef BSWAP_NEEDED
#define bswap_ehdr32(e) do { } while (0)
#define bswap_phdr32(e) do { } while (0)
#define bswap_shdr32(e) do { } while (0)
#define bswap_sym32(e) do { } while (0)
#ifdef TARGET_SPARC64
#define bswap_ehdr64(e) do { } while (0)
#define bswap_phdr64(e) do { } while (0)
#define bswap_shdr64(e) do { } while (0)
#define bswap_sym64(e) do { } while (0)
#endif
#endif
#define SZ 32
#define elf_word uint32_t
#define bswapSZs bswap32s
#include "elf_ops.h"
#ifdef TARGET_SPARC64
#undef elfhdr
#undef elf_phdr
#undef elf_shdr
#undef elf_sym
#undef elf_note
#undef elf_word
#undef bswapSZs
#undef SZ
#define elfhdr elf64_hdr
#define elf_phdr elf64_phdr
#define elf_note elf64_note
#define elf_shdr elf64_shdr
#define elf_sym elf64_sym
#define elf_word uint64_t
#define bswapSZs bswap64s
#define SZ 64
#include "elf_ops.h"
#endif
int load_elf(const char *filename, uint8_t *addr)
{
struct elf32_hdr ehdr;
int retval, fd;
Elf32_Half machine;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
goto error;
retval = read(fd, &ehdr, sizeof(ehdr));
if (retval < 0)
goto error;
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
goto error;
machine = tswap16(ehdr.e_machine);
if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
struct elf32_phdr phdr;
bswap_ehdr32(&ehdr);
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
goto error;
retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
if (retval < 0)
goto error;
load_symbols32(&ehdr, fd);
}
#ifdef TARGET_SPARC64
else if (machine == EM_SPARCV9) {
struct elf64_hdr ehdr64;
struct elf64_phdr phdr;
lseek(fd, 0, SEEK_SET);
retval = read(fd, &ehdr64, sizeof(ehdr64));
if (retval < 0)
goto error;
bswap_ehdr64(&ehdr64);
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
goto error;
retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry);
if (retval < 0)
goto error;
load_symbols64(&ehdr64, fd);
}
#endif
close(fd);
return retval;
error:
close(fd);
return -1;
}
int load_aout(const char *filename, uint8_t *addr)
{
int fd, size, ret;
struct exec e;
uint32_t magic;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
size = read(fd, &e, sizeof(e));
if (size < 0)
goto fail;
bswap_ahdr(&e);
magic = N_MAGIC(e);
switch (magic) {
case ZMAGIC:
case QMAGIC:
case OMAGIC:
lseek(fd, N_TXTOFF(e), SEEK_SET);
size = read(fd, addr, e.a_text + e.a_data);
if (size < 0)
goto fail;
break;
case NMAGIC:
lseek(fd, N_TXTOFF(e), SEEK_SET);
size = read(fd, addr, e.a_text);
if (size < 0)
goto fail;
ret = read(fd, addr + N_DATADDR(e), e.a_data);
if (ret < 0)
goto fail;
size += ret;
break;
default:
goto fail;
}
close(fd);
return size;
fail:
close(fd);
return -1;
}

View File

@@ -1,254 +0,0 @@
#include "vl.h"
#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000
extern FILE *logfile;
static void pic_irq_request(void *opaque, int level)
{
if (level) {
cpu_single_env->CP0_Cause |= 0x00000400;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_single_env->CP0_Cause &= ~0x00000400;
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
void cpu_mips_irqctrl_init (void)
{
}
uint32_t cpu_mips_get_random (CPUState *env)
{
uint32_t now = qemu_get_clock(vm_clock);
return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
}
/* MIPS R4K timer */
uint32_t cpu_mips_get_count (CPUState *env)
{
return env->CP0_Count +
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
100 * 1000 * 1000, ticks_per_sec);
}
static void cpu_mips_update_count (CPUState *env, uint32_t count,
uint32_t compare)
{
uint64_t now, next;
uint32_t tmp;
tmp = count;
if (count == compare)
tmp++;
now = qemu_get_clock(vm_clock);
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
if (next == now)
next++;
#if 1
if (logfile) {
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
__func__, now, count, compare, next - now);
}
#endif
/* Store new count and compare registers */
env->CP0_Compare = compare;
env->CP0_Count =
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
/* Adjust timer */
qemu_mod_timer(env->timer, next);
}
void cpu_mips_store_count (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, value, env->CP0_Compare);
}
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
pic_set_irq(5, 0);
}
static void mips_timer_cb (void *opaque)
{
CPUState *env;
env = opaque;
#if 1
if (logfile) {
fprintf(logfile, "%s\n", __func__);
}
#endif
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
pic_set_irq(5, 1);
}
void cpu_mips_clock_init (CPUState *env)
{
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
env->CP0_Compare = 0;
cpu_mips_update_count(env, 1, 0);
}
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
cpu_outw(NULL, addr & 0xffff, value);
}
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
cpu_outl(NULL, addr & 0xffff, value);
}
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
CPUWriteMemoryFunc *io_write[] = {
&io_writeb,
&io_writew,
&io_writel,
};
CPUReadMemoryFunc *io_read[] = {
&io_readb,
&io_readw,
&io_readl,
};
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
unsigned long bios_offset;
int io_memory;
int linux_boot;
int ret;
printf("%s: start\n", __func__);
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(0x1fc00000),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
#if 0
memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
cpu_single_env->PC = 0x80010004;
#else
cpu_single_env->PC = 0xBFC00004;
#endif
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename,
phys_ram_base + (kernel_base - 0x80000000));
if (kernel_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
cpu_single_env->PC = KERNEL_LOAD_ADDR;
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Init internal devices */
cpu_mips_clock_init(cpu_single_env);
cpu_mips_irqctrl_init();
/* Register 64 KB of ISA IO space at 0x14000000 */
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
isa_mem_base = 0x10000000;
isa_pic = pic_init(pic_irq_request, cpu_single_env);
serial_init(0x3f8, 4, serial_hds[0]);
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
isa_ne2000_init(0x300, 9, &nd_table[0]);
}
QEMUMachine mips_machine = {
"mips",
"mips r4k platform",
mips_r4k_init,
};

View File

@@ -61,9 +61,6 @@
#define EN1_CURPAG 0x17
#define EN1_MULT 0x18
#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
@@ -153,7 +150,7 @@ static void ne2000_reset(NE2000State *s)
static void ne2000_update_irq(NE2000State *s)
{
int isr;
isr = (s->isr & s->imr) & 0x7f;
isr = s->isr & s->imr;
#if defined(DEBUG_NE2000)
printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
s->irq, isr ? 1 : 0, s->isr, s->imr);
@@ -249,7 +246,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
int offset, page, index;
int offset, page;
addr &= 0xf;
#ifdef DEBUG_NE2000
@@ -258,7 +255,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (addr == E8390_CMD) {
/* control register */
s->cmd = val;
if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
if (val & E8390_START) {
s->isr &= ~ENISR_RESET;
/* test specific case: zero length transfert */
if ((val & (E8390_RREAD | E8390_RWRITE)) &&
@@ -267,18 +264,10 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
ne2000_update_irq(s);
}
if (val & E8390_TRANS) {
index = (s->tpsr << 8);
/* XXX: next 2 lines are a hack to make netware 3.11 work */
if (index >= NE2000_PMEM_END)
index -= NE2000_PMEM_SIZE;
/* fail safe: check range on the transmitted length */
if (index + s->tcnt <= NE2000_PMEM_END) {
qemu_send_packet(s->nd, s->mem + index, s->tcnt);
}
qemu_send_packet(s->nd, s->mem + (s->tpsr << 8), s->tcnt);
/* signal end of transfert */
s->tsr = ENTSR_PTX;
s->isr |= ENISR_TX;
s->cmd &= ~E8390_TRANS;
ne2000_update_irq(s);
}
}
@@ -379,12 +368,6 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
case EN0_RSR:
ret = s->rsr;
break;
case EN2_STARTPG:
ret = s->start >> 8;
break;
case EN2_STOPPG:
ret = s->stop >> 8;
break;
default:
ret = 0x00;
break;
@@ -555,59 +538,6 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
return 0;
}
static void ne2000_save(QEMUFile* f,void* opaque)
{
NE2000State* s=(NE2000State*)opaque;
qemu_put_8s(f, &s->cmd);
qemu_put_be32s(f, &s->start);
qemu_put_be32s(f, &s->stop);
qemu_put_8s(f, &s->boundary);
qemu_put_8s(f, &s->tsr);
qemu_put_8s(f, &s->tpsr);
qemu_put_be16s(f, &s->tcnt);
qemu_put_be16s(f, &s->rcnt);
qemu_put_be32s(f, &s->rsar);
qemu_put_8s(f, &s->rsr);
qemu_put_8s(f, &s->isr);
qemu_put_8s(f, &s->dcfg);
qemu_put_8s(f, &s->imr);
qemu_put_buffer(f, s->phys, 6);
qemu_put_8s(f, &s->curpag);
qemu_put_buffer(f, s->mult, 8);
qemu_put_be32s(f, &s->irq);
qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
}
static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
{
NE2000State* s=(NE2000State*)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->cmd);
qemu_get_be32s(f, &s->start);
qemu_get_be32s(f, &s->stop);
qemu_get_8s(f, &s->boundary);
qemu_get_8s(f, &s->tsr);
qemu_get_8s(f, &s->tpsr);
qemu_get_be16s(f, &s->tcnt);
qemu_get_be16s(f, &s->rcnt);
qemu_get_be32s(f, &s->rsar);
qemu_get_8s(f, &s->rsr);
qemu_get_8s(f, &s->isr);
qemu_get_8s(f, &s->dcfg);
qemu_get_8s(f, &s->imr);
qemu_get_buffer(f, s->phys, 6);
qemu_get_8s(f, &s->curpag);
qemu_get_buffer(f, s->mult, 8);
qemu_get_be32s(f, &s->irq);
qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
return 0;
}
void isa_ne2000_init(int base, int irq, NetDriverState *nd)
{
NE2000State *s;
@@ -632,9 +562,6 @@ void isa_ne2000_init(int base, int irq, NetDriverState *nd)
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
}
/***********************************************************/
@@ -685,7 +612,7 @@ void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 1; // interrupt pin 0
pci_register_io_region(&d->dev, 0, 0x100,
pci_register_io_region((PCIDevice *)d, 0, 0x100,
PCI_ADDRESS_SPACE_IO, ne2000_map);
s = &d->ne2000;
s->irq = 16; // PCI interrupt
@@ -693,9 +620,4 @@ void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
s->nd = nd;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
/* XXX: instance number ? */
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
&d->dev);
}

View File

@@ -320,9 +320,8 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ)
}
}
void openpic_set_irq(void *opaque, int n_IRQ, int level)
void openpic_set_irq(openpic_t *opp, int n_IRQ, int level)
{
openpic_t *opp = opaque;
IRQ_src_t *src;
src = &opp->src[n_IRQ];
@@ -346,7 +345,7 @@ static void openpic_reset (openpic_t *opp)
int i;
opp->glbc = 0x80000000;
/* Initialise controller registers */
/* Initialise controler registers */
opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
opp->veni = VENI;
opp->spve = 0x000000FF;
@@ -630,7 +629,7 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
break;
case 0x10: /* TIBC */
if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
(val & 0x80000000) == 0 &&
(val & 0x800000000) == 0 &&
(opp->timers[idx].tibc & 0x80000000) != 0)
opp->timers[idx].ticc &= ~0x80000000;
opp->timers[idx].tibc = val;

View File

@@ -1,183 +0,0 @@
/*
* QEMU Parallel PORT emulation
*
* Copyright (c) 2003-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
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_PARALLEL
/*
* These are the definitions for the Printer Status Register
*/
#define PARA_STS_BUSY 0x80 /* Busy complement */
#define PARA_STS_ACK 0x40 /* Acknowledge */
#define PARA_STS_PAPER 0x20 /* Out of paper */
#define PARA_STS_ONLINE 0x10 /* Online */
#define PARA_STS_ERROR 0x08 /* Error complement */
/*
* These are the definitions for the Printer Control Register
*/
#define PARA_CTR_INTEN 0x10 /* IRQ Enable */
#define PARA_CTR_SELECT 0x08 /* Select In complement */
#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */
#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */
#define PARA_CTR_STROBE 0x01 /* Strobe complement */
struct ParallelState {
uint8_t data;
uint8_t status; /* read only register */
uint8_t control;
int irq;
int irq_pending;
CharDriverState *chr;
};
static void parallel_update_irq(ParallelState *s)
{
if (s->irq_pending)
pic_set_irq(s->irq, 1);
else
pic_set_irq(s->irq, 0);
}
static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
ParallelState *s = opaque;
addr &= 7;
#ifdef DEBUG_PARALLEL
printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
#endif
switch(addr) {
case 0:
s->data = val;
parallel_update_irq(s);
break;
case 2:
if ((val & PARA_CTR_INIT) == 0 ) {
s->status = PARA_STS_BUSY;
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_ONLINE;
s->status |= PARA_STS_ERROR;
}
else if (val & PARA_CTR_SELECT) {
if (val & PARA_CTR_STROBE) {
s->status &= ~PARA_STS_BUSY;
if ((s->control & PARA_CTR_STROBE) == 0)
qemu_chr_write(s->chr, &s->data, 1);
} else {
if (s->control & PARA_CTR_INTEN) {
s->irq_pending = 1;
}
}
}
parallel_update_irq(s);
s->control = val;
break;
}
}
static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
{
ParallelState *s = opaque;
uint32_t ret = 0xff;
addr &= 7;
switch(addr) {
case 0:
ret = s->data;
break;
case 1:
ret = s->status;
s->irq_pending = 0;
if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
/* XXX Fixme: wait 5 microseconds */
if (s->status & PARA_STS_ACK)
s->status &= ~PARA_STS_ACK;
else {
/* XXX Fixme: wait 5 microseconds */
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_BUSY;
}
}
parallel_update_irq(s);
break;
case 2:
ret = s->control;
break;
}
#ifdef DEBUG_PARALLEL
printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
#endif
return ret;
}
static int parallel_can_receive(ParallelState *s)
{
return 0;
}
static void parallel_receive_byte(ParallelState *s, int ch)
{
}
static int parallel_can_receive1(void *opaque)
{
ParallelState *s = opaque;
return parallel_can_receive(s);
}
static void parallel_receive1(void *opaque, const uint8_t *buf, int size)
{
ParallelState *s = opaque;
parallel_receive_byte(s, buf[0]);
}
static void parallel_event(void *opaque, int event)
{
}
/* If fd is zero, it means that the parallel device uses the console */
ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
{
ParallelState *s;
s = qemu_mallocz(sizeof(ParallelState));
if (!s)
return NULL;
s->irq = irq;
s->data = 0;
s->status = PARA_STS_BUSY;
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_ONLINE;
s->status |= PARA_STS_ERROR;
s->control = PARA_CTR_SELECT;
s->control |= PARA_CTR_INIT;
register_ioport_write(base, 8, 1, parallel_ioport_write, s);
register_ioport_read(base, 8, 1, parallel_ioport_read, s);
s->chr = chr;
qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s);
qemu_chr_add_event_handler(chr, parallel_event);
return s;
}

154
hw/pc.c
View File

@@ -41,7 +41,6 @@ int dummy_refresh_clock;
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
static IOAPICState *ioapic;
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
{
@@ -66,31 +65,6 @@ uint64_t cpu_get_tsc(CPUX86State *env)
return qemu_get_clock(vm_clock);
}
/* IRQ handling */
int cpu_get_pic_interrupt(CPUState *env)
{
int intno;
intno = apic_get_interrupt(env);
if (intno >= 0) {
/* set irq request if a PIC irq is still pending */
/* XXX: improve that */
pic_update_irq(isa_pic);
return intno;
}
/* read the irq from the PIC */
intno = pic_read_irq(isa_pic);
return intno;
}
static void pic_irq_request(void *opaque, int level)
{
if (level)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PC cmos mappings */
#define REG_EQUIPMENT_BYTE 0x14
@@ -127,32 +101,13 @@ static int cmos_get_fd_drive_type(int fd0)
return val;
}
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
{
RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
rtc_set_memory(s, type_ofs, 47);
rtc_set_memory(s, info_ofs, cylinders);
rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
rtc_set_memory(s, info_ofs + 2, heads);
rtc_set_memory(s, info_ofs + 3, 0xff);
rtc_set_memory(s, info_ofs + 4, 0xff);
rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
rtc_set_memory(s, info_ofs + 6, cylinders);
rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
rtc_set_memory(s, info_ofs + 8, sectors);
}
/* hd_table must contain 4 block drivers */
static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table)
static void cmos_init(int ram_size, int boot_device)
{
RTCState *s = rtc_state;
int val;
int fd0, fd1, nb;
time_t ti;
struct tm *tm;
int i;
/* set the CMOS date */
time(&ti);
@@ -232,43 +187,6 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
val |= 0x04; /* PS/2 mouse installed */
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
/* hard drives */
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
if (hd_table[0])
cmos_init_hd(0x19, 0x1b, hd_table[0]);
if (hd_table[1])
cmos_init_hd(0x1a, 0x24, hd_table[1]);
val = 0;
for (i = 0; i < 4; i++) {
if (hd_table[i]) {
int cylinders, heads, sectors, translation;
/* NOTE: bdrv_get_geometry_hint() returns the physical
geometry. It is always such that: 1 <= sects <= 63, 1
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
geometry can be different if a translation is done. */
translation = bdrv_get_translation_hint(hd_table[i]);
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
/* No translation. */
translation = 0;
} else {
/* LBA translation. */
translation = 1;
}
} else {
translation--;
}
val |= translation << (i * 2);
}
}
rtc_set_memory(s, 0x39, val);
/* Disable check of 0x55AA signature on the last two bytes of
first sector of disk. XXX: make it the default ? */
// rtc_set_memory(s, 0x38, 1);
}
static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -365,7 +283,7 @@ int load_kernel(const char *filename, uint8_t *addr,
int fd, size;
int setup_sects;
fd = open(filename, O_RDONLY | O_BINARY);
fd = open(filename, O_RDONLY);
if (fd < 0)
return -1;
@@ -396,27 +314,21 @@ static const int ide_irq[2] = { 14, 15 };
#define NE2000_NB_MAX 6
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
/* PC hardware initialisation */
static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
void pc_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot, initrd_size, i, nb_nics1;
int ret, linux_boot, initrd_size, i, nb_nics1, fd;
unsigned long bios_offset, vga_bios_offset;
int bios_size, isa_bios_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
@@ -546,7 +458,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
}
} else {
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
vga_ram_size);
}
rtc_state = rtc_init(0x70, 8);
@@ -556,27 +468,11 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
if (pci_enabled) {
apic_init(cpu_single_env);
ioapic = ioapic_init();
}
isa_pic = pic_init(pic_irq_request, cpu_single_env);
pic_init();
pit = pit_init(0x40, 0);
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
}
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
}
}
fd = serial_open_device();
serial_init(0x3f8, 4, fd);
if (pci_enabled) {
for(i = 0; i < nb_nics; i++) {
@@ -600,25 +496,17 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
kbd_init();
DMA_init(0);
#ifndef _WIN32
if (audio_enabled) {
/* no audio supported yet for win32 */
AUD_init();
#ifdef USE_SB16
if (sb16_enabled)
SB16_init ();
#endif
#ifdef CONFIG_ADLIB
if (adlib_enabled)
Adlib_init ();
#endif
#ifdef USE_GUS
if (gus_enabled)
GUS_init ();
#endif
SB16_init();
}
#endif
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
cmos_init(ram_size, boot_device, bs_table);
cmos_init(ram_size, boot_device);
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
@@ -626,9 +514,3 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
pci_bios_init();
}
}
QEMUMachine pc_machine = {
"pc",
"Standard PC",
pc_init1,
};

507
hw/pci.c
View File

@@ -45,9 +45,7 @@ struct PCIBus {
int devfn_min;
void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level);
uint32_t config_reg; /* XXX: suppress */
/* low level pic */
SetIRQFunc *low_set_irq;
void *irq_opaque;
openpic_t *openpic; /* XXX: suppress */
PCIDevice *devices[256];
};
@@ -64,24 +62,6 @@ static PCIBus *pci_register_bus(void)
return bus;
}
void generic_pci_save(QEMUFile* f, void *opaque)
{
PCIDevice* s=(PCIDevice*)opaque;
qemu_put_buffer(f, s->config, 256);
}
int generic_pci_load(QEMUFile* f, void *opaque, int version_id)
{
PCIDevice* s=(PCIDevice*)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->config, 256);
return 0;
}
/* -1 for devfn means auto assign */
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
int instance_size, int devfn,
@@ -496,31 +476,10 @@ PIIX3State *piix3_state;
static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
{
int slot_addend;
slot_addend = (pci_dev->devfn >> 3) - 1;
slot_addend = (pci_dev->devfn >> 3);
return (irq_num + slot_addend) & 3;
}
static inline int get_pci_irq_level(int irq_num)
{
int pic_level;
#if (PCI_IRQ_WORDS == 2)
pic_level = ((pci_irq_levels[irq_num][0] |
pci_irq_levels[irq_num][1]) != 0);
#else
{
int i;
pic_level = 0;
for(i = 0; i < PCI_IRQ_WORDS; i++) {
if (pci_irq_levels[irq_num][i]) {
pic_level = 1;
break;
}
}
}
#endif
return pic_level;
}
static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
{
int irq_index, shift, pic_irq, pic_level;
@@ -533,20 +492,26 @@ static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
*p = (*p & ~(1 << shift)) | (level << shift);
/* now we change the pic irq level according to the piix irq mappings */
/* XXX: optimize */
pic_irq = piix3_state->dev.config[0x60 + irq_num];
if (pic_irq < 16) {
/* the pic level is the logical OR of all the PCI irqs mapped
to it */
pic_level = 0;
if (pic_irq == piix3_state->dev.config[0x60])
pic_level |= get_pci_irq_level(0);
if (pic_irq == piix3_state->dev.config[0x61])
pic_level |= get_pci_irq_level(1);
if (pic_irq == piix3_state->dev.config[0x62])
pic_level |= get_pci_irq_level(2);
if (pic_irq == piix3_state->dev.config[0x63])
pic_level |= get_pci_irq_level(3);
#if (PCI_IRQ_WORDS == 2)
pic_level = ((pci_irq_levels[irq_num][0] |
pci_irq_levels[irq_num][1]) != 0);
#else
{
int i;
pic_level = 0;
for(i = 0; i < PCI_IRQ_WORDS; i++) {
if (pci_irq_levels[irq_num][i]) {
pic_level = 1;
break;
}
}
}
#endif
pic_set_irq(pic_irq, pic_level);
}
}
@@ -593,8 +558,6 @@ void piix3_init(PCIBus *bus)
d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State),
-1, NULL, NULL);
register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
piix3_state = d;
pci_conf = d->dev.config;
@@ -711,39 +674,29 @@ PCIBus *pci_prep_init(void)
s = pci_register_bus();
s->set_irq = prep_set_irq;
register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
PPC_PCIIO_write, s);
cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
/* PCI host bridge */
d = pci_register_device(s, "PREP Host Bridge - Motorola Raven",
sizeof(PCIDevice), 0, NULL, NULL);
d->config[0x00] = 0x57; // vendor_id : Motorola
d->config[0x01] = 0x10;
d->config[0x02] = 0x01; // device_id : Raven
d->config[0x03] = 0x48;
d->config[0x08] = 0x00; // revision
d->config[0x0A] = 0x00; // class_sub = pci host
d->config[0x0B] = 0x06; // class_base = PCI_bridge
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
d = pci_register_device(s, "PREP PCI Bridge", sizeof(PCIDevice), 0,
NULL, NULL);
/* XXX: put correct IDs */
d->config[0x00] = 0x11; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x26; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x04; // class_sub = pci2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x01; // header_type
return s;
}
/* pmac pci init */
#if 0
/* Grackle PCI host */
static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
@@ -848,93 +801,7 @@ static CPUReadMemoryFunc *pci_grackle_read[] = {
&pci_grackle_readw,
&pci_grackle_readl,
};
void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque)
{
bus->low_set_irq = set_irq;
bus->irq_opaque = irq_opaque;
}
/* XXX: we do not simulate the hardware - we rely on the BIOS to
set correctly for irq line field */
static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level)
{
PCIBus *s = d->bus;
s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level);
}
PCIBus *pci_grackle_init(uint32_t base)
{
PCIBus *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data;
s = pci_register_bus();
s->set_irq = pci_set_irq_simple;
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
pci_grackle_config_write, s);
pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
pci_grackle_write, s);
cpu_register_physical_memory(base, 0x1000, pci_mem_config);
cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice),
0, NULL, NULL);
d->config[0x00] = 0x57; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x02; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x01;
d->config[0x0a] = 0x00; // class_sub = host
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x00; // header_type
d->config[0x18] = 0x00; // primary_bus
d->config[0x19] = 0x01; // secondary_bus
d->config[0x1a] = 0x00; // subordinate_bus
d->config[0x1c] = 0x00;
d->config[0x1d] = 0x00;
d->config[0x20] = 0x00; // memory_base
d->config[0x21] = 0x00;
d->config[0x22] = 0x01; // memory_limit
d->config[0x23] = 0x00;
d->config[0x24] = 0x00; // prefetchable_memory_base
d->config[0x25] = 0x00;
d->config[0x26] = 0x00; // prefetchable_memory_limit
d->config[0x27] = 0x00;
#if 0
/* PCI2PCI bridge same values as PearPC - check this */
d->config[0x00] = 0x11; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x26; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x04; // class_sub = pci2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x01; // header_type
d->config[0x18] = 0x0; // primary_bus
d->config[0x19] = 0x1; // secondary_bus
d->config[0x1a] = 0x1; // subordinate_bus
d->config[0x1c] = 0x10; // io_base
d->config[0x1d] = 0x20; // io_limit
d->config[0x20] = 0x80; // memory_base
d->config[0x21] = 0x80;
d->config[0x22] = 0x90; // memory_limit
d->config[0x23] = 0x80;
d->config[0x24] = 0x00; // prefetchable_memory_base
d->config[0x25] = 0x84;
d->config[0x26] = 0x00; // prefetchable_memory_limit
d->config[0x27] = 0x85;
#endif
return s;
}
/* Uninorth PCI host (for all Mac99 and newer machines */
static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
@@ -1176,6 +1043,23 @@ static CPUReadMemoryFunc *pci_unin_read[] = {
};
#endif
static void pmac_set_irq(PCIDevice *d, int irq_num, int level)
{
openpic_t *openpic;
/* XXX: we do not simulate the hardware - we rely on the BIOS to
set correctly for irq line field */
openpic = d->bus->openpic;
#ifdef TARGET_PPC
if (openpic)
openpic_set_irq(openpic, d->config[PCI_INTERRUPT_LINE], level);
#endif
}
void pci_pmac_set_openpic(PCIBus *bus, openpic_t *openpic)
{
bus->openpic = openpic;
}
PCIBus *pci_pmac_init(void)
{
PCIBus *s;
@@ -1185,7 +1069,7 @@ PCIBus *pci_pmac_init(void)
/* Use values found on a real PowerMac */
/* Uninorth main bus */
s = pci_register_bus();
s->set_irq = pci_set_irq_simple;
s->set_irq = pmac_set_irq;
pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
pci_unin_main_config_write, s);
@@ -1288,253 +1172,34 @@ PCIBus *pci_pmac_init(void)
d->config[0x0E] = 0x00; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
#endif
return s;
}
/* Ultrasparc APB PCI host */
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
int i;
for (i = 11; i < 32; i++) {
if ((val & (1 << i)) != 0)
break;
}
s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
}
static uint32_t pci_apb_config_readl (void *opaque,
target_phys_addr_t addr)
{
PCIBus *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 void pci_apb_writeb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
pci_data_write(s, addr & 7, val, 1);
}
static void pci_apb_writew (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
pci_data_write(s, addr & 7, val, 2);
}
static void pci_apb_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
pci_data_write(s, addr & 7, val, 4);
}
static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
val = pci_data_read(s, addr & 7, 1);
return val;
}
static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
val = pci_data_read(s, addr & 7, 2);
return val;
}
static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
val = pci_data_read(s, addr, 4);
return val;
}
static CPUWriteMemoryFunc *pci_apb_write[] = {
&pci_apb_writeb,
&pci_apb_writew,
&pci_apb_writel,
};
static CPUReadMemoryFunc *pci_apb_read[] = {
&pci_apb_readb,
&pci_apb_readw,
&pci_apb_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,
};
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
{
PCIBus *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
/* Ultrasparc APB main bus */
s = pci_register_bus();
s->set_irq = pci_set_irq_simple;
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, "Advanced PCI Bus", sizeof(PCIDevice),
-1, NULL, NULL);
d->config[0x00] = 0x8e; // vendor_id : Sun
#if 0 // Grackle ?
/* same values as PearPC - check this */
d->config[0x00] = 0x11; // vendor_id
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
d->config[0x02] = 0x26; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x04; // class_sub = pci2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x01; // header_type
d->config[0x18] = 0x0; // primary_bus
d->config[0x19] = 0x1; // secondary_bus
d->config[0x1a] = 0x1; // subordinate_bus
d->config[0x1c] = 0x10; // io_base
d->config[0x1d] = 0x20; // io_limit
d->config[0x20] = 0x80; // memory_base
d->config[0x21] = 0x80;
d->config[0x22] = 0x90; // memory_limit
d->config[0x23] = 0x80;
d->config[0x24] = 0x00; // prefetchable_memory_base
d->config[0x25] = 0x84;
d->config[0x26] = 0x00; // prefetchable_memory_limit
d->config[0x27] = 0x85;
#endif
return s;
}
@@ -1556,40 +1221,40 @@ static void pci_info_device(PCIDevice *d)
int i, class;
PCIIORegion *r;
term_printf(" Bus %2d, device %3d, function %d:\n",
printf(" Bus %2d, device %3d, function %d:\n",
d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE)));
term_printf(" ");
printf(" ");
switch(class) {
case 0x0101:
term_printf("IDE controller");
printf("IDE controller");
break;
case 0x0200:
term_printf("Ethernet controller");
printf("Ethernet controller");
break;
case 0x0300:
term_printf("VGA controller");
printf("VGA controller");
break;
default:
term_printf("Class %04x", class);
printf("Class %04x", class);
break;
}
term_printf(": PCI device %04x:%04x\n",
printf(": PCI device %04x:%04x\n",
le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))),
le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID))));
if (d->config[PCI_INTERRUPT_PIN] != 0) {
term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
}
for(i = 0;i < PCI_NUM_REGIONS; i++) {
r = &d->io_regions[i];
if (r->size != 0) {
term_printf(" BAR%d: ", i);
printf(" BAR%d: ", i);
if (r->type & PCI_ADDRESS_SPACE_IO) {
term_printf("I/O at 0x%04x [0x%04x].\n",
printf("I/O at 0x%04x [0x%04x].\n",
r->addr, r->addr + r->size - 1);
} else {
term_printf("32 bit memory at 0x%08x [0x%08x].\n",
printf("32 bit memory at 0x%08x [0x%08x].\n",
r->addr, r->addr + r->size - 1);
}
}

View File

@@ -539,7 +539,6 @@ static void kbd_write_mouse(KBDState *s, int val)
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
s->mouse_type = 0;
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, 0xaa, 1);
kbd_queue(s, s->mouse_type, 1);
@@ -550,6 +549,7 @@ static void kbd_write_mouse(KBDState *s, int val)
break;
case AUX_SET_SAMPLE:
s->mouse_sample_rate = val;
#if 0
/* detect IMPS/2 or IMEX */
switch(s->mouse_detect_state) {
default:
@@ -576,6 +576,7 @@ static void kbd_write_mouse(KBDState *s, int val)
s->mouse_detect_state = 0;
break;
}
#endif
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;

View File

@@ -107,16 +107,13 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint32_t decr;
int64_t diff;
diff = tb_env->decr_next - qemu_get_clock(vm_clock);
if (diff >= 0)
decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
else
decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
tb_env->tb_freq, ticks_per_sec);
#if defined(DEBUG_TB)
printf("%s: 0x%08x\n", __func__, decr);
#endif
return decr;
}
@@ -443,4 +440,23 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}
/*****************************************************************************/
void ppc_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
if (prep_enabled) {
ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
} else {
ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
}
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}

View File

@@ -24,22 +24,19 @@
#include "vl.h"
#define BIOS_FILENAME "ppc_rom.bin"
#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
NVRAM */
NVRAM (not implemented). */
static int dbdma_mem_index;
static int cuda_mem_index;
static int ide0_mem_index = -1;
static int ide1_mem_index = -1;
static int openpic_mem_index = -1;
static int heathrow_pic_mem_index = -1;
static int macio_nvram_mem_index = -1;
static int ide0_mem_index;
static int ide1_mem_index;
static int openpic_mem_index;
/* DBDMA: currently no op - should suffice right now */
@@ -84,75 +81,17 @@ static CPUReadMemoryFunc *dbdma_read[] = {
&dbdma_readl,
};
/* macio style NVRAM device */
typedef struct MacIONVRAMState {
uint8_t data[0x2000];
} MacIONVRAMState;
static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
MacIONVRAMState *s = opaque;
addr = (addr >> 4) & 0x1fff;
s->data[addr] = value;
// printf("macio_nvram_writeb %04x = %02x\n", addr, value);
}
static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
{
MacIONVRAMState *s = opaque;
uint32_t value;
addr = (addr >> 4) & 0x1fff;
value = s->data[addr];
// printf("macio_nvram_readb %04x = %02x\n", addr, value);
return value;
}
static CPUWriteMemoryFunc *macio_nvram_write[] = {
&macio_nvram_writeb,
&macio_nvram_writeb,
&macio_nvram_writeb,
};
static CPUReadMemoryFunc *macio_nvram_read[] = {
&macio_nvram_readb,
&macio_nvram_readb,
&macio_nvram_readb,
};
static MacIONVRAMState *macio_nvram_init(void)
{
MacIONVRAMState *s;
s = qemu_mallocz(sizeof(MacIONVRAMState));
if (!s)
return NULL;
macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
macio_nvram_write, s);
return s;
}
static void macio_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
if (heathrow_pic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x00000, 0x1000,
heathrow_pic_mem_index);
}
cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
if (ide0_mem_index >= 0)
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
if (ide1_mem_index >= 0)
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
if (openpic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x40000, 0x40000,
openpic_mem_index);
}
if (macio_nvram_mem_index >= 0)
cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index);
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index);
}
static void macio_init(PCIBus *bus, int device_id)
static void macio_init(PCIBus *bus)
{
PCIDevice *d;
@@ -162,8 +101,8 @@ static void macio_init(PCIBus *bus, int device_id)
in PearPC */
d->config[0x00] = 0x6b; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = device_id;
d->config[0x03] = device_id >> 8;
d->config[0x02] = 0x22;
d->config[0x03] = 0x00;
d->config[0x0a] = 0x00; // class_sub = pci2pci
d->config[0x0b] = 0xff; // class_base = bridge
@@ -177,141 +116,20 @@ static void macio_init(PCIBus *bus, int device_id)
PCI_ADDRESS_SPACE_MEM, macio_map);
}
/* UniN device */
static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *unin_write[] = {
&unin_writel,
&unin_writel,
&unin_writel,
};
static CPUReadMemoryFunc *unin_read[] = {
&unin_readl,
&unin_readl,
&unin_readl,
};
/* temporary frame buffer OSI calls for the video.x driver. The right
solution is to modify the driver to use VGA PCI I/Os */
static int vga_osi_call(CPUState *env)
{
static int vga_vbl_enabled;
int linesize;
// printf("osi_call R5=%d\n", env->gpr[5]);
/* same handler as PearPC, coming from the original MOL video
driver. */
switch(env->gpr[5]) {
case 4:
break;
case 28: /* set_vmode */
if (env->gpr[6] != 1 || env->gpr[7] != 0)
env->gpr[3] = 1;
else
env->gpr[3] = 0;
break;
case 29: /* get_vmode_info */
if (env->gpr[6] != 0) {
if (env->gpr[6] != 1 || env->gpr[7] != 0) {
env->gpr[3] = 1;
break;
}
}
env->gpr[3] = 0;
env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
env->gpr[7] = 85 << 16; /* refresh rate */
env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
linesize = ((graphic_depth + 7) >> 3) * graphic_width;
linesize = (linesize + 3) & ~3;
env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
break;
case 31: /* set_video power */
env->gpr[3] = 0;
break;
case 39: /* video_ctrl */
if (env->gpr[6] == 0 || env->gpr[6] == 1)
vga_vbl_enabled = env->gpr[6];
env->gpr[3] = 0;
break;
case 47:
break;
case 59: /* set_color */
/* R6 = index, R7 = RGB */
env->gpr[3] = 0;
break;
case 64: /* get color */
/* R6 = index */
env->gpr[3] = 0;
break;
case 116: /* set hwcursor */
/* R6 = x, R7 = y, R8 = visible, R9 = data */
break;
default:
fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]);
break;
}
return 1; /* osi_call handled */
}
/* XXX: suppress that */
static void pic_irq_request(void *opaque, int level)
{
}
static uint8_t nvram_chksum(const uint8_t *buf, int n)
{
int sum, i;
sum = 0;
for(i = 0; i < n; i++)
sum += buf[i];
return (sum & 0xff) + (sum >> 8);
}
/* set a free Mac OS NVRAM partition */
void pmac_format_nvram_partition(uint8_t *buf, int len)
{
char partition_name[12] = "wwwwwwwwwwww";
buf[0] = 0x7f; /* free partition magic */
buf[1] = 0; /* checksum */
buf[2] = len >> 8;
buf[3] = len;
memcpy(buf + 4, partition_name, 12);
buf[1] = nvram_chksum(buf, 16);
}
/* PowerPC CHRP hardware initialisation */
static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
int is_heathrow)
/* PowerPC PREP hardware initialisation */
void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
SetIRQFunc *set_irq;
void *pic;
openpic_t *openpic;
m48t59_t *nvram;
int PPC_io_memory, unin_memory;
int linux_boot, i;
unsigned long bios_offset, vga_bios_offset;
int PPC_io_memory;
int ret, linux_boot, i, fd;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
const char *arch_name;
int vga_bios_size, bios_size;
linux_boot = (kernel_filename != NULL);
@@ -321,36 +139,15 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
/* allocate and load VGA BIOS */
vga_bios_offset = bios_offset + bios_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
if (vga_bios_size < 0) {
/* if no bios is present, we can still work */
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
vga_bios_size = 0;
} else {
/* set a specific header (XXX: find real Apple format for NDRV
drivers) */
phys_ram_base[vga_bios_offset] = 'N';
phys_ram_base[vga_bios_offset + 1] = 'D';
phys_ram_base[vga_bios_offset + 2] = 'R';
phys_ram_base[vga_bios_offset + 3] = 'V';
cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
vga_bios_size);
vga_bios_size += 8;
}
vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_single_env->nip = 0xfffffffc;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
@@ -382,129 +179,51 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
initrd_size = 0;
}
/* Register CPU as a 74x/75x */
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def); // Linux boot OK
// ppc_find_by_name("750fx", &def); // Linux boot OK
/* Linux does not boot on 750cxe (and probably other 750cx based)
* because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
*/
// ppc_find_by_name("750cxe", &def);
// ppc_find_by_name("750p", &def);
// ppc_find_by_name("740p", &def);
ppc_find_by_name("750", &def);
// ppc_find_by_name("740", &def);
// ppc_find_by_name("G3", &def);
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
// ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
cpu_ppc_register(cpu_single_env, 0x00080000);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
cpu_single_env->osi_call = vga_osi_call;
isa_mem_base = 0x80000000;
pci_bus = pci_pmac_init();
if (is_heathrow) {
isa_mem_base = 0x80000000;
pci_bus = pci_grackle_init(0xfec00000);
/* Register 2 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
pic = heathrow_pic_init(&heathrow_pic_mem_index);
set_irq = heathrow_pic_set_irq;
pci_set_pic(pci_bus, set_irq, pic);
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
openpic = openpic_init(NULL, &openpic_mem_index, 1);
pci_pmac_set_openpic(pci_bus, openpic);
/* XXX: suppress that */
pic_init();
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(set_irq, pic, 0x12);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
{
MacIONVRAMState *nvr;
nvr = macio_nvram_init();
pmac_format_nvram_partition(nvr->data, 0x2000);
}
/* XXX: use Mac Serial port */
fd = serial_open_device();
serial_init(0x3f8, 4, fd);
macio_init(pci_bus, 0x0017);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
pci_bus = pci_pmac_init();
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
/* UniN init */
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
pic = openpic_init(NULL, &openpic_mem_index, 1);
set_irq = openpic_set_irq;
pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
#if 1
ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
#else
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
#endif
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(set_irq, pic, 0x19);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus, 0x0022);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
arch_name = "MAC99";
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13);
ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x13);
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(openpic, 0x19);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "CHRP", ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
@@ -512,45 +231,4 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
0,
graphic_width, graphic_height, graphic_depth);
/* No PCI init: the BIOS will do it */
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 0);
}
static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 1);
}
QEMUMachine core99_machine = {
"mac99",
"Mac99 based PowerMAC",
ppc_core99_init,
};
QEMUMachine heathrow_machine = {
"g3bw",
"Heathrow based PowerMAC",
ppc_heathrow_init,
};

View File

@@ -96,14 +96,6 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
return 0;
}
static void pic_irq_request(void *opaque, int level)
{
if (level)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PCI intack register */
/* Read-only register (?) */
static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -116,7 +108,7 @@ static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
uint32_t retval = 0;
if (addr == 0xBFFFFFF0)
retval = pic_intack_read(isa_pic);
retval = pic_intack_read(NULL);
// printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
return retval;
@@ -257,8 +249,6 @@ typedef struct sysctrl_t {
uint8_t state;
uint8_t syscontrol;
uint8_t fake_io[2];
int contiguous_map;
int endian;
} sysctrl_t;
enum {
@@ -298,9 +288,8 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
}
/* Check LE mode */
if (val & 0x02) {
sysctrl->endian = 1;
} else {
sysctrl->endian = 0;
printf("Little Endian mode isn't supported (yet ?)\n");
abort();
}
break;
case 0x0800:
@@ -339,7 +328,10 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
break;
case 0x0850:
/* I/O map type register */
sysctrl->contiguous_map = val & 0x01;
if (!(val & 0x01)) {
printf("No support for non-continuous I/O map mode\n");
abort();
}
break;
default:
printf("ERROR: unaffected IO port write: %04lx => %02x\n",
@@ -383,9 +375,6 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
/* Motorola base module extended feature register */
retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
break;
case 0x0814:
/* L2 invalidate: don't care */
break;
case 0x0818:
/* Keylock */
retval = 0x00;
@@ -402,7 +391,7 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
break;
case 0x0850:
/* I/O map type register */
retval = sysctrl->contiguous_map;
retval = 0x01;
break;
default:
printf("ERROR: unaffected IO port: %04lx read\n", (long)addr);
@@ -413,123 +402,22 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
return retval;
}
static inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl,
target_phys_addr_t addr)
{
if (sysctrl->contiguous_map == 0) {
/* 64 KB contiguous space for IOs */
addr &= 0xFFFF;
} else {
/* 8 MB non-contiguous space for IOs */
addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
}
return addr;
}
static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
sysctrl_t *sysctrl = opaque;
addr = prep_IO_address(sysctrl, addr);
cpu_outb(NULL, addr, value);
}
static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t ret;
addr = prep_IO_address(sysctrl, addr);
ret = cpu_inb(NULL, addr);
return ret;
}
static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
sysctrl_t *sysctrl = opaque;
addr = prep_IO_address(sysctrl, addr);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value);
cpu_outw(NULL, addr, value);
}
static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t ret;
addr = prep_IO_address(sysctrl, addr);
ret = cpu_inw(NULL, addr);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret);
return ret;
}
static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
sysctrl_t *sysctrl = opaque;
addr = prep_IO_address(sysctrl, addr);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value);
cpu_outl(NULL, addr, value);
}
static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
{
sysctrl_t *sysctrl = opaque;
uint32_t ret;
addr = prep_IO_address(sysctrl, addr);
ret = cpu_inl(NULL, addr);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret);
return ret;
}
CPUWriteMemoryFunc *PPC_prep_io_write[] = {
&PPC_prep_io_writeb,
&PPC_prep_io_writew,
&PPC_prep_io_writel,
};
CPUReadMemoryFunc *PPC_prep_io_read[] = {
&PPC_prep_io_readb,
&PPC_prep_io_readw,
&PPC_prep_io_readl,
};
extern CPUPPCState *global_env;
#define NVRAM_SIZE 0x2000
/* PowerPC PREP hardware initialisation */
static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
m48t59_t *nvram;
int PPC_io_memory;
int linux_boot, i, nb_nics1, bios_size;
int ret, linux_boot, i, nb_nics1, fd;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
@@ -544,14 +432,14 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_single_env->nip = 0xfffffffc;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
@@ -584,35 +472,28 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
initrd_size = 0;
}
/* Register CPU as a 604 */
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Register CPU as a 74x/75x */
cpu_ppc_register(cpu_single_env, 0x00080000);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
isa_mem_base = 0xc0000000;
pci_bus = pci_prep_init();
// pci_bus = i440fx_init();
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read,
PPC_prep_io_write, sysctrl);
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
/* Register 64 KB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
vga_ram_size);
rtc_init(0x70, 8);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
isa_pic = pic_init(pic_irq_request, cpu_single_env);
// pic_init(openpic);
pic_init();
// pit = pit_init(0x40, 0);
serial_init(0x3f8, 4, serial_hds[0]);
fd = serial_open_device();
serial_init(0x3f8, 4, fd);
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
@@ -665,13 +546,4 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
QEMUMachine prep_machine = {
"prep",
"PowerPC PREP platform",
ppc_prep_init,
};

1322
hw/sb16.c

File diff suppressed because it is too large Load Diff

View File

@@ -84,7 +84,7 @@ struct SerialState {
it can be reset while reading iir */
int thr_ipending;
int irq;
CharDriverState *chr;
int out_fd;
};
static void serial_update_irq(SerialState *s)
@@ -107,6 +107,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
SerialState *s = opaque;
unsigned char ch;
int ret;
addr &= 7;
#ifdef DEBUG_SERIAL
@@ -121,8 +122,13 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->thr_ipending = 0;
s->lsr &= ~UART_LSR_THRE;
serial_update_irq(s);
ch = val;
qemu_chr_write(s->chr, &ch, 1);
if (s->out_fd >= 0) {
ch = val;
do {
ret = write(s->out_fd, &ch, 1);
} while (ret != 1);
}
s->thr_ipending = 1;
s->lsr |= UART_LSR_THRE;
s->lsr |= UART_LSR_TEMT;
@@ -133,10 +139,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->lcr & UART_LCR_DLAB) {
s->divider = (s->divider & 0x00ff) | (val << 8);
} else {
s->ier = val & 0x0f;
if (s->lsr & UART_LSR_THRE) {
s->thr_ipending = 1;
}
s->ier = val;
serial_update_irq(s);
}
break;
@@ -146,7 +149,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->lcr = val;
break;
case 4:
s->mcr = val & 0x1f;
s->mcr = val;
break;
case 5:
break;
@@ -220,19 +223,19 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
return ret;
}
static int serial_can_receive(SerialState *s)
int serial_can_receive(SerialState *s)
{
return !(s->lsr & UART_LSR_DR);
}
static void serial_receive_byte(SerialState *s, int ch)
void serial_receive_byte(SerialState *s, int ch)
{
s->rbr = ch;
s->lsr |= UART_LSR_DR;
serial_update_irq(s);
}
static void serial_receive_break(SerialState *s)
void serial_receive_break(SerialState *s)
{
s->rbr = 0;
s->lsr |= UART_LSR_BI | UART_LSR_DR;
@@ -251,15 +254,8 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
serial_receive_byte(s, buf[0]);
}
static void serial_event(void *opaque, int event)
{
SerialState *s = opaque;
if (event == CHR_EVENT_BREAK)
serial_receive_break(s);
}
/* If fd is zero, it means that the serial device uses the console */
SerialState *serial_init(int base, int irq, CharDriverState *chr)
SerialState *serial_init(int base, int irq, int fd)
{
SerialState *s;
@@ -272,8 +268,16 @@ SerialState *serial_init(int base, int irq, CharDriverState *chr)
register_ioport_write(base, 8, 1, serial_ioport_write, s);
register_ioport_read(base, 8, 1, serial_ioport_read, s);
s->chr = chr;
qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
qemu_chr_add_event_handler(chr, serial_event);
if (fd < 0) {
/* no associated device */
s->out_fd = -1;
} else if (fd != 0) {
qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s);
s->out_fd = fd;
} else {
serial_console = s;
s->out_fd = 1;
}
return s;
}

View File

@@ -1,335 +0,0 @@
/*
* QEMU Sparc SLAVIO interrupt controller emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_IRQ_COUNT
//#define DEBUG_IRQ
#ifdef DEBUG_IRQ
#define DPRINTF(fmt, args...) \
do { printf("IRQ: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
/*
* Registers of interrupt controller in sun4m.
*
* This is the interrupt controller part of chip STP2001 (Slave I/O), also
* produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
*
* There is a system master controller and one for each cpu.
*
*/
#define MAX_CPUS 16
typedef struct SLAVIO_INTCTLState {
uint32_t intreg_pending[MAX_CPUS];
uint32_t intregm_pending;
uint32_t intregm_disabled;
uint32_t target_cpu;
#ifdef DEBUG_IRQ_COUNT
uint64_t irq_count[32];
#endif
} SLAVIO_INTCTLState;
#define INTCTL_MAXADDR 0xf
#define INTCTLM_MAXADDR 0xf
static void slavio_check_interrupts(void *opaque);
// per-cpu interrupt controller
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
{
SLAVIO_INTCTLState *s = opaque;
uint32_t saddr;
int cpu;
cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
saddr = (addr & INTCTL_MAXADDR) >> 2;
switch (saddr) {
case 0:
return s->intreg_pending[cpu];
default:
break;
}
return 0;
}
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
SLAVIO_INTCTLState *s = opaque;
uint32_t saddr;
int cpu;
cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
saddr = (addr & INTCTL_MAXADDR) >> 2;
switch (saddr) {
case 1: // clear pending softints
if (val & 0x4000)
val |= 80000000;
val &= 0xfffe0000;
s->intreg_pending[cpu] &= ~val;
DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
break;
case 2: // set softint
val &= 0xfffe0000;
s->intreg_pending[cpu] |= val;
DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
break;
default:
break;
}
}
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
slavio_intctl_mem_readl,
slavio_intctl_mem_readl,
slavio_intctl_mem_readl,
};
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
slavio_intctl_mem_writel,
slavio_intctl_mem_writel,
slavio_intctl_mem_writel,
};
// master system interrupt controller
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
{
SLAVIO_INTCTLState *s = opaque;
uint32_t saddr;
saddr = (addr & INTCTLM_MAXADDR) >> 2;
switch (saddr) {
case 0:
return s->intregm_pending & 0x7fffffff;
case 1:
return s->intregm_disabled;
case 4:
return s->target_cpu;
default:
break;
}
return 0;
}
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
SLAVIO_INTCTLState *s = opaque;
uint32_t saddr;
saddr = (addr & INTCTLM_MAXADDR) >> 2;
switch (saddr) {
case 2: // clear (enable)
// Force clear unused bits
val &= ~0x4fb2007f;
s->intregm_disabled &= ~val;
DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
slavio_check_interrupts(s);
break;
case 3: // set (disable, clear pending)
// Force clear unused bits
val &= ~0x4fb2007f;
s->intregm_disabled |= val;
s->intregm_pending &= ~val;
DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
break;
case 4:
s->target_cpu = val & (MAX_CPUS - 1);
DPRINTF("Set master irq cpu %d\n", s->target_cpu);
break;
default:
break;
}
}
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
slavio_intctlm_mem_readl,
slavio_intctlm_mem_readl,
slavio_intctlm_mem_readl,
};
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
slavio_intctlm_mem_writel,
slavio_intctlm_mem_writel,
slavio_intctlm_mem_writel,
};
void slavio_pic_info(void *opaque)
{
SLAVIO_INTCTLState *s = opaque;
int i;
for (i = 0; i < MAX_CPUS; i++) {
term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
}
term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
}
void slavio_irq_info(void *opaque)
{
#ifndef DEBUG_IRQ_COUNT
term_printf("irq statistic code not compiled.\n");
#else
SLAVIO_INTCTLState *s = opaque;
int i;
int64_t count;
term_printf("IRQ statistics:\n");
for (i = 0; i < 32; i++) {
count = s->irq_count[i];
if (count > 0)
term_printf("%2d: %lld\n", i, count);
}
#endif
}
static const uint32_t intbit_to_level[32] = {
2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
};
static void slavio_check_interrupts(void *opaque)
{
SLAVIO_INTCTLState *s = opaque;
uint32_t pending = s->intregm_pending;
unsigned int i, max = 0;
pending &= ~s->intregm_disabled;
if (pending && !(s->intregm_disabled & 0x80000000)) {
for (i = 0; i < 32; i++) {
if (pending & (1 << i)) {
if (max < intbit_to_level[i])
max = intbit_to_level[i];
}
}
if (cpu_single_env->interrupt_index == 0) {
DPRINTF("Triggered pil %d\n", max);
#ifdef DEBUG_IRQ_COUNT
s->irq_count[max]++;
#endif
cpu_single_env->interrupt_index = TT_EXTINT | max;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
else
DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, cpu_single_env->interrupt_index);
}
else
DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
}
/*
* "irq" here is the bit number in the system interrupt register to
* separate serial and keyboard interrupts sharing a level.
*/
void slavio_pic_set_irq(void *opaque, int irq, int level)
{
SLAVIO_INTCTLState *s = opaque;
DPRINTF("Set irq %d level %d\n", irq, level);
if (irq < 32) {
uint32_t mask = 1 << irq;
uint32_t pil = intbit_to_level[irq];
if (pil > 0) {
if (level) {
s->intregm_pending |= mask;
s->intreg_pending[s->target_cpu] |= 1 << pil;
}
else {
s->intregm_pending &= ~mask;
s->intreg_pending[s->target_cpu] &= ~(1 << pil);
}
}
}
slavio_check_interrupts(s);
}
static void slavio_intctl_save(QEMUFile *f, void *opaque)
{
SLAVIO_INTCTLState *s = opaque;
int i;
for (i = 0; i < MAX_CPUS; i++) {
qemu_put_be32s(f, &s->intreg_pending[i]);
}
qemu_put_be32s(f, &s->intregm_pending);
qemu_put_be32s(f, &s->intregm_disabled);
qemu_put_be32s(f, &s->target_cpu);
}
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
{
SLAVIO_INTCTLState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
for (i = 0; i < MAX_CPUS; i++) {
qemu_get_be32s(f, &s->intreg_pending[i]);
}
qemu_get_be32s(f, &s->intregm_pending);
qemu_get_be32s(f, &s->intregm_disabled);
qemu_get_be32s(f, &s->target_cpu);
return 0;
}
static void slavio_intctl_reset(void *opaque)
{
SLAVIO_INTCTLState *s = opaque;
int i;
for (i = 0; i < MAX_CPUS; i++) {
s->intreg_pending[i] = 0;
}
s->intregm_disabled = ~0xffb2007f;
s->intregm_pending = 0;
s->target_cpu = 0;
}
void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
{
int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
SLAVIO_INTCTLState *s;
s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
if (!s)
return NULL;
for (i = 0; i < MAX_CPUS; i++) {
slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
}
slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
qemu_register_reset(slavio_intctl_reset, s);
slavio_intctl_reset(s);
return s;
}

View File

@@ -1,240 +0,0 @@
/*
* QEMU Sparc SLAVIO aux io port emulation
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug misc */
//#define DEBUG_MISC
/*
* This is the auxio port, chip control and system control part of
* chip STP2001 (Slave I/O), also produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
*
* This also includes the PMC CPU idle controller.
*/
#ifdef DEBUG_MISC
#define MISC_DPRINTF(fmt, args...) \
do { printf("MISC: " fmt , ##args); } while (0)
#else
#define MISC_DPRINTF(fmt, args...)
#endif
typedef struct MiscState {
int irq;
uint8_t config;
uint8_t aux1, aux2;
uint8_t diag, mctrl;
} MiscState;
#define MISC_MAXADDR 1
static void slavio_misc_update_irq(void *opaque)
{
MiscState *s = opaque;
if ((s->aux2 & 0x4) && (s->config & 0x8)) {
pic_set_irq(s->irq, 1);
} else {
pic_set_irq(s->irq, 0);
}
}
static void slavio_misc_reset(void *opaque)
{
MiscState *s = opaque;
// Diagnostic register not cleared in reset
s->config = s->aux1 = s->aux2 = s->mctrl = 0;
}
void slavio_set_power_fail(void *opaque, int power_failing)
{
MiscState *s = opaque;
MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
if (power_failing && (s->config & 0x8)) {
s->aux2 |= 0x4;
} else {
s->aux2 &= ~0x4;
}
slavio_misc_update_irq(s);
}
static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
MiscState *s = opaque;
switch (addr & 0xfff0000) {
case 0x1800000:
MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
s->config = val & 0xff;
slavio_misc_update_irq(s);
break;
case 0x1900000:
MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
s->aux1 = val & 0xff;
break;
case 0x1910000:
val &= 0x3;
MISC_DPRINTF("Write aux2 %2.2x\n", val);
val |= s->aux2 & 0x4;
if (val & 0x2) // Clear Power Fail int
val &= 0x1;
s->aux2 = val;
if (val & 1)
qemu_system_shutdown_request();
slavio_misc_update_irq(s);
break;
case 0x1a00000:
MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
s->diag = val & 0xff;
break;
case 0x1b00000:
MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
s->mctrl = val & 0xff;
break;
case 0x1f00000:
MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
if (val & 1)
qemu_system_reset_request();
break;
case 0xa000000:
MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
#if 0
// XXX: halting CPU does not work
raise_exception(EXCP_HLT);
cpu_loop_exit();
#endif
break;
}
}
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
{
MiscState *s = opaque;
uint32_t ret = 0;
switch (addr & 0xfff0000) {
case 0x1800000:
ret = s->config;
MISC_DPRINTF("Read config %2.2x\n", ret);
break;
case 0x1900000:
ret = s->aux1;
MISC_DPRINTF("Read aux1 %2.2x\n", ret);
break;
case 0x1910000:
ret = s->aux2;
MISC_DPRINTF("Read aux2 %2.2x\n", ret);
break;
case 0x1a00000:
ret = s->diag;
MISC_DPRINTF("Read diag %2.2x\n", ret);
break;
case 0x1b00000:
ret = s->mctrl;
MISC_DPRINTF("Read modem control %2.2x\n", ret);
break;
case 0x1f00000:
MISC_DPRINTF("Read system control %2.2x\n", ret);
break;
case 0xa000000:
MISC_DPRINTF("Read power management %2.2x\n", ret);
break;
}
return ret;
}
static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
slavio_misc_mem_readb,
slavio_misc_mem_readb,
slavio_misc_mem_readb,
};
static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
slavio_misc_mem_writeb,
slavio_misc_mem_writeb,
slavio_misc_mem_writeb,
};
static void slavio_misc_save(QEMUFile *f, void *opaque)
{
MiscState *s = opaque;
qemu_put_be32s(f, &s->irq);
qemu_put_8s(f, &s->config);
qemu_put_8s(f, &s->aux1);
qemu_put_8s(f, &s->aux2);
qemu_put_8s(f, &s->diag);
qemu_put_8s(f, &s->mctrl);
}
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
{
MiscState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->irq);
qemu_get_8s(f, &s->config);
qemu_get_8s(f, &s->aux1);
qemu_get_8s(f, &s->aux2);
qemu_get_8s(f, &s->diag);
qemu_get_8s(f, &s->mctrl);
return 0;
}
void *slavio_misc_init(uint32_t base, int irq)
{
int slavio_misc_io_memory;
MiscState *s;
s = qemu_mallocz(sizeof(MiscState));
if (!s)
return NULL;
slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
// Slavio control
cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
// AUX 1
cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
// AUX 2
cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
// Diagnostics
cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
// Modem control
cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
// System control
cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
// Power management
cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
s->irq = irq;
register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
qemu_register_reset(slavio_misc_reset, s);
slavio_misc_reset(s);
return s;
}

View File

@@ -1,505 +0,0 @@
/*
* QEMU Sparc SLAVIO serial port emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug serial */
//#define DEBUG_SERIAL
/* debug keyboard */
//#define DEBUG_KBD
/* debug mouse */
//#define DEBUG_MOUSE
/*
* This is the serial port, mouse and keyboard part of chip STP2001
* (Slave I/O), also produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
*
* The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
* mouse and keyboard ports don't implement all functions and they are
* only asynchronous. There is no DMA.
*
*/
#ifdef DEBUG_SERIAL
#define SER_DPRINTF(fmt, args...) \
do { printf("SER: " fmt , ##args); } while (0)
#else
#define SER_DPRINTF(fmt, args...)
#endif
#ifdef DEBUG_KBD
#define KBD_DPRINTF(fmt, args...) \
do { printf("KBD: " fmt , ##args); } while (0)
#else
#define KBD_DPRINTF(fmt, args...)
#endif
#ifdef DEBUG_MOUSE
#define MS_DPRINTF(fmt, args...) \
do { printf("SER: " fmt , ##args); } while (0)
#else
#define MS_DPRINTF(fmt, args...)
#endif
typedef enum {
chn_a, chn_b,
} chn_id_t;
typedef enum {
ser, kbd, mouse,
} chn_type_t;
#define KBD_QUEUE_SIZE 256
typedef struct {
uint8_t data[KBD_QUEUE_SIZE];
int rptr, wptr, count;
} KBDQueue;
typedef struct ChannelState {
int irq;
int reg;
int rxint, txint;
chn_id_t chn; // this channel, A (base+4) or B (base+0)
chn_type_t type;
struct ChannelState *otherchn;
uint8_t rx, tx, wregs[16], rregs[16];
KBDQueue queue;
CharDriverState *chr;
} ChannelState;
struct SerialState {
struct ChannelState chn[2];
};
#define SERIAL_MAXADDR 7
static void handle_kbd_command(ChannelState *s, int val);
static int serial_can_receive(void *opaque);
static void serial_receive_byte(ChannelState *s, int ch);
static void put_queue(void *opaque, int b)
{
ChannelState *s = opaque;
KBDQueue *q = &s->queue;
KBD_DPRINTF("put: 0x%02x\n", b);
if (q->count >= KBD_QUEUE_SIZE)
return;
q->data[q->wptr] = b;
if (++q->wptr == KBD_QUEUE_SIZE)
q->wptr = 0;
q->count++;
serial_receive_byte(s, 0);
}
static uint32_t get_queue(void *opaque)
{
ChannelState *s = opaque;
KBDQueue *q = &s->queue;
int val;
if (q->count == 0) {
return 0;
} else {
val = q->data[q->rptr];
if (++q->rptr == KBD_QUEUE_SIZE)
q->rptr = 0;
q->count--;
}
KBD_DPRINTF("get 0x%02x\n", val);
if (q->count > 0)
serial_receive_byte(s, 0);
return val;
}
static void slavio_serial_update_irq(ChannelState *s)
{
if ((s->wregs[1] & 1) && // interrupts enabled
(((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
s->rxint == 1) || // rx ints enabled, pending
((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
pic_set_irq(s->irq, 1);
} else {
pic_set_irq(s->irq, 0);
}
}
static void slavio_serial_reset_chn(ChannelState *s)
{
int i;
s->reg = 0;
for (i = 0; i < SERIAL_MAXADDR; i++) {
s->rregs[i] = 0;
s->wregs[i] = 0;
}
s->wregs[4] = 4;
s->wregs[9] = 0xc0;
s->wregs[11] = 8;
s->wregs[14] = 0x30;
s->wregs[15] = 0xf8;
s->rregs[0] = 0x44;
s->rregs[1] = 6;
s->rx = s->tx = 0;
s->rxint = s->txint = 0;
}
static void slavio_serial_reset(void *opaque)
{
SerialState *s = opaque;
slavio_serial_reset_chn(&s->chn[0]);
slavio_serial_reset_chn(&s->chn[1]);
}
static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
SerialState *ser = opaque;
ChannelState *s;
uint32_t saddr;
int newreg, channel;
val &= 0xff;
saddr = (addr & 3) >> 1;
channel = (addr & SERIAL_MAXADDR) >> 2;
s = &ser->chn[channel];
switch (saddr) {
case 0:
SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
newreg = 0;
switch (s->reg) {
case 0:
newreg = val & 7;
val &= 0x38;
switch (val) {
case 8:
s->reg |= 0x8;
break;
case 0x20:
s->rxint = 0;
break;
case 0x28:
s->txint = 0;
break;
default:
break;
}
break;
case 1 ... 8:
case 10 ... 15:
s->wregs[s->reg] = val;
break;
case 9:
switch (val & 0xc0) {
case 0:
default:
break;
case 0x40:
slavio_serial_reset_chn(&ser->chn[1]);
return;
case 0x80:
slavio_serial_reset_chn(&ser->chn[0]);
return;
case 0xc0:
slavio_serial_reset(ser);
return;
}
break;
default:
break;
}
if (s->reg == 0)
s->reg = newreg;
else
s->reg = 0;
break;
case 1:
SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
if (s->wregs[5] & 8) { // tx enabled
s->tx = val;
if (s->chr)
qemu_chr_write(s->chr, &s->tx, 1);
else if (s->type == kbd) {
handle_kbd_command(s, val);
}
s->txint = 1;
s->rregs[0] |= 4;
// Interrupts reported only on channel A
if (s->chn == 0)
s->rregs[3] |= 0x10;
else {
s->otherchn->rregs[3] |= 2;
}
slavio_serial_update_irq(s);
}
break;
default:
break;
}
}
static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
{
SerialState *ser = opaque;
ChannelState *s;
uint32_t saddr;
uint32_t ret;
int channel;
saddr = (addr & 3) >> 1;
channel = (addr & SERIAL_MAXADDR) >> 2;
s = &ser->chn[channel];
switch (saddr) {
case 0:
SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
ret = s->rregs[s->reg];
s->reg = 0;
return ret;
case 1:
SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', s->rx);
s->rregs[0] &= ~1;
if (s->type == kbd)
ret = get_queue(s);
else
ret = s->rx;
return ret;
default:
break;
}
return 0;
}
static int serial_can_receive(void *opaque)
{
ChannelState *s = opaque;
if (((s->wregs[3] & 1) == 0) // Rx not enabled
|| ((s->rregs[0] & 1) == 1)) // char already available
return 0;
else
return 1;
}
static void serial_receive_byte(ChannelState *s, int ch)
{
s->rregs[0] |= 1;
// Interrupts reported only on channel A
if (s->chn == 0)
s->rregs[3] |= 0x20;
else {
s->otherchn->rregs[3] |= 4;
}
s->rx = ch;
s->rxint = 1;
slavio_serial_update_irq(s);
}
static void serial_receive_break(ChannelState *s)
{
s->rregs[0] |= 0x80;
slavio_serial_update_irq(s);
}
static void serial_receive1(void *opaque, const uint8_t *buf, int size)
{
ChannelState *s = opaque;
serial_receive_byte(s, buf[0]);
}
static void serial_event(void *opaque, int event)
{
ChannelState *s = opaque;
if (event == CHR_EVENT_BREAK)
serial_receive_break(s);
}
static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
slavio_serial_mem_readb,
slavio_serial_mem_readb,
slavio_serial_mem_readb,
};
static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
slavio_serial_mem_writeb,
slavio_serial_mem_writeb,
slavio_serial_mem_writeb,
};
static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
{
qemu_put_be32s(f, &s->irq);
qemu_put_be32s(f, &s->reg);
qemu_put_be32s(f, &s->rxint);
qemu_put_be32s(f, &s->txint);
qemu_put_8s(f, &s->rx);
qemu_put_8s(f, &s->tx);
qemu_put_buffer(f, s->wregs, 16);
qemu_put_buffer(f, s->rregs, 16);
}
static void slavio_serial_save(QEMUFile *f, void *opaque)
{
SerialState *s = opaque;
slavio_serial_save_chn(f, &s->chn[0]);
slavio_serial_save_chn(f, &s->chn[1]);
}
static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
{
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->irq);
qemu_get_be32s(f, &s->reg);
qemu_get_be32s(f, &s->rxint);
qemu_get_be32s(f, &s->txint);
qemu_get_8s(f, &s->rx);
qemu_get_8s(f, &s->tx);
qemu_get_buffer(f, s->wregs, 16);
qemu_get_buffer(f, s->rregs, 16);
return 0;
}
static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
{
SerialState *s = opaque;
int ret;
ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
if (ret != 0)
return ret;
ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
return ret;
}
SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
{
int slavio_serial_io_memory, i;
SerialState *s;
s = qemu_mallocz(sizeof(SerialState));
if (!s)
return NULL;
slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
s->chn[0].chr = chr1;
s->chn[1].chr = chr2;
for (i = 0; i < 2; i++) {
s->chn[i].irq = irq;
s->chn[i].chn = 1 - i;
s->chn[i].type = ser;
if (s->chn[i].chr) {
qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]);
qemu_chr_add_event_handler(s->chn[i].chr, serial_event);
}
}
s->chn[0].otherchn = &s->chn[1];
s->chn[1].otherchn = &s->chn[0];
register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
qemu_register_reset(slavio_serial_reset, s);
slavio_serial_reset(s);
return s;
}
static const uint8_t keycodes[128] = {
127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
};
static void sunkbd_event(void *opaque, int ch)
{
ChannelState *s = opaque;
int release = ch & 0x80;
ch = keycodes[ch & 0x7f];
KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press");
put_queue(s, ch | release);
}
static void handle_kbd_command(ChannelState *s, int val)
{
KBD_DPRINTF("Command %d\n", val);
switch (val) {
case 1: // Reset, return type code
put_queue(s, 0xff);
put_queue(s, 0xff);
put_queue(s, 5); // Type 5
break;
case 7: // Query layout
put_queue(s, 0xfe);
put_queue(s, 0x20); // XXX, layout?
break;
default:
break;
}
}
static void sunmouse_event(void *opaque,
int dx, int dy, int dz, int buttons_state)
{
ChannelState *s = opaque;
int ch;
// XXX
ch = 0x42;
serial_receive_byte(s, ch);
}
void slavio_serial_ms_kbd_init(int base, int irq)
{
int slavio_serial_io_memory, i;
SerialState *s;
s = qemu_mallocz(sizeof(SerialState));
if (!s)
return;
for (i = 0; i < 2; i++) {
s->chn[i].irq = irq;
s->chn[i].chn = 1 - i;
s->chn[i].chr = NULL;
}
s->chn[0].otherchn = &s->chn[1];
s->chn[1].otherchn = &s->chn[0];
s->chn[0].type = mouse;
s->chn[1].type = kbd;
slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0]);
qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
qemu_register_reset(slavio_serial_reset, s);
slavio_serial_reset(s);
}

View File

@@ -1,295 +0,0 @@
/*
* QEMU Sparc SLAVIO timer controller emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_TIMER
#ifdef DEBUG_TIMER
#define DPRINTF(fmt, args...) \
do { printf("TIMER: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
/*
* Registers of hardware timer in sun4m.
*
* This is the timer/counter part of chip STP2001 (Slave I/O), also
* produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
*
* The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
* are zero. Bit 31 is 1 when count has been reached.
*
*/
typedef struct SLAVIO_TIMERState {
uint32_t limit, count, counthigh;
int64_t count_load_time;
int64_t expire_time;
int64_t stop_time, tick_offset;
QEMUTimer *irq_timer;
int irq;
int reached, stopped;
int mode; // 0 = processor, 1 = user, 2 = system
} SLAVIO_TIMERState;
#define TIMER_MAXADDR 0x1f
#define CNT_FREQ 2000000
#define MAX_CPUS 16
// Update count, set irq, update expire_time
static void slavio_timer_get_out(SLAVIO_TIMERState *s)
{
int out;
int64_t diff, ticks, count;
uint32_t limit;
// There are three clock tick units: CPU ticks, register units
// (nanoseconds), and counter ticks (500 ns).
if (s->mode == 1 && s->stopped)
ticks = s->stop_time;
else
ticks = qemu_get_clock(vm_clock) - s->tick_offset;
out = (ticks >= s->expire_time);
if (out)
s->reached = 0x80000000;
if (!s->limit)
limit = 0x7fffffff;
else
limit = s->limit;
// Convert register units to counter ticks
limit = limit >> 9;
// Convert cpu ticks to counter ticks
diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
// Calculate what the counter should be, convert to register
// units
count = diff % limit;
s->count = count << 9;
s->counthigh = count >> 22;
// Expire time: CPU ticks left to next interrupt
// Convert remaining counter ticks to CPU ticks
s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
if (s->mode != 1)
pic_set_irq(s->irq, out);
}
// timer callback
static void slavio_timer_irq(void *opaque)
{
SLAVIO_TIMERState *s = opaque;
if (!s->irq_timer)
return;
slavio_timer_get_out(s);
if (s->mode != 1)
qemu_mod_timer(s->irq_timer, s->expire_time);
}
static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
{
SLAVIO_TIMERState *s = opaque;
uint32_t saddr;
saddr = (addr & TIMER_MAXADDR) >> 2;
switch (saddr) {
case 0:
// read limit (system counter mode) or read most signifying
// part of counter (user mode)
if (s->mode != 1) {
// clear irq
pic_set_irq(s->irq, 0);
s->count_load_time = qemu_get_clock(vm_clock);
s->reached = 0;
return s->limit;
}
else {
slavio_timer_get_out(s);
return s->counthigh & 0x7fffffff;
}
case 1:
// read counter and reached bit (system mode) or read lsbits
// of counter (user mode)
slavio_timer_get_out(s);
if (s->mode != 1)
return (s->count & 0x7fffffff) | s->reached;
else
return s->count;
case 3:
// read start/stop status
return s->stopped;
case 4:
// read user/system mode
return s->mode & 1;
default:
return 0;
}
}
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
SLAVIO_TIMERState *s = opaque;
uint32_t saddr;
saddr = (addr & TIMER_MAXADDR) >> 2;
switch (saddr) {
case 0:
// set limit, reset counter
s->count_load_time = qemu_get_clock(vm_clock);
// fall through
case 2:
// set limit without resetting counter
if (!val)
s->limit = 0x7fffffff;
else
s->limit = val & 0x7fffffff;
slavio_timer_irq(s);
break;
case 3:
// start/stop user counter
if (s->mode == 1) {
if (val & 1) {
s->stop_time = qemu_get_clock(vm_clock);
s->stopped = 1;
}
else {
if (s->stopped)
s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
s->stopped = 0;
}
}
break;
case 4:
// bit 0: user (1) or system (0) counter mode
if (s->mode == 0 || s->mode == 1)
s->mode = val & 1;
break;
default:
break;
}
}
static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
slavio_timer_mem_readl,
slavio_timer_mem_readl,
slavio_timer_mem_readl,
};
static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
slavio_timer_mem_writel,
slavio_timer_mem_writel,
slavio_timer_mem_writel,
};
static void slavio_timer_save(QEMUFile *f, void *opaque)
{
SLAVIO_TIMERState *s = opaque;
qemu_put_be32s(f, &s->limit);
qemu_put_be32s(f, &s->count);
qemu_put_be32s(f, &s->counthigh);
qemu_put_be64s(f, &s->count_load_time);
qemu_put_be64s(f, &s->expire_time);
qemu_put_be64s(f, &s->stop_time);
qemu_put_be64s(f, &s->tick_offset);
qemu_put_be32s(f, &s->irq);
qemu_put_be32s(f, &s->reached);
qemu_put_be32s(f, &s->stopped);
qemu_put_be32s(f, &s->mode);
}
static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
{
SLAVIO_TIMERState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->limit);
qemu_get_be32s(f, &s->count);
qemu_get_be32s(f, &s->counthigh);
qemu_get_be64s(f, &s->count_load_time);
qemu_get_be64s(f, &s->expire_time);
qemu_get_be64s(f, &s->stop_time);
qemu_get_be64s(f, &s->tick_offset);
qemu_get_be32s(f, &s->irq);
qemu_get_be32s(f, &s->reached);
qemu_get_be32s(f, &s->stopped);
qemu_get_be32s(f, &s->mode);
return 0;
}
static void slavio_timer_reset(void *opaque)
{
SLAVIO_TIMERState *s = opaque;
s->limit = 0;
s->count = 0;
s->count_load_time = qemu_get_clock(vm_clock);;
s->stop_time = s->count_load_time;
s->tick_offset = 0;
s->reached = 0;
s->mode &= 2;
s->stopped = 1;
slavio_timer_get_out(s);
}
static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
{
int slavio_timer_io_memory;
SLAVIO_TIMERState *s;
s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
if (!s)
return;
s->irq = irq;
s->mode = mode;
s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
slavio_timer_mem_write, s);
cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
qemu_register_reset(slavio_timer_reset, s);
slavio_timer_reset(s);
}
void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2)
{
int i;
for (i = 0; i < MAX_CPUS; i++) {
slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0);
}
slavio_timer_init_internal(addr2, irq2, 2);
}

View File

@@ -1,301 +0,0 @@
/*
* QEMU Sun4m System Emulator
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t08.h"
#define KERNEL_LOAD_ADDR 0x00004000
#define CMDLINE_ADDR 0x007ff000
#define INITRD_LOAD_ADDR 0x00800000
#define PROM_ADDR 0xffd00000
#define PROM_FILENAMEB "proll.bin"
#define PROM_FILENAMEE "proll.elf"
#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */
#define PHYS_JJ_IDPROM_OFF 0x1FD8
#define PHYS_JJ_EEPROM_SIZE 0x2000
// IRQs are not PIL ones, but master interrupt controller register
// bits
#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */
#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */
#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */
#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
#define PHYS_JJ_ESP_IRQ 18
#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */
#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */
#define PHYS_JJ_LE_IRQ 16
#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */
#define PHYS_JJ_CLOCK_IRQ 7
#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */
#define PHYS_JJ_CLOCK1_IRQ 19
#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */
#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */
#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */
#define PHYS_JJ_MS_KBD_IRQ 14
#define PHYS_JJ_SER 0x71100000 /* Serial */
#define PHYS_JJ_SER_IRQ 15
#define PHYS_JJ_FDC 0x71400000 /* Floppy */
#define PHYS_JJ_FLOPPY_IRQ 22
#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */
/* TSC handling */
uint64_t cpu_get_tsc()
{
return qemu_get_clock(vm_clock);
}
int DMA_get_channel_mode (int nchan)
{
return 0;
}
int DMA_read_memory (int nchan, void *buf, int pos, int size)
{
return 0;
}
int DMA_write_memory (int nchan, void *buf, int pos, int size)
{
return 0;
}
void DMA_hold_DREQ (int nchan) {}
void DMA_release_DREQ (int nchan) {}
void DMA_schedule(int nchan) {}
void DMA_run (void) {}
void DMA_init (int high_page_enable) {}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
void *opaque)
{
}
static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value)
{
m48t08_write(nvram, addr++, (value >> 8) & 0xff);
m48t08_write(nvram, addr++, value & 0xff);
}
static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value)
{
m48t08_write(nvram, addr++, value >> 24);
m48t08_write(nvram, addr++, (value >> 16) & 0xff);
m48t08_write(nvram, addr++, (value >> 8) & 0xff);
m48t08_write(nvram, addr++, value & 0xff);
}
static void nvram_set_string (m48t08_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max)
{
unsigned int i;
for (i = 0; i < max && str[i] != '\0'; i++) {
m48t08_write(nvram, addr + i, str[i]);
}
m48t08_write(nvram, addr + max - 1, '\0');
}
static m48t08_t *nvram;
extern int nographic;
static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
int boot_device, uint32_t RAM_size,
uint32_t kernel_size,
int width, int height, int depth)
{
unsigned char tmp = 0;
int i, j;
// Try to match PPC NVRAM
nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */
// NVRAM_size, arch not applicable
m48t08_write(nvram, 0x2F, nographic & 0xff);
nvram_set_lword(nvram, 0x30, RAM_size);
m48t08_write(nvram, 0x34, boot_device & 0xff);
nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR);
nvram_set_lword(nvram, 0x3C, kernel_size);
if (cmdline) {
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
nvram_set_lword(nvram, 0x40, CMDLINE_ADDR);
nvram_set_lword(nvram, 0x44, strlen(cmdline));
}
// initrd_image, initrd_size passed differently
nvram_set_word(nvram, 0x54, width);
nvram_set_word(nvram, 0x56, height);
nvram_set_word(nvram, 0x58, depth);
// Sun4m specific use
i = 0x1fd8;
m48t08_write(nvram, i++, 0x01);
m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
j = 0;
m48t08_write(nvram, i++, macaddr[j++]);
m48t08_write(nvram, i++, macaddr[j++]);
m48t08_write(nvram, i++, macaddr[j++]);
m48t08_write(nvram, i++, macaddr[j++]);
m48t08_write(nvram, i++, macaddr[j++]);
m48t08_write(nvram, i, macaddr[j]);
/* Calculate checksum */
for (i = 0x1fd8; i < 0x1fe7; i++) {
tmp ^= m48t08_read(nvram, i);
}
m48t08_write(nvram, 0x1fe7, tmp);
}
static void *slavio_intctl;
void pic_info()
{
slavio_pic_info(slavio_intctl);
}
void irq_info()
{
slavio_irq_info(slavio_intctl);
}
void pic_set_irq(int irq, int level)
{
slavio_pic_set_irq(slavio_intctl, irq, level);
}
static void *tcx;
void vga_update_display()
{
tcx_update_display(tcx);
}
void vga_invalidate_display()
{
tcx_invalidate_display(tcx);
}
void vga_screen_dump(const char *filename)
{
tcx_screen_dump(tcx, filename);
}
static void *iommu;
uint32_t iommu_translate(uint32_t addr)
{
return iommu_translate_local(iommu, addr);
}
static void *slavio_misc;
void qemu_system_powerdown(void)
{
slavio_set_power_fail(slavio_misc, 1);
}
/* Sun4m hardware initialisation */
static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot;
unsigned int i;
long vram_size = 0x100000, prom_offset, initrd_size, kernel_size;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
iommu = iommu_init(PHYS_JJ_IOMMU);
slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
// Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
// Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
prom_offset = ram_size + vram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
ret = load_elf(buf, phys_ram_base + prom_offset);
if (ret < 0) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
ret = load_image(buf, phys_ram_base + prom_offset);
}
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
exit(1);
}
cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
kernel_size = 0;
if (linux_boot) {
kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
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);
}
/* load initrd */
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 initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
}
if (initrd_size > 0) {
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
== 0x48647253) { // HdrS
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
break;
}
}
}
}
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
}
QEMUMachine sun4m_machine = {
"sun4m",
"Sun4m platform",
sun4m_init,
};

View File

@@ -1,375 +0,0 @@
/*
* QEMU Sun4u System Emulator
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t59.h"
#define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000
#define INITRD_LOAD_ADDR 0x00300000
#define PROM_ADDR 0x1fff0000000ULL
#define APB_SPECIAL_BASE 0x1fe00000000ULL
#define APB_MEM_BASE 0x1ff00000000ULL
#define VGA_BASE (APB_MEM_BASE + 0x400000ULL)
#define PROM_FILENAMEB "proll-sparc64.bin"
#define PROM_FILENAMEE "proll-sparc64.elf"
#define NVRAM_SIZE 0x2000
/* TSC handling */
uint64_t cpu_get_tsc()
{
return qemu_get_clock(vm_clock);
}
int DMA_get_channel_mode (int nchan)
{
return 0;
}
int DMA_read_memory (int nchan, void *buf, int pos, int size)
{
return 0;
}
int DMA_write_memory (int nchan, void *buf, int pos, int size)
{
return 0;
}
void DMA_hold_DREQ (int nchan) {}
void DMA_release_DREQ (int nchan) {}
void DMA_schedule(int nchan) {}
void DMA_run (void) {}
void DMA_init (int high_page_enable) {}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
void *opaque)
{
}
/* NVRAM helpers */
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value);
}
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
{
m48t59_set_addr(nvram, addr);
return m48t59_read(nvram);
}
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 8);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, value & 0xFF);
}
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
{
uint16_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 24);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, (value >> 16) & 0xFF);
m48t59_set_addr(nvram, addr + 2);
m48t59_write(nvram, (value >> 8) & 0xFF);
m48t59_set_addr(nvram, addr + 3);
m48t59_write(nvram, value & 0xFF);
}
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
{
uint32_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 24;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram) << 16;
m48t59_set_addr(nvram, addr + 2);
tmp |= m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 3);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max)
{
int i;
for (i = 0; i < max && str[i] != '\0'; i++) {
m48t59_set_addr(nvram, addr + i);
m48t59_write(nvram, str[i]);
}
m48t59_set_addr(nvram, addr + max - 1);
m48t59_write(nvram, '\0');
}
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
{
int i;
memset(dst, 0, max);
for (i = 0; i < max; i++) {
dst[i] = NVRAM_get_byte(nvram, addr + i);
if (dst[i] == '\0')
break;
}
return i;
}
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
{
uint16_t tmp;
uint16_t pd, pd1, pd2;
tmp = prev >> 8;
pd = prev ^ value;
pd1 = pd & 0x000F;
pd2 = ((pd >> 4) & 0x000F) ^ pd1;
tmp ^= (pd1 << 3) | (pd1 << 8);
tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
return tmp;
}
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
{
uint32_t i;
uint16_t crc = 0xFFFF;
int odd;
odd = count & 1;
count &= ~1;
for (i = 0; i != count; i++) {
crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
}
if (odd) {
crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
}
return crc;
}
extern int nographic;
int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
uint32_t RAM_size, int boot_device,
uint32_t kernel_image, uint32_t kernel_size,
const char *cmdline,
uint32_t initrd_image, uint32_t initrd_size,
uint32_t NVRAM_image,
int width, int height, int depth)
{
uint16_t crc;
/* Set parameters for Open Hack'Ware BIOS */
NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
NVRAM_set_word(nvram, 0x14, NVRAM_size);
NVRAM_set_string(nvram, 0x20, arch, 16);
NVRAM_set_byte(nvram, 0x2f, nographic & 0xff);
NVRAM_set_lword(nvram, 0x30, RAM_size);
NVRAM_set_byte(nvram, 0x34, boot_device);
NVRAM_set_lword(nvram, 0x38, kernel_image);
NVRAM_set_lword(nvram, 0x3C, kernel_size);
if (cmdline) {
/* XXX: put the cmdline in NVRAM too ? */
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
} else {
NVRAM_set_lword(nvram, 0x40, 0);
NVRAM_set_lword(nvram, 0x44, 0);
}
NVRAM_set_lword(nvram, 0x48, initrd_image);
NVRAM_set_lword(nvram, 0x4C, initrd_size);
NVRAM_set_lword(nvram, 0x50, NVRAM_image);
NVRAM_set_word(nvram, 0x54, width);
NVRAM_set_word(nvram, 0x56, height);
NVRAM_set_word(nvram, 0x58, depth);
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}
void pic_info()
{
}
void irq_info()
{
}
void pic_set_irq(int irq, int level)
{
}
void pic_set_irq_new(void *opaque, int irq, int level)
{
}
void qemu_system_powerdown(void)
{
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
static const int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static const int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
static fdctrl_t *floppy_controller;
/* Sun4u hardware initialisation */
static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
m48t59_t *nvram;
int ret, linux_boot;
unsigned int i;
long prom_offset, initrd_size, kernel_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
prom_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
ret = load_elf(buf, phys_ram_base + prom_offset);
if (ret < 0) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
ret = load_image(buf, phys_ram_base + prom_offset);
}
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
exit(1);
}
cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
kernel_size = 0;
initrd_size = 0;
if (linux_boot) {
kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
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);
}
/* load initrd */
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 initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
}
if (initrd_size > 0) {
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
== 0x48647253) { // HdrS
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
break;
}
}
}
}
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE);
isa_mem_base = VGA_BASE;
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size);
//pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
}
}
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_cmd646_ide_init(pci_bus, bs_table, 1);
kbd_init();
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE);
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
KERNEL_LOAD_ADDR, kernel_size,
kernel_cmdline,
INITRD_LOAD_ADDR, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
}
QEMUMachine sun4u_machine = {
"sun4u",
"Sun4u platform",
sun4u_init,
};

327
hw/tcx.c
View File

@@ -1,327 +0,0 @@
/*
* QEMU TCX Frame buffer
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#define MAXX 1024
#define MAXY 768
#define TCX_DAC_NREGS 16
typedef struct TCXState {
uint32_t addr;
DisplayState *ds;
uint8_t *vram;
unsigned long vram_offset;
uint16_t width, height;
uint8_t r[256], g[256], b[256];
uint8_t dac_index, dac_state;
} TCXState;
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
const uint8_t *s, int width)
{
int x;
uint8_t val;
for(x = 0; x < width; x++) {
val = *s++;
*d++ = s1->b[val];
*d++ = s1->g[val];
*d++ = s1->r[val];
d++;
}
}
static void tcx_draw_line24(TCXState *s1, uint8_t *d,
const uint8_t *s, int width)
{
int x;
uint8_t val;
for(x = 0; x < width; x++) {
val = *s++;
*d++ = s1->b[val];
*d++ = s1->g[val];
*d++ = s1->r[val];
}
}
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
const uint8_t *s, int width)
{
int x;
uint8_t val;
for(x = 0; x < width; x++) {
val = *s++;
/* XXX translate between palettes? */
*d++ = val;
}
}
/* Fixed line length 1024 allows us to do nice tricks not possible on
VGA... */
void tcx_update_display(void *opaque)
{
TCXState *ts = opaque;
uint32_t page;
int y, page_min, page_max, y_start, dd, ds;
uint8_t *d, *s;
void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
if (ts->ds->depth == 0)
return;
page = ts->vram_offset;
y_start = -1;
page_min = 0x7fffffff;
page_max = -1;
d = ts->ds->data;
s = ts->vram;
dd = ts->ds->linesize;
ds = 1024;
switch (ts->ds->depth) {
case 32:
f = tcx_draw_line32;
break;
case 24:
f = tcx_draw_line24;
break;
default:
case 8:
f = tcx_draw_line8;
break;
case 0:
return;
}
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
if (y_start < 0)
y_start = y;
if (page < page_min)
page_min = page;
if (page > page_max)
page_max = page;
f(ts, d, s, ts->width);
d += dd;
s += ds;
f(ts, d, s, ts->width);
d += dd;
s += ds;
f(ts, d, s, ts->width);
d += dd;
s += ds;
f(ts, d, s, ts->width);
d += dd;
s += ds;
} else {
if (y_start >= 0) {
/* flush to display */
dpy_update(ts->ds, 0, y_start,
ts->width, y - y_start);
y_start = -1;
}
d += dd * 4;
s += ds * 4;
}
}
if (y_start >= 0) {
/* flush to display */
dpy_update(ts->ds, 0, y_start,
ts->width, y - y_start);
}
/* reset modified pages */
if (page_max != -1) {
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
}
}
void tcx_invalidate_display(void *opaque)
{
TCXState *s = opaque;
int i;
for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
cpu_physical_memory_set_dirty(s->vram_offset + i);
}
}
static void tcx_save(QEMUFile *f, void *opaque)
{
TCXState *s = opaque;
qemu_put_be32s(f, (uint32_t *)&s->addr);
qemu_put_be32s(f, (uint32_t *)&s->vram);
qemu_put_be16s(f, (uint16_t *)&s->height);
qemu_put_be16s(f, (uint16_t *)&s->width);
qemu_put_buffer(f, s->r, 256);
qemu_put_buffer(f, s->g, 256);
qemu_put_buffer(f, s->b, 256);
qemu_put_8s(f, &s->dac_index);
qemu_put_8s(f, &s->dac_state);
}
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
{
TCXState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, (uint32_t *)&s->addr);
qemu_get_be32s(f, (uint32_t *)&s->vram);
qemu_get_be16s(f, (uint16_t *)&s->height);
qemu_get_be16s(f, (uint16_t *)&s->width);
qemu_get_buffer(f, s->r, 256);
qemu_get_buffer(f, s->g, 256);
qemu_get_buffer(f, s->b, 256);
qemu_get_8s(f, &s->dac_index);
qemu_get_8s(f, &s->dac_state);
return 0;
}
static void tcx_reset(void *opaque)
{
TCXState *s = opaque;
/* Initialize palette */
memset(s->r, 0, 256);
memset(s->g, 0, 256);
memset(s->b, 0, 256);
s->r[255] = s->g[255] = s->b[255] = 255;
memset(s->vram, 0, MAXX*MAXY);
cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
VGA_DIRTY_FLAG);
s->dac_index = 0;
s->dac_state = 0;
}
static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
{
return 0;
}
static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
TCXState *s = opaque;
uint32_t saddr;
saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
switch (saddr) {
case 0:
s->dac_index = val >> 24;
s->dac_state = 0;
break;
case 1:
switch (s->dac_state) {
case 0:
s->r[s->dac_index] = val >> 24;
s->dac_state++;
break;
case 1:
s->g[s->dac_index] = val >> 24;
s->dac_state++;
break;
case 2:
s->b[s->dac_index] = val >> 24;
default:
s->dac_state = 0;
break;
}
break;
default:
break;
}
return;
}
static CPUReadMemoryFunc *tcx_dac_read[3] = {
tcx_dac_readl,
tcx_dac_readl,
tcx_dac_readl,
};
static CPUWriteMemoryFunc *tcx_dac_write[3] = {
tcx_dac_writel,
tcx_dac_writel,
tcx_dac_writel,
};
void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
unsigned long vram_offset, int vram_size, int width, int height)
{
TCXState *s;
int io_memory;
s = qemu_mallocz(sizeof(TCXState));
if (!s)
return NULL;
s->ds = ds;
s->addr = addr;
s->vram = vram_base;
s->vram_offset = vram_offset;
s->width = width;
s->height = height;
cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
qemu_register_reset(tcx_reset, s);
tcx_reset(s);
dpy_resize(s->ds, width, height);
return s;
}
void tcx_screen_dump(void *opaque, const char *filename)
{
TCXState *s = opaque;
FILE *f;
uint8_t *d, *d1, v;
int y, x;
f = fopen(filename, "wb");
if (!f)
return;
fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
d1 = s->vram;
for(y = 0; y < s->height; y++) {
d = d1;
for(x = 0; x < s->width; x++) {
v = *d;
fputc(s->r[v], f);
fputc(s->g[v], f);
fputc(s->b[v], f);
d++;
}
d1 += MAXX;
}
fclose(f);
return;
}

151
hw/vga.c
View File

@@ -28,8 +28,12 @@
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
//#define DEBUG_S3
//#define DEBUG_BOCHS_VBE
/* S3 VGA is deprecated - another graphic card will be emulated */
//#define CONFIG_S3VGA
/* force some bits to zero */
const uint8_t sr_mask[8] = {
(uint8_t)~0xfc,
@@ -220,6 +224,11 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
val = s->cr[s->cr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
#endif
#ifdef DEBUG_S3
if (s->cr_index >= 0x20)
printf("S3: CR read index=0x%x val=0x%x\n",
s->cr_index, val);
#endif
break;
case 0x3ba:
@@ -335,7 +344,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
#endif
/* handle CR0-7 protection */
if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
/* can always write bit 4 of CR7 */
if (s->cr_index == 7)
s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
@@ -350,10 +359,43 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case 0x12: /* veritcal display end */
s->cr[s->cr_index] = val;
break;
#ifdef CONFIG_S3VGA
/* S3 registers */
case 0x2d:
case 0x2e:
case 0x2f:
case 0x30:
/* chip ID, cannot write */
break;
case 0x31:
/* update start address */
{
int v;
s->cr[s->cr_index] = val;
v = (val >> 4) & 3;
s->cr[0x69] = (s->cr[69] & ~0x03) | v;
}
break;
case 0x51:
/* update start address */
{
int v;
s->cr[s->cr_index] = val;
v = val & 3;
s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
}
break;
#endif
default:
s->cr[s->cr_index] = val;
break;
}
#ifdef DEBUG_S3
if (s->cr_index >= 0x20)
printf("S3: CR write index=0x%x val=0x%x\n",
s->cr_index, val);
#endif
break;
case 0x3ba:
case 0x3da:
@@ -620,7 +662,7 @@ static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
VGAState *s = opaque;
int memory_map_mode, plane, write_mode, b, func_select, mask;
int memory_map_mode, plane, write_mode, b, func_select;
uint32_t write_mask, bit_mask, set_mask;
#ifdef DEBUG_VGA_MEM
@@ -653,26 +695,22 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
if (s->sr[4] & 0x08) {
/* chain 4 mode : simplest access */
plane = addr & 3;
mask = (1 << plane);
if (s->sr[2] & mask) {
if (s->sr[2] & (1 << plane)) {
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x%x]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
cpu_physical_memory_set_dirty(s->vram_offset + addr);
}
} else if (s->gr[5] & 0x10) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[4] & 2) | (addr & 1);
mask = (1 << plane);
if (s->sr[2] & mask) {
if (s->sr[2] & (1 << plane)) {
addr = ((addr & ~1) << 1) | plane;
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x%x]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
cpu_physical_memory_set_dirty(s->vram_offset + addr);
}
} else {
@@ -737,9 +775,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
do_write:
/* mask data according to sr[2] */
mask = s->sr[2];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
write_mask = mask16[s->sr[2]];
((uint32_t *)s->vram_ptr)[addr] =
(((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
(val & write_mask);
@@ -788,7 +824,8 @@ typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
{
return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
/* XXX: TODO */
return 0;
}
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
@@ -912,10 +949,22 @@ static void vga_get_offsets(VGAState *s,
{
/* compute line_offset in bytes */
line_offset = s->cr[0x13];
#ifdef CONFIG_S3VGA
{
uinr32_t v;
v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
if (v == 0)
v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
line_offset |= (v << 8);
}
#endif
line_offset <<= 3;
/* starting address */
start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
#ifdef CONFIG_S3VGA
start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
#endif
}
*pline_offset = line_offset;
*pstart_addr = start_addr;
@@ -1040,12 +1089,7 @@ static void vga_draw_text(VGAState *s, int full_update)
s->font_offsets[1] = offset;
full_update = 1;
}
if (s->plane_updated & (1 << 2)) {
/* if the plane 2 was modified since the last display, it
indicates the font may have been modified */
s->plane_updated = 0;
full_update = 1;
}
full_update |= update_basic_params(s);
line_offset = s->line_offset;
@@ -1303,13 +1347,11 @@ static void vga_draw_graphic(VGAState *s, int full_update)
disp_width = width;
shift_control = (s->gr[0x05] >> 5) & 3;
double_scan = (s->cr[0x09] >> 7);
if (shift_control != 1) {
multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
double_scan = (s->cr[0x09] & 0x80);
if (shift_control > 1) {
multi_scan = (s->cr[0x09] & 0x1f);
} else {
/* in CGA modes, multi_scan is ignored */
/* XXX: is it correct ? */
multi_scan = double_scan;
multi_scan = 0;
}
multi_run = multi_scan;
if (shift_control != s->shift_control ||
@@ -1376,7 +1418,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
line_offset = s->line_offset;
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
#endif
addr1 = (s->start_addr * 4);
@@ -1400,13 +1442,11 @@ static void vga_draw_graphic(VGAState *s, int full_update)
}
page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
update = full_update |
cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
update = full_update | cpu_physical_memory_is_dirty(page0) |
cpu_physical_memory_is_dirty(page1);
if ((page1 - page0) > TARGET_PAGE_SIZE) {
/* if wide line, can use another page */
update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
}
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
@@ -1429,17 +1469,21 @@ static void vga_draw_graphic(VGAState *s, int full_update)
}
}
if (!multi_run) {
mask = (s->cr[0x17] & 3) ^ 3;
if ((y1 & mask) == mask)
addr1 += line_offset;
y1++;
if (!double_scan || (y & 1) != 0) {
if (y1 == s->line_compare) {
addr1 = 0;
} else {
mask = (s->cr[0x17] & 3) ^ 3;
if ((y1 & mask) == mask)
addr1 += line_offset;
}
y1++;
}
multi_run = multi_scan;
} else {
multi_run--;
y1++;
}
/* line compare acts on the displayed lines */
if (y == s->line_compare)
addr1 = 0;
d += linesize;
}
if (y_start >= 0) {
@@ -1449,8 +1493,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
}
/* reset modified pages */
if (page_max != -1) {
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
}
memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
}
@@ -1543,6 +1586,13 @@ void vga_invalidate_display(void)
static void vga_reset(VGAState *s)
{
memset(s, 0, sizeof(VGAState));
#ifdef CONFIG_S3VGA
/* chip ID for 8c968 */
s->cr[0x2d] = 0x88;
s->cr[0x2e] = 0xb0;
s->cr[0x2f] = 0x01; /* XXX: check revision code */
s->cr[0x30] = 0xe1;
#endif
s->graphic_mode = -1; /* force full update */
}
@@ -1654,11 +1704,8 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
VGAState *s = vga_state;
if (region_num == PCI_ROM_SLOT) {
cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
} else {
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
}
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
}
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
@@ -1704,8 +1751,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size,
unsigned long vga_bios_offset, int vga_bios_size)
unsigned long vga_ram_offset, int vga_ram_size)
{
VGAState *s;
@@ -1780,17 +1826,6 @@ int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
/* XXX: vga_ram_size must be a power of two */
pci_register_io_region(d, 0, vga_ram_size,
PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
if (vga_bios_size != 0) {
unsigned int bios_total_size;
s->bios_offset = vga_bios_offset;
s->bios_size = vga_bios_size;
/* must be a power of two */
bios_total_size = 1;
while (bios_total_size < vga_bios_size)
bios_total_size <<= 1;
pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size,
PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
}
} else {
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */

Some files were not shown because too many files have changed in this diff Show More